qemu-system-arm

armに関する記事を見てたら、 初歩から学ぶ、マイコン開発とARMプロセッサー なんてのに出会った。

クロス開発をやる為に、何の疑問もなく qemu-user-static, gcc-arm-linux-gnueabi を入れて ウブに環境を作ったけど、世は雲の中に環境が 有るのが当たり前なのね。ちっとも知らんかったぞ。

それは兎も角、 mbed OSとは何かなんてトピックがあった。誰かさんが好きなIoTについての動向記事だ。 armみたいな石は、安いんで大量に使うにはうってつけ。更に市場を拡大しましょってんで やっきになっている。そして、お山の大将になりたくて、優位性を示すべく頑張ってる訳ね。

コーヒーサーバーに、石を(無理して)くっつけてみたり。。。何でも有りのインターネットでは 既にその為のプロトコルがRFCになってた。興味が有ったので、RFCを取り寄せてみたぞ。

Network Working Group                                       L. Masinter
Request for Comments: 2324                                 1 April 1998
Category: Informational


          Hyper Text Coffee Pot Control Protocol (HTCPCP/1.0)

   Increasingly, home and consumer devices are being connected to the
   Internet. Early networking experiments demonstrated vending devices
   connected to the Internet for status monitoring [COKE]. One of the
   first remotely _operated_ machine to be hooked up to the Internet,
   the Internet Toaster, (controlled via SNMP) was debuted in 1990
   [RFC2235].

先例はSNMP上に実装したトースターか。そして、HTTPを拡張してコーヒーポットとの やり取りを提案するとな。

下記はコーヒーポットからのレスポンス。ヘッダーを拡張する形で実装する。

       Accept-Additions = "Accept-Additions" ":"
                          #( addition-range [ accept-params ] )

        addition-type   = ( "*"
                          | milk-type
                          | syrup-type
                          | sweetener-type
                          | spice-type
                          | alcohol-type
                          ) *( ";" parameter )
        milk-type       = ( "Cream" | "Half-and-half" | "Whole-milk"
                          | "Part-Skim" | "Skim" | "Non-Dairy" )
        syrup-type      = ( "Vanilla" | "Almond" | "Raspberry"
                          | "Chocolate" )
        alcohol-type    = ( "Whisky" | "Rum" | "Kahlua" | "Aquavit" )

コーヒーにウィスキーを入れるなんて、初めて聞いたぞ。つらつら見てくと、 ステータスコードも拡張されてた。そう、あの、404 Blog Not Found みたいなやつね。

2.3.2 418 I'm a teapot

   Any attempt to brew coffee with a teapot should result in the error
   code "418 I'm a teapot". The resulting entity body MAY be short and
   stout.

コーヒーポットと思っていたら、ティーポットでございますってステータスも 用意してた。これは、Teaに恨みがあるLisper用だな。

スッチィーが、コーヒーと紅茶のポットを掲げて、機内サービス中。

Tea Coffe? と言いながら回ってます。やがてLisperの所へ来て、Coff? って、尋ねます。

コーヒーを飲みたかった Lisperは、Yesの積もりで思わず、T と回答。

スッチーは、並々と紅茶をカップに注いだとさ。そんなこんなで、TeaとCoffeの区別は しっかりしておかんとな。

コーヒーとアルコールって、世界中にある楽しみ方なんだね。紅茶とブランディーってのは 知ってたけど、コーヒーまで酒ってのは思い至らなかった。

有名なのは、アイリッシュ・コーヒーらしい。アイリッシュ(アイルランド)には、有名な ミスト・ウィスキー(ミルク入りウィスキー、乳白色してる)ってのがあるから、それをたらせば、アイリッシュ・コーヒーの出来上がりか。

一度、やってみたいぞ。って、家にウィスキー無いじゃん。これから熱くなるから、 ハイボールとでも洒落込んで、そのウィスキーを流用すればOK。

ああ、飲み物で思い出した。台湾だかの自販機で売ってる、日本茶。どれもこれも、砂糖入り なのね。あれには、びっくりしたよ。気が向いたらやってみるか。

FreeBSDはどうよ

前回やった、arm用の小さなカーネルもどき、i386なLinuxに移植したら、当然SEGV。それを 回避する方法が見つかった。で、その時にStack領域に実行属性がついてきた事に気がついた。 これって梅雨の季節のかびの温床と言うか、ウィルスの巣にならないかい。OpenBSDのあの人が 怒るだろうね。

本当に怒るかは、環境を作ってやってみればいいだろうけど、面倒なのでBSDのお仲間、FreeBSDでは どうか、調べてみるよ。

clangに--builtinのスイッチが無かったので、それを外してコンパイル。objdumpした 結果が下記。

app.img:     file format elf32-i386-freebsd
app.img
architecture: i386, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x000101c8

Program Header:
    LOAD off    0x00001000 vaddr 0x00010000 paddr 0x00010000 align 2**12
         filesz 0x000001ed memsz 0x000001ed flags r-x
    LOAD off    0x00002000 vaddr 0x101f1000 paddr 0x101f1000 align 2**12
         filesz 0x00000000 memsz 0x00002000 flags rw-
   STACK off    0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**2
         filesz 0x00000000 memsz 0x00000000 flags rwx

うーん、FreeBSDよお前もそうか。で、気を取り直して実行してみると

[sakae@fb10 ~/src/i386]$ ./app.img
elf_load_section: truncated ELF file
Abort trap

Linuxでは文句も言わずに実行出来ちゃったんだけど、FreeBSDでは、不完全なファイルって 事で、実行を拒否された。お前はウィルスバスターか!

念のために、どこでチェックしてるか見ておく。きっとカーネル内のローダーで、不正ファイルの 判定をしてるに違いない。

[sakae@fb10 ~]$ cd /sys/kern/
[sakae@fb10 /sys/kern]$ fgrep 'elf_load_section' *
imgact_elf.c:           uprintf("elf_load_section: truncated ELF file\n");

おお、kernel内で使うprintfは自前で用意してるね。前回、生意気にもカーネルファイルって 言ったけど、それの具備する条件に、全部自分の中だけで完結していなければならないってのがある。 すなわち、一般ユーザーが使うライブラリィは使えないって事。ライブラリィにウィルスが 注入でもされていたら、大変な事になりますからね。

あと、ユーザーが使うlibcとかlibmみたいなやつは、ユーザー空間に鎮座する。それをカーネルが 利用するって事になると、空間の切り替えとかで、大きなロスを生む。そんなこんなで、 カーネルに必要なものを、全部カーネル側に用意するんだった。と、頭の整理をしましたよ。

        /*
         * It's necessary to fail if the filsz + offset taken from the
         * header is greater than the actual file pager object's size.
         * If we were to allow this, then the vm_map_find() below would
         * walk right off the end of the file object and into the ether.
         *
         * While I'm here, might as well check for something else that
         * is invalid: filsz cannot be greater than memsz.
         */
        if ((off_t)filsz + offset > imgp->attr->va_size || filsz > memsz) {
                uprintf("elf_load_section: truncated ELF file\n");
                return (ENOEXEC);
        }

作りが悪いファイルは、怪しいって事でエラーにしてるのね。行け行けドンドンのLinuxとは 違う訳だな。逆に軽いノリのLinuxは、この問題をどう処理してるのがリナス君に聞いて みたいぞ。

qemuを自前でコンパイルしてみる

qemu-system-armを自前で入れて、遊んでみる。遊ぶってのはソース観光の事ね。

[sakae@fedora qemu]$ mkdir build
[sakae@fedora qemu]$ cd build
[sakae@fedora build]$ ../configure --target-list=arm-softmmu  --disable-docs
Disabling libtool due to broken toolchain support

ERROR: glib-2.22 gthread-2.0 is required to compile QEMU

早速エラーの洗礼を受けた。gthreadをサポートしたglibが必要って事?gthreadって パッケージが有るかと思ったら、そんなの無いし。。。ぐぐる先生に聞いたら、glibの開発パッケージを入れろとな。 上記エラーからそんなの想像出来ないよ。初心者お断りフィルターがかかっているんだな。

[sakae@fedora qemu]$ sudo dnf install glib2-devel

入れてあげた。最初glib-develを入れて、戸惑ったのは秘密だ。で、先に進むとまたもやエラー。 今度は解決策が提示されてたぞ。

ERROR: pixman >= 0.21.8 not present. Your options:
         (1) Preferred: Install the pixman devel package (any recent
             distro should have packages as Xorg needs pixman too).
         (2) Fetch the pixman submodule, using:
             git submodule update --init pixman

方針2に従って、qemuのtop-dirで、ソースをお取り寄せ。

[sakae@fedora qemu]$ git submodule update --init pixman
Submodule 'pixman' (git://anongit.freedesktop.org/pixman) registered for path 'pixman'
Cloning into 'pixman'...
  :

先に進むかと思ったら DTC (libfdt) も必要との事。また、gitのお世話になる。で、やっとこさ config出来たんで、make

[sakae@fedora build]$ make
  GEN   arm-softmmu/config-devices.mak.tmp
  GEN  arm-softmmu/config-devices.mak
  GEN   config-all-devices.mak
  GEN   config-host.h
(cd /home/sakae/src/qemu/pixman; autoreconf -v --install)
/bin/sh: autoreconf: コマンドが見つかりません
Makefile:182: recipe for target '/home/sakae/src/qemu/pixman/configure' failed
make: *** [/home/sakae/src/qemu/pixman/configure] Error 127

エラーの嵐、エラー潰しのもぐら叩きが無料で楽しめます。autoconf libtool とかが、効果的でしたよ。

makeする時に、何分かかるか調べたら

  :
  CC    arm-softmmu/target-arm/crypto_helper.o
  GEN   trace/generated-helpers.c
  CC    arm-softmmu/trace/generated-helpers.o
  LINK  arm-softmmu/qemu-system-arm
  CPP   optionrom/multiboot.asm
  AS    optionrom/multiboot.o
  Building optionrom/multiboot.img
  Building optionrom/multiboot.raw
  Signing optionrom/multiboot.bin
  CPP   optionrom/linuxboot.asm
  AS    optionrom/linuxboot.o
  Building optionrom/linuxboot.img
  Building optionrom/linuxboot.raw
  Signing optionrom/linuxboot.bin
  CPP   optionrom/kvmvapic.asm
  AS    optionrom/kvmvapic.o
  Building optionrom/kvmvapic.img
  Building optionrom/kvmvapic.raw
  Signing optionrom/kvmvapic.bin

real    10m11.719s
user    5m27.159s
sys     3m47.546s

こんな風に、10分かかってました。以前gdbをコンパイルした時は13分かかっていたから、 まあ、速い方ですな。

一応、出来たのを確認

[sakae@fedora build]$ arm-softmmu/qemu-system-arm -version
QEMU emulator version 2.3.50, Copyright (c) 2003-2008 Fabrice Bellard

そして、早速、gdbにかけて見ると言う変態的な態度を取ります。メインは、qemu/vl.c に 有るとな。

折角なので、前回やったカーネルもどきを実行してみると

[sakae@fedora arm]$ make run
qemu-system-arm -M versatilepb -nographic -kernel app.img
audio: Could not init `oss' audio driver
hello, ARM on Fedora
1234
1234
QEMU 2.3.50 monitor - type 'help' for more information
(qemu) quit

惜しいな、ちょいと警告が出てきた。もう一度、ossを禁止にしてコンパイルしてみるか。 調べたらossを禁止には出来ないようだ。残念でした。このエラーを消すにはossのドライバーを 入れればいいんだな。(やらないけど)

gdbを使って、どのあたりを回っているか調べようとしたら、fedoraではselinuxとかが 効いていてptraceが禁止になってた。解除する方法が載ってたので試してみたけどだめだったので、 舞台をウブに移してやってみた。(ええ、性懲りもなくウブでもqemuをコンパイルしたのさ。 色々な環境でコンパイルすると経験値が上がるな。fedoraのそれとは違ったエラーを楽しめ ましたよ)

カーネルモードのアプリを動かして、キー入力待ちになった時の、qemuの状態。

(gdb) bt
#0  0xb7209be0 in __kernel_vsyscall ()
#1  0xb6d4a4b2 in __GI_ppoll (fds=0xb9ce7688, nfds=4, timeout=0xbff88cc8,
    sigmask=0x0) at ../sysdeps/unix/sysv/linux/ppoll.c:56
#2  0xb75020a5 in ppoll (__ss=0x0, __timeout=0xbff88d04, __nfds=4,
    __fds=0xb9ce7688) at /usr/include/i386-linux-gnu/bits/poll2.h:77
#3  qemu_poll_ns (fds=0xb9ce7688, nfds=4, timeout=1000000000)
    at /home/sakae/src/qemu/qemu-timer.c:322
#4  0xb7501711 in os_host_main_loop_wait (timeout=1000000000)
    at /home/sakae/src/qemu/main-loop.c:239
#5  main_loop_wait (nonblocking=0) at /home/sakae/src/qemu/main-loop.c:494
#6  0xb7271247 in main_loop () at /home/sakae/src/qemu/vl.c:1786
#7  main (argc=6, argv=0xbff89004, envp=0xbff89020)
    at /home/sakae/src/qemu/vl.c:4382

ここでずっと止まったままかと思ったら違った。

(gdb) c
Continuing.

Program received signal SIGUSR1, User defined signal 1.
[Switching to Thread 0xb32eeb40 (LWP 2300)]
memory_region_access_valid (mr=0xb9add248, addr=24, size=4, is_write=false)
    at /home/sakae/src/qemu/memory.c:1074
1074    {
(gdb)
Continuing.

Program received signal SIGUSR1, User defined signal 1.
pl011_read (opaque=0xb9add000, offset=24, size=4)
    at /home/sakae/src/qemu/hw/char/pl011.c:64
64      {
(gdb) c
Continuing.

Program received signal SIGUSR1, User defined signal 1.
io_readl (retaddr=<optimized out>, addr=<optimized out>,
    iotlbentry=<optimized out>, env=0xb9835658)
    at /home/sakae/src/qemu/softmmu_template.h:156
156         cpu->mem_io_pc = retaddr;

つらつらと、動き回っているよ。qemu/hw/char/pl011.c なんて、前回見た所だな。 ちゃんとポーリングしてる。

(gdb) b /home/sakae/src/qemu/hw/char/pl011.c:64
Breakpoint 1 at 0xb73fec20: file /home/sakae/src/qemu/hw/char/pl011.c, line 64.
(gdb) c
Continuing.

Breakpoint 1, pl011_read (opaque=0xb9add000, offset=24, size=4)
    at /home/sakae/src/qemu/hw/char/pl011.c:64
64      {
(gdb) bt
#0  pl011_read (opaque=0xb9add000, offset=24, size=4)
    at /home/sakae/src/qemu/hw/char/pl011.c:64
#1  0xb72bced5 in memory_region_read_accessor (mr=0xb9add248, addr=24,
    value=0xb32edcf0, size=4, shift=0, mask=4294967295, attrs=...)
    at /home/sakae/src/qemu/memory.c:400
#2  0xb72bccfc in access_with_adjusted_size (addr=<optimized out>,
    value=0xb32edcf0, size=4, access_size_min=1,
    access_size_max=<optimized out>,
    access=0xb72bce80 <memory_region_read_accessor>, mr=0xb9add248, attrs=...)
    at /home/sakae/src/qemu/memory.c:516
#3  0xb72beb21 in memory_region_dispatch_read1 (attrs=..., size=4,
    pval=0xb32edcf0, addr=24, mr=0xb9add248)
    at /home/sakae/src/qemu/memory.c:1128
#4  memory_region_dispatch_read (mr=0xb9add248, addr=24, pval=0xb32edcf0,
    size=4, attrs=...) at /home/sakae/src/qemu/memory.c:1147
#5  0xb72c9c81 in io_readl (retaddr=<optimized out>, addr=<optimized out>,
    iotlbentry=<optimized out>, env=0xb9835658)
    at /home/sakae/src/qemu/softmmu_template.h:162
#6  helper_le_ldul_mmu (env=0xb9835658, addr=270471192, oi=33,
    retaddr=3024027107) at /home/sakae/src/qemu/softmmu_template.h:208
#7  0xb43efe66 in ?? ()
#8  0x00000080 in ?? ()
#9  0x0000007f in ?? ()
#10 0x101f1018 in ?? ()
#11 0x00000000 in ?? ()

大分道しるべが出来たな。でも、スレッドで動いていて、追い駆けるの大変そう。あちこち 引き回されそうで、恐い。

都会は色々あって、羨ましい。

熱血!アセンブラ入門 読書会