--- 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