2014年4月23日

Raspberry PiをQEMUエミュレータ上で走らせる(2) 立ち上げ、X Window、ネットワーク

前回でQUEMが動き、エミュレータ上でカーネルとシェルが動き、基本的な動作が確認できた。次は、これを開発に必要な実用レベルに持って行く。

QEMU版への移行

まず、RPiには標準ではバッテリバックアップ付きのリアルタイムクロックはなく、この段階ではNTPDはおろかネットワークも動いていないので、時計が例の1970年元旦になっている。このままでも致命的ではないが、以下に述べるファイル修正の履歴(タイムスタンプ)が後日奇妙に見えるので、dateコマンドでそれらしい時刻を設定する。

root@rpi:/# date 04221250

次に、ホスト名がディスクイメージのコピー元と同じだと紛らわしいのでエディタで変えておく。エディタはディスクイメージにインストールされているものなら何でも使えるが、viが多少不安定な挙動を示したので、最悪nanoで。

root@rpi:/# cat /etc/hostname
rpi-qemu

余計なライブラリのプリロードを禁止。

root@rpi:/# cat /etc/ld.so.preload
#/usr/lib/arm-linux-gnuebihf/libcofi_rpi.so

最後に、必ずしも必要ではないが、実機とディスクデバイスの名前を揃えるためのudevルールファイルを作る。

root@rpi:/# cat /etc/udev/rules.d/90-qemu.rules
KERNEL=="sda", SYMLINK+="mmcblk0"
KERNEL=="sda?", SYMLINK+="mmcblk0p%n"
KERNEL=="sda2", SYMLINK+="root"

で、一度システムをシャットダウン。

root@rpi:/# halt

ホスト側のQEMUを^Cで殺し、もう一度本チャン起動してシステムをフル稼働にする。

h@spice:~/projects/rip$ qemu-system-arm -kernel kernel-qemu -cpu arm1176 -m 256 -M versatilepb -no-reboot -serial stdio -append "root=/dev/sda2 panic=1 rootfstype=ext4 rw" -hda rpi.img -redir tcp:2222::22

パラメタについていくつか…
-m 256 システムメモリは256MBがハードコードされているのでこれより大きい値は指定するな、と言われている。
-M versatilepb QEMU上の仮想プラットフォーム。実機ではBCM2708。
-hda rpi.img 最初の立ち上げに使ったのと同じ自前のディスクイメージファイル。
-redir tcp:2222:22 ホストのTCPポート2222をQEMUターゲットのポート22にリディレクトする。SSH用(後述)。

Xウィンドウ


これはあっけなく動いた。実機からコピーしたディスクイメージを使っているので、実機とほぼ同じ。ただし、QEMUの問題と思われる以下の問題が発見された。
・マウスポインタがホストから見える「物理ポインタ」(四角い小さなドット)とターゲット(RPi)に見える論理ポインタ(矢印、Iビームなど)が乖離する。論理ポインタがQEMUのウィンドウの外には出られないクリッピングを起こすので両者を近づけることはできるが、そのうちまた離れてしまうので煩わしい。VNCクライアントなどでもこの兆候はあるが、あちらは自分でできるだけ一致させるように働くのに、こちらはその努力が見えない。
・ロカール(locale)が正しくないのか、ASCIIキーボード「@」や「|」のキーが違うコードを出力している模様。まるでJIS配列キーボードの感じ。
・上下の矢印キーが上手く認識されない(左右の矢印キーはOK)。スクリーンエディタは別のキーを使えるが、bashでリコールバッファが使えないのは痛い。

2番目と3番目のキーコードの問題はロカールとかXの設定ファイルをいじれば動きそうな感じもするが、小生はこの辺が不得手であり、また元々現在の時計プロジェクトでは入力UIは不要なので詮索しない。キーが正常に動作したとしても、マウスポインタの問題でこのUIを使っての開発は実際的ではない。

ネットワーク

これも考えるより産むが易し、と言うか、考えと違う形であっけなく動いた、と言うより動いていた。

以下のスタートアップファイルがあることを確認する。

root@rpi:/# cat /etc/network/interfaces
auto lo

iface lo inet loopback
iface eth0 inet dhcp

ここで実現されるネットワークは、ターゲット側は仮想イーサネット。ホスト側のQEMUのユーザコードがNAT付きラウタ、DHCPサーバ、DNSサーバを実現する閉じたLAN。ターゲットは常に10.0.2.15、ホスト側仮想ゲートウェイは10.0.2.2、仮想DNSサーバは10.0.2.3を与えられるようだ(ターゲットの/etc/resolv.confはNetwork Managerが自動的に書き換える)。ホスト側の仮想DNSサーバはキャッシュオンリーなのでホスト側では何も特別なことをする必要はない。また、DHCPのベースアドレスはQEMU起動時のオプションで設定できるようだが試していない。

このNAT付きラウタというトポロジーのため、QEMUホストがファイアウォールとなり、QEMUホスト以外の他のネットワークホストからはターゲットは見えない。また、ラウタは純粋にユーザコードで実現されているので、QEMUホストの他のプロセスから見えるネットワークデバイスなども存在せず、ターゲットに対するトリッキーなラウティングとかも不可能。

従って、QEMUで走るターゲットをサーバとして使うアプリケーションの開発には向いていない

唯一の抜け穴は、QEMU起動時に指定した -redir tcp:2222::22 でリディレクトされたTCPポート。QEMUホストのポート2222にアクセスすればターゲットRPiのポート22にアクセスしたことになるから、QEMUホストが見えるところならどこからでもターゲットでSSHでアクセスできる。

この辺のことは、5年ほど前にAndroidタブレットの立ち上げの仕事(OSはまだDonutだった)をしていたときに使っていたはずなのに、すっかり忘れている。加齢とともに記憶の揮発性が高まってきたのか…。

逆に、ターゲットからはQEMUホストが見えるところならどこでもアクセスできる。ただし、アクセスされた方はアクセス元はQEMUホストに見えるので注意。例えば、ターゲットからQEMUホストにSSHでアクセスすると、SSH_CONNECTIONは127.0.0.1(localhost)からアクセスされたと主張する。うちのシステムはセキュリティのためにSSHのアクセス元でフィルタリングをしているの修正が必要だった。

もう一つ気がついたことは、QEMUのラウタはICMPを通していないようだ。例えば、ターゲットからwww.yahoo.comにpingすると、IPアドレスは解決するのにpingその物は到達できないという現象に2時間悩んだ。

なお、設定によってはターゲットのコンソールがQEMUを起動したセッション(シェルウィンドウ)にリディレクトされ、loginプロンプトが出ることがあるが、これはよほどのことがない限り使わない方が無難。^Cを押すとコンソールに食われるのではなく、QEMUプロセスを殺してしまう。

さて、これで実機とほぼ同等の動作をするエミュレータができたので開発がし易くなる。仕事が増えた。

なお、QEMUでエミュレートされるCPUはあまり速くない。/proc/cpuinfoには600 BogoMIPSが表示されるが、ターゲットのX上でマウスを振り回すだけでtopのCPU使用率は100%になってしまう。だからリアルタイム性とかの確認は当然のことながら実機ですべき。

0 件のコメント:

コメントを投稿