先日参加した自作OSもくもく会で「Linuxカーネルのコマンドラインはブートローダーからどう渡されるのか?」のような話が聞こえたので、調べようと思い調べてみました。確認はLinux kernel v4.5とsystemd-bootの2016/05/02 23:00 JSTのコードです。 uefiじゃない環境も確認しようかなと思ってgrubのコードをgit cloneはしました。が、うちのメイン環境で使っているのはsystemd-bootだしってことで確認してません。
masami@saga:~/codes$ cat /proc/cmdline initrd=\initramfs-4.6.0-rc5-ktest+.img root=/dev/sda2 rw crashkernel=256M
コマンドラインをカーネルに渡すとしたら、どこかしらのアドレスに置くんだろうというのは想像できますが、ブートローダーの好きな場所に置くとも考えにくいので、何かしらのプロトコルは決まっているはずです。というわけで、カーネルのドキュメントを確認します。確認するのはDocumentation/x86/boot.txtです。 これを見ると、カーネルのコマンドラインはヒープの終わりから0xA0000までの間の好きなところに置けると書かれています。
532 Set this field to the linear address of the kernel command line. 533 The kernel command line can be located anywhere between the end of 534 the setup heap and 0xA0000; it does not have to be located in the 535 same 64K segment as the real-mode code itself.
そして、systemd-bootのsrc/boot/efi/linux.cのコードを見ると、0xA0000がありますね。systemd-bootはアドレス0xA0000にカーネルのコマンドラインを置くようです。
if (cmdline) { addr = 0xA0000; err = uefi_call_wrapper(BS->AllocatePages, 4, AllocateMaxAddress, EfiLoaderData, EFI_SIZE_TO_PAGES(cmdline_len + 1), &addr); if (EFI_ERROR(err)) return err; CopyMem((VOID *)(UINTN)addr, cmdline, cmdline_len); ((CHAR8 *)addr)[cmdline_len] = 0; boot_setup->cmd_line_ptr = (UINT32)addr; }
そして、if文を抜けた後は、linux_efi_handover()を呼び、この関数からLinuxカーネルに制御が移ります。
#ifdef __x86_64__ typedef VOID(*handover_f)(VOID *image, EFI_SYSTEM_TABLE *table, struct SetupHeader *setup); static inline VOID linux_efi_handover(EFI_HANDLE image, struct SetupHeader *setup) { handover_f handover; asm volatile ("cli"); handover = (handover_f)((UINTN)setup->code32_start + 512 + setup->handover_offset); handover(image, ST, setup); } #else
ここから呼ばれるのはarch/x86/kernel/head_32.Sのstartup_32だと思います。そして、この辺でブートパラメータのコピー処理があります。
127 /* 128 * Copy bootup parameters out of the way. 129 * Note: %esi still has the pointer to the real-mode data. 130 * With the kexec as boot loader, parameter segment might be loaded beyond 131 * kernel image and might not even be addressable by early boot page tables. 132 * (kexec on panic case). Hence copy out the parameters before initializing 133 * page tables. 134 */ 135 movl $pa(boot_params),%edi 136 movl $(PARAM_SIZE/4),%ecx 137 cld 138 rep 139 movsl 140 movl pa(boot_params) + NEW_CL_POINTER,%esi 141 andl %esi,%esi 142 jz 1f # No command line 143 movl $pa(boot_command_line),%edi 144 movl $(COMMAND_LINE_SIZE/4),%ecx 145 rep 146 movsl
boot_command_lineはinit/main.cにあります。linux/include/init.hでextern宣言しているのでhead_32.Sからもアクセスできます。
122 /* Untouched command line saved by arch-specific code. */ 123 char __initdata boot_command_line[COMMAND_LINE_SIZE];
今回はこんなところで( ´ー`)フゥー...
- 作者: Mat Ryer,鵜飼文敏,牧野聡
- 出版社/メーカー: オライリージャパン
- 発売日: 2016/01/22
- メディア: 大型本
- この商品を含むブログ (2件) を見る