Magellan Linux

Contents of /trunk/mkinitrd-magellan/isolinux/runkernel.inc

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1133 - (show annotations) (download)
Thu Aug 19 09:50:43 2010 UTC (13 years, 8 months ago) by niro
File size: 17162 byte(s)
-updated to isolinux-3.86
1 ;; -----------------------------------------------------------------------
2 ;;
3 ;; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
4 ;; Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
5 ;;
6 ;; This program is free software; you can redistribute it and/or modify
7 ;; it under the terms of the GNU General Public License as published by
8 ;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
9 ;; Boston MA 02111-1307, USA; either version 2 of the License, or
10 ;; (at your option) any later version; incorporated herein by reference.
11 ;;
12 ;; -----------------------------------------------------------------------
13
14 ;;
15 ;; runkernel.inc
16 ;;
17 ;; Common code for running a Linux kernel
18 ;;
19
20 ;
21 ; Hook macros, that may or may not be defined
22 ;
23 %ifndef HAVE_UNLOAD_PREP
24 %macro UNLOAD_PREP 0
25 %endmacro
26 %endif
27
28 ;
29 ; A Linux kernel consists of three parts: boot sector, setup code, and
30 ; kernel code. The boot sector is never executed when using an external
31 ; booting utility, but it contains some status bytes that are necessary.
32 ;
33 ; First check that our kernel is at least 1K, or else it isn't long
34 ; enough to have the appropriate headers.
35 ;
36 ; We used to require the kernel to be 64K or larger, but it has gotten
37 ; popular to use the Linux kernel format for other things, which may
38 ; not be so large.
39 ;
40 ; Additionally, we used to have a test for 8 MB or smaller. Equally
41 ; obsolete.
42 ;
43 is_linux_kernel:
44 push si ; <A> file pointer
45
46 ;
47 ; Now start transferring the kernel
48 ;
49 push word real_mode_seg
50 pop es
51
52 ;
53 ; Start by loading the bootsector/setup code, to see if we need to
54 ; do something funky. It should fit in the first 32K (loading 64K won't
55 ; work since we might have funny stuff up near the end of memory).
56 ;
57 call abort_check ; Check for abort key
58 mov cx,8000h >> SECTOR_SHIFT ; Half a moby (32K)
59 xor bx,bx
60 pop si ; <A> file pointer
61 call getfssec
62 cmp cx,1024
63 jb kernel_corrupt
64 cmp word [es:bs_bootsign],0AA55h
65 jne kernel_corrupt ; Boot sec signature missing
66
67 ;
68 ; Save the file pointer for later...
69 ;
70 push si ; <A> file pointer
71
72 ;
73 ; Construct the command line (append options have already been copied)
74 ;
75 construct_cmdline:
76 mov di,[CmdLinePtr]
77 mov si,boot_image ; BOOT_IMAGE=
78 mov cx,boot_image_len
79 rep movsb
80 mov si,KernelCName ; Unmangled kernel name
81 mov cx,[KernelCNameLen]
82 rep movsb
83 mov al,' ' ; Space
84 stosb
85
86 call do_ip_append ; Handle IPAppend
87
88 mov si,[CmdOptPtr] ; Options from user input
89 call strcpy
90
91 ;
92 ; Scan through the command line for anything that looks like we might be
93 ; interested in. The original version of this code automatically assumed
94 ; the first option was BOOT_IMAGE=, but that is no longer certain.
95 ;
96 parse_cmdline:
97 mov di,cmd_line_here
98 .skipspace: mov al,[es:di]
99 inc di
100 .skipspace_loaded:
101 and al,al
102 jz cmdline_end
103 cmp al,' '
104 jbe .skipspace
105 dec di
106
107 ; ES:DI now points to the beginning of an option
108 mov si,options_list
109 .next_opt:
110 movzx cx,byte [si]
111 jcxz .skip_opt
112 push di
113 inc si
114 repe cmpsb
115 jne .no_match
116
117 ; This either needs to have been an option with parameter,
118 ; or be followed by EOL/whitespace
119 mov ax,[es:di-1] ; AL = last chr; AH = following
120 cmp al,'='
121 je .is_match
122 cmp ah,' '
123 ja .no_match
124 .is_match:
125 pop ax ; Drop option pointer on stack
126 call [si]
127 .skip_opt:
128 mov al,[es:di]
129 inc di
130 cmp al,' '
131 ja .skip_opt
132 jmp .skipspace_loaded
133 .no_match:
134 pop di
135 add si,cx ; Skip remaining bytes
136 inc si ; Skip function pointer
137 inc si
138 jmp .next_opt
139
140 opt_vga:
141 mov ax,[es:di-1]
142 mov bx,-1
143 cmp ax,'=n' ; vga=normal
144 je .vc0
145 dec bx ; bx <- -2
146 cmp ax,'=e' ; vga=ext
147 je .vc0
148 dec bx ; bx <- -3
149 cmp ax,'=a' ; vga=ask
150 je .vc0
151 mov bx,0x0f04 ; bx <- 0x0f04 (current mode)
152 cmp ax,'=c' ; vga=current
153 je .vc0
154 call parseint_esdi ; vga=<number>
155 jc .skip ; Not an integer
156 .vc0: mov [es:bs_vidmode],bx ; Set video mode
157 .skip:
158 ret
159
160 opt_mem:
161 call parseint_esdi
162 jc .skip
163 %if HIGHMEM_SLOP != 0
164 sub ebx,HIGHMEM_SLOP
165 %endif
166 mov [MyHighMemSize],ebx
167 .skip:
168 ret
169
170 opt_quiet:
171 mov byte [QuietBoot],QUIET_FLAG
172 ret
173
174 %if IS_PXELINUX
175 opt_keeppxe:
176 or byte [KeepPXE],1 ; KeepPXE set by command line
177 ret
178 %endif
179
180 opt_initrd:
181 mov ax,di
182 cmp byte [es:di],' '
183 ja .have_initrd
184 xor ax,ax
185 .have_initrd:
186 mov [InitRDPtr],ax
187 ret
188
189 ;
190 ; After command line parsing...
191 ;
192 cmdline_end:
193 sub di,cmd_line_here
194 mov [CmdLineLen],di ; Length including final null
195
196 ;
197 ; Now check if we have a large kernel, which needs to be loaded high
198 ;
199 prepare_header:
200 mov dword [RamdiskMax], HIGHMEM_MAX ; Default initrd limit
201 cmp dword [es:su_header],HEADER_ID ; New setup code ID
202 jne old_kernel ; Old kernel, load low
203 mov ax,[es:su_version]
204 mov [KernelVersion],ax
205 cmp ax,0200h ; Setup code version 2.0
206 jb old_kernel ; Old kernel, load low
207 cmp ax,0201h ; Version 2.01+?
208 jb new_kernel ; If 2.00, skip this step
209 ; Set up the heap (assuming loading high for now)
210 mov word [es:su_heapend],linux_stack-512
211 or byte [es:su_loadflags],80h ; Let the kernel know we care
212 cmp ax,0203h ; Version 2.03+?
213 jb new_kernel ; Not 2.03+
214 mov eax,[es:su_ramdisk_max]
215 mov [RamdiskMax],eax ; Set the ramdisk limit
216
217 ;
218 ; We definitely have a new-style kernel. Let the kernel know who we are,
219 ; and that we are clueful
220 ;
221 new_kernel:
222 mov byte [es:su_loader],my_id ; Show some ID
223 xor eax,eax
224 mov [es:su_ramdisklen],eax ; No initrd loaded yet
225
226 ;
227 ; About to load the kernel. This is a modern kernel, so use the boot flags
228 ; we were provided.
229 ;
230 mov al,[es:su_loadflags]
231 or al,[QuietBoot] ; Set QUIET_FLAG if needed
232 mov [es:su_loadflags],al
233 mov [LoadFlags],al
234
235 any_kernel:
236 mov si,loading_msg
237 call writestr_qchk
238 mov si,KernelCName ; Print kernel name part of
239 call writestr_qchk ; "Loading" message
240
241 ;
242 ; Load the kernel. We always load it at 100000h even if we're supposed to
243 ; load it "low"; for a "low" load we copy it down to low memory right before
244 ; jumping to it.
245 ;
246 read_kernel:
247 movzx ax,byte [es:bs_setupsecs] ; Setup sectors
248 and ax,ax
249 jnz .sects_ok
250 mov al,4 ; 0 = 4 setup sectors
251 .sects_ok:
252 inc ax ; Including the boot sector
253 mov [SetupSecs],ax
254
255 call dot_pause
256
257 ;
258 ; Move the stuff beyond the setup code to high memory at 100000h
259 ;
260 movzx esi,word [SetupSecs] ; Setup sectors
261 shl si,9 ; Convert to bytes
262 mov ecx,8000h ; 32K
263 sub ecx,esi ; Number of bytes to copy
264 add esi,(real_mode_seg << 4) ; Pointer to source
265 mov edi,100000h ; Copy to address 100000h
266
267 call bcopy ; Transfer to high memory
268
269 pop si ; <A> File pointer
270 and si,si ; EOF already?
271 jz high_load_done
272
273 ; On exit EDI -> where to load the rest
274
275 mov bx,dot_pause
276 or eax,-1 ; Load the whole file
277 mov dx,3 ; Pad to dword
278 call load_high
279
280 high_load_done:
281 mov [KernelEnd],edi
282 mov ax,real_mode_seg ; Set to real mode seg
283 mov es,ax
284
285 mov si,dot_msg
286 call writestr_qchk
287
288 ;
289 ; Some older kernels (1.2 era) would have more than 4 setup sectors, but
290 ; would not rely on the boot protocol to manage that. These kernels fail
291 ; if they see protected-mode kernel data after the setup sectors, so
292 ; clear that memory.
293 ;
294 push di
295 mov di,[SetupSecs]
296 shl di,9
297 xor eax,eax
298 mov cx,cmd_line_here
299 sub cx,di
300 shr cx,2
301 rep stosd
302 pop di
303
304 ;
305 ; Now see if we have an initial RAMdisk; if so, do requisite computation
306 ; We know we have a new kernel; the old_kernel code already will have objected
307 ; if we tried to load initrd using an old kernel
308 ;
309 load_initrd:
310 ; Cap the ramdisk memory range if appropriate
311 mov eax,[RamdiskMax]
312 cmp eax,[MyHighMemSize]
313 ja .ok
314 mov [MyHighMemSize],eax
315 .ok:
316 xor eax,eax
317 cmp [InitRDPtr],ax
318 jz .noinitrd
319 call parse_load_initrd
320 .noinitrd:
321
322 ;
323 ; Abandon hope, ye that enter here! We do no longer permit aborts.
324 ;
325 call abort_check ; Last chance!!
326
327 mov si,ready_msg
328 call writestr_qchk
329
330 UNLOAD_PREP ; Module-specific hook
331
332 ;
333 ; Now, if we were supposed to load "low", copy the kernel down to 10000h
334 ; and the real mode stuff to 90000h. We assume that all bzImage kernels are
335 ; capable of starting their setup from a different address.
336 ;
337 mov ax,real_mode_seg
338 mov es,ax
339 mov fs,ax
340
341 ;
342 ; If the default root device is set to FLOPPY (0000h), change to
343 ; /dev/fd0 (0200h)
344 ;
345 cmp word [es:bs_rootdev],byte 0
346 jne root_not_floppy
347 mov word [es:bs_rootdev],0200h
348 root_not_floppy:
349
350 ;
351 ; Copy command line. Unfortunately, the old kernel boot protocol requires
352 ; the command line to exist in the 9xxxxh range even if the rest of the
353 ; setup doesn't.
354 ;
355 setup_command_line:
356 mov dx,[KernelVersion]
357 test byte [LoadFlags],LOAD_HIGH
358 jz .need_high_cmdline
359 cmp dx,0202h ; Support new cmdline protocol?
360 jb .need_high_cmdline
361 ; New cmdline protocol
362 ; Store 32-bit (flat) pointer to command line
363 ; This is the "high" location, since we have bzImage
364 mov dword [fs:su_cmd_line_ptr],(real_mode_seg << 4)+cmd_line_here
365 mov word [HeapEnd],linux_stack
366 mov word [fs:su_heapend],linux_stack-512
367 jmp .setup_done
368
369 .need_high_cmdline:
370 ;
371 ; Copy command line down to fit in high conventional memory
372 ; -- this happens if we have a zImage kernel or the protocol
373 ; is less than 2.02.
374 ;
375 mov si,cmd_line_here
376 mov di,old_cmd_line_here
377 mov [fs:kern_cmd_magic],word CMD_MAGIC ; Store magic
378 mov [fs:kern_cmd_offset],di ; Store pointer
379 mov word [HeapEnd],old_linux_stack
380 mov ax,255 ; Max cmdline limit
381 cmp dx,0201h
382 jb .adjusted
383 ; Protocol 2.01+
384 mov word [fs:su_heapend],old_linux_stack-512
385 jbe .adjusted
386 ; Protocol 2.02+
387 ; Note that the only reason we would end up here is
388 ; because we have a zImage, so we anticipate the move
389 ; to 90000h already...
390 mov dword [fs:su_cmd_line_ptr],0x90000+old_cmd_line_here
391 mov ax,old_max_cmd_len ; 2.02+ allow a higher limit
392 .adjusted:
393
394 mov cx,[CmdLineLen]
395 cmp cx,ax
396 jna .len_ok
397 mov cx,ax ; Truncate the command line
398 .len_ok:
399 fs rep movsb
400 stosb ; Final null, note AL=0 already
401 mov [CmdLineEnd],di
402 cmp dx,0200h
403 jb .nomovesize
404 mov [es:su_movesize],di ; Tell the kernel what to move
405 .nomovesize:
406 .setup_done:
407
408 ;
409 ; Time to start setting up move descriptors
410 ;
411 setup_move:
412 mov di,trackbuf
413 xor cx,cx ; Number of descriptors
414
415 mov bx,es ; real_mode_seg
416 mov fs,bx
417 push ds ; We need DS == ES == CS here
418 pop es
419
420 test byte [LoadFlags],LOAD_HIGH
421 jnz .loading_high
422
423 ; Loading low: move real_mode stuff to 90000h, then move the kernel down
424 mov eax,90000h
425 stosd
426 mov eax,real_mode_seg << 4
427 stosd
428 movzx eax,word [CmdLineEnd]
429 stosd
430 inc cx
431
432 mov eax,10000h ; Target address of low kernel
433 stosd
434 mov eax,100000h ; Where currently loaded
435 stosd
436 neg eax
437 add eax,[KernelEnd]
438 stosd
439 inc cx
440
441 mov bx,9000h ; Revised real mode segment
442
443 .loading_high:
444
445 cmp word [InitRDPtr],0 ; Did we have an initrd?
446 je .no_initrd
447
448 mov eax,[fs:su_ramdiskat]
449 stosd
450 mov eax,[InitRDStart]
451 stosd
452 mov eax,[fs:su_ramdisklen]
453 stosd
454 inc cx
455
456 .no_initrd:
457 push dword run_linux_kernel
458 push cx ; Length of descriptor list
459
460 ; BX points to the final real mode segment, and will be loaded
461 ; into DS.
462
463 test byte [QuietBoot],QUIET_FLAG
464 jz replace_bootstrap
465 jmp replace_bootstrap_noclearmode
466
467 run_linux_kernel:
468 ;
469 ; Set up segment registers and the Linux real-mode stack
470 ; Note: ds == the real mode segment
471 ;
472 cli
473 mov ax,ds
474 mov ss,ax
475 mov sp,strict word linux_stack
476 ; Point HeapEnd to the immediate of the instruction above
477 HeapEnd equ $-2 ; Self-modifying code! Fun!
478 mov es,ax
479 mov fs,ax
480 mov gs,ax
481
482 ;
483 ; We're done... now RUN THAT KERNEL!!!!
484 ; Setup segment == real mode segment + 020h; we need to jump to offset
485 ; zero in the real mode segment.
486 ;
487 add ax,020h
488 push ax
489 push word 0h
490 retf
491
492 ;
493 ; Load an older kernel. Older kernels always have 4 setup sectors, can't have
494 ; initrd, and are always loaded low.
495 ;
496 old_kernel:
497 xor ax,ax
498 cmp word [InitRDPtr],ax ; Old kernel can't have initrd
499 je .load
500 mov si,err_oldkernel
501 jmp abort_load
502 .load:
503 mov byte [LoadFlags],al ; Always low
504 mov word [KernelVersion],ax ; Version 0.00
505 jmp any_kernel
506
507 ;
508 ; parse_load_initrd
509 ;
510 ; Parse an initrd= option and load the initrds. This sets
511 ; InitRDStart and InitRDEnd with dword padding between; we then
512 ; do a global memory shuffle to move it to the end of memory.
513 ;
514 ; On entry, EDI points to where to start loading.
515 ;
516 parse_load_initrd:
517 push es
518 push ds
519 mov ax,real_mode_seg
520 mov ds,ax
521 push cs
522 pop es ; DS == real_mode_seg, ES == CS
523
524 mov [cs:InitRDStart],edi
525 mov [cs:InitRDEnd],edi
526
527 mov si,[cs:InitRDPtr]
528
529 .get_chunk:
530 ; DS:SI points to the start of a name
531
532 mov bx,si
533 .find_end:
534 lodsb
535 cmp al,','
536 je .got_end
537 cmp al,' '
538 jbe .got_end
539 jmp .find_end
540
541 .got_end:
542 push ax ; Terminating character
543 push si ; Next filename (if any)
544 mov byte [si-1],0 ; Zero-terminate
545 mov si,bx ; Current filename
546
547 push di
548 mov di,InitRD ; Target buffer for mangled name
549 call mangle_name
550 pop di
551 call loadinitrd
552
553 pop si
554 pop ax
555 mov [si-1],al ; Restore ending byte
556
557 cmp al,','
558 je .get_chunk
559
560 ; Compute the initrd target location
561 ; Note: we round to a page boundary twice here. The first
562 ; time it is to make sure we don't use any fractional page
563 ; which may be valid RAM but which will be ignored by the
564 ; kernel (and therefore is inaccessible.) The second time
565 ; it is to make sure we start out on page boundary.
566 mov edx,[cs:InitRDEnd]
567 sub edx,[cs:InitRDStart]
568 mov [su_ramdisklen],edx
569 mov eax,[cs:MyHighMemSize]
570 and ax,0F000h ; Round to a page boundary
571 sub eax,edx
572 and ax,0F000h ; Round to a page boundary
573 mov [su_ramdiskat],eax
574
575 pop ds
576 pop es
577 ret
578
579 ;
580 ; Load RAM disk into high memory
581 ;
582 ; Input: InitRD - set to the mangled name of the initrd
583 ; EDI - location to load
584 ; Output: EDI - location for next initrd
585 ; InitRDEnd - updated
586 ;
587 loadinitrd:
588 push ds
589 push es
590 mov ax,cs ; CS == DS == ES
591 mov ds,ax
592 mov es,ax
593 push edi
594 mov si,InitRD
595 mov di,InitRDCName
596 call unmangle_name ; Create human-readable name
597 sub di,InitRDCName
598 mov [InitRDCNameLen],di
599 mov di,InitRD
600 call searchdir ; Look for it in directory
601 pop edi
602 jz .notthere
603
604 push si
605 mov si,crlfloading_msg ; Write "Loading "
606 call writestr_qchk
607 mov si,InitRDCName ; Write ramdisk name
608 call writestr_qchk
609 mov si,dotdot_msg ; Write dots
610 call writestr_qchk
611 pop si
612
613 .li_skip_echo:
614 mov dx,3
615 mov bx,dot_pause
616 call load_high
617 mov [InitRDEnd],ebx
618
619 pop es
620 pop ds
621 ret
622
623 .notthere:
624 mov si,err_noinitrd
625 call writestr
626 mov si,InitRDCName
627 call writestr
628 mov si,crlf_msg
629 jmp abort_load
630
631 ;
632 ; writestr_qchk: writestr, except allows output to be suppressed
633 ; assumes CS == DS
634 ;
635 writestr_qchk:
636 test byte [QuietBoot],QUIET_FLAG
637 jz writestr
638 ret
639
640 section .data
641 crlfloading_msg db CR, LF
642 loading_msg db 'Loading ', 0
643 dotdot_msg db '.'
644 dot_msg db '.', 0
645 ready_msg db 'ready.', CR, LF, 0
646 err_oldkernel db 'Cannot load a ramdisk with an old kernel image.'
647 db CR, LF, 0
648 err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0
649
650 boot_image db 'BOOT_IMAGE='
651 boot_image_len equ $-boot_image
652
653 ;
654 ; Command line options we'd like to take a look at
655 ;
656 %macro cmd_opt 2
657 %strlen cmd_opt_len %1
658 db cmd_opt_len
659 db %1
660 dw %2
661 %endmacro
662 options_list:
663 cmd_opt "vga=", opt_vga
664 cmd_opt "mem=", opt_mem
665 cmd_opt "quiet", opt_quiet
666 str_initrd equ $+1 ; Pointer to "initrd=" in memory
667 cmd_opt "initrd=", opt_initrd
668 %if IS_PXELINUX
669 cmd_opt "keeppxe", opt_keeppxe
670 %endif
671 db 0
672
673 section .bss
674 alignb 4
675 MyHighMemSize resd 1 ; Possibly adjusted highmem size
676 RamdiskMax resd 1 ; Highest address for ramdisk
677 KernelSize resd 1 ; Size of kernel in bytes
678 KernelSects resd 1 ; Size of kernel in sectors
679 KernelEnd resd 1 ; Ending address of the kernel image
680 InitRDStart resd 1 ; Start of initrd (pre-relocation)
681 InitRDEnd resd 1 ; End of initrd (pre-relocation)
682 CmdLineLen resw 1 ; Length of command line including null
683 CmdLineEnd resw 1 ; End of the command line in real_mode_seg
684 SetupSecs resw 1 ; Number of setup sectors (+bootsect)
685 KernelVersion resw 1 ; Kernel protocol version
686 ;
687 ; These are derived from the command-line parser
688 ;
689 InitRDPtr resw 1 ; Pointer to initrd= option in command line
690 LoadFlags resb 1 ; Loadflags from kernel
691 QuietBoot resb 1 ; Set if a quiet boot is requested