VOOZH about

URL: https://qiita.com/tomoyafujita/items/929b32e8ff9da2c0589c

⇱ Linux Boot Process(compressed) #x86 - Qiita


👁 Image
12

Go to list of users who liked

9

Share on X(Twitter)

Share on Facebook

Add to Hatena Bookmark

More than 5 years have passed since last update.

@tomoyafujita(Tomoya Fujita)

Linux Boot Process(compressed)

12
Posted at

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に成功後、612bytekernel header情報をlhreadし、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

12

Go to list of users who liked

9
0

Go to list of comments

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12

Go to list of users who liked

9