wok-4.x view etherboot/stuff/etherboot-prefix.u @ rev 540
Etherboot: by the way, add DOS/COM support
author | Pascal Bellard <pascal.bellard@slitaz.org> |
---|---|
date | Thu Apr 10 22:34:56 2008 +0000 (2008-04-10) |
parents | 8d43117e4680 |
children | 4a87a0aa0476 |
line source
1 --- etherboot-5.4.3/src/arch/i386/prefix/liloprefix.S
2 +++ etherboot-5.4.3/src/arch/i386/prefix/liloprefix.S
3 @@ -1,92 +1,393 @@
4 -/*
5 - Copyright (C) 2000, Entity Cyber, Inc.
6 -
7 - Authors: Gary Byers (gb@thinguin.org)
8 - Marty Connor (mdc@thinguin.org)
9 -
10 - This software may be used and distributed according to the terms
11 - of the GNU Public License (GPL), incorporated herein by reference.
12 -
13 - Description:
14 -
15 - This is just a little bit of code and data that can get prepended
16 - to an Etherboot ROM image in order to allow LILO to load the
17 - result as if it were a Linux kernel image.
18 -
19 - A real Linux kernel image consists of a one-sector boot loader
20 - (to load the image from a floppy disk), followed a few sectors
21 - of setup code, followed by the kernel code itself. There's
22 - a table in the first sector (starting at offset 497) that indicates
23 - how many sectors of setup code follow the first sector and which
24 - contains some other parameters that aren't interesting in this
25 - case.
26 -
27 - When LILO loads the sectors that comprise a kernel image, it doesn't
28 - execute the code in the first sector (since that code would try to
29 - load the image from a floppy disk.) The code in the first sector
30 - below doesn't expect to get executed (and prints an error message
31 - if it ever -is- executed.) LILO's only interested in knowing the
32 - number of setup sectors advertised in the table (at offset 497 in
33 - the first sector.)
34 -
35 - Etherboot doesn't require much in the way of setup code.
36 - Historically, the Linux kernel required at least 4 sectors of
37 - setup code. Current versions of LILO look at the byte at
38 - offset 497 in the first sector to indicate how many sectors
39 - of setup code are contained in the image.
40 -
41 -*/
42 +/* NOTE: this boot sector contains instructions that need at least an 80186.
43 + * Yes, as86 has a bug somewhere in the valid instruction set checks.
44 + *
45 + * SYS_SIZE is the number of clicks (16 bytes) to be loaded. For Etherboot
46 + * purposes, we need to load everything but the boot sector itself, i.e. 32
47 + * clicks less than the size of the entire (verbatim) image. The image size
48 + * is practically limited only by the available base memory size.
49 + */
50 +.globl SYSSIZE
51 +.equ SYSSIZE, _verbatim_size_pgh - 32
52 +
53 +/* floppyload.S Copyright (C) 1991, 1992 Linus Torvalds
54 + * modified by Drew Eckhardt
55 + * modified by Bruce Evans (bde)
56 + *
57 + * floppyprefix.S is loaded at 0x0000:0x7c00 by the bios-startup routines.
58 + *
59 + * It then loads the system at SYSSEG<<4, using BIOS interrupts.
60 + *
61 + * The loader has been made as simple as possible, and continuous read errors
62 + * will result in a unbreakable loop. Reboot by hand. It loads pretty fast by
63 + * getting whole tracks at a time whenever possible.
64 + */
66 #define SETUPSECS 4 /* Minimal nr of setup-sectors */
67 #define PREFIXSIZE ((SETUPSECS+1)*512)
68 #define PREFIXPGH (PREFIXSIZE / 16 )
69 -#define BOOTSEG 0x07C0 /* original address of boot-sector */
70 #define INITSEG 0x9000 /* we move boot here - out of the way */
71 #define SETUPSEG 0x9020 /* setup starts here */
72 -#define SYSSEG 0x1000 /* system loaded at 0x10000 (65536). */
74 - .text
75 - .code16
76 - .arch i386
77 - .org 0
78 - .section ".prefix", "ax", @progbits
79 .globl _prefix
80 _prefix:
81 +.equ BOOTSEG, 0x07C0 /* original address of boot-sector */
83 -/*
84 - This is a minimal boot sector. If anyone tries to execute it (e.g., if
85 - a .lilo file is dd'ed to a floppy), print an error message.
86 -*/
87 +.equ SYSSEG, 0x1000 /* system loaded at SYSSEG<<4 */
88 +
89 + .org 0
90 + .arch i386
91 + .text
92 + .section ".prefix", "ax", @progbits
93 + .code16
95 -bootsector:
96 - jmp $BOOTSEG, $go - _prefix /* reload cs:ip to match relocation addr */
97 + call here
98 +here:
99 + pop %ax
100 + cmpw $0x103, %ax /* COM entry point is cs:0x100 */
101 + jne bootsector
102 +/* We need a real mode stack that won't be stomped on by Etherboot
103 + which starts at 0x20000. Choose something that's sufficiently high,
104 + but not in DOC territory. Note that we couldn't do this in a real
105 + .com program since stack variables are in the same segment as the
106 + code and data, but this isn't really a .com program, it just looks
107 + like one to make DOS load it into memory. It still has the 64kB
108 + limitation of .com files though. */
109 +#define STACK_SEG 0x7000
110 +#define STACK_SIZE 0x4000
111 + /* Set up temporary stack */
112 + movw $STACK_SEG, %ax
113 + movw %ax, %ss
114 + movw $STACK_SIZE, %sp
115 +
116 + pushl $0 /* No parameters to preserve for exit path */
117 + pushw $0 /* Dummy return address - use prefix_exit */
118 +
119 + /* Calculate segment address of image start */
120 + pushw %cs
121 + popw %ax
122 + addw $(0x100/16), %ax
123 + pushw %ax
124 + pushw $_start
125 + /* Calculated lcall to _start with %cs:0000 = image start */
126 + lret
127 +
128 +bootsector:
129 + jmp $BOOTSEG, $go /* reload cs:ip to match relocation addr */
130 go:
131 - movw $0x2000, %di /* 0x2000 is arbitrary value >= length
132 - of bootsect + room for stack */
133 + movw $0x2000-12, %di /* 0x2000 is arbitrary value >= length */
134 + /* of bootsect + room for stack + 12 for */
135 + /* saved disk parm block */
137 movw $BOOTSEG, %ax
138 movw %ax,%ds
139 movw %ax,%es
140 -
141 - cli
142 - movw %ax, %ss /* put stack at BOOTSEG:0x2000. */
143 + movw %ax,%ss /* put stack at initial position */
144 movw %di,%sp
145 - sti
147 - movw $why_end-why, %cx
148 - movw $why - _prefix, %si
149 +/* Many BIOS's default disk parameter tables will not recognize multi-sector
150 + * reads beyond the maximum sector number specified in the default diskette
151 + * parameter tables - this may mean 7 sectors in some cases.
152 + *
153 + * Since single sector reads are slow and out of the question, we must take care
154 + * of this by creating new parameter tables (for the first disk) in RAM. We
155 + * will set the maximum sector count to 36 - the most we will encounter on an
156 + * ED 2.88. High doesn't hurt. Low does.
157 + *
158 + * Segments are as follows: ds=es=ss=cs - BOOTSEG
159 + */
160 +
161 + xorw %cx,%cx
162 + movw %cx,%es /* access segment 0 */
163 + movw $0x78, %bx /* 0:bx is parameter table address */
164 + pushw %ds /* save ds */
165 +/* 0:bx is parameter table address */
166 + ldsw %es:(%bx),%si /* loads ds and si */
167 +
168 + movw %ax,%es /* ax is BOOTSECT (loaded above) */
169 + movb $6, %cl /* copy 12 bytes */
170 + cld
171 + pushw %di /* keep a copy for later */
172 + rep
173 + movsw /* ds:si is source, es:di is dest */
174 + popw %di
175 +
176 + movb $36,%es:4(%di)
177 +
178 + movw %cx,%ds /* access segment 0 */
179 + xchgw %di,(%bx)
180 + movw %es,%si
181 + xchgw %si,2(%bx)
182 + popw %ds /* restore ds */
183 + movw %di, dpoff /* save old parameters */
184 + movw %si, dpseg /* to restore just before finishing */
185 + pushw %ds
186 + popw %es /* reload es */
187 +
188 +/* Note that es is already set up. Also cx is 0 from rep movsw above. */
189 +
190 + xorb %ah,%ah /* reset FDC */
191 + xorb %dl,%dl
192 + int $0x13
193 +
194 +/* Get disk drive parameters, specifically number of sectors/track.
195 + *
196 + * It seems that there is no BIOS call to get the number of sectors. Guess
197 + * 36 sectors if sector 36 can be read, 18 sectors if sector 18 can be read,
198 + * 15 if sector 15 can be read. Otherwise guess 9.
199 + */
200 +
201 + movw $disksizes, %si /* table of sizes to try */
202 +
203 +probe_loop:
204 + lodsb
205 + cbtw /* extend to word */
206 + movw %ax, sectors
207 + cmpw $disksizes+4, %si
208 + jae got_sectors /* if all else fails, try 9 */
209 + xchgw %cx,%ax /* cx = track and sector */
210 + xorw %dx,%dx /* drive 0, head 0 */
211 + movw $0x0200, %bx /* address after boot sector */
212 + /* (512 bytes from origin, es = cs) */
213 + movw $0x0201, %ax /* service 2, 1 sector */
214 + int $0x13
215 + jc probe_loop /* try next value */
216 +
217 +got_sectors:
218 + movw $msg1end-msg1, %cx
219 + movw $msg1, %si
220 + call print_str
221 +
222 +/* ok, we've written the Loading... message, now we want to load the system */
223 +
224 + pushw %es /* = ds */
225 + movw $SYSSEG, %ax
226 + movw %ax,%es /* segment of SYSSEG<<4 */
227 + pushw %es
228 + call read_it
229 +
230 +/* This turns off the floppy drive motor, so that we enter the kernel in a
231 + * known state, and don't have to worry about it later.
232 + */
233 + movw $0x3f2, %dx
234 + xorb %al,%al
235 + outb %al,%dx
236 +
237 + call print_nl
238 + pop %es /* = SYSSEG */
239 + pop %es /* balance push/pop es */
240 +sigok:
241 +
242 +/* Restore original disk parameters */
243 + movw $0x78, %bx
244 + movw dpoff, %di
245 + movw dpseg, %si
246 + xorw %ax,%ax
247 + movw %ax,%ds
248 + movw %di,(%bx)
249 + movw %si,2(%bx)
250 +
251 +/* after that (everything loaded), we call to the .ROM file loaded. */
252 +
253 + pushl $0 /* No parameters to preserve for exit path */
254 + pushw $0 /* Use prefix exit path mechanism */
255 + ljmp $SYSSEG, $_start
256 +
257 +/* This routine loads the system at address SYSSEG<<4, making sure no 64kB
258 + * boundaries are crossed. We try to load it as fast as possible, loading whole
259 + * tracks whenever we can.
260 + *
261 + * in: es - starting address segment (normally SYSSEG)
262 + */
263 +read_it:
264 + movw $0,sread /* read whole image incl boot sector */
265 + movw %es,%ax
266 + testw $0x0fff, %ax
267 +die: jne die /* es must be at 64kB boundary */
268 + xorw %bx,%bx /* bx is starting address within segment */
269 +rp_read:
270 + movw %es,%ax
271 + movw %bx,%dx
272 + movb $4, %cl
273 + shrw %cl,%dx /* bx is always divisible by 16 */
274 + addw %dx,%ax
275 + cmpw $SYSSEG+SYSSIZE, %ax /* have we loaded all yet? */
276 + jb ok1_read
277 + ret
278 +ok1_read:
279 + movw sectors, %ax
280 + subw sread, %ax
281 + movw %ax,%cx
282 + shlw $9, %cx
283 + addw %bx,%cx
284 + jnc ok2_read
285 + je ok2_read
286 + xorw %ax,%ax
287 + subw %bx,%ax
288 + shrw $9, %ax
289 +ok2_read:
290 + call read_track
291 + movw %ax,%cx
292 + addw sread, %ax
293 + cmpw sectors, %ax
294 + jne ok3_read
295 + movw $1, %ax
296 + subw head, %ax
297 + jne ok4_read
298 + incw track
299 +ok4_read:
300 + movw %ax, head
301 + xorw %ax,%ax
302 +ok3_read:
303 + movw %ax, sread
304 + shlw $9, %cx
305 + addw %cx,%bx
306 + jnc rp_read
307 + movw %es,%ax
308 + addb $0x10, %ah
309 + movw %ax,%es
310 + xorw %bx,%bx
311 + jmp rp_read
312 +
313 +read_track:
314 + pusha
315 + pushw %ax
316 + pushw %bx
317 + pushw %bp /* just in case the BIOS is buggy */
318 + movw $0x0e2e, %ax /* 0x2e = . */
319 + movw $0x0007, %bx
320 + int $0x10
321 + popw %bp
322 + popw %bx
323 + popw %ax
324 +
325 + movw track, %dx
326 + movw sread, %cx
327 + incw %cx
328 + movb %dl,%ch
329 + movw head, %dx
330 + movb %dl,%dh
331 + andw $0x0100, %dx
332 + movb $2, %ah
333 +
334 + pushw %dx /* save for error dump */
335 + pushw %cx
336 + pushw %bx
337 + pushw %ax
338 +
339 + int $0x13
340 + jc bad_rt
341 + addw $8, %sp
342 + popa
343 + ret
344 +
345 +bad_rt: pushw %ax /* save error code */
346 + call print_all /* ah = error, al = read */
347 +
348 + xorb %ah,%ah
349 + xorb %dl,%dl
350 + int $0x13
351 +
352 + addw $10, %sp
353 + popa
354 + jmp read_track
355 +
356 +/* print_all is for debugging purposes. It will print out all of the registers.
357 + * The assumption is that this is called from a routine, with a stack frame like
358 + * dx
359 + * cx
360 + * bx
361 + * ax
362 + * error
363 + * ret <- sp
364 + */
365 +
366 +print_all:
367 + call print_nl /* nl for readability */
368 + movw $5, %cx /* error code + 4 registers */
369 + movw %sp,%bp
370 +
371 +print_loop:
372 + pushw %cx /* save count left */
373 +
374 + cmpb $5, %cl
375 + jae no_reg /* see if register name is needed */
377 movw $0x0007, %bx /* page 0, attribute 7 (normal) */
378 + movw $0xe05+0x41-1, %ax
379 + subb %cl,%al
380 + int $0x10
381 +
382 + movb $0x58, %al /* 'X' */
383 + int $0x10
384 +
385 + movb $0x3A, %al /* ':' */
386 + int $0x10
387 +
388 +no_reg:
389 + addw $2, %bp /* next register */
390 + call print_hex /* print it */
391 + movb $0x20, %al /* print a space */
392 + int $0x10
393 + popw %cx
394 + loop print_loop
395 + call print_nl /* nl for readability */
396 + ret
397 +
398 +print_str:
399 + movw $0x0007, %bx /* page 0, attribute 7 (normal) */
400 movb $0x0e, %ah /* write char, tty mode */
401 prloop:
402 lodsb
403 int $0x10
404 loop prloop
405 -freeze: jmp freeze
406 + ret
407 +
408 +print_nl:
409 + movw $0x0007, %bx /* page 0, attribute 7 (normal) */
410 + movw $0xe0d, %ax /* CR */
411 + int $0x10
412 + movb $0xa, %al /* LF */
413 + int $0x10
414 + ret
415 +
416 +/* print_hex prints the word pointed to by ss:bp in hexadecimal. */
417 +
418 +print_hex:
419 + movw (%bp),%dx /* load word into dx */
420 + movb $4, %cl
421 + movb $0x0e, %ah /* write char, tty mode */
422 + movw $0x0007, %bx /* page 0, attribute 7 (normal) */
423 + call print_digit2
424 +print_digit2:
425 + call print_digit
426 +/* fall through */
427 +print_digit:
428 + rol %cl,%dx /* rotate so that lowest 4 bits are used */
429 + movb $0x0f, %al /* mask for nybble */
430 + andb %dl,%al
431 + addb $0x90, %al /* convert al to ascii hex (four instructions) */
432 + daa
433 + adcb $0x40, %al
434 + daa
435 + int $0x10
436 + ret
437 +
438 +sread: .word 0 /* sectors read of current track */
439 +head: .word 0 /* current head */
440 +track: .word 0 /* current track */
441 +
442 +sectors:
443 + .word 0
444 +
445 +dpseg: .word 0
446 +dpoff: .word 0
448 -why: .ascii "This image cannot be loaded from a floppy disk.\r\n"
449 -why_end:
450 +disksizes:
451 + .byte 36,18,15,9
453 +msg1:
454 + .ascii "Loading ROM"
455 +msg1end:
457 .org 497
458 setup_sects: