33.5. Semihosting

Semihosting is a publicly documented interface specified by ARM Holdings that allows us to do some magic operations very useful in development, such as writting to the terminal or reading and writing host files.

For example, all the following code make QEMU exit:

./run --arch arm --baremetal baremetal/arch/arm/semihost_exit.S
./run --arch arm --baremetal baremetal/arch/arm/no_bootloader/semihost_exit.S
./run --arch aarch64 --baremetal baremetal/arch/aarch64/semihost_exit.S
./run --arch aarch64 --baremetal baremetal/arch/aarch64/no_bootloader/semihost_exit.S

Sources:

That arm program program contains the code:

mov r0, #0x18
ldr r1, =#0x20026
svc 0x00123456

and we can see from the docs that 0x18 stands for the SYS_EXIT command.

This is also how we implement the exit(0) system call in C for QEMU, which is used for example at userland/c/exit0.c through the Newlib via the _exit function at baremetal/lib/syscalls.c.

Other magic operations we can do with semihosting besides exiting the on the host include:

  • read and write to host stdin and stdout

  • read and write to host files

Alternatives exist for some semihosting operations, e.g.:

  • UART IO for host stdin and stdout in both emulators and real hardware

  • m5ops for gem5, e.g. m5 exit makes the emulator quit

The big advantage of semihosting is that it is standardized across all ARM boards, and therefore allows you to make a single image that does those magic operations instead of having to compile multiple images with different magic addresses.

The downside of semihosting is that it is ARM specific. TODO is it an open standard that other vendors can implement?

In QEMU, we enable semihosting with:

-semihosting

Newlib 9c84bfd47922aad4881f80243320422b621c95dc already has a semi-hosting implementation at:

newlib/libc/sys/arm/syscalls.c

TODO: how to use it? Possible through crosstool-NG? In the worst case we could just copy it.

Bibliography: