Initramfsを使用したboot
from min1visor
やること
Initramfsについて知る
実装で必要な処理を考える
実装する
Initramfsについて知る
第384回 Initramfsのしくみ | gihyo.jp
ファイルシステムをマウントするためにはドライバが必要だが、どのようなドライバなのか起動前には分からない
全てのディスクドライバを用意してしまうとカーネルが大きくなってしまう
メモリ上に展開されるファイルシステムをcpio形式でアーカイブしてgzipで圧縮したものがInitramfs
ブートローダーから渡されたアドレスを元にInitramfsをカーネルがメモリ上に展開する
init=オプションで渡されたスクリプトを実行する
デフォルトは/init
そもそも今使用しているLinuxのイメージがこれを使用していないのか確認する
ログからKernel command line: earlycon=pl011,0x9000000 console=ttyAMA0 root=/dev/vdaと出ており、/dev/vdaをrootfsとしてマウントしている
virtio-blkのドライバだけ最初から持ってるのかな
はじめからディスクのファイルシステムを読み込めているのでビルトイン
そのときはCONFIG_VIRTIO_BLK=yでビルドされている
どのファイルシステムを使って起動するかは設定で決まっているのかカーネルの起動引数で変えられたりするのか
code:dts
chosen {
stdout-path = "/pl011@9000000";
bootargs = "earlycon=pl011,0x9000000 console=ttyAMA0 root=/dev/vda";
// 例えば root=/dev/ram0 rdinit=/init にするとInitramfsを使用
};
実装で必要な処理を考える
Initramfsの作成
QEMUで起動するときに渡す
HVがメモリ上にロードする
VMの起動時の引数としてアドレスを渡す
Initramfsの作成
code:sh
mkdir mnt
sudo mount -o loop ./bin/disk/DISK0 mnt
sudo find . | sudo cpio -o -H newc | gzip > ../initramfs.cpio.gz
QEMUで起動するときに渡す
ディスクイメージにして渡すのでスクリプトで指定されているディレクトリに置くだけでいい
ログで確認できた
code:_
INFO list_files RAMFS.GZ: File Size: 0x1DFEF4
HVがメモリ上にロードする
カーネルの後ろに配置する
RAM_SIZE = 0x10000000;で256MiB確保していて、Initramfsの大きさは2MB程度かつgzip -lで確認すると展開後は約4MBになるので十分足りそう
code:rs
let initramfs_virtual_address =
((kernel_virtual_address + kernel_size - 1) & !(ALIGN_SIZE - 1)) + ALIGN_SIZE;
let initramfs_physical_address = vm.get_physical_address(initramfs_virtual_address).unwrap();
fat32
.read(&initramfs, blk, initramfs_physical_address, 0, initramfs_size)
.expect("Failed to read Initramfs");
dtsの書き換えを行う
code:dts
chosen {
stdout-path = "/pl011@9000000";
bootargs = "earlycon=pl011,0x9000000 console=ttyAMA0 rdinit=/linuxrc";
linux,initrd-start = <0x0 0x48000000>;
linux,initrd-end = <0x0 0x481DFEF4>; /* 0x48000000 + 0x1DFEF4 */
/* bootargs = "earlycon=pl011,0x9000000 console=ttyAMA0 root=/dev/vda"; */
};
panicした
code:_
VFS: Cannot open root device "" or unknown-block(0,0): error -6
Please append a correct "root=" boot option; here are the available partitions:
List of all bdev filesystems:
ext3
ext2
ext4
fuseblk
Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0)
CPU: 0 UID: 0 PID: 1 Comm: swapper/0 Not tainted 6.12.27 #2
Call trace:
dump_backtrace+0x90/0xe8
show_stack+0x18/0x24
dump_stack_lvl+0x34/0x8c
dump_stack+0x18/0x24
panic+0x388/0x39c
mount_root_generic+0x274/0x354
mount_root+0x198/0x26c
prepare_namespace+0x5c/0x2e8
kernel_init_freeable+0x284/0x2e0
kernel_init+0x20/0x1d0
ret_from_fork+0x10/0x20
Kernel Offset: disabled
CPU features: 0x00,000000c0,00200000,4200420b
Memory Limit: none
--- end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0) ---
試したこと
はじめにアドレスの書き方を間違えていて、64bitを2つに分けて書くのを忘れていたから修正した
/initが無いので/bin/busyboxのシンボリックリンクの/linuxrcにした
ビルドの設定を確認する
ビルド設定でInitramfsが使用できなくなっている可能性がある
CONFIG_BLK_DEV_INITRD=yが有効になっているか調べる
カーネルのビルドスクリプトを見るとqemu_aarch64_virt_defconfigでビルドしている
buildroot-2025.05/board/qemu/aarch64-virt/linux.configに設定があるらしいので確認したら、CONFIG_BLK_DEV_INITRDが無い
これが主要な原因だった
ビルドスクリプトはLLMに書いてもらって再度試してみたら起動に成功した
デバイスツリーに書くサイズは少しずれると変なエラーメッセージが増えるだけでpanicしないときもあり、起動できなくなるわけではないということを覚えておこう
#min1visor
#hypervisor