Quantcast
Channel: aimdevel’s blog
Viewing all articles
Browse latest Browse all 35

LinuxをFITイメージ+initramfsで起動する on ラズパイ4B

$
0
0

前回はラズパイ実機でu-bootとFIT imageを使用してLinuxを起動した。

aimdevel.hatenablog.com

今回はそこから進んで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ブートの流れ

  1. u-boot起動
  2. u-bootがFIT imageからlinux kernelとdevicetree、initramfsをロード
  3. initramfsを使用してlinux起動
  4. initramfs内のinit処理を実行
  5. initramfs内のinit処理の最後にsdカードのパーティション2のrootfsに切り替え
  6. パーティション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内では特に何もしていないが、一般的なシェルスクリプトを動かせることは確認できたので、基本的にはどんな処理でも実行できそうだ。

参考にしたサイト


Viewing all articles
Browse latest Browse all 35

Latest Images

Trending Articles