Arm Cortex-MのRustベアメタルをQEMUでデバッグ

前回記事で紹介したTockのように、RustでもArmでのベアメタルプログラムができるようになってきた。
ベアメタルプログラミングで複雑なことをやろうとするとやはりエミュレータが欲しいな(以前、ハイパーバイザをつくった時はエミュレータなしでつらかった)、と思ったのでやってみた。

STM32 Nucleo

省電力な組込み向けのアーキテクチャのCortex-MシリーズのMCU評価ボードは様々あるのだが、今回はSTM32 Nucleoをターゲットとすることとした。
理由としては

  • 以前、STM32 Discoveryを使用していたことがある
  • 日本でも比較的安価な評価ボードが購入できる(3000円くらい)
  • Mbedに対応しているため、C/C++ベースではあるがサンプルコードが豊富なため

なお、Tockは独自の評価ボードを提供し、それを利用している。

GNU MCU Eclipse QEMU

今回使うことにしたQEMUは本家のではなく、そのフォークであるGNU MCU Eclipse QEMUを用いる。

参考: QEMUでCortex-M3/M4マイコンボードをエミュレーションしてLチカする話

Eclipseのプラグインのためのものであるが、コマンドラインから直接叩いて動かすのも可能。
本家QEMUより多くのボードをサポートしており、ボードの画像を表示してLチカのデバッグも可能なようだ。
xpmを用いて簡単に導入することができる。

詳しい導入は公式ドキュメントに従えば良い。

サンプルコードの入手

参考: ARM Cortex-M 32ビットマイコンでベアメタル “Safe” Rust

今回動かしたコードはjaparic氏が提供しているcortex-m-quickstartを用いた。
参考にしたブログ記事は微妙に古いのでこちらのcrateのドキュメントを参照した。

実行

cortex-m-quickstartをドキュメント通りにビルドする。ただし、このQEMUはFPUのサポートがないため、targetはFPUなしのものを(hfで終わらないもの)を選ぶ必要がある。
生成物はcargo build --releaseの後、target/thumbv7em-none-eabi/releaseにできる。以下のようなシェルスクリプトを用意してQEMUを実行した。

qemu-system-gnuarmeclipse.sh
1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/sh

qemu_command=$HOME/opt/xPacks/@gnu-mcu-eclipse/qemu/2.8.0-3.1/.content/bin/qemu-system-gnuarmeclipse
board_name=NUCLEO-F411RE
mcu_name=STM32F411RE

$qemu_command \
--verbose --verbose --board $board_name --gdb tcp::3333 \
--mcu $mcu_name -d unimp,guest_errors \
--image $1 \
--semihosting-config enable=on,target=native \
--semihosting-cmdline $1

gdbのポートはcortex-m-quickstartの.gdbinitで3333になっているので3333を指定した。
実行結果は以下の通り。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
$ ./qemu-system-gnuarmeclipse.sh target/thumbv7em-none-eabi/release/cortex-m-quickstart

GNU MCU Eclipse 64-bits QEMU v2.8.0-3 (qemu-system-gnuarmeclipse).
Board: 'NUCLEO-F411RE' (ST Nucleo Development Board for STM32 F4 series).
Board picture: '/home/garasubo/opt/xPacks/@gnu-mcu-eclipse/qemu/2.8.0-3.1/.content/share/qemu/graphics/NUCLEO-F411RE.jpg'.
Device file: '/home/garasubo/opt/xPacks/@gnu-mcu-eclipse/qemu/2.8.0-3.1/.content/share/qemu/devices/STM32F411xx-qemu.json'.
Device: 'STM32F411RE' (Cortex-M4 r0p0, MPU, 4 NVIC prio bits, 86 IRQs), Flash: 512 kB, RAM: 128 kB.
Image: 'target/thumbv7em-none-eabi/release/cortex-m-quickstart'.
Command line: 'target/thumbv7em-none-eabi/release/cortex-m-quickstart' (54 bytes).
Load 16028 bytes at 0x08000000-0x08003E9B.
Cortex-M4 r0p0 core initialised.
'/machine/mcu/stm32/RCC', address: 0x40023800, size: 0x0400
'/machine/mcu/stm32/FLASH', address: 0x40023C00, size: 0x0400
'/machine/mcu/stm32/PWR', address: 0x40007000, size: 0x0400
'/machine/mcu/stm32/SYSCFG', address: 0x40013800, size: 0x0400
'/machine/mcu/stm32/EXTI', address: 0x40013C00, size: 0x0400
'/machine/mcu/stm32/GPIOA', address: 0x40020000, size: 0x0400
'/machine/mcu/stm32/GPIOB', address: 0x40020400, size: 0x0400
'/machine/mcu/stm32/GPIOC', address: 0x40020800, size: 0x0400
'/machine/mcu/stm32/GPIOD', address: 0x40020C00, size: 0x0400
'/machine/mcu/stm32/GPIOE', address: 0x40021000, size: 0x0400
'/machine/mcu/stm32/GPIOH', address: 0x40021C00, size: 0x0400
'/machine/mcu/stm32/USART1', address: 0x40011000, size: 0x0400
'/machine/mcu/stm32/USART2', address: 0x40004400, size: 0x0400
'/machine/mcu/stm32/USART6', address: 0x40011400, size: 0x0400
'/peripheral/led:green' 8*6 @(316,307) active high '/machine/mcu/stm32/GPIOA',5
'/peripheral/button:reset' 30*30 @(312,214)
'/peripheral/button:user' 30*30 @(204,219) active low '/machine/mcu/stm32/GPIOC',13
GDB Server listening on: 'tcp::3333'...
Cortex-M4 r0p0 core reset.

Hello, world!
^Cqemu-system-gnuarmeclipse: terminating on signal 2

Rust on baremetal Armの現状

cortex-m-quickstartの作者であるjapric氏はXargoをつくった人でもあり、かなり積極的にこの分野に貢献している人である。

彼が今年初めに去年あったベアメタルArmのRustで起きたバグと今年の展望をまとめている。
Embedded Rust in 2018 | Embedded in Rust

現状、ベアメタルArmでプログラミングするためにはunstableなfeatureを使わざるを得ないため、完全に安定とは言えないものの、かなり状況はよくなってきているようだ。