wok-next view ipxe/stuff/lkrnprefix.S @ rev 15368
Up ipxe (1.0.0-20130925)
author | Pascal Bellard <pascal.bellard@slitaz.org> |
---|---|
date | Mon Oct 14 13:38:36 2013 +0000 (2013-10-14) |
parents | |
children | 4ae7c7dde4e2 |
line source
1 /*
2 Copyright (C) 2000, Entity Cyber, Inc.
4 Authors: Gary Byers (gb@thinguin.org)
5 Marty Connor (mdc@thinguin.org)
7 This software may be used and distributed according to the terms
8 of the GNU Public License (GPL), incorporated herein by reference.
10 Description:
12 This is just a little bit of code and data that can get prepended
13 to a ROM image in order to allow bootloaders to load the result
14 as if it were a Linux kernel image.
16 A real Linux kernel image consists of a one-sector boot loader
17 (to load the image from a floppy disk), followed a few sectors
18 of setup code, followed by the kernel code itself. There's
19 a table in the first sector (starting at offset 497) that indicates
20 how many sectors of setup code follow the first sector and which
21 contains some other parameters that aren't interesting in this
22 case.
24 When a bootloader loads the sectors that comprise a kernel image,
25 it doesn't execute the code in the first sector (since that code
26 would try to load the image from a floppy disk.) The code in the
27 first sector below doesn't expect to get executed (and prints an
28 error message if it ever -is- executed.)
30 We don't require much in the way of setup code. Historically, the
31 Linux kernel required at least 4 sectors of setup code.
32 Therefore, at least 4 sectors must be present even though we don't
33 use them.
35 */
37 FILE_LICENCE ( GPL_ANY )
39 #define SETUPSECS 4 /* Minimal nr of setup-sectors */
40 #define PREFIXSIZE ((SETUPSECS+1)*512)
41 #define PREFIXPGH (PREFIXSIZE / 16 )
42 #define BOOTSEG 0x07C0 /* original address of boot-sector */
43 #define INITSEG 0x9000 /* we move boot here - out of the way */
44 #define SETUPSEG 0x9020 /* setup starts here */
45 #define SYSSEG 0x1000 /* system loaded at 0x10000 (65536). */
47 .text
48 .code16
49 .arch i386
50 .org 0
51 .section ".prefix", "ax", @progbits
52 .globl _lkrn_start
53 _lkrn_start:
55 bootsector:
56 _start:
58 /* some extra features */
59 #define EXE_SUPPORT real mode dos .exe file support
61 #define EXEADRS(x) (x+0xE0)
63 /* some contraints to reduce the size */
64 //#define FLOPPY_1440K_ONLY 1.44M floppies support only
66 #ifdef EXE_SUPPORT
67 /* Initial temporary stack size */
68 #define EXE_STACK_SIZE 0x400
70 /* Temporary decompression area (avoid DOS high memory area) */
71 #define EXE_DECOMPRESS_ADDRESS 0x110000
73 /* Fields within the Program Segment Prefix */
74 #define PSP_CMDLINE_LEN 0x80
75 #define PSP_CMDLINE_START 0x81
77 #define HEADER_SIZE 0x20
79 signature:
80 decw %bp // Magic number: MZ
81 popw %dx
82 jmp start // Bytes on last page of file
83 blocks:
84 .word 0 // Pages in file
85 .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
86 .ascii "ADDW"
87 .long blocks
88 .long 512
89 .long 0
90 .previous
91 .word 0 // Relocations
92 .word ( HEADER_SIZE / 16 ) // Size of header in paragraphs
93 .word ( EXE_STACK_SIZE / 16 ) // Minimum extra paragraphs needed
94 .word ( EXE_STACK_SIZE / 16 ) // Maximum extra paragraphs needed
95 init_ss:
96 .word -( ( _exe_start - signature ) / 16 ) // Initial (relative) SS value
97 .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
98 .ascii "ADDW"
99 .long init_ss
100 .long 16
101 .long 0
102 .previous
103 .word EXE_STACK_SIZE // Initial SP value
104 .word 0 // Checksum
105 .word _exe_start // Initial IP value
106 /* Initial code segment (relative to start of executable) */
107 //.word -( ( _exe_start - signature ) / 16 ) // Initial (relative) CS value
108 .word -( HEADER_SIZE / 16 ) // Initial (relative) CS value
109 // .word 0x001C // File address of relocation table
110 // .word 0,0,0 // Overlay number
112 start:
113 pushw %dx
114 xorw %dx, %dx
115 #endif
116 cld # assume nothing
117 stacktop = 0x9E00 # in 0x8000 .. 0xA000
118 zeroed = 12 # zeroed registers
119 movw $stacktop-12-zeroed, %di # stacktop is an arbitrary value >=
120 # length of bootsect + length of
121 # setup + room for stack;
122 # 12 is disk parm size.
123 pushw $INITSEG
124 popw %ss # %ss contain INITSEG
125 movw %di, %sp # put stack at INITSEG:stacktop-...
127 # Many BIOS's default disk parameter tables will not recognize
128 # multi-sector reads beyond the maximum sector number specified
129 # in the default diskette parameter tables - this may mean 7
130 # sectors in some cases.
131 #
132 # Since single sector reads are slow and out of the question,
133 # we must take care of this by creating new parameter tables
134 # (for the first disk) in RAM. We can set the maximum sector
135 # count to 36 - the most we will encounter on an ED 2.88.
136 #
137 # High doesn't hurt. Low does. Let's use the max: 63
139 pushw %ss
140 popw %es # %es = %ss = INITSEG
141 xorw %ax, %ax # %ax = 0
142 movw $zeroed/2, %cx # clear gdt + offset, %ds, limits
143 rep # don't worry about cld
144 stosw # already done above
145 popw %bx # offset = 0
146 popw %ds # %ds = 0
147 popw %fs # %fs = 0
149 movb setup_sects+0x7C00, %al # read bootsector + setup (%ds = 0)
150 incw %ax
152 ldsw 0x78(%bx), %si # %ds:%bx+0x78 is parameter table address
153 pushw %es
154 pushw %di
155 movb $6, %cl # copy 12 bytes
156 rep # don't worry about cld
157 movsw # already done above
158 pushw %ss
159 popw %ds # now %ds = %es = %ss = INITSEG
160 popl %fs:0x78(%bx) # update parameter table address
161 movb $63, 0x4-12(%di) # patch sector count, %di = stacktop
162 cli
164 xchg %ax, %di # sector count
165 popw %ax # limits = 0
166 incw %cx # cylinder 0, sector 1, clear Z
167 call read_first_sectors # read setup
169 # This routine loads the system at address LOADSEG, making sure
170 # no 64kB boundaries are crossed. We try to load it as fast as
171 # possible, loading whole tracks whenever we can.
173 popw %bx # clear %bx
174 movw syssize, %di
175 addw $(512/16)-1, %di
176 shrw $9-4, %di
177 movw $SYSSEG, %cx
178 call read_sectorsCX
180 # This procedure turns off the floppy drive motor, so
181 # that we enter the kernel in a known state, and
182 # don't have to worry about it later.
184 kill_motor:
185 xchgw %ax, %di # reset FDC (%di < 128)
186 int $0x13
188 # After that (everything loaded), we jump to the setup-routine
189 # loaded directly after the bootblock:
190 # Segments are as follows: %ds = %ss = INITSEG
192 ljmp $SETUPSEG, $0
194 #ifdef EXE_SUPPORT
195 dosexit:
196 movw $0x4c00, %ax
197 int $0x21
199 _exe_start:
200 pushw $dosexit
201 movw $EXEADRS(need386), %si
202 pushfw // save flags
203 // bits 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
204 // flags 0 NT IOPL OF DF IF TF SF ZF 0 AF 0 PF 1 CF
205 movb $0x10, %ah // DF = IF = TF = 0
206 pushw %ax
207 popfw // < 286 : flags[12..15] are forced 1
208 pushfw // = 286 : flags[12..15] are forced 0
209 popw %cx // > 286 : only flags[15] is forced 0
210 popfw // restore flags
211 addb %ah, %ch // test F0 and 00 cases
212 cmpb %ah, %ch
213 jbe puts // C=8086/80186, Z=80286
214 // smsww %ax
215 // andb $1, %al
216 // jne puts
218 /* Terminate command line with a NUL */
219 movzbw PSP_CMDLINE_LEN, %si
220 movb $0, PSP_CMDLINE_START(%si)
221 cmpb $'?', PSP_CMDLINE_START-1(%si)
222 je help
223 pushw %si
225 /* Install iPXE. Use a fixed temporary decompression area to
226 * avoid trashing the DOS high memory area.
227 */
228 call alloc_basemem
229 movl $EXE_DECOMPRESS_ADDRESS, %edi
230 stc
231 sbbl %ebp, %ebp /* Allow arbitrary relocation */
232 xorl %esi, %esi
233 call install_prealloc
235 xorl %ebp, %ebp
236 xorl %ecx, %ecx
238 /* Calculate command line physical address */
239 xorl %edx, %edx
240 movw %ds, %dx
241 shll $4, %edx
242 popw %si
243 orw %si, %si
244 jne gotarg
245 movw $EXEADRS(default_config), %bp
246 addl %edx, %ebp
247 movw $0xA00-default_config, %cx
248 gotarg:
249 addl $PSP_CMDLINE_START, %edx
251 jmp start_ipxe
253 help:
254 movw $EXEADRS(helpmsg), %si
255 puts:
256 lodsb
257 orb %al, %al
258 je exit
259 call putc
260 jmp puts
261 #endif
263 putcdot:
264 movb $0x2E, %al
265 putc:
266 movb $0xE, %ah
267 movw $7, %bx
268 int $0x10
269 exit:
270 ret
273 # read_sectors reads %di sectors into %es:0 buffer.
274 # %es:0 is updated to the next memory location.
275 # First, sectors are read sector by sector until
276 # sector per track count is known. Then they are
277 # read track by track.
278 # Assume no error on first track.
280 #ifdef FLOPPY_1440K_ONLY
281 #define FLOPPY_HEADS 2 /* 2 heads */
282 #define FLOPPY_SECTORS 18 /* 18 sectors */
283 #else
284 #define FLOPPY_HEADS 2 /* 2 heads minimum */
285 #define FLOPPY_SECTORS 9 /* 9 sectors minimum */
286 #endif
288 check_limits:
289 #ifndef FLOPPY_1440K_ONLY
290 popw %dx
291 #ifdef FLOPPY_SECTORS
292 cmpb $FLOPPY_SECTORS+1, %cl # minimum sector count
293 jb check_head
294 #endif
295 cmpb %al, %cl # max sector known ?
296 ja next_head # no -> store it
297 check_head:
298 #ifdef FLOPPY_HEADS
299 cmpb $FLOPPY_HEADS, %dh # 2 heads minimum
300 jb check_cylinder
301 #endif
302 cmpb %ah, %dh # max head known ?
303 ja next_cylinder # no -> store it
304 check_cylinder:
305 #endif
306 pushaw
307 #ifndef FLOPPY_1440K_ONLY
308 cbw # %ah = 0
309 #endif
310 int $0x13 # reset controler
311 popaw
312 movb $1, %al # sector by sector...
313 read_sectorslp:
314 pushw %dx # some bios break dx...
315 #ifndef FLOPPY_1440K_ONLY
316 pushw %ax # limits
317 subb %cl, %al # sectors remaining in track
318 ja tolastsect
319 movb $1, %al # 1 sector mini
320 tolastsect:
321 #else
322 mov $FLOPPY_SECTORS+1, %al
323 subb %cl, %al # sectors remaining in track
324 #endif
325 cbw
326 cmpw %di, %ax
327 jb more1trk
328 movw %di, %ax # sectors to read
329 more1trk:
330 pushw %ax # save context
331 movb $2, %ah # cmd: read chs
332 int $0x13
333 #ifndef FLOPPY_1440K_ONLY
334 popw %dx # save %ax
335 popw %ax # limits
336 #else
337 popw %ax # restore context
338 popw %dx
339 #endif
340 jc check_limits
341 #ifndef FLOPPY_1440K_ONLY
342 xchgw %ax, %bp
343 addw %dx,%cx # next sector
344 movw %cx, %gs
345 movw %es, %cx
346 pushw %dx
347 shlw $5, %dx
348 addw %dx, %cx
349 popw %dx
350 subw %dx,%di # update sector counter
351 popw %dx
352 read_sectorsCX:
353 movw %cx, %es # next location
354 jz putcdot
355 #else
356 addw %ax,%cx # next sector
357 movw %cx, %gs
358 movw %es, %cx
359 pushw %ax
360 shlw $5, %ax
361 addw %ax, %cx
362 popw %ax
363 subw %ax,%di # update sector counter
364 read_sectorsCX:
365 movw %cx, %es # next location
366 jz putcdot
367 #endif
368 read_sectors:
369 movw %gs, %cx
370 #ifndef FLOPPY_1440K_ONLY
371 # al is last sector+1
372 # ah is last cylinder+1
373 xchgw %ax, %bp
374 #endif
375 #ifndef FLOPPY_1440K_ONLY
376 cmpb %al,%cl # reach sector limit ?
377 jne bdendlp
378 next_head:
379 movb %cl,%al
380 #else
381 cmpb $FLOPPY_SECTORS+1,%cl # reach sector limit ?
382 jne bdendlp
383 #endif
384 incb %dh # next head
385 movb $1,%cl # first sector
386 #ifndef FLOPPY_1440K_ONLY
387 cmpb %ah, %dh # reach head limit ?
388 jne bdendlp
389 next_cylinder:
390 movb %dh,%ah
391 #else
392 cmpb %cl,%dh # reach head limit ?
393 je bdendlp
394 #endif
395 # NOTE : support 256 cylinders max
396 incb %ch # next cylinder
397 read_first_sectors:
398 movb $0,%dh # first head
399 bdendlp:
400 jmp read_sectorslp
402 #ifdef EXE_SUPPORT
403 need386:
404 .ascii "No 386+."
405 .byte 13,10
406 .byte 0
407 helpmsg:
408 .ascii "No help available."
409 .byte 13,10
410 .byte 0
411 #endif
413 /*
414 The following header is documented in the Linux source code at
415 Documentation/x86/boot.txt
416 */
417 .org 497
418 setup_sects:
419 .byte SETUPSECS
420 root_flags:
421 .word 0
422 syssize:
423 .long -PREFIXPGH
425 .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
426 .ascii "ADDL"
427 .long syssize
428 .long 16
429 .long 0
430 .previous
432 ram_size:
433 .word 0
434 vid_mode:
435 .word 0
436 root_dev:
437 .word 0
438 boot_flag:
439 .word 0xAA55
440 jump:
441 /* Manually specify a two-byte jmp instruction here rather
442 * than leaving it up to the assembler. */
443 .byte 0xeb
444 .byte setup_code - header
445 header:
446 .byte 'H', 'd', 'r', 'S'
447 version:
448 .word 0x0207 /* 2.07 */
449 realmode_swtch:
450 .long 0
451 start_sys:
452 .word 0
453 kernel_version:
454 .word 0
455 type_of_loader:
456 .byte 0
457 loadflags:
458 .byte 0
459 setup_move_size:
460 .word 0
461 code32_start:
462 .long SYSSEG*16
463 ramdisk_image:
464 .long 0
465 ramdisk_size:
466 .long 0
467 bootsect_kludge:
468 .long 0
469 heap_end_ptr:
470 .word 0
471 pad1:
472 .word 0
473 cmd_line_ptr:
474 .long 0
475 initrd_addr_max:
476 /* We don't use an initrd but some bootloaders (e.g. SYSLINUX) have
477 * been known to require this field. Set the value to 2 GB. This
478 * value is also used by the Linux kernel. */
479 .long 0x7fffffff
480 kernel_alignment:
481 .long 0
482 relocatable_kernel:
483 .byte 0
484 pad2:
485 .byte 0, 0, 0
486 cmdline_size:
487 .long 0x7ff
488 hardware_subarch:
489 .long 0
490 hardware_subarch_data:
491 .byte 0, 0, 0, 0, 0, 0, 0, 0
493 /*
494 We don't need to do too much setup.
496 This code gets loaded at SETUPSEG:0. It wants to start
497 executing the image that's loaded at SYSSEG:0 and
498 whose entry point is SYSSEG:0.
499 */
500 setup_code:
501 movl ramdisk_image, %eax
502 orl %eax, %eax
503 jnz setup_done
505 movw $default_config, %di
506 movw $-1, %bx
508 movw $9, %cx
509 1:
510 pushw %ax
511 loop 1b
512 pushw $0x9310
513 pushw %ax
514 pushw %bx
515 pushw %ax
516 pushw $0x9300+(INITSEG>>12)
517 pushw %di
518 pushw %bx
519 movb $8, %cl
520 1:
521 pushw %ax
522 loop 1b
523 1:
524 incw %bx
525 cmpb %al, (%bx,%di)
526 jne 1b
527 movw %bx, ramdisk_size
528 movb $0x10, ramdisk_image+2
530 pushw %ss
531 popw %es
532 movw %sp, %si
533 movb $0x87, %ah
534 movw $(run_ipxe-default_config)/2+1, %cx
535 int $0x15
537 setup_done:
538 /* We expect to be contiguous in memory once loaded. The Linux image
539 * boot process requires that setup code is loaded separately from
540 * "non-real code". Since we don't need any information that's left
541 * in the prefix, it doesn't matter: we just have to ensure that
542 * %cs:0000 is where the start of the image *would* be.
543 */
544 ljmp $(SYSSEG-(PREFIXSIZE/16)), $run_ipxe
546 default_config:
548 .org PREFIXSIZE
549 /*
550 We're now at the beginning of the kernel proper.
551 */
552 run_ipxe:
553 /* Set up stack just below 0x7c00 and clear direction flag */
554 xorw %ax, %ax
555 movw %ax, %ss
556 movw $0x7c00, %sp
557 cld
559 /* Retrieve command-line pointer */
560 movl %ds:cmd_line_ptr, %edx
561 testl %edx, %edx
562 jz no_cmd_line
564 /* Set up %es:%di to point to command line */
565 movl %edx, %edi
566 andl $0xf, %edi
567 rorl $4, %edx
568 movw %dx, %es
570 /* Find length of command line */
571 pushw %di
572 movw $0xffff, %cx
573 repnz scasb
574 notw %cx
575 popw %si
577 /* Make space for command line on stack */
578 movw %sp, %di
579 subw %cx, %di
580 andw $~0xf, %di
581 movw %di, %sp
583 /* Copy command line to stack */
584 pushw %ds
585 pushw %es
586 popw %ds
587 pushw %ss
588 popw %es
589 rep movsb
590 popw %ds
592 /* Store new command-line pointer */
593 movzwl %sp, %edx
594 no_cmd_line:
596 /* Calculate maximum relocation address */
597 movl ramdisk_image, %ebp
598 testl %ebp, %ebp
599 jnz 1f
600 decl %ebp /* Allow arbitrary relocation if no initrd */
601 1:
603 /* Install iPXE */
604 call alloc_basemem
605 xorl %esi, %esi
606 xorl %edi, %edi
607 call install_prealloc
609 /* Retrieve initrd pointer and size */
610 movl ramdisk_image, %ebp
611 movl ramdisk_size, %ecx
613 start_ipxe:
614 /* Set up real-mode stack */
615 movw %bx, %ss
616 movw $_estack16, %sp
618 /* Jump to .text16 segment */
619 pushw %ax
620 pushw $1f
621 lret
622 .section ".text16", "awx", @progbits
623 1:
624 /* Set up %ds for access to .data16 */
625 movw %bx, %ds
627 /* Store command-line pointer */
628 movl %edx, cmdline_phys
630 /* Store initrd pointer and size */
631 movl %ebp, initrd_phys
632 movl %ecx, initrd_len
634 /* Run iPXE */
635 pushl $main
636 pushw %cs
637 call prot_call
638 popl %ecx /* discard */
640 /* Uninstall iPXE */
641 call uninstall
643 /* Boot next device */
644 int $0x18