[RPi][Linux] boot upstream Linux from TFA/EDK2 on Raspberry Pi 3

Linux
.

TF-A と EDK II が Raspberry Pi 3 (RPi3) にポーティングされているということで、これらをビルドして Linux kernel の起動までの手順を追ってみました。

過去記事では、RPi3 では U-Boot からの kernel 起動、QEMU では TF-A/EDK II からの kernel 起動を試しています。

一部これらの手順は流用しますが、QEMU と RPi3 では異なる部分もあるため全て一から流してみます。

clone & build

QEMUの場合 は EDK II の FV (firmware volume) を BL33 イメージとして TF-A に指定して FIP に統合しましたが、ここでは TF-A の BLx イメージを EDK II の FV に統合することにします。

git clone https://github.com/ARM-software/arm-trusted-firmware
cd arm-trusted-firmwaremake PLAT=rpi3 realclean
make PLAT=rpi3 CROSS_COMPILE=aarch64-linux-gnu- all fip \
    PRELOADED_BL33_BASE=0x30000
export ATF_BUILD_DIR=${PWD}/build/rpi3/release
cd -

BL33 は含まないので、外部バイナリの位置を表す"PRELOADED_BL33_BASE"で offset を指定します。

この値は EDK II の RPi3 イメージ構成に含まれる "UEFI image" の位置を指します。

後で TF-A のビルド結果を参照するため、ATF_BUILD_DIR に入れておきます。ここには BLx イメージバイナリが含まれています。

EDK II リポジトリを clone します。RPi3 をターゲットにするため、新たに edk2-platforms と edk2-non-osi リポジトリを clone しています。これらは edk2/ 以下にある必要があります。

git clone https://github.com/tianocore/edk2
git checkout -b stable
git reset --hard edk2-stable202002
cd edk2
git clone https://github.com/tianocore/edk2-platforms
git clone https://github.com/tianocore/edk2-non-osi
export PACKAGES_PATH=${PWD}:${PWD}/edk2-platforms:${PWD}/edk2-non-osi
export GCC5_AARCH64_PREFIX=aarch64-linux-gnu-

おまじないを実行して EDK II をビルドします。

make -C BaseTools
. edksetup.sh
build -a AARCH64 -t GCC5 -p Platform/RaspberryPi/RPi3/RPi3.dsc \
    -D TFA_BUILD_ARTIFACT=${ATF_BUILD_DIR}

TFA_BUILD_ARTIFACT マクロに TF-A のビルド結果ディレクトリとして ATF_BUILD_DIR を指定します。

このビルドで "edk2/Build/RPi3/DEBUG_GCC5/FV/RPI_EFI.fd" が生成されます。ここに TF-A で生成された BLx イメージも含まれています。

Linux build

Linux もビルドします。そのまま upstream kernel を持ってきた場合、upstream kernel に含まれる RPi3 は起動方法が "spin-table" になっているため、TF-A を介する場合は Sub CPU が起動できません。TF-A を介して起動する場合は "psci" に変更する必要があります。これは devicetree にて行います。

例として GitHub に新たに "psci" に対応するための RPi3 用 branch を置いています。以下の方法でビルドすると、追加した devicetree の bcm2837-rpi-3-b-tfa.dtb が得られます。

export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-
git clone https://github.com/kunih/linux.git -b rpi3-tfa --single-branch
make defconfig
make Image dtbs
cd -

準備

全てのバイナリが用意出来たら、microSD による起動準備を行います。ここからは GitHub にあるドキュメントの手順に従います。

まず microSD を FAT32 でフォーマットしてマウントし、上記ビルドで生成したイメージ "RPI_EFI.fd" を microSD カードにコピーします。

※ PC 上の microSD のデバイス名 (以下 /dev/sdX) は dmesg などで確認してください。microSD 購入時はほぼ1パーティションが作成済のため、パーティションは存在する前提にしています。

sudo mkfs.vfat /dev/sdX1
sudo mount /dev/sdX1 /mnt
sudo cp edk2/Build/RPi3/DEBUG_GCC5/FV/RPI_EFI.fd /mnt/

boot に必要なバイナリを RPi の GitHub から取得し、microSD カードにコピーします。

wget https://github.com/raspberrypi/firmware/raw/master/boot/bootcode.bin
wget https://github.com/raspberrypi/firmware/raw/master/boot/fixup.dat
wget https://github.com/raspberrypi/firmware/raw/master/boot/start.elf
sudo cp bootcode.bin fixup.dat start.elf /mnt/

さらに microSD 上に config.txtを作成します。

arm_control=0x200
enable_uart=1
armstub=RPI_EFI.fd
disable_commandline_tags=2

ビルドした Linux kernel と devicetree、さらに ramdisk イメージを microSD にコピーします。ramdisk イメージは過去記事などを参照して入手してください。形式は cpio でも cpio.gz でも uboot image でも通ります。

sudo cp linux/arch/arm64/boot/Image /mnt/
sudo cp linux/arch/arm64/boot/dts/broadcom/bcm2837-rpi-3-b-tfa.dtb /mnt/
sudo cp rootfs.cpio.gz /mnt/

全てをコピーしたら、microSD をアンマウントして PC から RPi3 本体に移します。

sudo umount /mnt

シリアルケーブルを PC に接続して端末ソフトを開いておきます。

起動

RPi3 に AC アダプタを接続して電源を入れます。

.

シリアル端末には TF-A が起動するログが出始めます。その後、EDK II の起動ログが出始め、HDMI 出力には大きな RPi ロゴが出てきます。

.

起動が完了すると EDK II の 標準ブートローダ画面が出てきますが、途中で [F1] を押すと EFI Shell が起動します。ここではブートローダは用意していないので、EFI Shell を起動するようにしてください。

標準ブートローダ

EFI Shell

EFI Shell から Linux kernel を起動する場合、UEFI Application であるブートローダ(Grubなど) を使うのが一般的ですが、ここでは直接 kernel を起動します。

arm64 の場合 "CONFIG_EFI_STUB" が有効になっていますが、この定義が有効になっていると kernel イメージをそのまま UEFI Application として扱うことができます。EFI Shell にて以下のように入力して kernel を起動します。

Shell> FS0:
FS0:\> \Image dtb=\bcm2837-rpi-3-b-tfa.dtb initrd=\rootfs.cpio.gz
         console=ttyS1,115200 rootfstype=ramfs rdinit=/sbin/init rootwait debug

この例では、準備のところで microSD にコピーしたファイルを指定しています。

\Image microSD 上の kernel イメージファイル (= EFI Application)
dtb=\bcm2837-rpi-3-b-tfa.dtb microSD 上の devicetree blob ファイル
initrd=\rootfs.cpio.gz microSD 上の rootfs イメージファイル

上記以外は kernel command line としてそのまま取り込まれます。シリアル端子(microUSB)は ttyS1、HDMI 出力コンソールは tty0 に割り当てられているため、それに合わせて指定します。

console=ttyS1,115200 コンソール出力をシリアル端子、115200bps に設定
rootfstype=ramfs rootfs 種別に RAM filesystem を指定
rdinit=/sbin/init RAM filesystem の初期起動プログラムを指定
rootwait rootfs が使えるようになるまで待つ
debug ログレベルを debug に設定

うまく起動できるとおなじみの kernel message が console で指定したデバイスに表示されます。

.

参考


コメント

タイトルとURLをコピーしました