#はじめに
最近のARMプロセッサはbyte orderを選択できるようになっています。NetBSD/evbarmはデフォルトでlittle endianモードで動作しますが、一部のSoCでbig endianモードをサポートしています1。
普段x86にどっぷり漬かっていると、気付かないうちにlittle endianを前提としたコーディングをしてしまわないか心配です(謎マシン愛好家の皆さんには釈迦に説法でしょうが...)。そこそこ速くて、そこそこ安い、省電力な実機でbig endianな環境を楽しむには、なんといってもevbarmがオススメです。
今回はAllwinner A20を搭載した評価ボード、Cubietruckでbig endianな環境を構築してみます。Cubietruckを選択したポイントは
- SATAをサポートしている
- メモリが潤沢 (2GB)
- NetBSDでSMPが安定している (dual core)
という点です。SDカードは耐久性に問題があるので、1.はポイントが高いと思っています。さて、前置きはこれぐらいにして、早速本題に入りましょう。
##必要なもの
Cubietruckでbig endianな環境を構築するには、次のアイテムが必要です。
- Cubietruck本体、ACアダプタ
- NetBSD/evbarmをクロスビルドできる母艦
- 1GB以上のmicro SDカード
- 母艦で使えるカードリーダ
- USBキーボード
- HDMI接続のディスプレイまたはテレビ
- LANケーブル (オンボードのWiFiアダプタには技適マークもドライバもありません)
- (必要に応じて) 2.5インチのSATAハードディスクまたはSSD、USBマウス
リストアップしてみると、いろいろ必要ですね。。。
##手順
次のような手順でbig endianな環境を構築します。
- スナップショットの作成
- u-bootのインストール
- ライブイメージの起動、必要に応じてSATAディスクへのインストール
これから各ステップを詳しく解説します。
#スナップショットの作成
公式サイトで配布されているNetBSD/evbarmのスナップショット(or リリース)はlittle endianモードで動作するバイナリです。big endian環境を楽しむためには、自分でスナップショットをクロスビルドする必要があります。後述のようにNetBSD 7.0にはXサーバに不具合があるので、-currentをオススメします。
どこのご家庭のメインマシンにも-currentのソース一式がミラーされていると思いますが、そうでない場合は適当なPOSIX compatibleな母艦(NetBSDである必要はありません。クロスビルドについては昨年のadvent calenderの記事が参考になります)に、日本のanoncvsサーバから-currentのsrcとxsrcを取得してください。
まず/etc/mk.confを次のような内容で作成します。
.if ${MACHINE} == "evbarm"
CPUFLAGS+= -mtune=cortex-a7 -mfpu=neon-vfpv4
.endif
BSDSRCDIR= /XXX/YYY/src
X11SRCDIR= /XXX/YYY/xsrc
BSDOBJDIR= /XXX/YYY/obj/${MACHINE}
DESTDIR= /XXX/YYY/dest/${MACHINE}
RELEASEDIR= /XXX/YYY/release
TOOLDIR= /XXX/YYY/tools
CPUFLAGSにはCubietruck向けの最適化オプションを指定しておきます。BSDSRCDIRとX11SRCDIRは-currentのsrcとxsrcの場所を指定する変数です。BSDOBJDIRはクロスビルドの作業ディレクトリ、DESTDIRはでき上がったバイナリ(+α)がインストールされる先、RELEASEDIRはスナップショットのディスクイメージやtar ballがインストールされるディレクトリです。ここで指定したディレクトリはあらかじめ作成しておく必要があります(${MACHINE}にはevbarmが代入されます)。
2016/01/05追記
最近の-currentではCubietruckのVGAポートが実験的にサポートされています。デフォルトではVGAをコンソールとして使用するようです(自宅にアナログ入力を受け付けるディスプレイがないため、確認できていません。時代!!)。出力先の切り替えはまだサポートされていないようなので、以前のようにHDMI出力を利用したい場合、src/sys/arch/evbarm/conf/CUBIETRUCKから次の2つのデバイスをコメントアウトしてください:
# we need awinii2c to talk to VGA monitors
#awiniic* at awinio? port ?
# TV encoder / VGA output
#awintve0 at awinio0
追記おわり
これらの準備の下、
% cd /XXX/YYY/src
% ./build.sh -U -m evbearmv7hf-eb -x -j 16 tools release
を実行します。ここでbuild.shのオプションは
- -U
- 一般ユーザー権限で実行する。あらかじめ/XXX/YYY以下の各ディレクトリを書き込み可能にしておく必要があります(常套手段としては自分をwsrcグループに追加、もろもろのディレクトリをchgrp -R wsrc && chmod -R g+xしておく等)。root権限を使う場合は不要です。
- -m evbearmv7hf-eb
- EABI、ARMv7、FPU、big endianの環境をビルドします。
- -x
- Xサーバ・クライアントを作成します。
- -j n
- n個のジョブで並列ビルドします。マシンに実装されているコア数x1〜2程度を指定するといいようです。
- tools release
- tool chainを作成した後、スナップショットを作成します。
を意味しています。詳しくはsrc/BUILDINGをご覧ください。
build.shを実行して数十分〜数時間程度待つと、/XXX/YYY/release/evbarm/binary/gzimgにライブイメージarmv7.img.gzが生成されます。
#u-bootのインストール
ライブイメージにはブートローダであるu-bootが書き込まれていないため、本家wikiでも解説されている通り、別途取得してインストールする必要があります。
まずはディスクイメージをmicro SDカードに書き込みます。次の例ではUSB接続のカードリーダを介して、micro SDカードがsd0として認識されています。
umass0 at uhub1 port 1 configuration 1 interface 0
umass0: Generic USB2.0-CRW, rev 2.00/9.59, addr 2
umass0: using SCSI over Bulk-Only
scsibus0 at umass0: 2 targets, 1 lun per target
sd0 at scsibus0 target 0 lun 0: <Generic-, SD/MMC, 1.00> disk removable
sd0: fabricating a geometry
sd0: 7600 MB, 7600 cyl, 64 head, 32 sec, 512 bytes/sect x 15564800 sectors
sd0: fabricating a geometry
ddコマンドで書き込みを行います。ここで対象のデバイス名を間違えると、大事なデータを破損する可能性があります。十分注意してください。
% cd /XXX/YYY/release/evbarm/binary/gzimg
% progress -zf armv7.img.gz sudo dd if=/dev/stdin of=/dev/rsd0d bs=1m
progressコマンドを使うと、進行状況がチェックできるので、イライラが低減します(しない場合もあります)。bsとして少し大きめの値を取って、raw deviceを指定すると書き込みが高速化します(しない場合もあります)。
次にu-bootを書き込みます。Cubietruck用のu-bootのバイナリを取得し2、先のディスクに書き込みます。
% tar zxf u-boot-sunxi-mainline-cubietruck.tar.xz
% cd u-boot-sunxi-mainline-cubietruck-*
% sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/sd0d bs=1k seek=8
ここでは先頭の8KBをseekするために、ブロックデバイスを指定する必要があります。次にu-boot用の設定ファイルboot.cmdを、次のような内容で作成します:
env set bootargs root=ld0a console=fb
fatload mmc 0:1 82000000 netbsd-CUBIETRUCK.ub
bootm 82000000
クロスビルドの過程で生成されるnbmkubootimageコマンドを使って、バイナリ形式に変換します。
% /XXX/YYY/tools/bin/nbmkubootimage -A arm -n armv7 -T script boot.cmd boot.scr
micro SDのFAT領域をマウントし、できあがったboot.scrをコピーします。
% sudo mount /dev/sd0e /mnt
% sudo cp boot.scr /mnt
% sudo umount /mnt
なお、この時点でx86などのlittle endianな母艦からはmicro SDカードのFAT partitionしかマウントできません。これはディスクラベルがbig endianで書き込まれているせいなので、心配は無用です3。
これで起動ディスクが完成しました。このmicro SDはライブイメージとして使用できます。
#ライブイメージの起動、インストール
micro SDカードをCubietruckに挿入し、ディスプレイ、キーボード等を接続して、電源を投入します。u-bootがカーネルをロードして、おなじみの起動メッセージが表示されます。初回起動時にはresize_ffsが自動的にroot partitionをSDカードの容量に合わせて拡大してくれます。resizeに成功すると、再起動ののち、ログインプロンプトが表示されます。
この時点ではパスワードが設定されていないrootアカウントが有効になっており、そのままmultiuser modeで利用することができます。もちろん、Xサーバも動きます。SATA接続のハードディスク or SSDにインストールする場合でも、復旧用の環境として利用することができます。
micro SDカードの寿命を考慮すると、SATAデバイスへのインストールを行うことをオススメします。sysinstコマンドを実行すると、おなじみの対話式インストーラが起動します。あとはx86の場合と同様にインストールを進めることができます。
ただし、ライブイメージにはインストールに必要なtar ballが含まれていません。事前に母艦の/XXX/YYY/release/evbarm/binary/setsから、適当なディレクトリにコピーしておきましょう。SDカードの書き込み回数が気になる方は、/var/shmに全メモリの1/4≒512MBのram diskが用意されているので、ここを使うといいでしょう。
# cd /var/shm
# scp -r hoge@piyo:/XXX/YYY/release/evbarm/binary/sets .
SATAデバイスから直接ブートすることはできないので、micro SDカードを起動ディスクとして利用することになります。boot.cmdの書き換えて、root partitionとしてSATAデバイス(この例ではwd0a)を指定します:
env set bootargs root=wd0a console=fb
fatload mmc 0:1 82000000 netbsd-CUBIETRUCK.ub
bootm 82000000
このboot.cmdからboot.scrを生成し、micro SDカードのFAT partitionにコピーします。
# mkubootimage -A arm -n armv7 -T script boot.cmd boot.scr
# mount /dev/ld0e /mnt
# cp boot.scr /mnt
# umount /mnt
カーネルは引き続きFAT partitionから読み込まれますので、/etc/fstabに
/dev/ld0e /boot msdos rw,noauto
を追加しておくと便利です。再起動すると、SATAデバイスがroot partitionとしてマウントされます。
#byte orderを確認
さて、実際にbig endianモードで動作しているかどうか、簡単なプログラムで確認してみましょう。
#include <stdint.h>
#include <stdio.h>
int
main(void)
{
uint16_t i;
uint8_t *p;
i = 0x1234;
p = (uint8_t *)&i;
printf("original data is 0x%04x\n", i);
printf("stored in memory as 0x%02x 0x%02x\n", *p, *(p + 1));
return 0;
}
解説するまでもないですが、これは2バイトの値0x1234をメモリ上に書き込んだ後、それを2つの1バイトの値として読み出すプログラムです。x86で実行すると次のような結果が得られます。
% uname -ps
NetBSD x86_64
% ./a.out
original data is 0x1234
stored in memory as 0x34 0x12
下位バイトが先に収納されていること(little endian)が確認できます。同じプログラムをCubietruckで実行すると、
% uname -ps
NetBSD earmv7hfeb
% ./a.out
original data is 0x1234
stored in memory as 0x12 0x34
じゃがじゃん!! 上位バイトが先に収納されています。これでbig endianモードで動作していることが確認できました!! なんという地味な結末でしょうか。。。
#おまけ
当初、タイトルを「NetBSD/evbarmでbig endianな環境(のトラブル)を楽しむ」としていましたが、特にトラブルもなくインストールが終了してしまいました。これでは残念(?)なので、以前の-currentに存在した可愛い(??)バグを紹介して、この記事を終わりたいと思います。インストールも終わり、何気なくXサーバを起動すると。。。
What's a miserable xeyes! X server with wsfb on NetBSD/armeb is broken. pic.twitter.com/wveqOIRbdk
— ぼんくら物理学者 (@LabDrunker) 2015, 10月 22
なんとも気の毒なxeyesが表示されてしまいます。これはARM環境をlittle endianと決め打ちしていたXサーバのバグが原因でした。現在の-currentではこのバグは修正されていますので、元気なxeyesと戯れることができます。
Now, it gets sanity. I'll send PR. pic.twitter.com/25cPw8zP1B
— ぼんくら物理学者 (@LabDrunker) 2015, 10月 22
おしまい。
-
biendianなSoCでも、big endianモードで動作させるためには、機種依存部にサポートコードが必要になります。実際、sys/arch/evbarm以下にはbyte orderを示すマクロ__ARMEB__や__ARMEL__をチェックしている箇所が沢山あります。NetBSDでbig endianモードをサポートしているのはCubietruckのほかに、Allwinner A80 (Cubieboard4, OptimusBoard等)、Broadcom BCM5301X評価ボード、Banana Pi、Cubieboard2、Merrii Hummingbird A31等があるようです(evbearmv7hf-ebの場合)。 ↩
-
Cubietruck用のu-bootは最近になって、開発が活発になっているようです。リンク先のバイナリ(最新版)が動作しない場合は、2015年12月11日版を試してみてください。 ↩
-
FFS_EIオプションが有効になっていると、big endianなFFS partitionもmountすることができるのですが、disklabelの読み替えはできないようです。どうなんでしょうか、この仕様。。。 ↩