|
|
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.