セミホスティング

セミホスティングは、組込みデバイスがホスト上でI/Oを行う仕組みです。主に、ホストのコンソールにログ出力するために使われます。 セミホスティングには、デバッグセッションが必要ですが、他には何も必要としません(追加の配線は不要です)。そのため、非常に便利です。 欠点は、非常に低速であることです。ハードウェアデバッガ(例えば、ST-Link)によっては、書き込み操作が数ミリ秒かかります。

cortex-m-semihostingクレートは、Cortex-Mデバイス上でセミホスティング操作をするためのAPIを提供します。 下のプログラムは、セミホスティングバージョンの「Hello, world!」です。

#![no_main]
#![no_std]

extern crate panic_halt;

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ファイルに既に含まれています。

$ # このプログラムは端末をブロックします
$ cargo run
     Running `qemu-system-arm (..)
Hello, world!

exitセミホスティング操作もあり、QEMUプロセスを終了するために使われます。 重要:ハードウェア上でdebug::exit使用しないで下さい。この関数は、OpenOCDセッションを破壊する可能性があり、 OpenOCDを再起動しない限り、それ以上のプログラムのデバッグができなくなります。

#![no_main]
#![no_std]

extern crate panic_halt;

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

最後のヒント:パニック時の挙動を、exit(EXIT_FAILURE)に設定することができます。 これで、QEMU上で実行できるno_stdランパステストを書くことができます。

利便性のために、panic-semihostingクレートは、「exit」フィーチャを持っています。 このフィーチャが有効化されていると、ホストの標準エラーにパニックメッセージをログ出力した後、exit(EXIT_FAILURE)を呼び出します。

#![no_main]
#![no_std]

extern crate panic_semihosting; // 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