純規の暇人趣味ブログ

首を突っ込んで足を洗う

RaspbianをQEMUで動かす

      2017/01/19    HimaJyun

どうも、ビンの王冠をスプーンで開けようとして指を怪我したニンゲンです。(怠慢ヨクナイネ)

ちなみにビンの王冠と芥川龍之介は同い年なんですよ、知らなくて良い雑学ですね、脳の容量の無駄遣いです(参考:Wikipediaの王冠芥川龍之介ページ)

どうでも良い雑学はさておき、今回はRaspbianをQEMUで動かす方法でもご紹介しようと思います。

Raspbianをテストしたい

さて、Raspberry Piで動作するRaspbian、これはいわゆるDebian系のLinuxなので普通にUbuntuなんかと同じソフトウェアが動作します。(パッケージがあれば)

延いてはサーバ目的での利用も可能ですし、実際にサーバとして利用している例が言わずもがな私です。(GitやMunin用のサーバとして利用)

とは言え、使えるなら全て同じかと言われるとそういう訳でもなく、パッケージのバージョンによって設定ファイルが微妙に異なっている事があります。

そんなこんなで実際にインストールする前に動作テストを行いたいなんてのは良くあることです。

という訳で、RaspbianがQEMUで動作すると言う情報を手に入れたので実際に試してみました。

環境

ホスト側はWindows 10(64bit)ですが極論QEMUさえ動けば後はどうでも良いです。

使用するRaspbianはJessie Lite(2017-01-11)で試しています。

途中でRaspbianのimgファイルを書き換えるのに仮想環境のUbuntuを使います、ここの所はLinuxなら何でも良いでしょう。(fdiskとmountさえ使えりゃOK)

Windows向けQEMUはこことかここからコンパイル済みが手に入ります、それが(信頼性的に)嫌なら仮想環境上のUbuntuとかでaptを使えば信頼出来そうなQEMUが手に入ります。

QEMUでRaspbian

とは言えQEMUで動かせば動く、というわけにはいかないみたいです。

いくつかの下準備と小細工が必要なのでそちらを先に済ませてやりましょう。

QEMU用Raspbianカーネルを手に入れる

どうやらQEMUでRaspbianを動かすにはそれ用のカーネルを手に入れる必要があるみたいです。

既に用意されたものがGitHubで公開されているみたいなのでそちらから手に入れると良いでしょう。

バージョンがいくつかありますが、Raspbian側のバージョンと合わせれば良いかと(大抵の場合最新版を選んでおけばOK……かな?)

Raspbianのimgに小細工

RaspbianのimgファイルをそのままQEMUに渡しても上手く行かないみたいです。

無理矢理(?)起動させて修正する方法があったみたいですが、手元のRaspbianではそれが出来なかったのでmountして編集します。

仮想環境上のUbuntuで試しますが、先の通りfdiskとmountが使えればOKです。(Bash on Ubuntu on Windowsで出来るかは未確認)

まずはRaspbianのimgファイルに対してfdiskします。

$ fdisk -l ./pi.img
Disk ./pi.img: 1.3 GiB, 1390411776 bytes, 2715648 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x244b8248

Device     Boot  Start     End Sectors  Size Id Type
./pi.img1         8192  137215  129024   63M  c W95 FAT32 (LBA)
./pi.img2       137216 2715647 2578432  1.2G 83 Linux

注目すべきは4行目と11行目、これは次のmountの際のoffset計算に必要です。

Raspbianのrootパーティションをマウントして読み書き出来る様にします。

sudo mount -v \
           -o offset=70254592 \
           -t ext4 \
           ./pi.img \
           /mnt/

offsetの値はセクタサイズ*rootパーティションの開始位置です。

$((512*137216))のようにしてBashで計算しても良いでしょう。

マウントされたRaspbianの/etc/fstab(すなわち今回の例だと/mnt/etc/fstab)をエディタで開きます。

sudo editor /mnt/etc/fstab

/dev/mmcblkを両方ともコメントアウト

proc            /proc           proc    defaults          0       0
#/dev/mmcblk0p1  /boot           vfat    defaults          0       2
#/dev/mmcblk0p2  /               ext4    defaults,noatime  0       1

Raspbianの/etc/ld.so.preload(/mnt/etc/ld.so.preload)を開いて1行目をコメントアウト

sudo editor /mnt/etc/ld.so.preload
#/usr/lib/arm-linux-gnueabihf/libarmmem.so

これでOK、念のためにumountしておきたいなら以下の通り。

sudo umount /mnt

起動

先程細工を施したRaspbianのimgと、QEMU用のカーネルを利用して以下のコマンドで起動します。

qemu-system-arm -kernel ./カーネルへのパス -cpu arm1176 -m 256 -M versatilepb -serial stdio -append "root=/dev/sda2 rootfstype=ext4 rw" -hda Raspbianのイメージ.img

その他、特定のポートを使用したい場合は以下の様な引数を追加してリダイレクトさせます。

例として2222を22(SSH)にリダイレクトする場合は以下の通り

-redir tcp:2222::22

2222を22へ、8080を80へリダイレクトする場合は以下の通り

-redir tcp:2222::22 -redir tcp:8080::80

QEMUで起動したRaspbianは何故かsshが起動していませんでした、sshを叩き起こすには以下の通り。

sudo systemctl start ssh

これでlocalhost::2222でRaspbianのSSHにアクセス出来ます。

ユーザーモードエミュレーション

先程の手法はハードウェアエミュレーションと言って動作を完全にエミュレーションするモードだそうです。

それとは別に、ユーザーモードエミュレーションという物があります。

早い話がWineがexeを動かす手法なんかと同じように、ホストOS側のマシンスペックをフルに活用しつつ、エミュレーションが必要なarmのバイナリだけをQEMU越しに実行するみたいです。

つまり動作が早い、(゚∀゚)キタコレ!!

環境

仮想環境上のUbuntu 16.04です、chrootとかが必要になるのでWindowsでは出来ません(多分

GUIは出来るかどうか分かりません、手元で試した分では上手く行かなかったのでとりあえずLite版で。

下準備

Ubuntuの場合は以下のコマンドでユーザーモードエミュレーション用のQEMUをインストールが必要です。

sudo apt-get install qemu-user-static

今回の記事では「/mnt/raspbian」に環境を構築していく(例示なのでどこでも構わない)のですが、imgをそのまま使うと容量周りで面倒なのでimgの中身をrsyncで移してしまいます。

まずはRaspbian用のimgをマウントします、ここでは/mnt/tmpにマウントします。(オフセット計算は「Raspbianのimgに小細工」の時と同じです)

sudo mkdir /mnt/tmp

sudo mount -v \
           -o offset=$((512*137216)) \
           -t ext4 \
           2017-01-11-raspbian-jessie-lite.img \
           /mnt/tmp

rsyncで中身をまるっと移します。

sudo mkdir /mnt/raspbian
sudo rsync -a /mnt/tmp/ /mnt/raspbian
sudo umount /mnt/tmp

ハードウェアエミュレーションの時と同じように「/etc/ld.so.preload」の1行目をアンコメントします。

sudo editor /mnt/raspbian/etc/ld.so.preload
#/usr/lib/arm-linux-gnueabihf/libarmmem.so

いくつかのファイルを移す

先程マウントしたRaspbianに対していくつかのファイルを移していきます。

まずはユーザーモードエミュレーション用のQEMUバイナリをコピー

sudo cp /usr/bin/qemu-arm-static /mnt/raspbian/usr/bin/

「/mnt/raspbian/proc」がなくて色々不便なのでホスト側の物をマウント

sudo mount /proc /mnt/raspbian/proc -t proc

そのままではネットに正しく繋がらないのでホスト側の設定をコピー

sudo cp /etc/network/interfaces /mnt/raspbian/etc/network/interfaces
sudo cp /etc/resolv.conf /mnt/raspbian/etc/resolv.conf
sudo cp /etc/hosts /mnt/raspbian/etc/hosts

下準備はこれでOK

起動(と言うか移動)

chrootでrootを移動する事で実現

sudo QEMU_CPU=arm11mpcore chroot /mnt/raspbian

ちなみに「arm11mpcore」を「arm1176」にするとシングルコア動作になるみたいです。

piユーザに移るには以下の通り

su pi
cd ~

Raspbianのバイナリを動作させている証拠として、unameしたり/etc/issueを見たりすれば以下の結果が得られます。

~$ uname -m
armv6l
~$ cat /etc/issue
Raspbian GNU/Linux 8 \n \l

ちなみに通常Ubuntuでは以下の通り

~$ uname -m
x86_64
~$ cat /etc/issue
Ubuntu 16.04.1 LTS \n \l

いつもの環境に戻るにはexitでOK

exit # これでpiユーザを抜ける
exit # これでchroot解除

これで実質大量のメモリを積んだRaspberry Piを手に入れた様な実験が出来る。

終わりに

ハードウェアエミュレーションのRaspbianはCPUやメモリを増やせない、超重い

ソフトウェアの動作確認なんかはユーザーモードエミュレーションで十分かと思う。

何はともあれ、これで前までみたいに失敗するたびに何度も何度もSDカードにddしなおす必要がなくなった。

 - パソコン