Processの流れは、MBR -> GRUB kernel -> Linux kernelとなる。
MBR/GRUB kernelはLinux Kernel Codeから分離してGNU GRUBで管理されている。GRUB
GRUB kernelの関数callstack
__start -> grub_main() -> ... -> grub_cmd_linux() -> grub_cmd_initrd() -> grub_linux_boot()
grub-2.00/grub-core/loader/i386/pc/linux.c
static grub_err_t
grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
int argc, char *argv[])
{
grub_file_t file = 0;
struct linux_kernel_header lh;
grub_uint8_t setup_sects;
grub_size_t real_size;
grub_ssize_t len;
int i;
char *grub_linux_prot_chunk;
int grub_linux_is_bzimage;
grub_addr_t grub_linux_prot_target;
grub_err_t err;
grub_dl_ref (my_mod);
if (argc == 0)
{
grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
goto fail;
}
file = grub_file_open (argv[0]);
^^^^^^^^^^^^^^^^^^^^^^^^!! read linux kernel file
if (! file)
goto fail;
-> file openに成功後、612byteのkernel header情報をlhへreadし、version/signatureのチェックを行っている。
grub-2.00/grub-core/loader/i386/linux.c-
static grub_err_t
grub_linux_boot (void)
{
...
state.ebp = state.edi = state.ebx = 0;
state.esi = real_mode_target;
state.esp = real_mode_target;
state.eip = params->code32_start;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^!! 命令ポインタにLinux Kernelのエントリポイントを設定。
return grub_relocator32_boot (relocator, state, 0);
}
o 圧縮Linux Kernelの解凍
Boot Loaderから物理アドレスLinux Kernelエントリポイントへ制御が移った後、圧縮データ(Linux Kernel)の解凍ルーチンが開始。
ここからLinux Kernelの仕事になるため、ソースコード的にはGRUBからLinuxへ移動。
arch/x86/boot/compressed/head_64.S
__HEAD
.code32
ENTRY(startup_32)
cld
/*
* Test KEEP_SEGMENTS flag to see if the bootloader is asking
* us to not reload segments
*/
testb $(1<<6), BP_loadflags(%esi)
jnz 1f
cli
movl $(__KERNEL_DS), %eax
movl %eax, %ds
movl %eax, %es
movl %eax, %ss
1:
...
/* Target address to relocate to for decompression */
addl $z_extract_offset, %ebx
^^^^^^^^^^^^^^^^!! 解凍後のkernelを配置するためのoffset
/* Set up the stack */
leal boot_stack_end(%ebx), %esp
/* Zero EFLAGS */
pushl $0
popfl
/*
* Copy the compressed kernel to the end of our buffer
* where decompression in place becomes safe.
*/
pushl %esi
leal (_bss-4)(%ebp), %esi
leal (_bss-4)(%ebx), %edi
movl $(_bss - startup_32), %ecx
shrl $2, %ecx
std
rep movsl
cld
popl %esi
/*
* Jump to the relocated address.
*/
leal relocated(%ebx), %eax
jmp *%eax
ENDPROC(startup_32)
.text
relocated:
-> ここまでで自分自身(解凍ルーチンと圧縮kernel)をoffset先へ飛ばしている。
これ以降で圧縮kernelを解凍して、移動前ベースへ配置する。
CPUモード32->64への切り替えはここでは省略。
/*
* Clear BSS (stack is currently empty)
*/
xorl %eax, %eax
leal _bss(%ebx), %edi
leal _ebss(%ebx), %ecx
subl %edi, %ecx
shrl $2, %ecx
rep stosl
/*
* Adjust our own GOT
*/
leal _got(%ebx), %edx
leal _egot(%ebx), %ecx
1:
cmpl %ecx, %edx
jae 2f
addl %ebx, (%edx)
addl $4, %edx
jmp 1b
2:
/*
* Do the decompression, and jump to the new kernel..
*/
leal z_extract_offset_negative(%ebx), %ebp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^!! minus offsetポイント。
/* push arguments for decompress_kernel: */
pushl %ebp /* output address */
pushl $z_input_len /* input_len */
leal input_data(%ebx), %eax
pushl %eax /* input_data */
leal boot_heap(%ebx), %eax
pushl %eax /* heap area */
pushl %esi /* real mode pointer */
call decompress_kernel
^^^^^^^^^^^^^^^^^!! decompression starts here.
addl $20, %esp
-> ここからstartup_64へjumpしてlinux kernel初期化が本格的に開始。
(ここまではすべてarch/x86/compressed/配下の処理)
[Note/Tips]
BIOS -> Boot Sector(512KB) -> Boot Loader -> Kernel
- 調査はすべてx86コードをベースに行っているので、他のarchは対象外。
主なBoot Loaderは以下。
o LILO
o SYSLINUX
o GRUB/GRUB2