wok-next view ipxe/stuff/lkrnprefix.S @ rev 15666
Add ddumbfs
author | Pascal Bellard <pascal.bellard@slitaz.org> |
---|---|
date | Fri Dec 13 16:18:29 2013 +0000 (2013-12-13) |
parents | 6c3718ca17b6 |
children | 6aed6fc5819d |
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 #endif
108 cld # assume nothing
109 stacktop = 0x9E00 # in 0x8000 .. 0xA000
110 zeroed = 12 # zeroed registers
111 movw $stacktop-12-zeroed, %di # stacktop is an arbitrary value >=
112 # length of bootsect + length of
113 # setup + room for stack;
114 # 12 is disk parm size.
115 pushw $INITSEG
116 popw %ss # %ss contain INITSEG
117 movw %di, %sp # put stack at INITSEG:stacktop-...
119 # Many BIOS's default disk parameter tables will not recognize
120 # multi-sector reads beyond the maximum sector number specified
121 # in the default diskette parameter tables - this may mean 7
122 # sectors in some cases.
123 #
124 # Since single sector reads are slow and out of the question,
125 # we must take care of this by creating new parameter tables
126 # (for the first disk) in RAM. We can set the maximum sector
127 # count to 36 - the most we will encounter on an ED 2.88.
128 #
129 # High doesn't hurt. Low does. Let's use the max: 63
131 pushw %ss
132 popw %es # %es = %ss = INITSEG
133 xorw %ax, %ax # %ax = 0
134 #ifdef EXE_SUPPORT
135 cwd # %dx = 0
136 #endif
137 movw $zeroed/2, %cx # clear gdt + offset, %ds, limits
138 rep # don't worry about cld
139 stosw # already done above
140 popw %bx # offset = 0
141 popw %ds # %ds = 0
142 popw %fs # %fs = 0
144 movb setup_sects+0x7C00, %al # read bootsector + setup (%ds = 0)
145 incw %ax
147 ldsw 0x78(%bx), %si # %ds:%bx+0x78 is parameter table address
148 pushw %es
149 pushw %di
150 movb $6, %cl # copy 12 bytes
151 rep # don't worry about cld
152 movsw # already done above
153 pushw %ss
154 popw %ds # now %ds = %es = %ss = INITSEG
155 popl %fs:0x78(%bx) # update parameter table address
156 movb $63, 0x4-12(%di) # patch sector count, %di = stacktop
157 cli
159 xchg %ax, %di # sector count
160 popw %ax # limits = 0
161 incw %cx # cylinder 0, sector 1, clear Z
162 call read_first_sectors # read setup
164 # This routine loads the system at address LOADSEG, making sure
165 # no 64kB boundaries are crossed. We try to load it as fast as
166 # possible, loading whole tracks whenever we can.
168 popw %bx # clear %bx
169 movw syssize, %di
170 addw $(512/16)-1, %di
171 shrw $9-4, %di
172 movw $SYSSEG, %cx
173 call read_sectorsCX
175 # This procedure turns off the floppy drive motor, so
176 # that we enter the kernel in a known state, and
177 # don't have to worry about it later.
179 kill_motor:
180 xchgw %ax, %di # reset FDC (%di < 128)
181 int $0x13
183 # After that (everything loaded), we jump to the setup-routine
184 # loaded directly after the bootblock:
185 # Segments are as follows: %ds = %ss = INITSEG
187 ljmp $SETUPSEG, $0
189 #ifdef EXE_SUPPORT
190 dosexit:
191 movw $0x4c00, %ax
192 int $0x21
194 _exe_start:
195 pushw $dosexit
196 movw $EXEADRS(need386), %si
197 pushfw // save flags
198 // bits 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
199 // flags 0 NT IOPL OF DF IF TF SF ZF 0 AF 0 PF 1 CF
200 movb $0x10, %ah // DF = IF = TF = 0
201 pushw %ax
202 popfw // < 286 : flags[12..15] are forced 1
203 pushfw // = 286 : flags[12..15] are forced 0
204 popw %cx // > 286 : only flags[15] is forced 0
205 popfw // restore flags
206 cmpb %ah, %ch // test Fx and 0x cases
207 js puts // S= not 386+
208 // smsww %ax
209 // andb $1, %al
210 // jne puts
212 /* Terminate command line with a NUL */
213 movzbw PSP_CMDLINE_LEN, %si
214 movb $0, PSP_CMDLINE_START(%si)
215 cmpb $'?', PSP_CMDLINE_START-1(%si)
216 je help
217 pushw %si
219 /* Install iPXE. Use a fixed temporary decompression area to
220 * avoid trashing the DOS high memory area.
221 */
222 call alloc_basemem
223 movl $EXE_DECOMPRESS_ADDRESS, %edi
224 stc
225 sbbl %ebp, %ebp /* Allow arbitrary relocation */
226 xorl %esi, %esi
227 call install_prealloc
229 xorl %ebp, %ebp
230 xorl %ecx, %ecx
232 /* Calculate command line physical address */
233 xorl %edx, %edx
234 movw %ds, %dx
235 shll $4, %edx
236 popw %si
237 orw %si, %si
238 jne gotarg
239 movw $EXEADRS(default_config), %bp
240 addl %edx, %ebp
241 movw $0xA00-default_config, %cx
242 gotarg:
243 addl $PSP_CMDLINE_START, %edx
245 jmp start_ipxe
247 help:
248 movw $EXEADRS(helpmsg), %si
249 puts:
250 lodsb
251 orb %al, %al
252 je exit
253 call putc
254 jmp puts
255 #endif
257 putcdot:
258 movb $0x2E, %al
259 putc:
260 movb $0xE, %ah
261 movw $7, %bx
262 int $0x10
263 exit:
264 ret
267 # read_sectors reads %di sectors into %es:0 buffer.
268 # %es:0 is updated to the next memory location.
269 # First, sectors are read sector by sector until
270 # sector per track count is known. Then they are
271 # read track by track.
272 # Assume no error on first track.
274 #ifdef FLOPPY_1440K_ONLY
275 #define FLOPPY_HEADS 2 /* 2 heads */
276 #define FLOPPY_SECTORS 18 /* 18 sectors */
277 #else
278 #define FLOPPY_HEADS 2 /* 2 heads minimum */
279 #define FLOPPY_SECTORS 9 /* 9 sectors minimum */
280 #endif
282 check_limits:
283 #ifndef FLOPPY_1440K_ONLY
284 popw %dx
285 #ifdef FLOPPY_SECTORS
286 cmpb $FLOPPY_SECTORS+1, %cl # minimum sector count
287 jb check_head
288 #endif
289 cmpb %al, %cl # max sector known ?
290 ja next_head # no -> store it
291 check_head:
292 #ifdef FLOPPY_HEADS
293 cmpb $FLOPPY_HEADS, %dh # 2 heads minimum
294 jb check_cylinder
295 #endif
296 cmpb %ah, %dh # max head known ?
297 ja next_cylinder # no -> store it
298 check_cylinder:
299 #endif
300 pushaw
301 #ifndef FLOPPY_1440K_ONLY
302 cbw # %ah = 0
303 #endif
304 int $0x13 # reset controler
305 popaw
306 movb $1, %al # sector by sector...
307 read_sectorslp:
308 pushw %dx # some bios break dx...
309 #ifndef FLOPPY_1440K_ONLY
310 pushw %ax # limits
311 subb %cl, %al # sectors remaining in track
312 ja tolastsect
313 movb $1, %al # 1 sector mini
314 tolastsect:
315 #else
316 mov $FLOPPY_SECTORS+1, %al
317 subb %cl, %al # sectors remaining in track
318 #endif
319 cbw
320 cmpw %di, %ax
321 jb more1trk
322 movw %di, %ax # sectors to read
323 more1trk:
324 pushw %ax # save context
325 movb $2, %ah # cmd: read chs
326 int $0x13
327 #ifndef FLOPPY_1440K_ONLY
328 popw %dx # save %ax
329 popw %ax # limits
330 #else
331 popw %ax # restore context
332 popw %dx
333 #endif
334 jc check_limits
335 #ifndef FLOPPY_1440K_ONLY
336 xchgw %ax, %bp
337 addw %dx,%cx # next sector
338 movw %cx, %gs
339 movw %es, %cx
340 pushw %dx
341 shlw $5, %dx
342 addw %dx, %cx
343 popw %dx
344 subw %dx,%di # update sector counter
345 popw %dx
346 read_sectorsCX:
347 movw %cx, %es # next location
348 jz putcdot
349 #else
350 addw %ax,%cx # next sector
351 movw %cx, %gs
352 movw %es, %cx
353 pushw %ax
354 shlw $5, %ax
355 addw %ax, %cx
356 popw %ax
357 subw %ax,%di # update sector counter
358 read_sectorsCX:
359 movw %cx, %es # next location
360 jz putcdot
361 #endif
362 read_sectors:
363 movw %gs, %cx
364 #ifndef FLOPPY_1440K_ONLY
365 # al is last sector+1
366 # ah is last cylinder+1
367 xchgw %ax, %bp
368 #endif
369 #ifndef FLOPPY_1440K_ONLY
370 cmpb %al,%cl # reach sector limit ?
371 jne bdendlp
372 next_head:
373 movb %cl,%al
374 #else
375 cmpb $FLOPPY_SECTORS+1,%cl # reach sector limit ?
376 jne bdendlp
377 #endif
378 incb %dh # next head
379 movb $1,%cl # first sector
380 #ifndef FLOPPY_1440K_ONLY
381 cmpb %ah, %dh # reach head limit ?
382 jne bdendlp
383 next_cylinder:
384 movb %dh,%ah
385 #else
386 cmpb %cl,%dh # reach head limit ?
387 je bdendlp
388 #endif
389 # NOTE : support 256 cylinders max
390 incb %ch # next cylinder
391 read_first_sectors:
392 movb $0,%dh # first head
393 bdendlp:
394 jmp read_sectorslp
396 #ifdef EXE_SUPPORT
397 need386:
398 .ascii "No 386+."
399 .byte 13,10
400 .byte 0
401 helpmsg:
402 .ascii "No help available."
403 .byte 13,10
404 .byte 0
405 #endif
407 /*
408 The following header is documented in the Linux source code at
409 Documentation/x86/boot.txt
410 */
411 .org 497
412 setup_sects:
413 .byte SETUPSECS
414 root_flags:
415 .word 0
416 syssize:
417 .long -PREFIXPGH
419 .section ".zinfo.fixup", "a", @progbits /* Compressor fixups */
420 .ascii "ADDL"
421 .long syssize
422 .long 16
423 .long 0
424 .previous
426 ram_size:
427 .word 0
428 vid_mode:
429 .word 0
430 root_dev:
431 .word 0
432 boot_flag:
433 .word 0xAA55
434 jump:
435 /* Manually specify a two-byte jmp instruction here rather
436 * than leaving it up to the assembler. */
437 .byte 0xeb
438 .byte setup_code - header
439 header:
440 .byte 'H', 'd', 'r', 'S'
441 version:
442 .word 0x0207 /* 2.07 */
443 realmode_swtch:
444 .long 0
445 start_sys:
446 .word 0
447 kernel_version:
448 .word 0
449 type_of_loader:
450 .byte 0
451 loadflags:
452 .byte 0
453 setup_move_size:
454 .word 0
455 code32_start:
456 .long SYSSEG*16
457 ramdisk_image:
458 .long 0
459 ramdisk_size:
460 .long 0
461 bootsect_kludge:
462 .long 0
463 heap_end_ptr:
464 .word 0
465 pad1:
466 .word 0
467 cmd_line_ptr:
468 .long 0
469 initrd_addr_max:
470 /* We don't use an initrd but some bootloaders (e.g. SYSLINUX) have
471 * been known to require this field. Set the value to 2 GB. This
472 * value is also used by the Linux kernel. */
473 .long 0x7fffffff
474 kernel_alignment:
475 .long 0
476 relocatable_kernel:
477 .byte 0
478 pad2:
479 .byte 0, 0, 0
480 cmdline_size:
481 .long 0x7ff
482 hardware_subarch:
483 .long 0
484 hardware_subarch_data:
485 .byte 0, 0, 0, 0, 0, 0, 0, 0
487 /*
488 We don't need to do too much setup.
490 This code gets loaded at SETUPSEG:0. It wants to start
491 executing the image that's loaded at SYSSEG:0 and
492 whose entry point is SYSSEG:0.
493 */
494 setup_code:
495 movl ramdisk_image, %eax
496 orl %eax, %eax
497 jnz setup_done
499 movw $default_config, %di
500 movw $-1, %bx
502 movw $9, %cx
503 1:
504 pushw %ax
505 loop 1b
506 pushw $0x9310
507 pushw %ax
508 pushw %bx
509 pushw %ax
510 pushw $0x9300+(INITSEG>>12)
511 pushw %di
512 pushw %bx
513 movb $8, %cl
514 1:
515 pushw %ax
516 loop 1b
517 1:
518 incw %bx
519 cmpb %al, (%bx,%di)
520 jne 1b
521 movw %bx, ramdisk_size
522 movb $0x10, ramdisk_image+2
524 pushw %ss
525 popw %es
526 movw %sp, %si
527 movb $0x87, %ah
528 movw $(run_ipxe-default_config)/2+1, %cx
529 int $0x15
531 setup_done:
532 /* We expect to be contiguous in memory once loaded. The Linux image
533 * boot process requires that setup code is loaded separately from
534 * "non-real code". Since we don't need any information that's left
535 * in the prefix, it doesn't matter: we just have to ensure that
536 * %cs:0000 is where the start of the image *would* be.
537 */
538 ljmp $(SYSSEG-(PREFIXSIZE/16)), $run_ipxe
540 default_config:
542 .org PREFIXSIZE
543 /*
544 We're now at the beginning of the kernel proper.
545 */
546 run_ipxe:
547 /* Set up stack just below 0x7c00 and clear direction flag */
548 xorw %ax, %ax
549 movw %ax, %ss
550 movw $0x7c00, %sp
551 cld
553 /* Retrieve command-line pointer */
554 movl %ds:cmd_line_ptr, %edx
555 testl %edx, %edx
556 jz no_cmd_line
558 /* Set up %es:%di to point to command line */
559 movl %edx, %edi
560 andl $0xf, %edi
561 rorl $4, %edx
562 movw %dx, %es
564 /* Find length of command line */
565 pushw %di
566 movw $0xffff, %cx
567 repnz scasb
568 notw %cx
569 popw %si
571 /* Make space for command line on stack */
572 movw %sp, %di
573 subw %cx, %di
574 andw $~0xf, %di
575 movw %di, %sp
577 /* Copy command line to stack */
578 pushw %ds
579 pushw %es
580 popw %ds
581 pushw %ss
582 popw %es
583 rep movsb
584 popw %ds
586 /* Store new command-line pointer */
587 movzwl %sp, %edx
588 no_cmd_line:
590 /* Calculate maximum relocation address */
591 movl ramdisk_image, %ebp
592 testl %ebp, %ebp
593 jnz 1f
594 decl %ebp /* Allow arbitrary relocation if no initrd */
595 1:
597 /* Install iPXE */
598 call alloc_basemem
599 xorl %esi, %esi
600 xorl %edi, %edi
601 call install_prealloc
603 /* Retrieve initrd pointer and size */
604 movl ramdisk_image, %ebp
605 movl ramdisk_size, %ecx
607 start_ipxe:
608 /* Set up real-mode stack */
609 movw %bx, %ss
610 movw $_estack16, %sp
612 /* Jump to .text16 segment */
613 pushw %ax
614 pushw $1f
615 lret
616 .section ".text16", "awx", @progbits
617 1:
618 /* Set up %ds for access to .data16 */
619 movw %bx, %ds
621 /* Store command-line pointer */
622 movl %edx, cmdline_phys
624 /* Store initrd pointer and size */
625 movl %ebp, initrd_phys
626 movl %ecx, initrd_len
628 /* Run iPXE */
629 pushl $main
630 pushw %cs
631 call prot_call
632 popl %ecx /* discard */
634 /* Uninstall iPXE */
635 call uninstall
637 /* Boot next device */
638 int $0x18