前回はラズパイ実機でu-bootとFIT imageを使用してLinuxを起動した。
今回はそこから進んでFIT imageにinitramfsを含めて起動する。
initramfs起動後はパーティション2に存在するrootfsに切り替えてLinuxを起動するところまで実施する。
また、initramfsを作成、起動する方法を調べる中で、前回の記事に修正したい点がいくつか見つかった。近いうちに修正したい。
はじめに
今回はinitramfsを使用するが、ラズパイを使用する場合はinitramfsを使用することを意識することは少ないと思う。というのも、ラズパイOSを使用する場合は何も考えなくてもsdカードのパーティション2がrootfsとしてマウントされるので意識しなくてよいし、yoctoのmeta-raspberrypiを使用してsdカードイメージを作成する場合でも、デフォルトはinitaramfsを使う設定ではないはずだ。
ではなぜ突然initramfsを使い始めたのかというと、本番のrootfsをマウントする前に行いたい処理をinitramfsで行うことができるからだ。例えば、secure boot関係の検証や復号処理など。
作るもの
以下の内容になるように作成する。
Linuxブートの流れ
- u-boot起動
- u-bootがFIT imageからlinux kernelとdevicetree、initramfsをロード
- initramfsを使用してlinux起動
- initramfs内のinit処理を実行
- initramfs内のinit処理の最後にsdカードのパーティション2のrootfsに切り替え
- パーティション2のinitを実行しラズパイOSを起動
実施環境
- ビルド環境
windows11のwslでubuntu24.04を使用してビルドなどを行い、sdカードの操作はwindows側で行った。 - 実機
ラズパイ4B - 対象バージョン
ラズパイOSの公式イメージ「2024-03-15-raspios-bookworm-arm64-lite.img.xz」と同等。 - raspi OS
bookworm - linux kernel
linux-stable_20240423
手順
前回の記事の内容を実施して、FIT imageからLinuxの起動に成功していることを前提に作業を進める。
ビルド環境で以下の資材を準備していく。
資材 | 説明 | 取得元/作成方法 |
---|---|---|
FITImage | 今回はlinux kernelとdevice treeとinitramfsを含んだイメージ | 自前で作成する |
sdカード | u-bootを起動できるように準備したものにlinuxを起動する設定を加える | 前回の記事のものを流用 |
initramfsを作成する
今回は最低限のinitスクリプトを実行するinitramfsを作成する。
初めにbusyboxをビルドする。
Linux kernelなどをビルドした環境ならビルドできるはず。
mkdir ~/initramfs-work && cd ~/initramfs-work wget https://github.com/mirror/busybox/archive/refs/tags/1_36_0.tar.gz tar xf 1_36_0.tar.gz && cd busybox-1_36_0 curl -fL -o busybox-no-cbq.patch 'https://bugs.busybox.net/attachment.cgi?id=9751' patch -p1 < busybox-no-cbq.patch rm busybox-no-cbq.patch make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- menuconfig
上記のコマンドを実行すると、menuが表示されるので、Setttings--->Build static binary (no shared libs)
を有効にして、ライブラリがスタティックリンクされるようにしておく。
その後ビルドする。
make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- install
ビルド成果物は_install
ディレクトリに格納されている。
initramfs用にファイルを作成する。
特殊なディレクトリ、ファイルを作成する。
cd _install mkdir proc sys dev run etc dev/pts etc/init.d sudo mknod -m 666 dev/null c 1 3 sudo mknod -m 600 dev/console c 5 1
initスクリプトを作成する。ついでに不要ファイルを削除する。
rm linuxrc touch init chmod +x init
initの内容は以下にする。
#!/bin/sh mount -v --bind /dev /dev mount -v --bind /dev/pts /dev/pts mount -vt proc proc /proc mount -vt sysfs sysfs /sys mount -vt tmpfs tmpfs /run echo "hello initramfs!" echo "start switch_root!" # wait mmcblk0p2. for i in {1..5} do /sbin/mdev -s TMP=`ls -l /dev/ | grep mmcblk0p2` if [ -n "${TMP}" ];then break fi echo "waiting rootfs..." sleep 1 done # mount mmcblk0p2. mkdir -p /dev/root mount /dev/mmcblk0p2 /dev/root # switch root exec switch_root -c /dev/console /dev/root /sbin/init
パーティション名がハードコーディングされているが、本来ならば/proc/cmdline
などから取得したほうがよい。
今回は使わないつもりだが、一応kernel moduleをインストールする。
一度、Linuxをビルドしたディレクトリに移動して作業する。
cd /path/to/linux make modules_install INSTALL_MOD_PATH=~/initramfs-work/busybox-1_36_0/_install cd ~/initramfs-work/busybox-1_36_0/_install
initramfsとして使えるように変換する
find . | cpio -H newc -ov -F ../rootfs.cpio cd ../ gzip rootfs.cpio
initramfsがrootfs.cpio.gz
として作成できた。
FIT imageにinitramfsを含める
前回FIT imageを作成したLinuxの作業ディレクトリにinitramfsをコピーし、作業ディレクトリに移動する。
cp rootfs.cpio.gz /path/to/linux/arch/arm64/boot/ cd /path/to/linux/arch/arm64/boot/
kernel.its
を以下の内容で作成する。
前回のものからinitramfsを含める設定とuartを使用する設定が追加されている。
各イメージのロードアドレスは適当。メモリ4GBのラズパイ4ならこのアドレスで動くはず。
/dts-v1/; / { description = "fitImage for raspberrypi"; #address-cells = <1>; images { kernel { description = "Linux kernel"; data = /incbin/("./Image.gz"); type = "kernel"; arch = "arm64"; os = "linux"; compression = "gzip"; load = <0x40480000>; entry = <0x40480000>; }; fdt { description = "Flattened devicetree blob"; data = /incbin/("./dts/broadcom/bcm2711-rpi-4-b.dtb"); type = "flat_dt"; arch = "arm64"; compression = "none"; load = <0x42000000>; }; fdt-uart1 { description = "Flattened devicetree blob"; data = /incbin/("./dts/overlays/uart1.dtbo"); type = "flat_dt"; arch = "arm64"; compression = "none"; load = <0x42080000>; }; ramdisk { description = "ramdisk"; data = /incbin/("./rootfs.cpio.gz"); type = "ramdisk"; arch = "arm64"; os = "linux"; compression = "gzip"; load = <0x80000000>; entry = <0x80000000>; }; }; configurations { default = "config-1"; config-1 { description = "kernel with fdt and ramdisk configuration"; kernel = "kernel"; fdt = "fdt", "fdt-uart1"; ramdisk = "ramdisk"; }; }; };
FIT imageをビルドする。
mkimage -f kernel.its FITImage
sdカードにFITImageをコピーする
前回と同様にsdカードのパーティション1にFITImageをコピーする。
以後の作業はラズパイ実機で行う。u-bootコンソールを触るので、uartか、HDMI+キーボードの環境を用意すること。
sdカードを装着してラズパイの電源を入れると、u-bootが起動するので、何らかのキーを押してu-bootコンソールに入る。
以下のコマンドで設定を変更、保存する。
setenv bootargs "coherent_pool=1M 8250.nr_uarts=1 root=/dev/mmcblk0p2 rw rootwait" setenv bootcmd "fatload mmc 0:1 0x1000000 FITImage;bootm 0x1000000;" saveenv
bootargs
には使われない設定が残っているが、今後のために残しておく。
以下のコマンドでブートする。次回以降は上記の設定なしで起動できるようになっている。
boot
作成に成功していれば、initramfsに仕込んだログを出力した後に、mmcblk0p2のパーティションでシステムが起動していることを確認できる。
ログの例は以下。目的のラズパイOS(Debian bookworm)が起動していることを確認できる。
[ 16.359865] Run /init as init process check PID 1 [ 16.378075] usb 1-1: new high-speed USB device number 2 using xhci_hcd [ 16.414107] mmc1: new high speed SDIO card at address 0001 hello initramfs! start switch_root! [ 16.459543] mmc0: new ultra high speed DDR50 SDHC card at address 0001 [ 16.467066] mmcblk0: mmc0:0001 EB1QT 29.8 GiB [ 16.473866] mmcblk0: p1 p2 [ 16.477381] mmcblk0: mmc0:0001 EB1QT 29.8 GiB [ 16.536635] usb 1-1: New USB device found, idVendor=2109, idProduct=3431, bcdDevice= 4.21 [ 16.545198] usb 1-1: New USB device strings: Mfr=0, Product=1, SerialNumber=0 [ 16.552653] usb 1-1: Product: USB2.0 Hub [ 16.559340] hub 1-1:1.0: USB hub found [ 16.563624] hub 1-1:1.0: 4 ports detected [ 16.661022] EXT4-fs (mmcblk0p2): recovery complete [ 16.669754] EXT4-fs (mmcblk0p2): mounted filesystem 93c89e92-8f2e-4522-ad32-68faed883d2f r/w with ordered data mode. Quota mode: none. [ 17.187645] systemd[1]: System time before build time, advancing clock. [ 17.250962] systemd[1]: systemd 252.22-1~deb12u1 running in system mode (+PAM +AUDIT +SELINUX +APPARMOR +IMA +SMACK +SECCOMP +GCRYPT -GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN +IPTC +KMOD +LIBCRYPTSETUP +LIBFDISK +PCRE2 -PWQUALITY +P11KIT +QRENCODE +TPM2 +BZIP2 +LZ4 +XZ +ZLIB +ZSTD -BPF_FRAMEWORK -XKBCOMMON +UTMP +SYSVINIT default-hierarchy=unified) [ 17.284347] systemd[1]: Detected architecture arm64. Welcome to Debian GNU/Linux 12 (bookworm)!
終わりに
linux+initramfsで起動し、その後本番用のパーティションに切り替える方法を試した。
今回はinitramfs内では特に何もしていないが、一般的なシェルスクリプトを動かせることは確認できたので、基本的にはどんな処理でも実行できそうだ。