#はじめに
長らく古い U-boot を使っていたのですが、最新(2016年1月現在)のU-bootではFPGAのロードなんかにも対応しているということで、導入してみました。しかし、次の点が少し不便だったので手を加えました。
- ZynqのBOOT.binにu-boot(ELFファイル)を入れるとデバイスツリーが無いという理由でu-bootの起動に失敗する。
- Linuxのブート方法がFIT(Flat Image Tree)しかない。
- 古い U-boot では有効だった uEnv.txt によるブート方法の変更が出来なくなっていた。
この記事ではこれらを修正した U-bootのビルド方法を説明します。
#U-Boot のビルドの手順
##U-boot のダウンロード
shell% git clone git://git.denx.de/u-boot.git
shell% cd u-boot
##ZYBO用のブランチを作る
今回はソースコードに手を加えるので、専用のブランチを切って作業します。
shell% git checkout -b zynq-zybo
##ビルドするu-boot(ELFファイル)にデバイスツリーを含めるように定義ファイルを修正する
デフォルトのままだと、u-boot(ELFファイル)にu-boot用のデバイスツリーが含まれません。これだとBOOT.binに含まれたu-bootが起動できないので、u-bootにデバイスツリーが含まれるように定義ファイルを修正します。
具体的には、configs/zynq_zybo_defconfig の最後に次の行を追加します。
:
中略
:
CONFIG_OF_EMBED=y
##ブート時にuEnv.txtの内容でブートするようにソースコードを修正する
include/configs/zynq-common.h で定義されている CONFIG_EXTRA_ENV_SETTINGS を次のように修正します。
#define CONFIG_EXTRA_ENV_SETTINGS \
"fit_image=fit.itb\0" \
"load_addr=0x2000000\0" \
"fit_size=0x800000\0" \
"flash_off=0x100000\0" \
"nor_flash_off=0xE2100000\0" \
"fdt_high=0x20000000\0" \
"initrd_high=0x20000000\0" \
"norboot=echo Copying FIT from NOR flash to RAM... && " \
"cp.b ${nor_flash_off} ${load_addr} ${fit_size} && " \
"bootm ${load_addr}\0" \
"sdboot=echo Copying FIT from SD to RAM... && " \
"load mmc 0 ${load_addr} ${fit_image} && " \
"bootm ${load_addr}\0" \
"jtagboot=echo TFTPing FIT to RAM... && " \
"tftpboot ${load_addr} ${fit_image} && " \
"bootm ${load_addr}\0" \
"usbboot=if usb start; then " \
"echo Copying FIT from USB to RAM... && " \
"load usb 0 ${load_addr} ${fit_image} && " \
"bootm ${load_addr}\0" \
"fi\0" \
"bootenv=uEnv.txt\0" \
"loadbootenv=load mmc 0 ${load_addr} ${bootenv}\0" \
"importbootenv=echo Importing environment from mmc ...;" \
"env import -t $load_addr $filesize\0" \
"loadbootscript=load mmc 0 ${load_addr} boot.scr\0" \
"bootscript=echo Running bootscript from mmc ...;" \
"source ${load_addr}\0" \
DFU_ALT_INFO
同様に CONFIG_BOOTCOMMAND も次のように修正します。
#define CONFIG_BOOTCOMMAND \
"if mmc rescan; then " \
"echo SD/MMC found on device...;" \
"if run loadbootenv; then " \
"echo Loaded environment from ${bootenv};" \
"run importbootenv;" \
"fi;" \
"if test -n $uenvcmd; then " \
"echo Running uenvcmd ...;" \
"run uenvcmd;" \
"fi;" \
"if run loadbootscript; then " \
"run bootscript; " \
"fi; " \
"fi;" \
"run $modeboot"
ついでに zImage でブートするコマンド bootz を使えるようにします。何故か Zynq 用の U-Boot は bootz コマンドが使えないようになっています。
#define CONFIG_CMD_BOOTZ
##U-Bootをコンパイルする
クロスコンパイルする場合は、CROSS_COMPILE環境変数を設定してコンパイルします。
shell% make zynq_zybo_defconfig
shell% make CROSS_COMPILE=arm-linux-gnueabihf- u-boot
これで u-bootと言う名前のELFファイルが出来ます。
#BOOT.binの作成
##FSBL.elf と FPGAのビットストリームファイルを準備
FPGAのビットストリームファイルとFSBL(First Stage Boot Loader)を用意します。
具体的なやり方は次の記事を参考にしてください。
- Synthesijerで作ったモジュールをMessagePack-RPCで制御する(ZYNQ論理合成編)
- Vivadoで論理合成と配置配線を実行するTclスクリプト
- Vivado SDK でZynq FSBL(First Stage Boot Loader)をビルドするTclスクリプト
##u-boot.bifを準備
Vivado の bootgen コマンドで BOOT.bin を作るにはBIFファイルが必要です。次のような u-boot.bif を用意します。
the_ROM_image:
{
[bootloader]fsbl.elf
design_1_wrapper.bit
u-boot
}
the_ROM_image の[bootlader]には前節で用意したFSBL.elfを指定します。
次の行はFPGAのビットストリームファイルを指定します。
最後にビルドしたu-boot(ELFファイル)を指定します。
##bootgenコマンドを実行してBOOT.bin を作る
shell% bootgen -image u-boot.bif -w on -o BOOT.bin
#uEnv.txtの例
ここではSDカードからLinuxをブートする場合の uEnv.txt の例を示します。
SDカードの第一パーティションをFAT(VFAT)でファイルシステムを作り、BOOT.bin(FSBLとFPGAビットストリームとu-bootが入っている)、uImage(Linuxカーネルイメージ)、devicetree.dtb(デバイスツリーファイル)、uEnv.txt(u-bootでLinuxをブートするための定義ファイル)を用意します。
SDカードの第二パーティションにはLinuxのルートディレクトリがあるものとします。
uEnv.txtの内容は次の通りです。
uenvcmd=fatload mmc 0 0x03000000 uImage && fatload mmc 0 0x02A00000 devicetree.dtb && bootm 0x03000000 - 0x02A00000