Raspberry PiベアメタルをQEMUでデバッグするメモ

Raspberry Piベアメタルプログラミングは、microSDをいちいち抜き差ししないといけないのが面倒です。
SDカードを使わない方法としては、ネットワークブートやUSB接続でホストをマスストレージに見せかけるなどの方法もあるようですが、GPIOなどを操作しない場合にはエミュレータが有効です。

今回Raspberry PiのベアメタルにMicroPythonのREPLを追加するにあたって、Linux上でQEMUを使ってみました。

ARMのバイナリを動作させられるQEMUは、Ubuntuのパッケージで用意されていますのでインストールは簡単です。
Raspberry Piのバイナリを動かす場合は、

qemu-system-arm \
-kernel firmware.elf \
-cpu arm1176 \
-M versatilepb \
-m 256 \
-no-reboot \
-nographic \
-monitor null \
-serial stdio \
-redir tcp:10022::22

というようにすれば動作します。これはMakefileの中にもrunというターゲットで入れてあります。

ただ、QEMUを使う場合にはMini-UARTはうまく動作させるのは難しいようです。
ですので、QEMUの場合はMiniでないほうのUARTを使う必要があります。
今のところ、uart-qemu.cに通常のUARTとMini-UARTの両方を入れて、

#if 1 // 0ならMini-UART
通常のUARTのコード
#else
Mini-UARTのコード
#endif

というやり方で選択できるようにしてあります。

QEMU上で動作しているARM用バイナリは、クロス開発環境用のGDBでデバッグすることができます。

まず、QEMU上でのバイナリは”-s -S”オプションをつけて起動します。

$ qemu-system-arm -kernel build/firmware.elf -cpu arm1176 -M versatilepb -m 256 -no-reboot -nographic -monitor null -serial stdio -s -S

次に、同じマシンの別のターミナルからGDBを起動します。
そして、targetコマンドで「remote localhost:1234」を指定します。

$ arm-none-eabi-gdb -q build/firmware.elf
Reading symbols from build/firmware.elf...done.
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
0x00008000 in start ()
(gdb)

あとは普通にGDBのコマンドが使えます。
よく使うのは

・l 現在位置のソースを表示
・n 次の行(関数の中には入らない)
・s ステップ(関数の中に入る)
・c continue
・b file:num fileのnum行をブレークポイントに
・b function functionの先頭をブレークポイントに
・p/x var 変数varを16進数表示(&varや*varという表現も可能)
・awatch var 変数varが読み書きされたらブレーク

あたりです。

以下に今回参考にしたサイトを挙げておきます。

piでベアメタルプログラミング – bobuhiro11's diary
RaspberryPi/kernel/src-qemu at master · richcole/RaspberryPi
QEMU ARM で遊ぼう
gdb の使い方・デバッグ方法まとめ

ちなみにQEMUでRaspbianを起動することもできますが、それにはQEMU用にビルドしたカーネルが必要です。
ビルド済みカーネルや起動方法は下記のGitHubにあります。

Home · dhruvvyas90/qemu-rpi-kernel Wiki

raspbian-on-qemu.png

コメント