手作り組み込み Linux の続きです。次は本物の開発ボードである BeagleBone Black (別名 BBB) に手作り Linux をインストールします。
BeagleBone Black 備忘録 のように BeagleBone Black と開発機を FTDI USB to Serial cable で接続した状態から作業します。
BBB 用に crosstool-NG を使った ツールチェインの作成
まず、BBB 用にツールチェインを作成します。QEMU で作った arm-unknown-linux-gnueabi
の代わりに arm-arm-cortex_a8-linux-gnueabi
をカスタマイズして作ります。
cd ~/src/crosstool-ng/
bin/ct-ng distclean
bin/ct-ng show-arm-cortex_a8-linux-gnueabi
bin/ct-ng arm-arm-cortex_a8-linux-gnueabi
bin/ct-ng menuconfig
menuconfig
でカスタマイズ画面になるので以下のように設定します。ツールチェインを書き込み可能にする所と、FPU の設定です。
- In Paths and misc options
- Render the toolchain read-only (
CT_PREFIX_DIR_RO
): 無効 (ツールチェインを書き込み可能にする)
- Render the toolchain read-only (
- In Target options
- Use specific FPU (
CT_ARCH_FPU
): neon を入力 (FPU の名前を入力) - Floating point (
CT_ARCH_FLOAT_HW
): hardware (FPU) を選択
- Use specific FPU (
.config の差分
# CT_PREFIX_DIR_RO is not set
CT_ARCH_FPU="neon"
CT_ARCH_FLOAT_HW=y
ビルドします。例によって 30 分以上待ちます。
bin/ct-ng build
FPU を有効にしたので、prefix は arm-cortex_a8-linux-gnueabi
から arm-cortex_a8-linux-gnuembihf
に変わりました。このツールチェインを使うには以下のように環境変数を設定します。
PATH=${HOME}/x-tools/arm-cortex_a8-linux-gnueabihf/bin/:$PATH
export CROSS_COMPILE=arm-cortex_a8-linux-gnueabihf-
export ARCH=arm
BBB 用にブートローダー u-boot の作成
QEMU とは違って BBB ではカーネルの起動にブートローダーが必要です。ここでは標準的な u-boot を使います。
cd ~/src
git clone git://git.denx.de/u-boot.git
cd u-boot
git checkout v2021.01
ビルドの前に設定を config/
の中から設定を選びます。選び方がよくわからないのですが、am335x_evm_defconfig
で良いそうです。https://source.denx.de/u-boot/u-boot/-/tree/v2021.01/board/ti/am335x に BBB 対応と書いてあります。特にカスタマイズ無しでそのままビルドします。
make am335x_evm_defconfig
make
ここで色んなファイルができますが、必要なのは以下の二つです。
- MLO: BBB の ROM に入っている最初のブートローダーが呼び出すプログラムです。u-boot をロードする役割があります。
- u-boot.img: u-boot 本体にヘッダがついた物です。
SD カードの作成
SD カードを刺して lsblk
でデバイス名を調べ、64MiB の FAT32 (bootable) と 1GiB の ext4 パーティションを作ります。ハマリ所としては、パーティションラベルに gpt (新しいパーティション方式) は使えなかったのでご注意下さい。Linux の SD カードで遊ぶ - Qiita にパーティションの作り方を書きました。
cat <<EOT | sudo sfdisk /dev/sdc
label: dos
size=64MiB, name="boot", type=c, bootable
size=1GiB, name="rootfs"
EOT
sudo mkfs.vfat -F 16 -n BOOT /dev/sdc1
sudo mkfs.ext4 -L rootfs /dev/sdc2
最初のパーティションをマウントして MLO と u-boot.img をコピーします。
mkdir -p ~/mnt/boot
sudo mount -o uid=$UID /dev/sdc1 ~/mnt/boot/
cp MLO u-boot.img ~/mnt/boot/
sudo umount ~/mnt/boot/
U-boot の動作確認
ここで早速作った u-boot を BBB で動かしてみます。開発機と BBB を USB シリアルケーブルで接続し、picocom かなんかでターミナルを開きます。
picocom -b 115200 /dev/tty.usbserial-なんとか
電源を落とした BBB に SD カードを刺して、SD カードスロット近くの USER/BOOT ボタンを押しながら電源コードを刺します。すかさずシリアルでスペースを押すとコマンドが打てる画面になります。表示されたバージョンを確認すれば成功です。間違って GPT でパーティションを作ると古い U-boot が起動する事があります。
U-Boot SPL 2021.01 (May 01 2023 - 16:45:37 +0900)
Trying to boot from MMC1
...
Hit any key to stop autoboot: 0
=>
BBB 用に Linux カーネルを作成
次に BBB 用に Linux カーネルをビルドします。u-boot のビルドで紹介したように PATH
, CROSS_COMPILE
, ARCH
を設定してから以下のようにビルドします。
cd ~/src/linux-stable
make mrproper
make multi_v7_defconfig
make -j4 zImage
make -j4 mudules
make dtbs
u-boot を入れた SD カードにカーネル zImage と dtb をコピーします。
sudo mount -o uid=$UID /dev/sdc1 ~/mnt/boot/
cp zImage dts/am335x-boneblack.dtb ~/mnt/boot/
sudo umount ~/mnt/boot/
USER/BOOT を押しながら BBB を起動して u-boot のコンソールの fatload コマンドでカーネルと dtb をメモリに読み込み、bootz コマンドでカーネルを起動します。
Boot# fatload mmc 0:1 0x80200000 zImage
Boot# fatload mmc 0:1 0x80f00000 am335x-boneblack.dtb
Boot# setenv bootargs console=ttyO0,115200
Boot# bootz 0x80200000 - 0x80f00000
## Flattened Device Tree blob at 80f00000
Booting using the fdt blob at 0x80f00000
Loading Device Tree to 8ffee000, end 8ffff46e ... OK
Starting kernel ...
...
[ 2.522542] ---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(0,0) ]---
カーネルがパニックすれば成功です。
ルートファイルシステム作成
ルートファイルシステムの作成 などを参考にルートファイルシステムを作ります。重複しますが、~/rootfs/
にルートファイルシステムを作った後、以下のように uRamdisk ファイルを作ります。uRamdisk というのは initramfs.cpio.gz に u-boot ヘッダを付けた物らしいです。(実はよく分かっていない)
cd ~/rootfs
find . | cpio -H newc -ov --owner root:root > ../initramfs.cpio
cd ..
gzip initramfs.cpio
mkimage -A arm -O linux -T ramdisk -d initramfs.cpio.gz uRamdisk
BBB で手作り LInux を実行する
BBB を起動して u-boot のコンソールで以下のように入力すれば作成したルートファイルシステムをカーネルに与える事が出来ます。
fatload mmc 0:1 0x80200000 zImage
fatload mmc 0:1 0x80f00000 am335x-boneblack.dtb
fatload mmc 0:1 0x81000000 uRamdisk
setenv bootargs console=ttyO0,115200 rdinit=/bin/sh
bootz 0x80200000 0x81000000 0x80f00000
毎回手で入力するのは面倒なので今回は自動起動をしてみましょう。uEnv.txt というファイルに key=value
形式でブート時に必要な情報を書き込みます。
cat <<EOT > uEnv.txt
bootargs=console=ttyO0,115200 rdinit=/bin/sh
uenvcmd=fatload mmc 0:1 0x80200000 zImage; fatload mmc 0:1 0x80f00000 am335x-boneblack.dtb; fatload mmc 0:1 0x81000000 uRamdisk; bootz 0x80200000 0x81000000 0x80f00000
EOT
実はこの eEnv.txt は u-boot 本体ではなく、各プラットフォームごとに決まっている仕組みのようです。かなり探しましたが仕様のような物が見当たらなかったので、uEnv.txt のサンプルを見ながら作りました。多分ですが、以下のような仕様なのでは無いかと思います。
-
key=value
のように書いてあると、setenv key value
を実行したように変数が設定される。 - 最後に
uenvcmd=
に設定した内容が実行される。
ルートファイルシステムと uEnv.txt を SD カードにコピーしたら完成です。
sudo mount -o uid=$UID /dev/sdc1 ~/mnt/boot/
cp uRamdisk uEnv.txt ~/mnt/boot/
sudo umount ~/mnt/boot/
検索するとどうやら boot.scr というファイルに u-boot の初期化スクリプトを書けるようですが、私の所では Wrong image format for "source" command
というエラーが出てうまく行きませんでした。
これで手作り Linux が起動して /bin/sh が使えるようになりました!
参考
-
https://github.com/PacktPublishing/Mastering-Embedded-Linux-Programming-Third-Edition
- サポートサイト
-
https://github.com/PacktPublishing/Mastering-Embedded-Linux-Programming-Third-Edition/blob/master/Chapter05/uEnv.txt
- uEnv.txt の例
- AM335x Generation — Das U-Boot unknown version documentation
宿題
- tftp を使って開発をスピードアップ。
- RAM filesystem ではなくファイルシステムをマウントしたい。
- /bin/sh ではなく init を実行する。
- ネットワークアクセスを有効にする。
- u-boot で色々遊ぶ。