RaspbianをCygwin上のNFSサーバのnfsrootとWindows上のqemuで起動するメモ
追記: nfs.enable_ino64=0 が必要なので追記、あとinit=/bin/shでrootパスワードをセットする必要があるのも。
そろそろteslawireのエンジン側をARM11に載せる算段を考えないといけないので、Raspbianの開発環境をWindows上で揃えることにした。
というわけで先ずはリモート起動環境を作る。
Raspbianイメージの展開
RaspbianはSDカードイメージの形で配布されているため、単純にloopback mountできない。
というわけで先ずはpartdに掛けてファイルシステムの先頭アドレスを出さないといけない。ext4をマウントする必要があるので、ここだけはLinuxで作業しないといけない。
# partd 2016-09-23-raspbian-jessie-lite.img (parted) unit b (parted) print モデル: (file) ディスク /home/oku/2016-09-23-raspbian-jessie-lite.img: 1389363200B セクタサイズ (論理/物理): 512B/512B パーティションテーブル: msdos ディスクフラグ: 番号 開始 終了 サイズ タイプ ファイルシステム フラグ 1 4194304B 70254591B 66060288B primary fat16 lba 2 70254592B 1389363199B 1319108608B primary ext4
"unit b"でバイト単位表示にしてから"print"でパーティションテーブルを表示することで、ファイルシステムまでのオフセットがわかる。このオフセットを指定して、
# mount ./2016-09-23-raspbian-jessie-lite.img /mnt -o loop,offset=70254592
のように、loopオプションにoffsetを渡してマウントする。マウントしたら
# tar cf raspb.tar /mnt
として.tarを作り、これをCygwin側に持ち込んで展開する。
イメージの編集
Raspbianのイメージはそのままではnfsrootでもqemuでも起動しないため、展開したファイルを修正する必要がある。
- /etc/fstab
proc /proc proc defaults 0 0 #/dev/mmcblk0p1 /boot vfat defaults 0 2 #/dev/mmcblk0p2 / ext4 defaults,noatime 0 1
fstabからはmmcblkのエントリをコメントアウトする。nfsrootだとこれらはマウントする必要が無い。
- /etc/ld.so.preload
# /usr/lib/arm-linux-gnueabihf/libarmmem.so
ld.so.preloadからは謎のlibarmmem.soのpreloadをコメントアウトする。これをやらないとinitが上がらずカーネルパニックする。
TAP-Win32のインストールと設定
パケットキャプチャ等の都合も有るので、qemuのネットワークにはTAP-Win32を使うのがおすすめ。
OpenVPNのサイトから https://openvpn.net/index.php/download/community-downloads.html Tap-windowsのNDIS 6版をダウンロードしてインストールする。
インストールしたらTAPインターフェースの名前をQemuTapのような指定しやすい名前に変更しておく。また、IPv4アドレスを割り当てる必要がある。
Windowsの自動ネットワーク構成はデフォルトルートの無いインターフェースは"識別できないネットワーク"に分類してしまうため、グループポリシか何かで識別できないネットワークをプライベートネットワークにしておく( http://www.atmarkit.co.jp/ait/articles/1012/24/news127.html )。ただし、この設定はクソ危険なので移動するシステムにはオススメできない。
NFSサーバの起動
Cygwinのunfs3パッケージをインストールし、
/usr/sbin/unfsd -e /home/oku/netboot/exports -l 192.168.150.1 -p -s -d
のようにして起動する。オプションの意味はman unfsd参照。重要なのは -p オプションで、これを指定することでportmapへの登録を省略できる。
NFSはいくつかの歴史的事情でちゃんとしたSun RPC環境を要求するが、portmapサーバを別に上げるのも面倒なので。Linuxのnfsrootではポート番号を明示的に指定することでportmapサーバを省略できる。
exportsは普通のNFSと同様のフォーマットで書くことができる。
/home/oku/netboot/raspb 192.168.150.0/24(rw)
qemuの起動
qemuには内蔵のLinuxカーネルローダが有るため、単にカーネルイメージを持ってくればカーネルまでは起動する。
- https://github.com/dhruvvyas90/qemu-rpi-kernel
- Raspbianに近いconfigのビルド済カーネルを配布している
- http://lassauge.free.fr/qemu/
ファイル kernel-qemu-4.4.13-jessie とQemuのバイナリをダウンロードして適当な所に配置し、
/cygdrive/c/prog/Qemu-windows-2.6.0/qemu-system-arm.exe -kernel kernel-qemu-4.4.13-jessie -cpu arm1176 \ -m 256 -M versatileab -serial stdio \ -append "root=/dev/nfs rw nfsroot=192.168.150.1:/home/oku/netboot/raspb,vers=3,port=2049,mountport=2049,tcp ip=192.168.150.200 console=ttyAMA0 nfs.enable_ino64=0" \ -net nic -net tap,id=tap,ifname=QemuTap
のようにして起動する。ifname=QemuTapは先程インストールしたTAP-Win32インターフェースの名前にする。nfsrootのオプションにはportとmountportの両方を含める必要がある。2049はNFSのデフォルトポートで、unfs3はNFSとMOUNTの両方に同じポート番号を指定できる。
ここでは、NFSサーバ、つまりWindows側のIPv4アドレスが192.168.150.1で、Qemu内のLinux側が192.168.150.200という指定になっている。このように全てを手動で設定すれば、portmapやdhcpサーバは無くても正常に動作する。
ブートパラメタは普通のnfsrootのもので十分だが、nfs.enable_ino64=0を付けてinode番号を32bitに抑えないとかなりミステリアスな起動失敗を起こす。あと、setuidビットをエミュレートできないので、sshやsudo等動作にsetuidビットが立っている必要のあるバイナリが動作しない。init=/bin/shで一旦シェルを起動し、passwdでrootパスワードを設定してから起動することになる。