|
|
1.1 root 1: ////////
2: /
3: / Patched bootstrap block for the IBM PC.
4: / This code, which lives in sector 1,
5: / track 0 of the floppy (or sector 1 of a hard disk partition)
6: / gets read into location 0x7C00 by the ROM.
7: / The code relocates itself to location 0x2060:0x0000
8: / (128K above the fixed memory used by the ROM). The system image is read
9: / in beginning at paragraph 0x0060.
10: /
11: / $Log: /newbits/conf/boot/RCS/pboot.m,v $
12: * Revision 1.2 91/05/29 09:42:16 bin
13: * bob h modified due to commented lines screwing the makefile
14: *
15: / * Revision 1.1 91/05/29 08:30:45 bin
16: / * Initial revision
17: / *
18: / Revision 1.1 88/03/24 16:44:09 src
19: / Initial revision
20: /
21: / 87/10/04 Allan Cornish /usr/src/sys/i8086/boot/boot.s
22: / Number of heads now defined by NHD macro. Should be 1 for f*d*, 2 for f*a*.
23: /
24: / 85/10/04 Allan Cornish /usr/src/sys/i8086/boot/boot.s
25: / Bootstrap extended to increase max file size from 64 Kbytes to 128 Kbytes.
26: / The private code segment is now loaded, where previously it had to be empty.
27: / File name editing enhanced to help cursor stay in the 14 char entry field,
28: / and to provide a destructive backspace.
29: /
30: / 85/01/04 Allan Cornish
31: / Added backspace editing of file name.
32: /
33: ////////
34:
35: ////////
36: / This is a patched version for machines with incorrect CMOS disk parameters.
37: / The values in traks, sects, heads, cntrl and wpcc are assumed correct.
38: / This BIOS is not interrogated to find the disk parameters.
39: / The controller is reset with the appropriate values.
40: ////////
41:
42: #ifndef NHD
43: #define NHD 1 / heads per drive [1 for f9d0].
44: #endif
45:
46: #ifndef NSPT
47: #define NSPT 9 / sectors per track on floppy.
48: #define NTRK 40 / tracks on floppy.
49: #endif
50:
51: #ifndef CNTRL
52: #define CNTRL 8
53: #endif
54:
55: #ifndef WPCC
56: #define WPCC 0xFFFF
57: #endif
58:
59: NSTK = 256 / bytes of stack.
60: BS = 0x08 / BS character.
61: CR = 0x0D / CR character.
62: LF = 0x0A / LF character.
63: SP = 0x20 / Backspace character.
64: BOOTLC = 0x7C00 / Boot location (ROM).
65: BOOTS = 0 / boot segment (ROM).
66: RBOOTS = 0x2060 / Relocated boot segment.
67: BSHIFT = 9 / Shift, bytes to blocks.
68: ROOTINO = 2 / Root inode #
69: INOORG = 2 / First inode block.
70: IBSHIFT = 3 / Shift, inode to blocks
71: IOSHIFT = 6 / Shift, inode to bytes
72: INOMASK = 0x0007 / Mask, inode to offset
73: DIRSIZE = 14 / Directory size.
74: DIRSIZ2 = 7 / Directory size / 2.
75: BUFSIZE = 512 / Block size.
76: HDRSIZE = 44 / L.out header size.
77: HDRSIZ2 = 22 / L.out header size / 2.
78: BUFMSK2 = 0x00FF / Block [word] mask, for reads.
79: DISK = 0x13 / Disk Interrupt
80: KEYBD = 0x16 / Keyboard Interrupt
81: READ1 = 0x0201 / read one sector
82: ND = 10 / # of direct blocks.
83: NIND = 128 / # of blocks in indirect block.
84: ISIZE = 8 / Offset of "di_size".
85: IADDR = 12 / Offset of "di_addr".
86: JMPF = 0xEA / Jump far, direct.
87: LMAGIC = 0 / Offset of "l_magic"
88: LFLAG = 2 / Offset of "l_flag"
89: LSHRI = 10 / Offset of "l_ssize[SHRI]"
90: LPRVI = 14 / Offset of "l_ssize[PRVI]"
91: LSHRD = 22 / Offset of "l_ssize[SHRD]"
92: LPRVD = 26 / Offset of "l_ssize[PRVD]"
93: LBSSD = 30 / Offset of "l_ssize[BSSD]"
94: LFMAG = 0x0107 / Magic number.
95: LFSEP = 0x02 / Sep I/D flag bit.
96: SYSBASE = 0x0060 / System load base paragraph.
97: FIRST = 8 / relative start of partition
98:
99: / Hard disk controller port addresses.
100: HF_REG = 0x3F6
101: NSEC_REG= 0x1F2
102: SEC_REG = 0x1F3
103: HDRV_REG= 0x1F6
104: CSR_REG = 0x1F7
105: BSY_ST = 0x80
106: SETPARM_CMD= 0x91
107:
108: ////////
109: /
110: / Bootstrap mainline. Relocate the
111: / boot to high memory, so it wont be written
112: / over by the system. Read in a file name. Look up
113: / the file name by following out the directory
114: / structure. Read in the image and jump to it.
115: /
116: ////////
117:
118: boot: xor di, di
119: mov ds, di
120: mov si, $BOOTLC / Make DS:SI point at the code
121: mov es, 1f(si) / Make ES:DI point at where it goes
122: mov cx, $512 / cx = # of bytes to move
123: cld
124: rep / Move the bootstrap
125: movsb / to high memory.
126:
127: mov si, bp / set si to partition
128: mov di, $drive / point to drive
129: movsb / set drive
130: add si, $FIRST-1 / point to first block
131: movsw
132: movsw / fetch first block
133:
134: / Bang on disk controller.
135: / See at.c/atreset().
136: #if 1
137: movb al, $4
138: mov dx, $HF_REG
139: outb dx, al / outb (HF_REG, 4);
140: mov cx, $-1
141: 0: loop 0b / delay
142: movb al, cntrl
143: andb al, $0x0F
144: outb dx, al / outb (HF_REG, ctrl & 0xF);
145: / call atbsyw
146:
147: / Wait for AT controller to become not busy.
148: / From atas.s.
149: / atbsyw:
150: mov cx, $-1
151: mov dx, $CSR_REG
152: 0: inb al, dx
153: testb al, $BSY_ST
154: loopne 0b
155: mov ax, cx
156: / ret
157: #endif
158: movb al, cntrl
159: mov dx, $HF_REG
160: outb dx, al / outb(HF_REG, cntrl);
161: movb al, sects
162: mov dx, $NSEC_REG
163: outb dx, al / outb(NSEC_REG, sects);
164: / The following should have drive << 4 added in, this assumes drive 0.
165: / Out of space to do it right now.
166: movb al, drive
167: sal ax, $4
168: addb al, $0x9F
169: addb al, heads
170: mov dx, $HDRV_REG
171: outb dx, al / outb(HDRV_REG, 0xA0+(drive<<4)+heads-1);
172: movb al, $SETPARM_CMD
173: mov dx, $CSR_REG
174: outb dx, al / outb(CSR_REG, SETPARM_CMD)
175: nop
176: nop / filler to make 512 byte bootstrap
177:
178: / Set registers.
179:
180: 0: mov bp, $stack+NSTK / stack pointer value
181: mov ax, es
182: mov ds, ax
183: mov ss, ax
184: mov sp, bp
185:
186: / call login / print signon message
187:
188: / Jump to (relocated) boot.
189:
190: .byte JMPF
191: .word entry
192: 1: .word RBOOTS
193:
194: ////////
195: /
196: / Read the inode specified by "ax"
197: / into the external variable "iaddr".
198: / No checking is done to make sure that
199: / the inumber is in range on the filesystem.
200: / Sets dx and cx to 0.
201: / Mungs si, di, ax.
202: /
203: ////////
204:
205: igrab: dec ax / Make origin 0 and
206: push ax / remember for later use.
207:
208: movb cl, $IBSHIFT / Convert to
209: shr ax, cl / inode block number,
210: inc ax / then to physical block number,
211: inc ax
212: call bread / and read in the data.
213:
214: pop ax / Get i-number back.
215: and ax, $INOMASK / Get inode within block
216: movb cl, $IOSHIFT / and convert to
217: shl ax, cl / a byte offset in the block.
218: add si, ax / si = inode pointer.
219:
220: add si, $IADDR / Point at address field.
221: mov di, $iaddr / Copy out area.
222:
223: movb cl, $ND / cx = # of direct blocks.
224: 0: inc si / Skip 0th byte.
225: movsw / Move 1st (lsb) and 2nd (msb)
226: loop 0b / Do them all.
227:
228: inc si / Skip 0th byte and
229: lodsw / grab block # of (first) indirect.
230:
231: inc si / Skip 0th byte and
232: push (si) / remember block # of double indirect.
233:
234: call bread / Read (first) indirect block.
235:
236: movb cl, $NIND / cx = # of indirect maps (ch=0)
237: 1: lodsw / Skip hi half (canon long)
238: movsw / and move low half.
239: loop 1b / Do them all.
240:
241: pop ax
242: call bread / Read double indirect block.
243: lodsw
244: lodsw
245: call bread / Read (second) indirect block.
246:
247: movb cl, $NIND / cx = # of indirect maps (ch=0)
248: 2: lodsw / Skip hi half (canon long)
249: movsw / and move low half.
250: loop 2b / Do them all.
251:
252: sub dx, dx / sets dx to first word
253: / jmp iread / Done return through iread.
254:
255: ////////
256: /
257: / This routine reads the virtual
258: / block described by the ofs in "dx" into the
259: / buffer "bbuf". It uses the mapping data that
260: / has been provided by a previous call to igrab
261: / On return "si" points at "bbuf".
262: / Holes in files are correctly done.
263: / mungs ax, bx, si.
264: / clears cx.
265: /
266: ///////
267:
268: iread:
269: sub bx, bx / Convert from words to blocks.
270: movb bl, dh /
271: shl bx, $1 / Get 2 * block number into
272: mov ax, iaddr(bx) / physical block from the table.
273: / jmp bread / Yes, return through "bread".
274:
275: ////////
276: /
277: / Read a block from the floppy disk,
278: / drive A:, using the code in the IBM firmware.
279: / The physical block # is in "ax".
280: /
281: ////////
282:
283: bread: push es / Save registers
284: push di
285: push dx
286:
287: push ds
288: pop es / set ES to the address of the buffer
289:
290: mov di, bp / if block 0, clear buffer
291: mov cx, $BUFSIZE
292: rep
293: stosb
294:
295: test ax, ax / if block 0, return zeroed buffer
296: jz 2f
297:
298: xor dx, dx / extend block number
299: add ax, first / add first block
300: adc dx, first+2 / add rest
301:
302: mov bx, ax / save block number
303: movb al, heads / get number of heads
304: movb cl, sects / get number of sectors
305: mulb cl / calculate sectors per cylinder
306: xchg bx,ax / swap block/sectors
307: div bx / calculate track
308: xchg dx, ax / put track in DX
309: divb cl / calculate head/sector
310:
311: movb cl, ah / set sector
312: inc cx / sectors start at 1 [incb cl]
313:
314: cmp dx, traks / check for second side
315: jb 0f
316: sub dx, traks / fold track
317: inc ax / next head [incb al]
318:
319: 0: rorb dh, $1 / rotate track(low) into
320: rorb dh, $1 / msbits of DX
321: orb cl, dh / set track(high)
322: movb ch, dl / set track(low)
323: movb dh, al / set head
324: movb dl, drive / set drive
325: mov bx, bp / set offset [bbuf]
326:
327: mov ax, $READ1 / Read, 1 sector.
328: int DISK / Disk I/O.
329: jnc 2f / Jump if no error.
330: mov ax, $READ1 / try again
331: int DISK
332: jc error
333:
334: 2: mov si, bp / set SI to point to buffer for return
335: sub cx, cx / clear CX here to save space
336: pop dx / restore registers.
337: pop di
338: pop es
339: ret / return.
340:
341: ////////
342: /
343: / Print signon message
344: /
345: ////////
346:
347: / login: mov si, $msg00 / point si to message
348:
349: print: lodsb / al=byte
350: cmpb al, $LF / check for end of message
351: call putc / Type it and
352: jne print / go back for more.
353: ret
354:
355: / Prompt with a "?" and read the file name
356: / into the "nbuf". No character editing facilities
357: / are provided.
358:
359: error: mov sp, bp / Reset stack
360: / call login / print boot message
361:
362: input: mov di, $nbuf / di=name buffer pointer
363: mov cx, $DIRSIZE / cx=size of
364: movb al, $0x3F / set prompt to ?
365: 0: call putc
366:
367: 1: movb ah, $0 / Get ASCII opcode.
368: int KEYBD / Read keyboard ROM call.
369:
370: #if 0
371: / Conditionalized out to make more space
372: cmpb al, $BS / BS ?
373: jne 2f /
374: cmpb cl, $DIRSIZE / At start of buffer?
375: je 1b / Yup, ignore BS
376: call putc / Output destructive backspace
377: movb al, $SP
378: call putc
379: movb al, $BS
380: dec di / Adjust pointer
381: inc cx / and char count
382: jmp 0b / and continue.
383: #endif
384:
385: 2: cmpb al, $CR / CR ?
386: je 3f / Yup, do next thing
387:
388: jcxz 1b / skip over too big name
389: stosb / put it into the buffer,
390: dec cx / adjust char count
391: jmp 0b / and continue.
392:
393: 3: mov si, $crlf / Echo LF followed by CR.
394: call print
395:
396: movb al, $0 / zero out
397: rep
398: stosb / rest of name
399:
400: entry: mov ax, $ROOTINO / ax = current inode
401: call igrab / Read in inode and set dx
402:
403: / Search directory.
404: / Assume directory size < 64 Kbytes.
405:
406: search: orb dl, dl / On block boundry ?
407: jnz 0f / Nope.
408: call iread / Read block, set si.
409:
410: 0: movb cl, $DIRSIZE / cx = count left
411: mov di, $nbuf / Point at name buffer and
412: lodsw / ax = inumber, this entry.
413: or ax, ax / Empty directory slot ?
414: je 1f / Yes, skip.
415: repe / compare the
416: cmpsb / two file names.
417: je found / If eq, go and get inode.
418:
419: 1: add si, cx / Advance by count remaining.
420: add dx, $DIRSIZ2+1 / Bump [word] seek pointer
421: jg search / Scan up to 64 Kbytes of directory.
422:
423: jmp input / File not found.
424:
425: ////////
426: /
427: / Found the file so read it in.
428: / ax = inode number of file
429: /
430: ////////
431:
432: found: call igrab / read in inode and first block
433: cmp LMAGIC(si),$LFMAG / Check the magic number.
434: jne error / not Ok.
435:
436: / push LBSSD(si) / Push the uninitialized data size.
437: mov ax, LSHRD(si) / Push the sum
438: add ax, LPRVD(si) / of the shared and private
439: push ax / [initialized] data sizes.
440: andb LFLAG(si), $LFSEP / check image flags.
441: pushf / Push result of test.
442: mov ax, LSHRI(si) / Get the sum of the
443: add ax, LPRVI(si) / shared and private code sizes.
444:
445: mov dx, $HDRSIZ2 / Seek after header and
446: add si, $HDRSIZE / set buffer pointer appropriately.
447: mov es, 1f / Set ES:DI to point to the load
448: sub di, di / base of the new system.
449:
450: call load / Load code.
451:
452: popf / Pop sep I/D flag test
453: jz 0f / Not sep.
454:
455: add di, $15 / Round up the system code
456: movb cl, $4 / size to 16 byte
457: shr di, cl / paragraphs.
458: mov ax, es / fetch program base
459: add ax, di / Compute the data base and
460: mov es, ax / set up ES:DI to point
461: sub di, di / at it.
462:
463: 0: pop ax / Pop off initialized data size and
464: call load / load the image.
465:
466: / pop cx / Pop off uninitialized data size and
467: / rep / clear it.
468: / stosb
469:
470: .byte JMPF / Jump to offset
471: .word 0x0100 / 0x0100 (after base) in system
472: 1: .word SYSBASE / code segment.
473:
474: ////////
475: /
476: / Load a segment. The "dx" holds the
477: / seek pointer into the file. The "si" holds
478: / a pointer into the "bbuf". The "es:di" pair
479: / holds the target address. The "ax" holds
480: / the number of bytes to load. On return the
481: / "ax" must equal 0 (the caller assumes this
482: / and uses "al" to clear the BSS).
483: /
484: ////////
485:
486: load: or ax, ax / Any left ?
487: jz return / Jump if all loaded.
488:
489: mov cx, $bbuf+BUFSIZE / Compute the number of bytes
490: sub cx, si / remaining in the block.
491: jnz 0f / Jump if some.
492:
493: push ax / Save count registers, then
494: call iread / read the next block
495: pop ax / of the file.
496: mov cx, $BUFSIZE / We now have a full block.
497:
498: 0: cmp cx, ax / More than we need ?
499: jbe 1f / Nope.
500: mov cx, ax / Only take what we need.
501:
502: 1: sub ax, cx / Fix up the count
503: shr cx, $1 /
504: add dx, cx / Fix up the seek [word] address, then
505: rep / copy the words from the block
506: movsw / buffer to the load point and
507: jmp load / loop until done.
508:
509: ////////
510: /
511: / Write the character in "al" out to
512: / the display, using routines in the ROM.
513: / Like most calls to the ROM, this routine spends
514: / most of its time saving and restoring the
515: / registers.
516: /
517: / Note: The ZF in the PSW word must be preserved.
518: /
519: ////////
520:
521: putc: push si / Save registers.
522: push di
523: push bp
524:
525: mov bx, $0x0007 / Page 0, white on black
526: movb ah, $0x0E / Write TTY.
527: int 0x10 / Call video I/O in ROM.
528:
529: pop bp / Restore registers.
530: pop di
531: pop si
532: return: ret / Return
533:
534: ////////
535: /
536: / Data. There is some pure data in
537: / the "prvd" segment. This data is moved to the
538: / new memory when the boot is relocated. All buffers
539: / are in the BSS, and are not actually moved, or even
540: / saved in the boot block.
541: /
542: ////////
543:
544: .prvd
545: nbuf: .ascii "autoboot" / Name buffer.
546: .blkb DIRSIZE-8 / rest of buffer
547:
548: traks: .word NTRK
549: sects: .byte NSPT
550: heads: .byte NHD
551: cntrl: .byte CNTRL
552: wpcc: .word WPCC / not used currently
553: drive: .byte 0
554: first: .word 0
555: .word 0
556:
557: / msg00: .ascii "Boot"
558: crlf: .byte CR, LF
559:
560: .byte 0x55,0xAA
561:
562: .bssd
563: stack: .blkb NSTK / Local Stack and name buffer
564: bbuf: .blkb BUFSIZE / Block buffer [must follow stack].
565: iaddr: .blkw ND+NIND+NIND / Inode map words.
566:
567:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.