运行内核
内核的跳转指令在相对于内核实模式部分为0x20的内存段处。也就是说,如果你把内核的实模式部分加载到了0x90000处,那么内核入口应该在0x9020:0000处。
在进入内核前,ds、es、ss应该指向内核实模式部分的所在内存的起始处,sp也需要被正确,通常它指向堆的顶部。另外,中断应该是禁止。还有,为了防止内核的BUG导致问题,最好将fs、gs、ds、es、ss都设置为同一个地址。
根据上面的描述,我们应该这样做:
/*Note: in the case of the "old" kernel protocol, base_ptrmust
be== 0x90000 at this point; see the previous sample code */
seg =base_ptr >> 4;
cli(); /*Enter with interrupts disabled! */
/*Set up the real-mode kernel stack */
_SS =seg;
_SP =heap_end;
_DS= _ES = _FS = _GS = seg;
jmp_far(seg+0x20,0); /* Run the kernel */
如果你的引导扇区访问了软驱,在运行内核前记得把软驱的马达关闭。因为内核引导过程中会关闭中断并且软盘马达也不会关闭。尤其是被加载的内核将软驱做为请求加载的模块时。
高级:引导加载程序钩子
如果内核加载程序运行于一些特殊的宿主环境中(比如,运行于DOS下的LOADLIN程序),呀可能需要遵循运行环境提供的标准内存。那么,内核加载程序可能需要使用以下钩子。这些钩子被设定后,内核会在适当的时候调用它们。应该仅在最后没有办法的时候才使用这些钩子
特别注意:所有的钩子都要求esp、ebp、esi和edi寄存器不能被更改。
realmode_swtch:
A16-bit real mode far subroutine invoked immediately before
enteringprotected mode. The default routine disables NMI, so
yourroutine should probably do so, too.
code32_start:
A32-bit flat-mode routine *jumped* to immediately after the
transitionto protected mode, but before the kernel is
uncompressed. No segments, except CS, are guaranteed to be
setup (current kernels do, but older ones do not); you should
setthem up to BOOT_DS (0x18) yourself.
Aftercompleting your hook, you should jump to the address
thatwas in this field before your boot loader overwrote it
(relocated,if appropriate.)
32位引导协议
Formachine with some new BIOS other than legacy BIOS, such as EFI,
LinuxBIOS,etc, and kexec, the 16-bit real mode setup code in kernel
basedon legacy BIOS can not be used, so a 32-bit boot protocol needs
to bedefined.
In32-bit boot protocol, the first step in loading a Linux kernel
shouldbe to setup the boot parameters (struct boot_params,
traditionallyknown as "zero page"). The memory for struct boot_params
shouldbe allocated and initialized to all zero. Then the setup header
fromoffset 0x01f1 of kernel image on should be loaded into struct
boot_paramsand examined. The end of setup header can be calculated as
follow:
0x0202+ byte value at offset 0x0201
Inaddition to read/modify/write the setup header of the struct
boot_paramsas that of 16-bit boot protocol, the boot loader should
alsofill the additional fields of the struct boot_params as that
describedin zero-page.txt.
Aftersetupping the struct boot_params, the boot loader can load the
32/64-bitkernel in the same way as that of 16-bit boot protocol.
In32-bit boot protocol, the kernel is started by jumping to the
32-bitkernel entry point, which is the start address of loaded
32/64-bitkernel.
Atentry, the CPU must be in 32-bit protected mode with paging
disabled;a GDT must be loaded with the descriptors for selectors
__BOOT_CS(0x10)and __BOOT_DS(0x18); both descriptors must be 4G flat
segment;__BOOS_CS must have execute/read permission, and __BOOT_DS
musthave read/write permission; CS must be __BOOT_CS and DS, ES, SS
mustbe __BOOT_DS; interrupt must be disabled; %esi must hold the base
addressof the struct boot_params; %ebp, %edi and %ebx must be zero.