wok-next view ipxe/stuff/lkrnprefix.S @ rev 19883

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