qemu-arm-static

ARM用のOpenBSDがQEMUで動かないか、調べていたんだ。だって、前回ソース見たら、 動くような事が書いてあった。でも、全くHitしない。そんな馬鹿な事を考えるの おまえぐらいだよーって態度。

でも、検索の途中で面白い物に出くわした。

Raspberry Pi用バイナリをQEMUエミュレータで動かす方法(ユーザーモードエミュレーション

普通ラズパイを動かすには、qemu-system-armを使って(但し、貧乏人用)カーネル から動かすけど、そんな事やってたら、遅くなるじゃん。素のカーネルを使わなければ 、結構早く動くよって事らしい。面白そうなので、追試してみる。(科学は、追試 して再現性が得られて、進歩した)

まずは、http://downloads.raspberrypi.org/raspbian/images/へ行って、必要なのを落としてくる。 回線が細いので、気長に待つ。

sakae@ub:~/ARM-rp$ ls -l
-rw-r--r-- 1 sakae sakae 2962227200 Jan  7  2014 2014-01-07-wheezy-raspbian.img
-rw-rw-r-- 1 sakae sakae  817931404 Jan  9  2014 2014-01-07-wheezy-raspbian.zip

zipファイルは、unzipすると4倍近く、膨れあがるのね。最新なのが、zipで1.3Gも 有ったから、膨らませると、5Gを超えるのな。

後は、指示書通りに、マウントポイント、rootfsを作成。fdiskで、imgがどうなって いるか確認。

sakae@ub:~/ARM-rp$ mkdir rootfs
sakae@ub:~/ARM-rp$ fdisk -l 2014-01-07-wheezy-raspbian.img
Disk 2014-01-07-wheezy-raspbian.img: 2.8 GiB, 2962227200 bytes, 5785600 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: 0x000981cb

Device                          Boot  Start     End Sectors  Size Id Type
2014-01-07-wheezy-raspbian.img1        8192  122879  114688   56M  c W95 FAT32 
2014-01-07-wheezy-raspbian.img2      122880 5785599 5662720  2.7G 83 Linux

Linuxの始まる場所は、122880x512って事なんで、それだけずらした場所をrootfsに マウント。凄い方法だな。そして、そこへqemu-arm-staticを転送。 ld.so.preloadを無効化するとな。

sakae@ub:~/ARM-rp$ sudo mount -o offset=62914560 2014-01-07-wheezy-raspbian.img rootfs
sakae@ub:~/ARM-rp$ sudo cp /usr/bin/qemu-arm-static rootfs/usr/bin/
sakae@ub:~/ARM-rp$ sudo sed -i 's/^/#/' rootfs/etc/ld.so.preload

そして、使う石を指示する為、環境変数をセットして、監獄へと入って行く。

sakae@ub:~/ARM-rp$ sudo QEMU_CPU=arm1176 chroot rootfs
root@ub:/# uname -a
Linux ub 4.4.0-34-generic #53-Ubuntu SMP Wed Jul 27 16:06:28 UTC 2016 armv6l GNU/Linux
root@ub:/# df
/bin/df: cannot read table of mounted file systems: No such file or directory
root@ub:/# ps awx
Error: /proc must be mounted
  To mount /proc at boot you need an /etc/fstab line like:
      proc   /proc   proc    defaults
  In the meantime, run "mount proc /proc -t proc"
root@ub:/# exit
exit

armな石が動いている事は分かるけど、難しい事は、出来ないみたい。armな世界から、 現実の糞石世界に戻るには、監獄から脱獄する事です。老いたら、三食、介護付きの 監獄に入るのも手、かもよ。

何はともあれ、apt-get updateだな。始めたら、こんなエラーを喰らった。

Try running the command
  gdk-pixbuf-query-loaders > /usr/lib/arm-linux-gnueabihf/gdk-pixbuf-2.0/2.10.0/loaders.cache
to make things work again for the time being.
Processing triggers for shared-mime-info ...
Errors were encountered while processing:
 /var/cache/apt/archives/wolfram-engine_10.0.2+2015020304_armhf.deb
E: Sub-process /usr/bin/dpkg returned an error code (1)
sakae@ub:~/ARM-rp$ df
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/sda1             13797456   7938772   5134768  61% /
 :
/dev/loop0             2721336   2627768         0 100% /home/sakae/ARM-rp/rootfs

disk-fullになったんだな。wolfram-engineって馬鹿でかいパッケージだったけど、 お前な何者? 調べてみたら、 Raspberry Pi で Wolfram Language & Mathematica を起動する こういう代物らしい。

使う事もなさそうなので、removeしてDiskの空きを作っておいた。(dfが動かないので 半信半疑ですけどね)

sakae@ub:~/ARM-rp$ df
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/sda1             13797456   7938776   5134764  61% /
/dev/loop0             2721336   1797644    765740  71% /home/sakae/ARM-rp/rootfs

ああ、親側のdfで代用出来る和。いらない物を消したら、空き地が広がったな。 ちゃんとupdateも出来たし。

sudo raspi-config

とかやると、色々設定出来るらしい。気分はラスビアン?

7 Overclock                      Configure overclocking for your P
8 Advanced Options               Configure advanced settings 

はやり、ハードがらみと言うと、オーバークロックが出てくるなあ。8番メニューは sshとかspi,i2cとかの、ハードに使う人用のメニューが並んでいた。

後、参考になりそうなのを挙げておこう。

chrootする前にprocをマウントしとく作戦

$ sudo mount /proc /export/debian_lenny_armel/root/proc -t proc
$ sudo chroot /export/debian_lenny_armel/root /bin/bash
# ls /proc
1      19631  20     29580  30116  45	 8		mdstat
10     19634  20432  29602  30131  48	  9			meminfo
1064   19640  21     29779  30132  49	   904				misc

DockerでユーザモードQEMUによるARMエミュレーション環境を構築する

Raspberry Life

余りrootでばかり作業してても、あれ なんで、pi さんになってみる。

root@ub:/# su pi
pi@ub / $ cd
pi@ub ~ $ ls
Desktop  ocr_pi.png  python_games
pi@ub / $ dpkg -l | wc
    807    7892  110153
pi@ub ~ $ exit
exit
root@ub:/#

簡単にarm環境を作る

ARM/BuildEABIChroot - Ubuntu Wiki

これも面白そうなんで試してみる。案内の通りにやったら、ボケ、debootstrap なんて 入っていないわいって言われたので、慌てて入れた。後は、

sudo qemu-debootstrap --arch armhf vivid eabi-chroot

するだけで、ミニマムなシステムがインストールされた。大体200Mぐらいだったよ。 起動は、

sudo chroot eabi-chroot

rootしかユーザーが居ないので、useradd -m sakae して、一般ユーザーを 作っておいた。その後、build-essential gdb emacs24-nox を追加した。 この時点で、

sakae@ub:~$ sudo du -sh eabi-chroot/
439M    eabi-chroot/

duするのに、なんでsudoの必要が有るか? rootの壁でしっかり覆われているので、 中を確認するには、権限が必要なのさ。正に監獄。FreeBSD風に言うと、jailです。

どんな監獄を作れるかと言うと、今の所

  amd64)
    qemu_arch="x86_64"
  ;;
  armel|armhf)
    qemu_arch="arm"
  ;;
  arm64)
    qemu_arch="aarch64"
  ;;
  lpia)
    qemu_arch="i386"
  ;;
  powerpc|powerpcspe)
    qemu_arch="ppc"
  ;;
  ppc64el)
    qemu_arch="ppc64le"
  ;;

こういうのを作れるようです。ラッパーにそう記されていた。 それはいいんだけど、どういう仕組みで動いているの? 大体、/bootの下が 空っぽなんですけど。

ラッパースクリプトの最後がこうなってた。

eval run debootstrap --arch "$deb_arch" --foreign $opts $args
mkdir -p "$target/usr/bin"
cp $(which "qemu-$qemu_arch-static") "$target/usr/bin"
run chroot "$target" /debootstrap/debootstrap --second-stage

debootstrapスクリプトを使って、欲しいarchのパッケージを取り寄せる。 指定したtargetって言うdirの中に/usr/binを作る。だから、外側ばrootの壁に なるんだな。

それから、qemu_xxx_static を、コピーする。そして、chrootで指定したdir中の debootstrapスクリプトを後処理用に起動するとな。 この環境は、pkgの試験用に使うものらしい。

で、どうやって起動する? まずは、chrootだな。chrootは、第一引数のdirをroot-dirと看做して、コマンドを 実行する。コマンドが指定されていなかったら、/bin/shをインタラクティブ・ シェルとして、隔離された環境で実行する。

 7659 pts/3    S      0:00 sudo chroot eabi-chroot/
 7660 pts/3    Sl+    0:00 /usr/bin/qemu-arm-static /bin/bash -i

うん、マニュアル通りだ。そうすると、bashとqemu-arm-staticの関係は?

root@ub:/# uname -m
armv7l
root@ub:/# file /bin/bash
/bin/bash: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=46943cea38a62570a7f7878d1ccc881fa8e29942, stripped
root@ub:/# ldd /bin/bash
        libtinfo.so.5 => /lib/arm-linux-gnueabihf/libtinfo.so.5 (0x40830000)
        libdl.so.2 => /lib/arm-linux-gnueabihf/libdl.so.2 (0x4085a000)
        libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0x4086d000)
        /lib/ld-linux-armhf.so.3 (0x40000000)

bashの起動を指示されたはずなのに、何故qemuが動いているのだろう?それより、 bashは、誰が起動してる? 普通に考えれば、カーネルだけど、この場合は そんなの動いていない。

ちょっと実験で、arm環境の中の、qemu-arm-staticをrenameする。そして起動。

sakae@ub:~$ sudo chroot eabi-chroot/
chroot: failed to run command ‘/bin/bash’: No such file or directory
sakae@ub:~$ sudo chroot eabi-chroot/
root@ub:/# exit
exit

renameしてあると、bashが無いぞエラーで起動失敗。元に戻すと、何喰わぬ顔して 起動成功。

更にしつこく、qemuの実行属性を落としてみると、

root@ub:~# chroot eabi-chroot/
chroot: failed to run command ‘/bin/bash’: Permission denied

まるで、qemu-arm-staticとbashは、一心同体のようだ。qemuは出身が卑しい糞石族、 bashは、ARMなんて言う英国生まれの高貴な族。それが何で癒着してる?

今の予測では、chrootした先の実行しようとしたバイナリー(bash)が、ネイティブな (i386)ものじゃ無い場合、気を利かせて、qemu-arm-static経由で起動するように なってるのかな。だったら、qemu-arm-staticが無いぞとか、属性が落ちてるぞと chrootが報告しても 良さそうなものに。さあ、どうする?

こういう時は、密会現場を押さえるために、探偵を雇って尾行させればいいのかな。 まずは、失敗する条件で、早く落ちて貰おう。

root@ub:~# strace chroot eabi-chroot/ 2>LOG
execve("/usr/sbin/chroot", ["chroot", "eabi-chroot/"], [/* 23 vars */]) = 0
 :
getcwd("/home/sakae", 4096)             = 12
lstat64("/home/sakae/eabi-chroot", {st_mode=S_IFDIR|0755, st_size=4096, ...}) =0
chroot("eabi-chroot/")                  = 0
chdir("/")                              = 0
execve("/bin/bash", ["/bin/bash", "-i"], [/* 23 vars */]) = -1 EACCES (Permission denied)

これを見る限り、何ら不審な点は無いな。chrootコマンドが発行されて、それが実行 された。そして、/bin/bashを起動しようとして、失敗。実行属性が無いとな。

ちゃんと動くように設定してからstraceさせると、長い長いログが採取出来た。 んでもって、qemuが含まれるかログ検査。

root@ub:~# grep qemu GOOD
open("/etc/qemu-binfmt/arm", O_RDONLY|O_NONBLOCK|O_LARGEFILE|O_DIRECTORY|O_CLOEXEC) = -1 ENOENT (No such file or directory)

怪しげなのが有るなあ。ああ、ファイル自体は、存在しないけど。。。 藁にもすがる思いで、qemu-binfmtって何ですかって訪ねてみたら、 QEMUのもうひとつの使い方: ユーザーモードエミュレーションとbinfmtとchrootの組み合わせ なんていう素晴らしい記事を紹介された。

カーネルが余計な口出しして、間に変換器を挟みこめるようなしかけが有るのね。 それを使ってるって訳か。

sakae@ub:~$ update-binfmts --display|grep arm
qemu-arm (enabled):
 interpreter = /usr/bin/qemu-arm-static
qemu-armeb (enabled):
 interpreter = /usr/bin/qemu-armeb-static
sakae@ub:~$ update-binfmts --display qemu-arm
qemu-arm (enabled):
     package = qemu-user-static
        type = magic
      offset = 0
       magic = \x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00
        mask = \xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff
 interpreter = /usr/bin/qemu-arm-static
    detector =

qemu-user-staticを入れると、カーネルにフックを設定出来る。そして今は、それが 有効になってる。

実行対象のファイルの冒頭から、マジックコードを見ていって、一致してたら、 インタープリターとして、qemu-arm-static上で、実行対象を走らせろ。

root@ub:~# od -t x1z eabi-chroot/bin/bash | head -2
0000000 7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00  >.ELF............<
0000020 02 00 28 00 01 00 00 00 b1 aa 02 00 34 00 00 00  >..(.........4...<

Linuxは、節操が無いと言うか、便利ならそれでいいじゃんって態度が素敵。 ああ、分かってほっとしたよ。

FreeBSDとかは、こういう節操の無い事をやってるのかなあ。後で調べてみよう。 それより先に、将来入る(かも知れない)jailの作法を身に付けておくかな。

複数バージョンのFreeBSDをJailで共有させる方法、なんてのが入門には良さそう。

なんせ、FreeBSDでjailがサポートされた時、真っ先に飛びついて、大変な思いを した記憶が有りますから。