1/* 2 * Debugging boot sector. Reads the first directory 3 * sector from disk and displays it. 4 * 5 * It relies on the _volid field in the FAT header containing 6 * the LBA of the root directory. 7 */ 8#include "x16.h" 9 10#define DIROFF 0x00200 /* where to read the root directory (offset) */ 11#define LOADSEG (0x10000/16) /* where to load code (64KB) */ 12#define LOADOFF 0 13 14/* 15 * FAT directory entry. 16 */ 17#define Dname 0x00 18#define Dext 0x08 19#define Dattr 0x0B 20#define Dtime 0x16 21#define Ddate 0x18 22#define Dstart 0x1A 23#define Dlengthlo 0x1C 24#define Dlengthhi 0x1E 25 26#define Dirsz 0x20 27 28/* 29 * We keep data on the stack, indexed by rBP. 30 */ 31#define Xdrive 0x00 /* boot drive, passed by BIOS in rDL */ 32#define Xrootlo 0x02 /* offset of root directory */ 33#define Xroothi 0x04 34#define Xrootsz 0x06 /* file data area */ 35#define Xtotal 0x08 /* sum of allocated data above */ 36#define Xdap 0x00 /* disc address packet */ 37 38TEXT _magic(SB), $0 39 BYTE $0xEB; BYTE $0x3C; /* jmp .+ 0x3C (_start0x3E) */ 40 BYTE $0x90 /* nop */ 41TEXT _version(SB), $0 42 BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00; 43 BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00 44TEXT _sectsize(SB), $0 45 BYTE $0x00; BYTE $0x00 46TEXT _clustsize(SB), $0 47 BYTE $0x00 48TEXT _nresrv(SB), $0 49 BYTE $0x00; BYTE $0x00 50TEXT _nfats(SB), $0 51 BYTE $0x00 52TEXT _rootsize(SB), $0 53 BYTE $0x00; BYTE $0x00 54TEXT _volsize(SB), $0 55 BYTE $0x00; BYTE $0x00 56TEXT _mediadesc(SB), $0 57 BYTE $0x00 58TEXT _fatsize(SB), $0 59 BYTE $0x00; BYTE $0x00 60TEXT _trksize(SB), $0 61 BYTE $0x00; BYTE $0x00 62TEXT _nheads(SB), $0 63 BYTE $0x00; BYTE $0x00 64TEXT _nhiddenlo(SB), $0 65 BYTE $0x00; BYTE $0x00 66TEXT _nhiddenhi(SB), $0 67 BYTE $0x00; BYTE $0x00; 68TEXT _bigvolsize(SB), $0 69 BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00; 70TEXT _driveno(SB), $0 71 BYTE $0x00 72TEXT _reserved0(SB), $0 73 BYTE $0x00 74TEXT _bootsig(SB), $0 75 BYTE $0x00 76TEXT _volid(SB), $0 77 BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00; 78TEXT _label(SB), $0 79 BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00; 80 BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00 81 BYTE $0x00; BYTE $0x00; BYTE $0x00 82TEXT _type(SB), $0 83 BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00; 84 BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00; 85 86_start0x3E: 87 CLI 88 CLR(rAX) 89 MTSR(rAX, rSS) /* 0000 -> rSS */ 90 MTSR(rAX, rDS) /* 0000 -> rDS, source segment */ 91 MTSR(rAX, rES) 92 LWI(_magic-Xtotal(SB), rSP) 93 MW(rSP, rBP) /* set the indexed-data pointer */ 94 SBPB(rDL, Xdrive) /* save the boot drive */ 95 96 /* VMware starts us at 7C0:0. Move to 0:7C00 */ 97 PUSHR(rAX) 98 LWI(_nxt(SB), rAX) 99 PUSHR(rAX) 100 BYTE $0xCB /* FAR RET */ 101 102TEXT _nxt(SB), $0 103 STI 104 LWI(confidence(SB), rSI) /* for that warm, fuzzy feeling */ 105 CALL16(BIOSputs(SB)) 106 107 CALL16(dreset(SB)) 108 109_jmp00: 110 LW(_volid(SB), rAX) /* Xrootlo */ 111 LW(_volid+2(SB), rDX) /* Xroothi */ 112 113 LWI(_magic+DIROFF(SB), rBX) 114 CALL16(BIOSread(SB)) /* read the root directory */ 115 116 CALL16(printnl(SB)) 117 LWI(_magic+DIROFF(SB), rBX) 118 LWI((512/2), rCX) 119 CALL16(printbuf(SB)) 120 121xloop: 122 JMP xloop 123 124 125TEXT buggery(SB), $0 126 LWI(error(SB), rSI) 127 CALL16(BIOSputs(SB)) 128 129TEXT quietbuggery(SB), $0 130xbuggery: 131 JMP xbuggery 132 133/* 134 * Read a sector from a disc. On entry: 135 * rDX:rAX sector number 136 * rES:rBX buffer address 137 * For BIOSCALL(0x13): 138 * rAH 0x02 139 * rAL number of sectors to read (1) 140 * rCH low 8 bits of cylinder 141 * rCL high 2 bits of cylinder (7-6), sector (5-0) 142 * rDH head 143 * rDL drive 144 * rES:rBX buffer address 145 */ 146TEXT BIOSread(SB), $0 147 LWI(5, rDI) /* retry count (ATAPI ZIPs suck) */ 148_retry: 149 PUSHA /* may be trashed by BIOSCALL */ 150 PUSHR(rBX) 151 152 LW(_trksize(SB), rBX) 153 LW(_nheads(SB), rDI) 154 IMUL(rDI, rBX) 155 OR(rBX, rBX) 156 JZ _ioerror 157 158_okay: 159 DIV(rBX) /* cylinder -> rAX, track,sector -> rDX */ 160 161 MW(rAX, rCX) /* save cylinder */ 162 ROLI(0x08, rCX) /* swap rC[HL] */ 163 SHLBI(0x06, rCL) /* move high bits up */ 164 165 MW(rDX, rAX) 166 CLR(rDX) 167 LW(_trksize(SB), rBX) 168 169 DIV(rBX) /* head -> rAX, sector -> rDX */ 170 171 INC(rDX) /* sector numbers are 1-based */ 172 ANDI(0x003F, rDX) /* should not be necessary */ 173 OR(rDX, rCX) 174 175 MW(rAX, rDX) 176 SHLI(0x08, rDX) /* form head */ 177 LBPB(Xdrive, rDL) /* form drive */ 178 179 POPR(rBX) 180 LWI(0x0201, rAX) /* form command and sectors */ 181 BIOSCALL(0x13) /* CF set on failure */ 182 JCC _BIOSreadret 183 184 POPA 185 DEC(rDI) /* too many retries? */ 186 JEQ _ioerror 187 188 CALL16(dreset(SB)) 189 JMP _retry 190 191_ioerror: 192 LWI(ioerror(SB), rSI) 193 CALL16(BIOSputs(SB)) 194 JMP xbuggery 195 196_BIOSreadret: 197 POPA 198 RET 199 200TEXT dreset(SB), $0 201 PUSHA 202 CLR(rAX) /* rAH == 0 == reset disc system */ 203 LBPB(Xdrive, rDL) 204 BIOSCALL(0x13) 205 ORB(rAH, rAH) /* status (0 == success) */ 206 POPA 207 JNE _ioerror 208 RET 209 210TEXT printsharp(SB), $0 211 LWI(sharp(SB), rSI) 212_doprint: 213 CALL16(BIOSputs(SB)) 214 RET 215 216TEXT printspace(SB), $0 217 LWI(space(SB), rSI) 218 JMP _doprint 219 220TEXT printnl(SB), $0 221 LWI(nl(SB), rSI) 222 JMP _doprint 223 224/* 225 * Output a string to the display. 226 * String argument is in rSI. 227 */ 228TEXT BIOSputs(SB), $0 229 PUSHA 230 CLR(rBX) 231_BIOSputs: 232 LODSB 233 ORB(rAL, rAL) 234 JEQ _BIOSputsret 235 236 LBI(0x0E, rAH) 237 BIOSCALL(0x10) 238 JMP _BIOSputs 239 240_BIOSputsret: 241 POPA 242 RET 243 244/* 245 * Output a register to the display. 246 */ 247TEXT printAX(SB), $0 248 PUSHW(rAX) 249 PUSHW(rBX) 250 PUSHW(rCX) 251 PUSHW(rDI) 252 253 LWI(4, rCX) 254 LWI(numbuf+4(SB), rSI) 255 256_nextchar: 257 DEC(rSI) 258 MW(rAX, rBX) 259 ANDI(0x000F, rBX) 260 ADDI(0x30, rBX) /* 0x30 = '0' */ 261 CMPI(0x39, rBX) /* 0x39 = '9' */ 262 JLE _dowrite 263 ADDI(0x07, rBX) /* 0x07 = 'A'-(1+'9')*/ 264 265_dowrite: 266 SXB(rBL, 0, xSI) 267 SHRI(4, rAX) 268 269 DEC(rCX) 270 JNE _nextchar 271 272 LWI(numbuf(SB), rSI) 273 CALL16(BIOSputs(SB)) 274 275 POPW(rDI) 276 POPW(rCX) 277 POPW(rBX) 278 POPW(rAX) 279 280 CALL16(printspace(SB)) 281 RET 282 283TEXT printDXAX(SB), $0 284 PUSHW(rAX) 285 MW(rDX, rAX) 286 CALL16(printAX(SB)) 287 POPW(rAX) 288 CALL16(printAX(SB)) 289 RET 290 291TEXT printBX(SB), $0 292 PUSHW(rAX) 293 MW(rBX, rAX) 294 CALL16(printAX(SB)) 295 POPW(rAX) 296 RET 297 298/* 299 * Output some number of words to the display 300 * rDS:rDI - buffer 301 * rCX: number of words 302 */ 303TEXT printbuf(SB), $0 304 PUSHW(rAX) 305 PUSHW(rBX) 306 PUSHW(rCX) 307 308_nextword: 309 LXW(0, xBX, rAX) 310 CALL16(printAX(SB)) 311 INC(rBX) 312 INC(rBX) 313 DEC(rCX) 314 JNE _nextword 315 316 POPW(rCX) 317 POPW(rBX) 318 POPW(rAX) 319 RET 320 321TEXT error(SB), $0 322 BYTE $'E'; 323 324TEXT ioerror(SB), $0 325 BYTE $'I'; 326 327TEXT nl(SB), $0 328 BYTE $'\r'; 329 BYTE $'\n'; 330 BYTE $'\z'; 331 332TEXT numbuf(SB), $0 333 BYTE $'X'; BYTE $'X'; BYTE $'X'; BYTE $'X'; 334 BYTE $'\z'; 335 336TEXT space(SB), $0 337 BYTE $' '; 338 BYTE $'\z'; 339 340TEXT sharp(SB), $0 341 BYTE $'#'; BYTE $'\z'; 342 343TEXT confidence(SB), $0 344 BYTE $'P'; BYTE $'\z' 345