|
|
1.1 ! root 1: /* ! 2: * Boot block. Loaded at 0x7C00 ! 3: * 8a bb.s; 8l -o bb -l -H3 -T0x7C00 bb.8 ! 4: */ ! 5: /* ! 6: * Can't write 16-bit code for 8a without getting into ! 7: * lots of bother, so define some simple commands and ! 8: * output the code directly. ! 9: * This was a mistake in so many ways it's not true. ! 10: * But I don't ever, ever have to do it again. ! 11: */ ! 12: #define rAX 0 /* rX */ ! 13: #define rCX 1 ! 14: #define rDX 2 ! 15: #define rBX 3 ! 16: #define rSP 4 /* SP */ ! 17: #define rBP 5 /* BP */ ! 18: #define rSI 6 /* SI */ ! 19: #define rDI 7 /* DI */ ! 20: ! 21: #define rAL 0 /* rL */ ! 22: #define rCL 1 ! 23: #define rDL 2 ! 24: #define rBL 3 ! 25: #define rAH 4 /* rH */ ! 26: #define rCH 5 ! 27: #define rDH 6 ! 28: #define rBH 7 ! 29: ! 30: #define rES 0 /* rS */ ! 31: #define rCS 1 ! 32: #define rSS 2 ! 33: #define rDS 3 ! 34: #define rFS 4 ! 35: #define rGS 5 ! 36: ! 37: #define OP(o, m, r, rm) BYTE $o; /* op + modr/m byte */ \ ! 38: BYTE $((m<<6)|(r<<3)|rm) ! 39: #define OPrm(o, r, m) OP(o, 0x00, r, 0x06); /* general r <-> m */ \ ! 40: WORD $m; ! 41: #define OPrr(o, r0, r1) OP(o, 0x03, r0, r1); /* general r -> r */ \ ! 42: ! 43: #define LW(m, rX) OPrm(0x8B, rX, m) /* m -> rX */ ! 44: #define LBPW(x, r) OP(0x8B, 0x02, r, 0x06);/* x(rBP) -> r */ \ ! 45: WORD $x ! 46: #define LB(m, rB) OPrm(0x8A, rB, m) /* m -> r[HL] */ ! 47: #define LBPB(x, r) OP(0x8A, 0x01, r, 0x06);/* x(rBP) -> r */ \ ! 48: BYTE $x ! 49: #define SW(rX, m) OPrm(0x89, rX, m) /* rX -> m */ ! 50: #define SBPW(r, x) OP(0x89, 0x02, r, 0x06);/* r -> x(rBP) */ \ ! 51: WORD $x ! 52: #define STB(rB, m) OPrm(0x88, rB, m) /* rB -> m */ ! 53: #define SBPB(r, x) OP(0x88, 0x01, r, 0x06);/* r -> x(rBP) */ \ ! 54: BYTE $x ! 55: #define LWI(i, rX) BYTE $(0xB8+rX); /* i -> rX */ \ ! 56: WORD $i; ! 57: #define LBI(i, rB) BYTE $(0xB0+rB); /* i -> r[HL] */ \ ! 58: BYTE $i ! 59: ! 60: #define MW(r0, r1) OPrr(0x89, r0, r1) /* r0 -> r1 */ ! 61: #define MFSR(rS, rX) OPrr(0x8C, rS, rX) /* rS -> rX */ ! 62: #define MTSR(rX, rS) OPrr(0x8E, rS, rX) /* rX -> rS */ ! 63: ! 64: #define ADC(r0, r1) OPrr(0x11, r0, r1) /* r0 + r1 -> r1 */ ! 65: #define ADD(r0, r1) OPrr(0x01, r0, r1) /* r0 + r1 -> r1 */ ! 66: #define AND(r0, r1) OPrr(0x21, r0, r1) /* r0 & r1 -> r1 */ ! 67: #define ANDI(i, r) OP(0x81, 0x03, 0x04, r);/* i & r -> r */ \ ! 68: WORD $i; ! 69: #define CLR(r) OPrr(0x31, r, r) /* r^r -> r */ ! 70: #define CLRB(r) OPrr(0x30, r, r) /* r^r -> r */ ! 71: #define CMP(r0, r1) OPrr(0x39, r0, r1) /* r1 - r0 -> flags */ ! 72: #define CMPB(r0, r1) OPrr(0x38, r0, r1) /* r1 - r0 -> flags */ ! 73: #define DEC(r) BYTE $(0x48|r) /* r-1 -> r */ ! 74: #define DIV(r) OPrr(0xF7, 0x06, r) /* rAX/r -> rDX:rAX */ ! 75: #define INC(r) BYTE $(0x40|r) /* r+1 -> r */ ! 76: #define MUL(r) OPrr(0xF7, 0x04, r) /* r * rAX -> rDX:rAX */ ! 77: #define OR(r0, r1) OPrr(0x09, r0, r1) /* r0|r1 -> r1 */ ! 78: #define ORB(r0, r1) OPrr(0x08, r0, r1) /* r0|r1 -> r1 */ ! 79: #define ROLI(i, r) OPrr(0xC1, 0x00, r); /* r<<>>i -> r */ \ ! 80: BYTE $i; ! 81: #define SHLI(i, r) OPrr(0xC1, 0x04, r); /* r<<i -> r */ \ ! 82: BYTE $i; ! 83: #define SHLBI(i, r) OPrr(0xC0, 0x04, r); /* r<<i -> r */ \ ! 84: BYTE $i; ! 85: ! 86: #define CALL(f) LWI(f, rDI); /* &f -> rDI */ \ ! 87: BYTE $0xFF; /* (*rDI) */ \ ! 88: BYTE $0xD7; ! 89: #define FARJUMP(s, o) BYTE $0xEA; /* far jump to s:o */ \ ! 90: WORD $o; WORD $s ! 91: #define DELAY BYTE $0xEB; /* jmp .+2 */ \ ! 92: BYTE $0x00 ! 93: #define SYSCALL(b) INT $b /* INT $b */ ! 94: ! 95: #define POKEW BYTE $0x26; /* MOVW rAX, rES:[rBX] */ \ ! 96: BYTE $0x89; BYTE $0x07 ! 97: #define OUTB(p, d) LBI(d, rAL); /* d -> I/O port p */ \ ! 98: BYTE $0xE6; \ ! 99: BYTE $p; DELAY ! 100: #define PUSHA BYTE $0x60 ! 101: #define PUSHW(r) BYTE $(0x50|r) /* r -> (--rSP) */ ! 102: #define POPA BYTE $0x61 ! 103: #define POPW(r) BYTE $(0x58|r) /* (rSP++) -> r */ ! 104: #define NOP BYTE $0x90 /* nop */ ! 105: ! 106: /* ! 107: * Now on to the real work. ! 108: * If you're stilll reading, you have a ! 109: * stomach of steel. ! 110: */ ! 111: #define RDIRBUF 0x00200 /* where to read the root directory (offset) */ ! 112: #define CODEBUF 0x10000 /* where to load code (64Kb) */ ! 113: ! 114: /* ! 115: * MS-DOS directory entry. ! 116: */ ! 117: #define Dname 0x00 ! 118: #define Dext 0x08 ! 119: #define Dattr 0x0B ! 120: #define Dtime 0x16 ! 121: #define Ddate 0x18 ! 122: #define Dstart 0x1A ! 123: #define Dlengthlo 0x1C ! 124: #define Dlengthhi 0x1E ! 125: ! 126: #define Dirsz 0x20 ! 127: ! 128: /* ! 129: * We keep data on the stack, indexed by rBP. ! 130: */ ! 131: #define Xdrive 0x00 /* boot drive, passed by BIOS in rDL */ ! 132: #define Xrootlo 0x02 /* offset of root directory */ ! 133: #define Xroothi 0x04 ! 134: #define Xrootsz 0x06 /* file data area */ ! 135: #define Xtotal 0x08 /* sum of allocated data above */ ! 136: ! 137: TEXT _magic(SB), $0 ! 138: BYTE $0xEB; BYTE $0x3C; /* jmp .+ 0x3C (_start0x3E) */ ! 139: BYTE $0x90 /* nop */ ! 140: TEXT _version(SB), $0 ! 141: BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00; ! 142: BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00 ! 143: TEXT _sectsize(SB), $0 ! 144: BYTE $0x00; BYTE $0x00 ! 145: TEXT _clustsize(SB), $0 ! 146: BYTE $0x00 ! 147: TEXT _nresrv(SB), $0 ! 148: BYTE $0x00; BYTE $0x00 ! 149: TEXT _nfats(SB), $0 ! 150: BYTE $0x00 ! 151: TEXT _rootsize(SB), $0 ! 152: BYTE $0x00; BYTE $0x00 ! 153: TEXT _volsize(SB), $0 ! 154: BYTE $0x00; BYTE $0x00 ! 155: TEXT _mediadesc(SB), $0 ! 156: BYTE $0x00 ! 157: TEXT _fatsize(SB), $0 ! 158: BYTE $0x00; BYTE $0x00 ! 159: TEXT _trksize(SB), $0 ! 160: BYTE $0x00; BYTE $0x00 ! 161: TEXT _nheads(SB), $0 ! 162: BYTE $0x00; BYTE $0x00 ! 163: TEXT _nhiddenlo(SB), $0 ! 164: BYTE $0x00; BYTE $0x00 ! 165: TEXT _nhiddenhi(SB), $0 ! 166: BYTE $0x00; BYTE $0x00; ! 167: TEXT _bigvolsize(SB), $0 ! 168: BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00; ! 169: TEXT _driveno(SB), $0 ! 170: BYTE $0x00 ! 171: TEXT _reserved0(SB), $0 ! 172: BYTE $0x00 ! 173: TEXT _bootsig(SB), $0 ! 174: BYTE $0x00 ! 175: TEXT _volid(SB), $0 ! 176: BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00; ! 177: TEXT _label(SB), $0 ! 178: BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00; ! 179: BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00 ! 180: BYTE $0x00; BYTE $0x00; BYTE $0x00 ! 181: TEXT _type(SB), $0 ! 182: BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00; ! 183: BYTE $0x00; BYTE $0x00; BYTE $0x00; BYTE $0x00; ! 184: ! 185: _start0x3E: ! 186: CLI ! 187: MFSR(rCS, rAX) /* set the data and stack segments */ ! 188: MTSR(rAX, rDS) ! 189: MTSR(rAX, rSS) ! 190: MTSR(rAX, rES) ! 191: LWI(_magic-Xtotal(SB), rSP) ! 192: MW(rSP, rBP) /* set the indexed-data pointer */ ! 193: ! 194: SBPB(rDL, Xdrive) /* save the boot drive */ ! 195: ! 196: STI ! 197: ! 198: LWI(confidence(SB), rSI) /* for that warm, fuzzy feeling */ ! 199: CALL(BIOSputs(SB)) ! 200: ! 201: CLR(rAX) /* rAH == 0 == reset disc system */ ! 202: PUSHW(rBP) /* may be trashed by SYSCALL */ ! 203: SYSCALL(0x13) /* rDL == boot drive */ ! 204: POPW(rBP) ! 205: ORB(rAH, rAH) /* status (0 == successful completion) */ ! 206: JEQ _jmp00 /* can't rely on 8l doing other than short jumps */ ! 207: CALL(buggery(SB)) ! 208: ! 209: _jmp00: ! 210: CLR(rAX) ! 211: ! 212: LB(_nfats(SB), rAL) /* calculate root directory offset */ ! 213: LW(_fatsize(SB), rCX) ! 214: MUL(rCX) ! 215: LW(_nhiddenlo(SB), rCX) ! 216: ADD(rCX, rAX) ! 217: LW(_nhiddenhi(SB), rCX) ! 218: ADC(rCX, rDX) ! 219: LW(_nresrv(SB), rCX) ! 220: ADD(rCX, rAX) ! 221: LWI(0x0000, rCX) /* don't set flags */ ! 222: ADC(rCX, rDX) ! 223: ! 224: SBPW(rAX, Xrootlo) /* save */ ! 225: SBPW(rDX, Xroothi) ! 226: ! 227: LWI(_magic+RDIRBUF(SB), rBX) ! 228: CALL(BIOSread(SB)) /* read the root directory */ ! 229: ! 230: LWI(_magic+RDIRBUF(SB), rDI) /* compare first directory entry */ ! 231: LWI(bootfile(SB), rSI) ! 232: LWI(Dattr, rCX) ! 233: REP ! 234: CMPSB ! 235: JEQ _jmp02 ! 236: CALL(buggery(SB)) ! 237: ! 238: _jmp02: ! 239: CLR(rBX) /* a handy value */ ! 240: LW(_rootsize(SB), rAX) /* calculate and save Xrootsz */ ! 241: LWI(Dirsz, rCX) ! 242: MUL(rCX) ! 243: LW(_sectsize(SB), rCX) ! 244: DEC(rCX) ! 245: ADD(rCX, rAX) ! 246: ADC(rBX, rDX); ! 247: LW(_sectsize(SB), rCX) ! 248: DIV(rCX) ! 249: SBPW(rAX, Xrootsz) ! 250: ! 251: LW(_magic+(RDIRBUF+Dstart)(SB), rAX) /* calculate starting sector address */ ! 252: DEC(rAX) /* that's just the way it is... */ ! 253: DEC(rAX) ! 254: LB(_clustsize(SB), rCL) ! 255: CLRB(rCH) ! 256: MUL(rCX) ! 257: LBPW(Xrootlo, rCX) ! 258: ADD(rCX, rAX) ! 259: LBPW(Xroothi, rCX) ! 260: ADC(rCX, rDX) ! 261: LBPW(Xrootsz, rCX) ! 262: ADD(rCX, rAX) ! 263: ADC(rBX, rDX); ! 264: ! 265: PUSHW(rAX) ! 266: PUSHW(rDX) ! 267: LW(_magic+(RDIRBUF+Dlengthlo)(SB), rAX) /* calculate how many sectors to read */ ! 268: LW(_magic+(RDIRBUF+Dlengthhi)(SB), rDX) ! 269: LW(_sectsize(SB), rCX) ! 270: DEC(rCX) ! 271: ADD(rCX, rAX) ! 272: ADC(rBX, rDX); ! 273: LW(_sectsize(SB), rCX) ! 274: DIV(rCX) ! 275: MW(rAX, rCX) ! 276: POPW(rDX) ! 277: POPW(rAX) ! 278: ! 279: LWI((CODEBUF/16), rBX) /* address to load into (seg + offset) */ ! 280: MTSR(rBX, rES) ! 281: LWI(0x0100, rBX) ! 282: ! 283: _readboot: ! 284: CALL(BIOSread(SB)) /* read the sector */ ! 285: ! 286: LW(_sectsize(SB), rDI) /* bump addresses/counts */ ! 287: ADD(rDI, rBX) ! 288: INC(rAX) ! 289: LWI(0x0000, rDI) /* don't set flags */ ! 290: ADC(rDI, rDX) ! 291: LOOP _readboot ! 292: ! 293: LWI((CODEBUF/16), rDI) /* set rDS for loaded code */ ! 294: MTSR(rDI, rDS) ! 295: FARJUMP((CODEBUF/16), 0x0100) /* no deposit, no return */ ! 296: ! 297: TEXT buggery(SB), $0 ! 298: LWI(error(SB), rSI) ! 299: CALL(BIOSputs(SB)) ! 300: ! 301: _wait: ! 302: CLR(rAX) /* wait for any key */ ! 303: SYSCALL(0x16) ! 304: ! 305: _reset: ! 306: CLR(rBX) /* set ES segment for BIOS area */ ! 307: MTSR(rBX, rES) ! 308: ! 309: LWI(0x0472, rBX) /* warm-start code address */ ! 310: LWI(0x1234, rAX) /* warm-start code */ ! 311: POKEW /* MOVW AX, ES:[BX] */ ! 312: ! 313: FARJUMP(0xFFFF, 0x0000) /* reset */ ! 314: ! 315: ! 316: /* ! 317: * Read a sector from a disc. On entry: ! 318: * rDX:rAX sector number ! 319: * rES:rBX buffer address ! 320: * For SYSCALL(0x13): ! 321: * rAH 0x02 ! 322: * rAL number of sectors to read (1) ! 323: * rCH low 8 bits of cylinder ! 324: * rCL high 2 bits of cylinder (7-6), sector (5-0) ! 325: * rDH head ! 326: * rDL drive ! 327: * rES:rBX buffer address ! 328: */ ! 329: TEXT BIOSread(SB), $0 ! 330: PUSHA /* may be trashed by SYSCALL */ ! 331: ! 332: LW(_trksize(SB), rDI) /* rDI is scratch */ ! 333: DIV(rDI) /* track -> rAX, sector -> rDX */ ! 334: ! 335: INC(rDX) /* sector numbers are 1-based */ ! 336: MW(rDX, rCX) ! 337: ANDI(0x003F, rCX) /* form sector bits in rCL */ ! 338: ! 339: CLR(rDX) ! 340: LW(_nheads(SB), rDI) ! 341: DIV(rDI) /* cylinder -> rAX, head -> rDX */ ! 342: ! 343: SHLBI(0x06, rAH) /* form cylinder hi and lo bits */ ! 344: ROLI(0x08, rAX) /* swap rA[HL] */ ! 345: OR(rAX, rCX) /* rCH, rCL now set */ ! 346: ! 347: SHLI(0x08, rDX) /* form head */ ! 348: LBPB(Xdrive, rDL) /* form drive */ ! 349: ! 350: LWI(0x0201, rAX) /* form command and sectors */ ! 351: SYSCALL(0x13) /* CF set on failure */ ! 352: JCC _BIOSreadret ! 353: CALL(buggery(SB)) ! 354: ! 355: _BIOSreadret: ! 356: POPA ! 357: RET ! 358: ! 359: /* ! 360: * Output a string to the display. ! 361: * String argument is in rSI. ! 362: */ ! 363: TEXT BIOSputs(SB), $0 ! 364: PUSHA ! 365: CLR(rBX) ! 366: _BIOSputs: ! 367: LODSB ! 368: ORB(rAL, rAL) ! 369: JEQ _BIOSputsret ! 370: ! 371: LBI(0x0E, rAH) ! 372: SYSCALL(0x10) ! 373: JMP _BIOSputs ! 374: ! 375: _BIOSputsret: ! 376: POPA ! 377: RET ! 378: ! 379: TEXT error(SB), $0 ! 380: BYTE $'N'; BYTE $'o'; BYTE $'t'; BYTE $' '; BYTE $'a'; BYTE $' '; BYTE $'b'; BYTE $'o'; ! 381: BYTE $'o'; BYTE $'t'; BYTE $'a'; BYTE $'b'; BYTE $'l'; BYTE $'e'; BYTE $' '; BYTE $'d'; ! 382: BYTE $'i'; BYTE $'s'; BYTE $'c'; BYTE $' '; BYTE $'o'; BYTE $'r'; BYTE $' '; BYTE $'d'; ! 383: BYTE $'i'; BYTE $'s'; BYTE $'c'; BYTE $' '; BYTE $'e'; BYTE $'r'; BYTE $'r'; BYTE $'o'; ! 384: BYTE $'r'; BYTE $'\r';BYTE $'\n';BYTE $'P'; BYTE $'r'; BYTE $'e'; BYTE $'s'; BYTE $'s'; ! 385: BYTE $' '; BYTE $'a'; BYTE $'l'; BYTE $'m'; BYTE $'o'; BYTE $'s'; BYTE $'t'; BYTE $' '; ! 386: BYTE $'a'; BYTE $'n'; BYTE $'y'; BYTE $' '; BYTE $'k'; BYTE $'e'; BYTE $'y'; BYTE $' '; ! 387: BYTE $'t'; BYTE $'o'; BYTE $' '; BYTE $'r'; BYTE $'e'; BYTE $'b'; BYTE $'o'; BYTE $'o'; ! 388: BYTE $'t'; BYTE $'.'; BYTE $'.'; BYTE $'.'; ! 389: BYTE $'\z'; ! 390: ! 391: TEXT bootfile(SB), $0 ! 392: BYTE $'B'; BYTE $' '; BYTE $' '; BYTE $' '; BYTE $' '; BYTE $' '; BYTE $' '; BYTE $' '; ! 393: BYTE $'C'; BYTE $'O'; BYTE $'M'; ! 394: BYTE $'\z'; ! 395: ! 396: TEXT confidence(SB), $0 ! 397: BYTE $'B'; BYTE $'o'; BYTE $'o'; BYTE $'t'; BYTE $'i'; BYTE $'n'; BYTE $'g'; BYTE $'.'; ! 398: BYTE $'.'; BYTE $'.'; BYTE $'\r';BYTE $'\n'; ! 399: BYTE $'\z';
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.