目次: Linux
今どき(?)のinitrdとカーネル引数の渡し方を知らなかったのでメモしておきます。
昔のARM LinuxですとATAGと呼ばれるブートの情報を並べたリストをメモリ領域に置いてカーネル引数やinitrdを渡して(ATAGの仕様はVincentさんのBooting ARM Linuxが詳しいです)いました。ATAGは今も使えます(Booting ARM Linuxの4a. Setup the kernel tagged list)けど主流はデバイスツリーのはずです。たぶん。ARM Linuxの場合レジスタに指定すべき情報はこんな感じだそうです。
RISC-V Linuxの場合はカーネルのドキュメント(RISC-V Kernel Boot Requirements and Constraints)によれば、RISC-V Linuxの場合レジスタに指定すべき情報はこんな感じだそうです。
ARM Linuxよりさらに減ってhartidとデバイスツリーのアドレスのたった2つです、シンプルですね。
仕様からデバイスツリーを書いても良いですが、目の前のQEMUでDebianが動作している(2024年8月2日の日記参照)のですから実際に動作しているものを調べたほうが早いでしょう。
QEMUが内部で生成しているデバイスツリーのダンプ方法は以前(2024年7月23日の日記参照)紹介した通りです。initrdとappend="root=/dev/nfs"を渡してQEMUを起動し、デバイスツリーをダンプして&dtsに変換します。
$ qemu-system-riscv64 \ -machine virt \ -bios none \ -chardev stdio,id=con,mux=on \ -serial chardev:con \ -smp 4 \ -kernel fw_payload.bin \ -initrd initramfs.cpio \ -append "root=/dev/nfs" (QEMUモニターにて) dumpdtb virt_initrd_cmd.dtb $ dtc -O dts virt_initrd_cmd.dtb > virt_initrd_cmd.dts
/* virt_initrd_cmd.dts */
/dts-v1/;
/ {
...
chosen {
bootargs = "root=/dev/nfs"; /* ★appendで渡したカーネル引数★ */
linux,initrd-end = <0x84227600>; /* ★initrd終端アドレス★ */
linux,initrd-start = <0x84000000>; /* ★initrd先頭アドレス★ */
stdout-path = "/soc/serial@10000000";
rng-seed = <0x2a0a5693 0x41742b2a 0x49faf2f1 0xaf1d27cc 0x9c06cb87 0x277e3472 0xfdf688c7 0x5029079c>;
};
...
ルートノード以下のchosenノードにあるbootargs, linux,initrd-なんとかがappendやinitrdオプションと対応しています。
以上、今どきのLinuxに対してカーネル引数やinitrdを渡す方法がわかりました。Linuxでデバイスツリーに対応したアーキテクチャは多いですから、一度実装しておけば多数のアーキテクチャでカーネルパラメーター指定ができます。便利ですね。
欠点はブートローダーでデバイスツリーのchosenノードを変更する必要がある、すなわちブートローダーにデバイスツリーを加工する処理を実装しなければならない点です。難しくはないでしょうけど、それなりに手間が掛かるでしょう。
ちなみにlinux,initrd-startのようなlinux,で始まるプロパティの仕様はLinuxカーネルのドキュメント(The chosen node - kernel.org)に記載があります。
先程まで見てきたbootargsやinitrd-なんとかが正しく生成できれば、QEMUのappendやinitrdオプション無しでもカーネル引数やinitrdをカーネルに渡すことができるはずです。やってみましょう。
/* virt_mod.dts */ /dts-v1/; / { ... chosen { /* ★この行を追加する★ */ bootargs = "root=/dev/nfs nfsroot=192.168.1.1:/path/to/debian_rootfs,v3 ip=on nfsrootdebug rw"; ...
以前作成したGDBスクリプト(2024年7月29日の日記参照)を使ってカーネルとデバイスツリーをロードします。
# load_dtb_opensbi.gdb restore virt_mod.dtb binary 0x87f00000 thread 1 set $a1=0x87f00000 thread 2 set $a1=0x87f00000 thread 3 set $a1=0x87f00000 thread 4 set $a1=0x87f00000 restore fw_payload.bin binary 0x80000000 thread 1 set $pc=0x80000000 thread 2 set $pc=0x80000000 thread 3 set $pc=0x80000000 thread 4 set $pc=0x80000000
QEMUをkernel, dtb, append引数なし、-Sオプション付き(デバッガーのアタッチ待ち)で起動します。
$ qemu-system-riscv64 \ -machine virt \ -bios none \ -nographic \ -chardev stdio,id=con,mux=on \ -serial chardev:con \ -mon chardev=con,mode=readline \ -netdev user,id=netdev0 \ -device virtio-net-device,netdev=netdev0 \ -m 2g \ -smp 4 \ -s \ -S $ riscv64-unknown-linux-gnu-gdb (gdb) target remote :1234 Remote debugging using :1234 warning: No executable has been specified and target does not support determining executable automatically. Try using the "file" command. 0x0000000000001000 in ?? () (gdb) source load_dtb_opensbi.gdb Restoring binary file virt_mod.dtb into memory (0x87f00000 to 0x87f01cb5) [Switching to thread 1 (Thread 1.1)] #0 0x0000000000001000 in ?? () [Switching to thread 2 (Thread 1.2)] #0 0x0000000000001000 in ?? () [Switching to thread 3 (Thread 1.3)] #0 0x0000000000001000 in ?? () [Switching to thread 4 (Thread 1.4)] #0 0x0000000000001000 in ?? () Restoring binary file fw_payload.bin into memory (0x80000000 to 0x81f51608) [Switching to thread 1 (Thread 1.1)] #0 0x0000000000001000 in ?? () [Switching to thread 2 (Thread 1.2)] #0 0x0000000000001000 in ?? () [Switching to thread 3 (Thread 1.3)] #0 0x0000000000001000 in ?? () [Switching to thread 4 (Thread 1.4)] #0 0x0000000000001000 in ?? () (gdb) continue Continuing.
最後のcontinueを実行するとQEMU側もログが出ます。例えばこんな感じです。
$ qemu-system-riscv64 \ -machine virt \ -bios none \ -nographic \ -chardev stdio,id=con,mux=on \ -serial chardev:con \ -mon chardev=con,mode=readline \ -netdev user,id=netdev0 \ -device virtio-net-device,netdev=netdev0 \ -m 2g \ -smp 4 \ -s \ -S OpenSBI v1.5 ____ _____ ____ _____ / __ \ / ____| _ \_ _| | | | |_ __ ___ _ __ | (___ | |_) || | | | | | '_ \ / _ \ '_ \ \___ \| _ < | | | |__| | |_) | __/ | | |____) | |_) || |_ \____/| .__/ \___|_| |_|_____/|____/_____| | | |_| Platform Name : riscv-virtio,qemo Platform Features : medeleg ... Boot HART MIDELEG : 0x0000000000001666 Boot HART MEDELEG : 0x0000000000f0b509 [ 0.000000] Linux version 6.9.0 (katsuhiro@blackbird) (riscv64-unknown-linux-gnu-gcc (GCC) 14.1.0, GNU ld (GNU Binutils) 2.42.50.20240622) #9 SMP Thu Aug 1 00:38:49 JST 2024 [ 0.000000] random: crng init done [ 0.000000] Machine model: riscv-virtio,qemo ... [ 2.652369] VFS: Mounted root (nfs filesystem) on device 0:20. [ 2.661913] devtmpfs: mounted [ 2.831443] Freeing unused kernel image (initmem) memory: 2260K [ 2.833459] Run /sbin/init as init process [ 4.984017] systemd[1]: systemd 256.4-2 running in system mode (+PAM +AUDIT +SELINUX +APPARMOR +IMA +SMACK +SECCOMP +GCRYPT -GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN +IPTC +KMOD +LIBCRYPTSETUP +LIBCRYPTSETUP_PLUGINS +LIBFDISK +PCRE2 +PWQUALITY +P11KIT +QRENCODE +TPM2 +BZIP2 +LZ4 +XZ +ZLIB +ZSTD +BPF_FRAMEWORK -XKBCOMMON +UTMP +SYSVINIT +LIBARCHIVE) [ 4.988413] systemd[1]: Detected virtualization qemu. [ 4.989856] systemd[1]: Detected architecture riscv64. Welcome to Debian GNU/Linux trixie/sid! [ 5.048884] systemd[1]: Hostname set to <qemu>. ... [ OK ] Reached target graphical.target - Graphical Interface. Starting systemd-update-utmp-runle…- Record Runlevel Change in UTMP... [ OK ] Finished systemd-update-utmp-runle…e - Record Runlevel Change in UTMP. Debian GNU/Linux trixie/sid qemu ttyS0 qemu login:
Debianのログインプロンプトまで表示されれば成功です。カーネル引数を変えたりinitrdのサイズが変わるたびにdtsを書き換えてdtcでコンパイルする……なんて考えると面倒くさいことこの上ないですが、QEMUや気の利いたブートローダーは自動的にデバイスツリーのchosenノードを加工してくれます。ありがたいですね。
< | 2024 | > | ||||
<< | < | 08 | > | >> | ||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
- | - | - | - | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
合計:
本日: