wok view ipxe/stuff/lkrnprefix.S @ rev 15369

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