Semihosting

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

The cortex-m-semihosting crate provides an API to do semihosting operationson Cortex-M devices. The program below is the semihosting version of "Hello,world!":

1. #![no_main]
2. #![no_std]

4. extern crate panic_halt;

6. use cortex_m_rt::entry;
7. use cortex_m_semihosting::hprintln;

9. #[entry]
10. fn main() -> ! {
11. hprintln!("Hello, world!").unwrap();

13. loop {}
14. }

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

1. $ openocd
2. (..)
3. Hello, world!
4. (..)

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

1. (gdb) monitor arm semihosting enable
2. semihosting is enabled

QEMU understands semihosting operations so the above program will also work withqemu-system-arm without having to start a debug session. Note that you'llneed to pass the -semihosting-config flag to QEMU to enable semihostingsupport; these flags are already included in the .cargo/config file of thetemplate.

1. $ # this program will block the terminal
2. $ cargo run
3. Running `qemu-system-arm (..)
4. Hello, world!

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

1. #![no_main]
2. #![no_std]

4. extern crate panic_halt;

6. use cortex_m_rt::entry;
7. use cortex_m_semihosting::debug;

9. #[entry]
10. fn main() -> ! {
11. let roses = "blue";

13. if roses == "red" {
14. debug::exit(debug::EXIT_SUCCESS);
15. } else {
16. debug::exit(debug::EXIT_FAILURE);
17. }

19. loop {}
20. }
1. $ cargo run
2. Running `qemu-system-arm (..)

4. $ echo $?
5. 1

One last tip: you can set the panicking behavior to exit(EXIT_FAILURE). Thiswill 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 whenenabled invokes exit(EXIT_FAILURE) after logging the panic message to the hoststderr.

1. #![no_main]
2. #![no_std]

4. extern crate panic_semihosting; // features = ["exit"]

6. use cortex_m_rt::entry;
7. use cortex_m_semihosting::debug;

9. #[entry]
10. fn main() -> ! {
11. let roses = "blue";

13. assert_eq!(roses, "red");

15. loop {}
16. }
1. $ cargo run
2. Running `qemu-system-arm (..)
3. panicked at 'assertion failed: `(left == right)`
4. left: `"blue"`,
5. right: `"red"`', examples/hello.rs:15:5

7. $ echo $?
8. 1

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

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

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