前回の記事でブートローダーを作るところまで行ったので、こんどはそれを使って、コンパイルを一切せずに FreeBSD をブートするところまで行きたいと思います。ZedBoard 用に配布されているファイルを使うので Ethernet は使えませんが、それ以外はふつうに使えますし、FreeBSD が動いている環境がなくても OK です。ただ、シリアルコンソールが使える環境を用意してください。
- ZedBoard 用のSD カードイメージをダウンロードして書き込む
- 起動用のファイルを ZYBO 用に差し替える
- 動かしてみる
といった手順で説明していきます。
Step 1: SDカードイメージをダウンロードして書き込む
配布されている SD カードイメージのサイズは 1GB 程度 (大半が空き領域ですが) なので、2GB 以上のカードならば問題ないと思います。Class 10 など、なるべく速いものを用意しましょう。
書き込むと、
- mmcsd0s1: FAT フォーマットのブート領域
- mmcsd0s2a: UFS な FreeBSD root filesystem
になりますので、書き込み前に Micro SD カードに入っていた内容は消えてしまいます。注意してください。
SD カードのイメージは、FreeBSD の FTP サイトの、pub/FreeBSD/releases/arm/armv6/ISO-IMAGES/ で配布されています。たとえば、10.1-RELEASE のものなら、10.1/FreeBSD-10.1-RELEASE-arm-armv6-ZEDBOARD.img.bz2 をダウンロードして、bunzip2 (最近のものは xz で圧縮されていますので unxz) で展開してください。これをそのまま dd で書き込めば OK です。
[code:plain]
% dd if=FreeBSD-10.1-RELEASE-arm-armv6-ZEDBOARD.img of=/dev/da0 bs=1048576
[/code]
とかそんな感じです。of= のところはデバイス名なので、OS や環境次第です。Mac でも、/dev/disk1 とかすれば、ちゃんと書き込むことができます。書き込みに成功すると、/dev/ の下にパーティションがふたつ生えてきます。次のステップでは、このうち 1 つ目の、FAT フォーマットのパーティションに、起動に必要なファイルを書き込みます。
Step 2: 起動用のファイルを ZYBO 用に差し替える
SD カードの起動用パーティションには以下のファイルがあります。
- boot.bin: FSBL + .bit ファイル + u-boot (ZedBoard 用)
- license.txt
- ubldr: u-boot 用の FreeBSD ブートローダ
- uenv.txt: u-boot の設定ファイル (ZedBoard 用)
- zedboard.dtb: ZedBoard の device tree blob
- zedboard.dts: zedboard.dts のソース
このうち boot.bin は前の記事で作ったもの、ubldr は SD カードにあるものをそのまま使えますので、最後の3つだけを準備すれば OK です。
uenv.txt には u-boot がどのファイルをどのアドレスにロードし、どこから起動するか、が記述されています。最低限変更しなければならないのは、device tree blob のファイル名だけです。また、ZedBoard 用に配布されているものは SD カードからの boot だけでなく、tftp での boot にも対応した記述がされていますが、これは不要なら削除しても構いません。たとえば、以下のようにします:
[code:plain]
kernel_addr=0x100000
ubldr_addr=0x100000
dtb_addr=0x1000
dtb_name=zybo.dtb
uenvcmd=echo Booting FreeBSD from SD…; mmcinfo ; fatload mmc 0 ${ubldr_addr} ubldr ; fatload mmc 0 ${dtb_addr} ${dtb_name} ; fdt addr ${dtb_addr} ; bootelf ${ubldr_addr}
[/code]
このうち、kernel_addr は実は使わないのですが、なんとなく残してあります。
これで、起動に必要なファイルを SD カードからメモリにロードして kernel を起動する準備ができました。しかし、 Zynq などで使われているバスは、PCI バスのようなネゴシエーションの仕組みを持っていないので、kernel には (かつて ISA バス時代の FreeBSD や Linux がそうであったように) 各デバイスのアドレスなどを教えてあげる必要があります。ISA バスの時代にはこれらは kernel にハードコードされており、ハードウェアの変更にあわせてカーネルを再構築する必要がありましたが、最近はこれを device tree blob (.dtbファイル) というのを使って再構築なしに簡単に実現する仕掛けが用意されています。.dtb は、簡単な構文のソースファイル (.dts) から生成することができ、.dtb から .dts への逆変換も可能です。
Device tree blob は Linux でも FreeBSD でも使われていますが、記述する内容は OS のバスアーキテクチャやデバイスドライバに依存するため、実質的に内容は OS 依存になります。したがって、Linux 用の .dtb をそのまま使うことはできません。なお、ZYBO + Linux 用の .dtb は Digilent が GitHub に置いている Linux カーネルのリポジトリから手に入れることができます。FreeBSD の場合には、以下で説明するように ZedBoard 用のものを変更するのがよいでしょう。
変更は2カ所必要で、まず一カ所目はタイマの周波数です。Zynq の Global Timer は CPU core clock の半分の周波数で動きますので、これを正しく設定する必要があります。ZedBoard の ARM core は 666MHz 動作ですが、ZYBO では 650MHz になりますので、325MHz を設定します。10進数でも16進数でも構いません。この数字を間違えると、タイマ割り込みの周波数が正しく設定されず、変なところで device timeout が発生したりして、あちこちおかしくなるので注意が必要です (PS への供給クロックかと思って 50MHzにしたら、SD カードがすぐタイムアウトするし、時計が5倍速くらいで進むのでびっくりしました…)。
[code:plain]
timer@f00600 {
compatible = “arm,mpcore-timers”;
– clock-frequency = <0x13de4355>;
+ clock-frequency = <325000000>;
#address-cells = <0x1>;
#size-cells = <0x0>;
reg = <0xf00200 0x100 0xf00600 0x20>;
interrupts = <0x1b 0x1d>;
interrupt-parent = <0x1>;
};
[/code]
もうひとつ、USB host (echi0) からは phy_vbus_ext を削除します。ZedBoard では USB PHY が外付けなのでこれが必要ですが、ZYBO ではこれがついていると USB PHY の初期化が行われず、USB が使えません。
[code:plain]
ehci0: ehci@2000 {
compatible = “xlnx,zy7_ehci”;
reg = <0x2000 0x1000>;
interrupts = <0x35>;
interrupt-parent = <0x1>;
– phy_vbus_ext;
};
[/code]
また、ZYBO 用のファイルですよ、ということをきちんと書いておいてもよいと思います (とりあえず動けばいいよ、というのなら関係ないですが)。
[code:plain]
– model = “zedboard”;
– compatible = “digilent,zedboard”;
+ model = “zybo”;
+ compatible = “digilent,zybo”;
[/code]
.dts をコンパイルして .dtc を作るには Device Tree Compilerが必要です。たいていのプラットフォームで make 一発でビルドできると思います。
[code:plain]
% dtc -I dts -O dtb zybo.dts -o zybo.dtb
[/code]
のようにすると zybo.dts から zybo.dtb を生成することができます。
boot.bin, uenv.txt, zybo.dtb を、Micro SD カードの1つ目のパーティション (FAT) にコピーすれば終わりです。
Step 3: 起動する
ZYBO は基本的に USB からの給電でも動くようですが、USB ハブの先につながっていたりすると、ARM core の負荷がかかったときなどに電源が落ちることがあるようです (僕の環境では起きるのですが、大丈夫な方もいらっしゃるようです)。5V の AC アダプタを用意することをおすすめします。同じ Digilent の Atlys ボードについていたもの (5V 4A) をそのまま使っています。
Micro SD カードを ZYBO の Micro SD スロットに挿し、JP5 のジャンパが “SD” の位置になっていることを確認したら、シリアルコンソールのホストになる PC に USB ケーブルをつないで、ボードの電源を入れましょう。シリアルポート (/dev/cuaU1 あるいは /dev/ttyUSB1 あたり) に 115200bps でつなげば、u-boot → ubldr → FreeBSD kernel の順番に起動し、パスワードなしの root アカウントでログインできると思います。
SD カードイメージに含まれている UFS パーティション (/dev/mmcsd0s2a) は、初回の起動時にカードのサイズいっぱいまで拡大されますので、それで不都合がある場合にはあらかじめ FreeBSD なマシンで Micro SD カード上の /etc/rc.conf を修正しておいてください。
ボードの電源を切る前に、shutdown -h now するのをお忘れなく。