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