Semihosting

Semihosting is a mechanism that lets embedded devices do I/O on the host and is mainly used to log messages to the host console. Semihosting requires a debug session and pretty much nothing else (no extra wires!) so it's super convenient to use. The downside is that it's super slow: each write operation can take several milliseconds depending on the hardware debugger (e.g. ST-Link) you use.

The cortex-m-semihosting crate provides an API to do semihosting operations on Cortex-M devices. The program below is the semihosting version of "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 {}

}

If you run this program on hardware you'll see the "Hello, world!" message within the OpenOCD logs.

$ openocd

(..)

Hello, world!

(..)

You do need to enable semihosting in OpenOCD from GDB first:

(gdb) monitor arm semihosting enable

semihosting is enabled

QEMU understands semihosting operations so the above program will also work with qemu-system-arm without having to start a debug session. Note that you'll need to pass the -semihosting-config flag to QEMU to enable semihosting support; these flags are already included in the .cargo/config.toml file of the template.

$ # this program will block the terminal

$ cargo run

Running `qemu-system-arm (..)

Hello, world!

There's also an exit semihosting operation that can be used to terminate the QEMU process. Important: do not use debug::exit on hardware; this function can corrupt your OpenOCD session and you will not be able to debug more programs until you restart it.

#![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

One last tip: you can set the panicking behavior to exit(EXIT_FAILURE). This will let you write no_std run-pass tests that you can run on QEMU.

For convenience, the panic-semihosting crate has an "exit" feature that when enabled invokes exit(EXIT_FAILURE) after logging the panic message to the host stderr.

#![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

NOTE: To enable this feature on panic-semihosting, edit your Cargo.toml dependencies section where panic-semihosting is specified with:

panic-semihosting = { version = "VERSION", features = ["exit"] }

where VERSION is the version desired. For more information on dependencies features check the specifying dependencies section of the Cargo book.

Загрузка...