セミホスティング
セミホスティングは、組み込みデバイスがホスト上で I/O を行えるようにする 仕組みで、主にホストのコンソールにメッセージをログ出力するために使われます。 セミホスティングに必要なのはデバッグセッションと、ほかにはほとんど何もありません (追加の配線も不要です!)ので、とても手軽に使えます。欠点は非常に遅いことです。 書き込み操作のたびに、使用するハードウェアデバッガ(例: ST-Link)によっては 数ミリ秒かかることがあります。
cortex-m-semihosting クレートは、Cortex-M デバイス上でセミホスティング操作を
行うための API を提供します。以下のプログラムは、「Hello, world!」の
セミホスティング版です。
#![no_main]
#![no_std]
use panic_halt as _;
use cortex_m_rt::entry;
use cortex_m_semihosting::hprintln;
#[entry]
fn main() -> ! {
hprintln!("Hello, world!").unwrap();
loop {}
}
このプログラムを実機で実行すると、OpenOCD のログ内に “Hello, world!” メッセージが表示されます。
$ openocd
(..)
Hello, world!
(..)
ただし、最初に GDB から OpenOCD でセミホスティングを有効にする必要があります:
(gdb) monitor arm semihosting enable
semihosting is enabled
QEMU はセミホスティング操作を理解するので、上のプログラムは
デバッグセッションを開始しなくても qemu-system-arm でも動作します。なお、
セミホスティングのサポートを有効にするには、QEMU に
-semihosting-config フラグを渡す必要があります。これらのフラグは、テンプレートの
.cargo/config.toml ファイルにすでに含まれています。
$ # このプログラムはターミナルをブロックします
$ cargo run
Running `qemu-system-arm (..)
Hello, world!
QEMU プロセスを終了するために使用できる exit セミホスティング操作もあります。
重要: 実機では debug::exit を 決して 使用しないでください。この関数は
OpenOCD セッションを壊す可能性があり、再起動するまでそれ以上プログラムを
デバッグできなくなります。
#![no_main]
#![no_std]
use panic_halt as _;
use cortex_m_rt::entry;
use cortex_m_semihosting::debug;
#[entry]
fn main() -> ! {
let roses = "blue";
if roses == "red" {
debug::exit(debug::EXIT_SUCCESS);
} else {
debug::exit(debug::EXIT_FAILURE);
}
loop {}
}
$ cargo run
Running `qemu-system-arm (..)
$ echo $?
1
最後にもう 1 つヒントです: panic 時の動作を exit(EXIT_FAILURE) に設定できます。これに
より、QEMU 上で実行できる no_std の run-pass テストを書けるようになります。
利便性のために、panic-semihosting クレートには “exit” feature があり、これを
有効にすると panic メッセージをホストの stderr に記録したあとで
exit(EXIT_FAILURE) を呼び出します。
#![no_main]
#![no_std]
use panic_semihosting as _; // features = ["exit"]
use cortex_m_rt::entry;
use cortex_m_semihosting::debug;
#[entry]
fn main() -> ! {
let roses = "blue";
assert_eq!(roses, "red");
loop {}
}
$ cargo run
Running `qemu-system-arm (..)
panicked at 'assertion failed: `(left == right)`
left: `"blue"`,
right: `"red"`', examples/hello.rs:15:5
$ echo $?
1
注: panic-semihosting でこの feature を有効にするには、
panic-semihosting を指定している Cargo.toml の依存関係セクションを次のように
編集してください:
panic-semihosting = { version = "VERSION", features = ["exit"] }
ここで VERSION は必要なバージョンです。依存関係の feature について詳しくは、
Cargo book の specifying dependencies セクションを参照してください。