More than 5 years have passed since last update.
Processの流れは、MBR -> GRUB kernel -> Linux kernelとなる。
MBR/GRUB kernelはLinux Kernel Codeから分離してGNU 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.code32ENTRY(startup_32)cld/**TestKEEP_SEGMENTSflagtoseeifthebootloaderisasking*ustonotreloadsegments*/testb$(1<<6),BP_loadflags(%esi)
jnz 1f
cli
movl $(__KERNEL_DS), %eaxmovl%eax, %dsmovl%eax, %esmovl%eax, %ss1:.../*Targetaddresstorelocatetofordecompression*/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 %esileal(_bss-4)(%ebp), %esileal(_bss-4)(%ebx), %edimovl$(_bss-startup_32),%ecx
shrl $2, %ecxstdrepmovslcldpopl%esi
/*
* Jump to the relocated address.
*/
leal relocated(%ebx),%eax
jmp *%eaxENDPROC(startup_32).textrelocated:->ここまでで自分自身(解凍ルーチンと圧縮kernel)をoffset先へ飛ばしている。これ以降で圧縮kernelを解凍して、移動前ベースへ配置する。CPUモード32->64への切り替えはここでは省略。/**ClearBSS(stackiscurrentlyempty)*/xorl%eax, %eaxleal_bss(%ebx), %edileal_ebss(%ebx), %ecxsubl%edi, %ecxshrl$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, %edxjmp1b2:/**Dothedecompression,andjumptothenewkernel..*/lealz_extract_offset_negative(%ebx), %ebp^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^!!minusoffsetポイント。/*pushargumentsfordecompress_kernel:*/pushl%ebp /* output address */
pushl $z_input_len /* input_len */
leal input_data(%ebx),%eax
pushl %eax/*input_data*/lealboot_heap(%ebx), %eaxpushl%eax /* heap area */
pushl %esi/*realmodepointer*/calldecompress_kernel^^^^^^^^^^^^^^^^^!!decompressionstartshere.addl$20,%esp->ここからstartup_64へjumpしてlinuxkernel初期化が本格的に開始。(ここまではすべてarch/x86/compressed/配下の処理)[Note/Tips]
BIOS -> Boot Sector(512KB) -> Boot Loader -> Kernel
- 調査はすべてx86コードをベースに行っているので、他のarchは対象外。
主なBoot Loaderは以下。
o LILO
o SYSLINUX
o GRUB/GRUB2
Register as a new user and use Qiita more conveniently
- You get articles that match your needs
- You can efficiently read back useful information
- You can use dark theme
