--- trunk/mkinitrd-magellan/isolinux/runkernel.inc 2010/08/19 08:27:19 1132
+++ trunk/mkinitrd-magellan/isolinux/runkernel.inc 2010/08/19 09:50:43 1133
@@ -1,7 +1,7 @@
-;; $Id: runkernel.inc,v 1.1 2007-09-01 22:44:05 niro Exp $
;; -----------------------------------------------------------------------
-;;
-;; Copyright 1994-2005 H. Peter Anvin - All Rights Reserved
+;;
+;; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
+;; Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
@@ -13,18 +13,13 @@
;;
;; runkernel.inc
-;;
+;;
;; Common code for running a Linux kernel
;;
;
; Hook macros, that may or may not be defined
;
-%ifndef HAVE_SPECIAL_APPEND
-%macro SPECIAL_APPEND 0
-%endmacro
-%endif
-
%ifndef HAVE_UNLOAD_PREP
%macro UNLOAD_PREP 0
%endmacro
@@ -35,87 +30,60 @@
; kernel code. The boot sector is never executed when using an external
; booting utility, but it contains some status bytes that are necessary.
;
-; First check that our kernel is at least 1K and less than 8M (if it is
-; more than 8M, we need to change the logic for loading it anyway...)
+; First check that our kernel is at least 1K, or else it isn't long
+; enough to have the appropriate headers.
;
; We used to require the kernel to be 64K or larger, but it has gotten
; popular to use the Linux kernel format for other things, which may
; not be so large.
;
+; Additionally, we used to have a test for 8 MB or smaller. Equally
+; obsolete.
+;
is_linux_kernel:
- cmp dx,80h ; 8 megs
- ja kernel_corrupt
- and dx,dx
- jnz kernel_sane
- cmp ax,1024 ; Bootsect + 1 setup sect
- jb kernel_corrupt
-kernel_sane: push ax
- push dx
- push si
- mov si,loading_msg
- call cwritestr
+ push si ; file pointer
+
;
; Now start transferring the kernel
;
push word real_mode_seg
pop es
- movzx eax,ax ; Fix this by using a 32-bit
- shl edx,16 ; register for the kernel size
- or eax,edx
- mov [KernelSize],eax
- add eax,SECTOR_SIZE-1
- shr eax,SECTOR_SHIFT
- mov [KernelSects],eax ; Total sectors in kernel
-
-;
-; Now, if we transfer these straight, we'll hit 64K boundaries. Hence we
-; have to see if we're loading more than 64K, and if so, load it step by
-; step.
-;
-
;
; Start by loading the bootsector/setup code, to see if we need to
; do something funky. It should fit in the first 32K (loading 64K won't
; work since we might have funny stuff up near the end of memory).
-; If we have larger than 32K clusters, yes, we're hosed.
;
call abort_check ; Check for abort key
- mov ecx,8000h >> SECTOR_SHIFT ; Half a moby (32K)
- cmp ecx,[KernelSects]
- jna .normalkernel
- mov ecx,[KernelSects]
-.normalkernel:
- sub [KernelSects],ecx
+ mov cx,8000h >> SECTOR_SHIFT ; Half a moby (32K)
xor bx,bx
- pop si ; Cluster pointer on stack
+ pop si ; file pointer
call getfssec
+ cmp cx,1024
+ jb kernel_corrupt
cmp word [es:bs_bootsign],0AA55h
jne kernel_corrupt ; Boot sec signature missing
;
-; Save the cluster pointer for later...
+; Save the file pointer for later...
;
- push si
-;
-; Get the BIOS' idea of what the size of high memory is.
-;
- call highmemsize
+ push si ; file pointer
+
;
; Construct the command line (append options have already been copied)
;
construct_cmdline:
mov di,[CmdLinePtr]
- mov si,boot_image ; BOOT_IMAGE=
+ mov si,boot_image ; BOOT_IMAGE=
mov cx,boot_image_len
rep movsb
- mov si,KernelCName ; Unmangled kernel name
+ mov si,KernelCName ; Unmangled kernel name
mov cx,[KernelCNameLen]
rep movsb
mov al,' ' ; Space
stosb
- SPECIAL_APPEND ; Module-specific hook
+ call do_ip_append ; Handle IPAppend
mov si,[CmdOptPtr] ; Options from user input
call strcpy
@@ -125,96 +93,123 @@
; interested in. The original version of this code automatically assumed
; the first option was BOOT_IMAGE=, but that is no longer certain.
;
- mov si,cmd_line_here
- xor ax,ax
- mov [InitRDPtr],ax ; No initrd= option (yet)
- push es ; Set DS <- real_mode_seg
- pop ds
-get_next_opt: lodsb
+parse_cmdline:
+ mov di,cmd_line_here
+.skipspace: mov al,[es:di]
+ inc di
+.skipspace_loaded:
and al,al
jz cmdline_end
cmp al,' '
- jbe get_next_opt
- dec si
- mov eax,[si]
- cmp eax,'vga='
- je is_vga_cmd
- cmp eax,'mem='
- je is_mem_cmd
-%if IS_PXELINUX
- cmp eax,'keep' ; Is it "keeppxe"?
- jne .notkeep
- cmp dword [si+3],'ppxe'
- jne .notkeep
- cmp byte [si+7],' ' ; Must be whitespace or EOS
- ja .notkeep
- or byte [cs:KeepPXE],1
-.notkeep:
-%endif
- push es ; Save ES -> real_mode_seg
- push cs
- pop es ; Set ES <- normal DS
- mov di,initrd_cmd
- mov cx,initrd_cmd_len
+ jbe .skipspace
+ dec di
+
+ ; ES:DI now points to the beginning of an option
+ mov si,options_list
+.next_opt:
+ movzx cx,byte [si]
+ jcxz .skip_opt
+ push di
+ inc si
repe cmpsb
- jne .not_initrd
+ jne .no_match
+ ; This either needs to have been an option with parameter,
+ ; or be followed by EOL/whitespace
+ mov ax,[es:di-1] ; AL = last chr; AH = following
+ cmp al,'='
+ je .is_match
+ cmp ah,' '
+ ja .no_match
+.is_match:
+ pop ax ; Drop option pointer on stack
+ call [si]
+.skip_opt:
+ mov al,[es:di]
+ inc di
cmp al,' '
- jbe .noramdisk
- mov [cs:InitRDPtr],si
- jmp .not_initrd
-.noramdisk:
- xor ax,ax
- mov [cs:InitRDPtr],ax
-.not_initrd: pop es ; Restore ES -> real_mode_seg
-skip_this_opt: lodsb ; Load from command line
- cmp al,' '
- ja skip_this_opt
- dec si
- jmp short get_next_opt
-is_vga_cmd:
- add si,4
- mov eax,[si-1]
- mov bx,-1
- cmp eax,'=nor' ; vga=normal
- je vc0
+ ja .skip_opt
+ jmp .skipspace_loaded
+.no_match:
+ pop di
+ add si,cx ; Skip remaining bytes
+ inc si ; Skip function pointer
+ inc si
+ jmp .next_opt
+
+opt_vga:
+ mov ax,[es:di-1]
+ mov bx,-1
+ cmp ax,'=n' ; vga=normal
+ je .vc0
dec bx ; bx <- -2
- cmp eax,'=ext' ; vga=ext
- je vc0
- dec bx ; bx <- -3
- cmp eax,'=ask' ; vga=ask
- je vc0
- call parseint ; vga=
- jc skip_this_opt ; Not an integer
-vc0: mov [bs_vidmode],bx ; Set video mode
- jmp short skip_this_opt
-is_mem_cmd:
- add si,4
- call parseint
- jc skip_this_opt ; Not an integer
+ cmp ax,'=e' ; vga=ext
+ je .vc0
+ dec bx ; bx <- -3
+ cmp ax,'=a' ; vga=ask
+ je .vc0
+ mov bx,0x0f04 ; bx <- 0x0f04 (current mode)
+ cmp ax,'=c' ; vga=current
+ je .vc0
+ call parseint_esdi ; vga=
+ jc .skip ; Not an integer
+.vc0: mov [es:bs_vidmode],bx ; Set video mode
+.skip:
+ ret
+
+opt_mem:
+ call parseint_esdi
+ jc .skip
%if HIGHMEM_SLOP != 0
sub ebx,HIGHMEM_SLOP
%endif
- mov [cs:HighMemSize],ebx
- jmp short skip_this_opt
+ mov [MyHighMemSize],ebx
+.skip:
+ ret
+
+opt_quiet:
+ mov byte [QuietBoot],QUIET_FLAG
+ ret
+
+%if IS_PXELINUX
+opt_keeppxe:
+ or byte [KeepPXE],1 ; KeepPXE set by command line
+ ret
+%endif
+
+opt_initrd:
+ mov ax,di
+ cmp byte [es:di],' '
+ ja .have_initrd
+ xor ax,ax
+.have_initrd:
+ mov [InitRDPtr],ax
+ ret
+
+;
+; After command line parsing...
+;
cmdline_end:
- push cs ; Restore standard DS
- pop ds
- sub si,cmd_line_here
- mov [CmdLineLen],si ; Length including final null
+ sub di,cmd_line_here
+ mov [CmdLineLen],di ; Length including final null
+
;
; Now check if we have a large kernel, which needs to be loaded high
;
+prepare_header:
mov dword [RamdiskMax], HIGHMEM_MAX ; Default initrd limit
cmp dword [es:su_header],HEADER_ID ; New setup code ID
- jne old_kernel ; Old kernel, load low
- cmp word [es:su_version],0200h ; Setup code version 2.0
- jb old_kernel ; Old kernel, load low
- cmp word [es:su_version],0201h ; Version 2.01+?
+ jne old_kernel ; Old kernel, load low
+ mov ax,[es:su_version]
+ mov [KernelVersion],ax
+ cmp ax,0200h ; Setup code version 2.0
+ jb old_kernel ; Old kernel, load low
+ cmp ax,0201h ; Version 2.01+?
jb new_kernel ; If 2.00, skip this step
- mov word [es:su_heapend],linux_stack ; Set up the heap
+ ; Set up the heap (assuming loading high for now)
+ mov word [es:su_heapend],linux_stack-512
or byte [es:su_loadflags],80h ; Let the kernel know we care
- cmp word [es:su_version],0203h ; Version 2.03+?
+ cmp ax,0203h ; Version 2.03+?
jb new_kernel ; Not 2.03+
mov eax,[es:su_ramdisk_max]
mov [RamdiskMax],eax ; Set the ramdisk limit
@@ -225,8 +220,6 @@
;
new_kernel:
mov byte [es:su_loader],my_id ; Show some ID
- movzx ax,byte [es:bs_setupsecs] ; Variable # of setup sectors
- mov [SetupSecs],ax
xor eax,eax
mov [es:su_ramdisklen],eax ; No initrd loaded yet
@@ -235,50 +228,54 @@
; we were provided.
;
mov al,[es:su_loadflags]
+ or al,[QuietBoot] ; Set QUIET_FLAG if needed
+ mov [es:su_loadflags],al
mov [LoadFlags],al
+
+any_kernel:
+ mov si,loading_msg
+ call writestr_qchk
+ mov si,KernelCName ; Print kernel name part of
+ call writestr_qchk ; "Loading" message
+
;
; Load the kernel. We always load it at 100000h even if we're supposed to
; load it "low"; for a "low" load we copy it down to low memory right before
; jumping to it.
;
read_kernel:
- mov si,KernelCName ; Print kernel name part of
- call cwritestr ; "Loading" message
- mov si,dotdot_msg ; Print dots
- call cwritestr
-
- mov eax,[HighMemSize]
- sub eax,100000h ; Load address
- cmp eax,[KernelSize]
- jb no_high_mem ; Not enough high memory
+ movzx ax,byte [es:bs_setupsecs] ; Setup sectors
+ and ax,ax
+ jnz .sects_ok
+ mov al,4 ; 0 = 4 setup sectors
+.sects_ok:
+ inc ax ; Including the boot sector
+ mov [SetupSecs],ax
+
+ call dot_pause
+
;
; Move the stuff beyond the setup code to high memory at 100000h
;
movzx esi,word [SetupSecs] ; Setup sectors
- inc si ; plus 1 boot sector
shl si,9 ; Convert to bytes
mov ecx,8000h ; 32K
sub ecx,esi ; Number of bytes to copy
- push ecx
add esi,(real_mode_seg << 4) ; Pointer to source
mov edi,100000h ; Copy to address 100000h
call bcopy ; Transfer to high memory
- ; On exit EDI -> where to load the rest
+ pop si ; File pointer
+ and si,si ; EOF already?
+ jz high_load_done
- mov si,dot_msg ; Progress report
- call cwritestr
- call abort_check
-
- pop ecx ; Number of bytes in the initial portion
- pop si ; Restore file handle/cluster pointer
- mov eax,[KernelSize]
- sub eax,8000h ; Amount of kernel not yet loaded
- jbe high_load_done ; Zero left (tiny kernel)
+ ; On exit EDI -> where to load the rest
- xor dx,dx ; No padding needed
- call load_high ; Copy the file
+ mov bx,dot_pause
+ or eax,-1 ; Load the whole file
+ mov dx,3 ; Pad to dword
+ call load_high
high_load_done:
mov [KernelEnd],edi
@@ -286,7 +283,23 @@
mov es,ax
mov si,dot_msg
- call cwritestr
+ call writestr_qchk
+
+;
+; Some older kernels (1.2 era) would have more than 4 setup sectors, but
+; would not rely on the boot protocol to manage that. These kernels fail
+; if they see protected-mode kernel data after the setup sectors, so
+; clear that memory.
+;
+ push di
+ mov di,[SetupSecs]
+ shl di,9
+ xor eax,eax
+ mov cx,cmd_line_here
+ sub cx,di
+ shr cx,2
+ rep stosd
+ pop di
;
; Now see if we have an initial RAMdisk; if so, do requisite computation
@@ -294,19 +307,25 @@
; if we tried to load initrd using an old kernel
;
load_initrd:
- cmp word [InitRDPtr],0
- jz nk_noinitrd
+ ; Cap the ramdisk memory range if appropriate
+ mov eax,[RamdiskMax]
+ cmp eax,[MyHighMemSize]
+ ja .ok
+ mov [MyHighMemSize],eax
+.ok:
+ xor eax,eax
+ cmp [InitRDPtr],ax
+ jz .noinitrd
call parse_load_initrd
-nk_noinitrd:
+.noinitrd:
+
;
; Abandon hope, ye that enter here! We do no longer permit aborts.
;
- call abort_check ; Last chance!!
+ call abort_check ; Last chance!!
mov si,ready_msg
- call cwritestr
-
- call vgaclearmode ; We can't trust ourselves after this
+ call writestr_qchk
UNLOAD_PREP ; Module-specific hook
@@ -316,148 +335,157 @@
; capable of starting their setup from a different address.
;
mov ax,real_mode_seg
+ mov es,ax
mov fs,ax
;
-; Copy command line. Unfortunately, the kernel boot protocol requires
+; If the default root device is set to FLOPPY (0000h), change to
+; /dev/fd0 (0200h)
+;
+ cmp word [es:bs_rootdev],byte 0
+ jne root_not_floppy
+ mov word [es:bs_rootdev],0200h
+root_not_floppy:
+
+;
+; Copy command line. Unfortunately, the old kernel boot protocol requires
; the command line to exist in the 9xxxxh range even if the rest of the
; setup doesn't.
;
- cli ; In case of hooked interrupts
+setup_command_line:
+ mov dx,[KernelVersion]
test byte [LoadFlags],LOAD_HIGH
- jz need_high_cmdline
- cmp word [fs:su_version],0202h ; Support new cmdline protocol?
- jb need_high_cmdline
+ jz .need_high_cmdline
+ cmp dx,0202h ; Support new cmdline protocol?
+ jb .need_high_cmdline
; New cmdline protocol
; Store 32-bit (flat) pointer to command line
- mov dword [fs:su_cmd_line_ptr],(real_mode_seg << 4) + cmd_line_here
- jmp short in_proper_place
-
-need_high_cmdline:
-;
-; Copy command line up to 90000h
+ ; This is the "high" location, since we have bzImage
+ mov dword [fs:su_cmd_line_ptr],(real_mode_seg << 4)+cmd_line_here
+ mov word [HeapEnd],linux_stack
+ mov word [fs:su_heapend],linux_stack-512
+ jmp .setup_done
+
+.need_high_cmdline:
+;
+; Copy command line down to fit in high conventional memory
+; -- this happens if we have a zImage kernel or the protocol
+; is less than 2.02.
;
- mov ax,9000h ; Note AL <- 0
- mov es,ax
mov si,cmd_line_here
- mov di,si
+ mov di,old_cmd_line_here
mov [fs:kern_cmd_magic],word CMD_MAGIC ; Store magic
mov [fs:kern_cmd_offset],di ; Store pointer
+ mov word [HeapEnd],old_linux_stack
+ mov ax,255 ; Max cmdline limit
+ cmp dx,0201h
+ jb .adjusted
+ ; Protocol 2.01+
+ mov word [fs:su_heapend],old_linux_stack-512
+ jbe .adjusted
+ ; Protocol 2.02+
+ ; Note that the only reason we would end up here is
+ ; because we have a zImage, so we anticipate the move
+ ; to 90000h already...
+ mov dword [fs:su_cmd_line_ptr],0x90000+old_cmd_line_here
+ mov ax,old_max_cmd_len ; 2.02+ allow a higher limit
+.adjusted:
mov cx,[CmdLineLen]
- cmp cx,255
+ cmp cx,ax
jna .len_ok
- mov cx,255 ; Protocol < 0x202 has 255 as hard limit
+ mov cx,ax ; Truncate the command line
.len_ok:
fs rep movsb
- stosb ; Final null, note AL == 0 already
+ stosb ; Final null, note AL=0 already
+ mov [CmdLineEnd],di
+ cmp dx,0200h
+ jb .nomovesize
+ mov [es:su_movesize],di ; Tell the kernel what to move
+.nomovesize:
+.setup_done:
+
+;
+; Time to start setting up move descriptors
+;
+setup_move:
+ mov di,trackbuf
+ xor cx,cx ; Number of descriptors
- push fs
+ mov bx,es ; real_mode_seg
+ mov fs,bx
+ push ds ; We need DS == ES == CS here
pop es
test byte [LoadFlags],LOAD_HIGH
- jnz in_proper_place ; If high load, we're done
-
-;
-; Loading low; we can't assume it's safe to run in place.
-;
-; Copy real_mode stuff up to 90000h
-;
- mov ax,9000h
- mov es,ax
- mov cx,[SetupSecs]
- inc cx ; Setup + boot sector
- shl cx,7 ; Sectors -> dwords
- xor si,si
- xor di,di
- fs rep movsd ; Copy setup + boot sector
-;
-; Some kernels in the 1.2 ballpark but pre-bzImage have more than 4
-; setup sectors, but the boot protocol had not yet been defined. They
-; rely on a signature to figure out if they need to copy stuff from
-; the "protected mode" kernel area. Unfortunately, we used that area
-; as a transfer buffer, so it's going to find the signature there.
-; Hence, zero the low 32K beyond the setup area.
-;
- mov di,[SetupSecs]
- inc di ; Setup + boot sector
- mov cx,32768/512 ; Sectors/32K
- sub cx,di ; Remaining sectors
- shl di,9 ; Sectors -> bytes
- shl cx,7 ; Sectors -> dwords
- xor eax,eax
- rep stosd ; Clear region
-;
-; Copy the kernel down to the "low" location
-;
- mov ecx,[KernelSize]
- mov esi,100000h
- mov edi,10000h
- call bcopy
+ jnz .loading_high
-;
-; Now everything is where it needs to be...
-;
-; When we get here, es points to the final segment, either
-; 9000h or real_mode_seg
-;
-in_proper_place:
+; Loading low: move real_mode stuff to 90000h, then move the kernel down
+ mov eax,90000h
+ stosd
+ mov eax,real_mode_seg << 4
+ stosd
+ movzx eax,word [CmdLineEnd]
+ stosd
+ inc cx
+
+ mov eax,10000h ; Target address of low kernel
+ stosd
+ mov eax,100000h ; Where currently loaded
+ stosd
+ neg eax
+ add eax,[KernelEnd]
+ stosd
+ inc cx
+
+ mov bx,9000h ; Revised real mode segment
+
+.loading_high:
+
+ cmp word [InitRDPtr],0 ; Did we have an initrd?
+ je .no_initrd
+
+ mov eax,[fs:su_ramdiskat]
+ stosd
+ mov eax,[InitRDStart]
+ stosd
+ mov eax,[fs:su_ramdisklen]
+ stosd
+ inc cx
+
+.no_initrd:
+ push dword run_linux_kernel
+ push cx ; Length of descriptor list
+
+ ; BX points to the final real mode segment, and will be loaded
+ ; into DS.
+
+ test byte [QuietBoot],QUIET_FLAG
+ jz replace_bootstrap
+ jmp replace_bootstrap_noclearmode
-;
-; If the default root device is set to FLOPPY (0000h), change to
-; /dev/fd0 (0200h)
-;
- cmp word [es:bs_rootdev],byte 0
- jne root_not_floppy
- mov word [es:bs_rootdev],0200h
-root_not_floppy:
-
-;
-; Copy the disk table to high memory, then re-initialize the floppy
-; controller
-;
-%if IS_SYSLINUX || IS_MDSLINUX
- lgs si,[cs:fdctab]
- mov di,linux_fdctab
- mov cx,6 ; 12 bytes
- gs rep movsw
- mov [cs:fdctab],word linux_fdctab ; Save new floppy tab pos
- mov [cs:fdctab+2],es
-%endif
-;
-; Linux wants the floppy motor shut off before starting the kernel,
-; at least bootsect.S seems to imply so.
-;
-kill_motor:
- xor ax,ax
- xor dx,dx
- int 13h
-
-;
-; If we're debugging, wait for a keypress so we can read any debug messages
-;
-%ifdef debug
- xor ax,ax
- int 16h
-%endif
+run_linux_kernel:
;
; Set up segment registers and the Linux real-mode stack
-; Note: es == the real mode segment
+; Note: ds == the real mode segment
;
cli
- mov bx,es
- mov ds,bx
- mov fs,bx
- mov gs,bx
- mov ss,bx
- mov sp,linux_stack
+ mov ax,ds
+ mov ss,ax
+ mov sp,strict word linux_stack
+ ; Point HeapEnd to the immediate of the instruction above
+HeapEnd equ $-2 ; Self-modifying code! Fun!
+ mov es,ax
+ mov fs,ax
+ mov gs,ax
+
;
; We're done... now RUN THAT KERNEL!!!!
; Setup segment == real mode segment + 020h; we need to jump to offset
; zero in the real mode segment.
;
- add bx,020h
- push bx
+ add ax,020h
+ push ax
push word 0h
retf
@@ -466,21 +494,24 @@
; initrd, and are always loaded low.
;
old_kernel:
- cmp word [InitRDPtr],0 ; Old kernel can't have initrd
- je load_old_kernel
+ xor ax,ax
+ cmp word [InitRDPtr],ax ; Old kernel can't have initrd
+ je .load
mov si,err_oldkernel
jmp abort_load
-load_old_kernel:
- mov word [SetupSecs],4 ; Always 4 setup sectors
- mov byte [LoadFlags],0 ; Always low
- jmp read_kernel
+.load:
+ mov byte [LoadFlags],al ; Always low
+ mov word [KernelVersion],ax ; Version 0.00
+ jmp any_kernel
;
; parse_load_initrd
;
-; Parse an initrd= option and load the initrds. Note that we load
-; from the high end of memory first, so we parse this option from
-; left to right.
+; Parse an initrd= option and load the initrds. This sets
+; InitRDStart and InitRDEnd with dword padding between; we then
+; do a global memory shuffle to move it to the end of memory.
+;
+; On entry, EDI points to where to start loading.
;
parse_load_initrd:
push es
@@ -490,47 +521,56 @@
push cs
pop es ; DS == real_mode_seg, ES == CS
+ mov [cs:InitRDStart],edi
+ mov [cs:InitRDEnd],edi
+
mov si,[cs:InitRDPtr]
-.find_end:
- lodsb
- cmp al,' '
- ja .find_end
- ; Now SI points to one character beyond the
- ; byte that ended this option.
.get_chunk:
- dec si
+ ; DS:SI points to the start of a name
- ; DS:SI points to a termination byte
+ mov bx,si
+.find_end:
+ lodsb
+ cmp al,','
+ je .got_end
+ cmp al,' '
+ jbe .got_end
+ jmp .find_end
- xor ax,ax
- xchg al,[si] ; Zero-terminate
- push si ; Save ending byte address
- push ax ; Save ending byte
-
-.find_start:
- dec si
- cmp si,[cs:InitRDPtr]
- je .got_start
- cmp byte [si],','
- jne .find_start
+.got_end:
+ push ax ; Terminating character
+ push si ; Next filename (if any)
+ mov byte [si-1],0 ; Zero-terminate
+ mov si,bx ; Current filename
- ; It's a comma byte
- inc si
-
-.got_start:
- push si
+ push di
mov di,InitRD ; Target buffer for mangled name
call mangle_name
+ pop di
call loadinitrd
- pop si
+ pop si
pop ax
- pop di
- mov [di],al ; Restore ending byte
+ mov [si-1],al ; Restore ending byte
+
+ cmp al,','
+ je .get_chunk
- cmp si,[cs:InitRDPtr]
- ja .get_chunk
+ ; Compute the initrd target location
+ ; Note: we round to a page boundary twice here. The first
+ ; time it is to make sure we don't use any fractional page
+ ; which may be valid RAM but which will be ignored by the
+ ; kernel (and therefore is inaccessible.) The second time
+ ; it is to make sure we start out on page boundary.
+ mov edx,[cs:InitRDEnd]
+ sub edx,[cs:InitRDStart]
+ mov [su_ramdisklen],edx
+ mov eax,[cs:MyHighMemSize]
+ and ax,0F000h ; Round to a page boundary
+ sub eax,edx
+ and ax,0F000h ; Round to a page boundary
+ mov [su_ramdiskat],eax
pop ds
pop es
@@ -540,6 +580,9 @@
; Load RAM disk into high memory
;
; Input: InitRD - set to the mangled name of the initrd
+; EDI - location to load
+; Output: EDI - location for next initrd
+; InitRDEnd - updated
;
loadinitrd:
push ds
@@ -547,6 +590,7 @@
mov ax,cs ; CS == DS == ES
mov ds,ax
mov es,ax
+ push edi
mov si,InitRD
mov di,InitRDCName
call unmangle_name ; Create human-readable name
@@ -554,82 +598,94 @@
mov [InitRDCNameLen],di
mov di,InitRD
call searchdir ; Look for it in directory
+ pop edi
jz .notthere
- mov cx,dx
- shl ecx,16
- mov cx,ax ; ECX <- ram disk length
-
- mov ax,real_mode_seg
- mov es,ax
-
- push ecx ; Bytes to load
- cmp dword [es:su_ramdisklen],0
- je .nopadding ; Don't pad the last initrd
- add ecx,4095
- and cx,0F000h
-.nopadding:
- add [es:su_ramdisklen],ecx
- mov edx,[HighMemSize] ; End of memory
- dec edx
- mov eax,[RamdiskMax] ; Highest address allowed by kernel
- cmp edx,eax
- jna .memsize_ok
- mov edx,eax ; Adjust to fit inside limit
-.memsize_ok:
- inc edx
- and dx,0F000h ; Round down to 4K boundary
- sub edx,ecx ; Subtract size of ramdisk
- and dx,0F000h ; Round down to 4K boundary
- cmp edx,[KernelEnd] ; Are we hitting the kernel image?
- jb no_high_mem
-
- mov [es:su_ramdiskat],edx ; Load address
- mov [RamdiskMax],edx ; Next initrd loaded here
-
- mov edi,edx ; initrd load address
push si
mov si,crlfloading_msg ; Write "Loading "
- call cwritestr
+ call writestr_qchk
mov si,InitRDCName ; Write ramdisk name
- call cwritestr
+ call writestr_qchk
mov si,dotdot_msg ; Write dots
- call cwritestr
+ call writestr_qchk
pop si
- pop eax ; Bytes to load
- mov dx,0FFFh ; Pad to page
- call load_high ; Load the file
+.li_skip_echo:
+ mov dx,3
+ mov bx,dot_pause
+ call load_high
+ mov [InitRDEnd],ebx
pop es
pop ds
- jmp crlf ; Print carriage return and return
+ ret
.notthere:
mov si,err_noinitrd
- call cwritestr
+ call writestr
mov si,InitRDCName
- call cwritestr
+ call writestr
mov si,crlf_msg
jmp abort_load
-no_high_mem: ; Error routine
- mov si,err_nohighmem
- jmp abort_load
-
- ret
+;
+; writestr_qchk: writestr, except allows output to be suppressed
+; assumes CS == DS
+;
+writestr_qchk:
+ test byte [QuietBoot],QUIET_FLAG
+ jz writestr
+ ret
section .data
+crlfloading_msg db CR, LF
+loading_msg db 'Loading ', 0
+dotdot_msg db '.'
+dot_msg db '.', 0
+ready_msg db 'ready.', CR, LF, 0
+err_oldkernel db 'Cannot load a ramdisk with an old kernel image.'
+ db CR, LF, 0
+err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0
+
boot_image db 'BOOT_IMAGE='
boot_image_len equ $-boot_image
+;
+; Command line options we'd like to take a look at
+;
+%macro cmd_opt 2
+%strlen cmd_opt_len %1
+ db cmd_opt_len
+ db %1
+ dw %2
+%endmacro
+options_list:
+ cmd_opt "vga=", opt_vga
+ cmd_opt "mem=", opt_mem
+ cmd_opt "quiet", opt_quiet
+str_initrd equ $+1 ; Pointer to "initrd=" in memory
+ cmd_opt "initrd=", opt_initrd
+%if IS_PXELINUX
+ cmd_opt "keeppxe", opt_keeppxe
+%endif
+ db 0
+
section .bss
alignb 4
+MyHighMemSize resd 1 ; Possibly adjusted highmem size
RamdiskMax resd 1 ; Highest address for ramdisk
KernelSize resd 1 ; Size of kernel in bytes
KernelSects resd 1 ; Size of kernel in sectors
KernelEnd resd 1 ; Ending address of the kernel image
+InitRDStart resd 1 ; Start of initrd (pre-relocation)
+InitRDEnd resd 1 ; End of initrd (pre-relocation)
CmdLineLen resw 1 ; Length of command line including null
-SetupSecs resw 1 ; Number of setup sectors
+CmdLineEnd resw 1 ; End of the command line in real_mode_seg
+SetupSecs resw 1 ; Number of setup sectors (+bootsect)
+KernelVersion resw 1 ; Kernel protocol version
+;
+; These are derived from the command-line parser
+;
InitRDPtr resw 1 ; Pointer to initrd= option in command line
LoadFlags resb 1 ; Loadflags from kernel
+QuietBoot resb 1 ; Set if a quiet boot is requested