📄 runkernel.inc
字号:
;; $Id$;; -----------------------------------------------------------------------;; ;; Copyright 1994-2005 H. Peter Anvin - All Rights Reserved;;;; 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;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,;; Boston MA 02111-1307, USA; either version 2 of the License, or;; (at your option) any later version; incorporated herein by reference.;;;; -----------------------------------------------------------------------;;;; 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%endif;; A Linux kernel consists of three parts: boot sector, setup code, and; 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...);; 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.;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_corruptkernel_sane: push ax push dx push si mov si,loading_msg call cwritestr;; 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 xor bx,bx pop si ; Cluster pointer on stack call getfssec cmp word [es:bs_bootsign],0AA55h jne kernel_corrupt ; Boot sec signature missing;; Save the cluster pointer for later...; push si;; Get the BIOS' idea of what the size of high memory is.; call highmemsize;; Construct the command line (append options have already been copied);construct_cmdline: mov di,[CmdLinePtr] mov si,boot_image ; BOOT_IMAGE= mov cx,boot_image_len rep movsb mov si,KernelCName ; Unmangled kernel name mov cx,[KernelCNameLen] rep movsb mov al,' ' ; Space stosb SPECIAL_APPEND ; Module-specific hook mov si,[CmdOptPtr] ; Options from user input call strcpy;; Scan through the command line for anything that looks like we might be; 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 dsget_next_opt: lodsb 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 repe cmpsb jne .not_initrd 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_segskip_this_opt: lodsb ; Load from command line cmp al,' ' ja skip_this_opt dec si jmp short get_next_optis_vga_cmd: add si,4 mov eax,[si-1] mov bx,-1 cmp eax,'=nor' ; 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=<number> jc skip_this_opt ; Not an integervc0: mov [bs_vidmode],bx ; Set video mode jmp short skip_this_optis_mem_cmd: add si,4 call parseint jc skip_this_opt ; Not an integer%if HIGHMEM_SLOP != 0 sub ebx,HIGHMEM_SLOP%endif mov [cs:HighMemSize],ebx jmp short skip_this_optcmdline_end: push cs ; Restore standard DS pop ds sub si,cmd_line_here mov [CmdLineLen],si ; Length including final null;; Now check if we have a large kernel, which needs to be loaded high; 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+? jb new_kernel ; If 2.00, skip this step mov word [es:su_heapend],linux_stack ; Set up the heap or byte [es:su_loadflags],80h ; Let the kernel know we care cmp word [es:su_version],0203h ; Version 2.03+? jb new_kernel ; Not 2.03+ mov eax,[es:su_ramdisk_max] mov [RamdiskMax],eax ; Set the ramdisk limit;; We definitely have a new-style kernel. Let the kernel know who we are,; and that we are clueful;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;; About to load the kernel. This is a modern kernel, so use the boot flags; we were provided.; mov al,[es:su_loadflags] mov [LoadFlags],al;; 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;; 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 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) xor dx,dx ; No padding needed call load_high ; Copy the filehigh_load_done: mov [KernelEnd],edi mov ax,real_mode_seg ; Set to real mode seg mov es,ax mov si,dot_msg call cwritestr;; Now see if we have an initial RAMdisk; if so, do requisite computation; We know we have a new kernel; the old_kernel code already will have objected; if we tried to load initrd using an old kernel;load_initrd: cmp word [InitRDPtr],0 jz nk_noinitrd call parse_load_initrdnk_noinitrd:;; Abandon hope, ye that enter here! We do no longer permit aborts.; call abort_check ; Last chance!! mov si,ready_msg call cwritestr call vgaclearmode ; We can't trust ourselves after this UNLOAD_PREP ; Module-specific hook;; Now, if we were supposed to load "low", copy the kernel down to 10000h; and the real mode stuff to 90000h. We assume that all bzImage kernels are; capable of starting their setup from a different address.; mov ax,real_mode_seg
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -