|
|
1.1 root 1: /* NOTE: this boot sector contains instructions that need at least an 80186.
2: * Yes, as86 has a bug somewhere in the valid instruction set checks.
3: *
4: */
5:
6: /* floppyload.S Copyright (C) 1991, 1992 Linus Torvalds
7: * modified by Drew Eckhardt
8: * modified by Bruce Evans (bde)
9: *
10: * floppyprefix.S is loaded at 0x0000:0x7c00 by the bios-startup routines.
11: *
12: * It then loads the system at SYSSEG<<4, using BIOS interrupts.
13: *
14: * The loader has been made as simple as possible, and continuous read errors
15: * will result in a unbreakable loop. Reboot by hand. It loads pretty fast by
16: * getting whole tracks at a time whenever possible.
17: */
18:
19: FILE_LICENCE ( GPL2_ONLY )
20:
21: .equ BOOTSEG, 0x07C0 /* original address of boot-sector */
22:
23: .equ SYSSEG, 0x1000 /* system loaded at SYSSEG<<4 */
24:
25: .org 0
26: .arch i386
27: .text
28: .section ".prefix", "ax", @progbits
29: .code16
30: .globl _dsk_start
31: _dsk_start:
32:
33: jmp $BOOTSEG, $go /* reload cs:ip to match relocation addr */
34: go:
35: movw $0x2000-12, %di /* 0x2000 is arbitrary value >= length */
36: /* of bootsect + room for stack + 12 for */
37: /* saved disk parm block */
38:
39: movw $BOOTSEG, %ax
40: movw %ax,%ds
41: movw %ax,%es
42: movw %ax,%ss /* put stack at BOOTSEG:0x4000-12. */
43: movw %di,%sp
44:
45: /* Many BIOS's default disk parameter tables will not recognize multi-sector
46: * reads beyond the maximum sector number specified in the default diskette
47: * parameter tables - this may mean 7 sectors in some cases.
48: *
49: * Since single sector reads are slow and out of the question, we must take care
50: * of this by creating new parameter tables (for the first disk) in RAM. We
51: * will set the maximum sector count to 36 - the most we will encounter on an
52: * ED 2.88. High doesn't hurt. Low does.
53: *
54: * Segments are as follows: ds=es=ss=cs - BOOTSEG
55: */
56:
57: xorw %cx,%cx
58: movw %cx,%es /* access segment 0 */
59: movw $0x78, %bx /* 0:bx is parameter table address */
60: pushw %ds /* save ds */
61: /* 0:bx is parameter table address */
62: ldsw %es:(%bx),%si /* loads ds and si */
63:
64: movw %ax,%es /* ax is BOOTSECT (loaded above) */
65: movb $6, %cl /* copy 12 bytes */
66: cld
67: pushw %di /* keep a copy for later */
68: rep
69: movsw /* ds:si is source, es:di is dest */
70: popw %di
71:
72: movb $36,%es:4(%di)
73:
74: movw %cx,%ds /* access segment 0 */
75: xchgw %di,(%bx)
76: movw %es,%si
77: xchgw %si,2(%bx)
78: popw %ds /* restore ds */
79: movw %di, dpoff /* save old parameters */
80: movw %si, dpseg /* to restore just before finishing */
81: pushw %ds
82: popw %es /* reload es */
83:
84: /* Note that es is already set up. Also cx is 0 from rep movsw above. */
85:
86: xorb %ah,%ah /* reset FDC */
87: xorb %dl,%dl
88: int $0x13
89:
90: /* Get disk drive parameters, specifically number of sectors/track.
91: *
92: * It seems that there is no BIOS call to get the number of sectors. Guess
93: * 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read,
94: * 15 if sector 15 can be read. Otherwise guess 9.
95: */
96:
97: movw $disksizes, %si /* table of sizes to try */
98:
99: probe_loop:
100: lodsb
101: cbtw /* extend to word */
102: movw %ax, sectors
103: cmpw $disksizes+4, %si
104: jae got_sectors /* if all else fails, try 9 */
105: xchgw %cx,%ax /* cx = track and sector */
106: xorw %dx,%dx /* drive 0, head 0 */
107: movw $0x0200, %bx /* address after boot sector */
108: /* (512 bytes from origin, es = cs) */
109: movw $0x0201, %ax /* service 2, 1 sector */
110: int $0x13
111: jc probe_loop /* try next value */
112:
113: got_sectors:
114: movw $msg1end-msg1, %cx
115: movw $msg1, %si
116: call print_str
117:
118: /* ok, we've written the Loading... message, now we want to load the system */
119:
120: movw $SYSSEG, %ax
121: movw %ax,%es /* segment of SYSSEG<<4 */
122: pushw %es
123: call read_it
124:
125: /* This turns off the floppy drive motor, so that we enter the kernel in a
126: * known state, and don't have to worry about it later.
127: */
128: movw $0x3f2, %dx
129: xorb %al,%al
130: outb %al,%dx
131:
132: call print_nl
133: pop %es /* = SYSSEG */
134:
135: /* Restore original disk parameters */
136: movw $0x78, %bx
137: movw dpoff, %di
138: movw dpseg, %si
139: xorw %ax,%ax
140: movw %ax,%ds
141: movw %di,(%bx)
142: movw %si,2(%bx)
143:
144: /* Everything now loaded. %es = SYSSEG, so %es:0000 points to
145: * start of loaded image.
146: */
147:
148: /* Jump to loaded copy */
149: ljmp $SYSSEG, $start_runtime
150:
151: endseg: .word SYSSEG
152: .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
153: .ascii "ADDW"
154: .long endseg
155: .long 16
156: .long 0
157: .previous
158:
159: /* This routine loads the system at address SYSSEG<<4, making sure no 64kB
160: * boundaries are crossed. We try to load it as fast as possible, loading whole
161: * tracks whenever we can.
162: *
163: * in: es - starting address segment (normally SYSSEG)
164: */
165: read_it:
166: movw $0,sread /* load whole image including prefix */
167: movw %es,%ax
168: testw $0x0fff, %ax
169: die: jne die /* es must be at 64kB boundary */
170: xorw %bx,%bx /* bx is starting address within segment */
171: rp_read:
172: movw %es,%ax
173: movw %bx,%dx
174: movb $4, %cl
175: shrw %cl,%dx /* bx is always divisible by 16 */
176: addw %dx,%ax
177: cmpw endseg, %ax /* have we loaded all yet? */
178: jb ok1_read
179: ret
180: ok1_read:
181: movw sectors, %ax
182: subw sread, %ax
183: movw %ax,%cx
184: shlw $9, %cx
185: addw %bx,%cx
186: jnc ok2_read
187: je ok2_read
188: xorw %ax,%ax
189: subw %bx,%ax
190: shrw $9, %ax
191: ok2_read:
192: call read_track
193: movw %ax,%cx
194: addw sread, %ax
195: cmpw sectors, %ax
196: jne ok3_read
197: movw $1, %ax
198: subw head, %ax
199: jne ok4_read
200: incw track
201: ok4_read:
202: movw %ax, head
203: xorw %ax,%ax
204: ok3_read:
205: movw %ax, sread
206: shlw $9, %cx
207: addw %cx,%bx
208: jnc rp_read
209: movw %es,%ax
210: addb $0x10, %ah
211: movw %ax,%es
212: xorw %bx,%bx
213: jmp rp_read
214:
215: read_track:
216: pusha
217: pushw %ax
218: pushw %bx
219: pushw %bp /* just in case the BIOS is buggy */
220: movw $0x0e2e, %ax /* 0x2e = . */
221: movw $0x0007, %bx
222: int $0x10
223: popw %bp
224: popw %bx
225: popw %ax
226:
227: movw track, %dx
228: movw sread, %cx
229: incw %cx
230: movb %dl,%ch
231: movw head, %dx
232: movb %dl,%dh
233: andw $0x0100, %dx
234: movb $2, %ah
235:
236: pushw %dx /* save for error dump */
237: pushw %cx
238: pushw %bx
239: pushw %ax
240:
241: int $0x13
242: jc bad_rt
243: addw $8, %sp
244: popa
245: ret
246:
247: bad_rt: pushw %ax /* save error code */
248: call print_all /* ah = error, al = read */
249:
250: xorb %ah,%ah
251: xorb %dl,%dl
252: int $0x13
253:
254: addw $10, %sp
255: popa
256: jmp read_track
257:
258: /* print_all is for debugging purposes. It will print out all of the registers.
259: * The assumption is that this is called from a routine, with a stack frame like
260: * dx
261: * cx
262: * bx
263: * ax
264: * error
265: * ret <- sp
266: */
267:
268: print_all:
269: call print_nl /* nl for readability */
270: movw $5, %cx /* error code + 4 registers */
271: movw %sp,%bp
272:
273: print_loop:
274: pushw %cx /* save count left */
275:
276: cmpb $5, %cl
277: jae no_reg /* see if register name is needed */
278:
279: movw $0x0007, %bx /* page 0, attribute 7 (normal) */
280: movw $0xe05+0x41-1, %ax
281: subb %cl,%al
282: int $0x10
283:
284: movb $0x58, %al /* 'X' */
285: int $0x10
286:
287: movb $0x3A, %al /* ':' */
288: int $0x10
289:
290: no_reg:
291: addw $2, %bp /* next register */
292: call print_hex /* print it */
293: movb $0x20, %al /* print a space */
294: int $0x10
295: popw %cx
296: loop print_loop
297: call print_nl /* nl for readability */
298: ret
299:
300: print_str:
301: movw $0x0007, %bx /* page 0, attribute 7 (normal) */
302: movb $0x0e, %ah /* write char, tty mode */
303: prloop:
304: lodsb
305: int $0x10
306: loop prloop
307: ret
308:
309: print_nl:
310: movw $0x0007, %bx /* page 0, attribute 7 (normal) */
311: movw $0xe0d, %ax /* CR */
312: int $0x10
313: movb $0xa, %al /* LF */
314: int $0x10
315: ret
316:
317: /* print_hex prints the word pointed to by ss:bp in hexadecimal. */
318:
319: print_hex:
320: movw (%bp),%dx /* load word into dx */
321: movb $4, %cl
322: movb $0x0e, %ah /* write char, tty mode */
323: movw $0x0007, %bx /* page 0, attribute 7 (normal) */
324: call print_digit
325: call print_digit
326: call print_digit
327: /* fall through */
328: print_digit:
329: rol %cl,%dx /* rotate so that lowest 4 bits are used */
330: movb $0x0f, %al /* mask for nybble */
331: andb %dl,%al
332: addb $0x90, %al /* convert al to ascii hex (four instructions) */
333: daa
334: adcb $0x40, %al
335: daa
336: int $0x10
337: ret
338:
339: sread: .word 0 /* sectors read of current track */
340: head: .word 0 /* current head */
341: track: .word 0 /* current track */
342:
343: sectors:
344: .word 0
345:
346: dpseg: .word 0
347: dpoff: .word 0
348:
349: disksizes:
350: .byte 36,18,15,9
351:
352: msg1:
353: .ascii "Loading ROM image"
354: msg1end:
355:
356: .org 510, 0
357: .word 0xAA55
358:
359: start_runtime:
360: /* Install iPXE */
361: call install
362:
363: /* Set up real-mode stack */
364: movw %bx, %ss
365: movw $_estack16, %sp
366:
367: /* Jump to .text16 segment */
368: pushw %ax
369: pushw $1f
370: lret
371: .section ".text16", "awx", @progbits
372: 1:
373: pushl $main
374: pushw %cs
375: call prot_call
376: popl %ecx /* discard */
377:
378: /* Uninstall iPXE */
379: call uninstall
380:
381: /* Boot next device */
382: int $0x18
383:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.