qemu_exit/lib.rs
1// SPDX-License-Identifier: MIT OR Apache-2.0
2//
3// Copyright (c) 2019-2022 Andre Richter <andre.o.richter@gmail.com>
4
5//! Exit QEMU with user-defined code.
6//!
7//! Quit a running QEMU session with user-defined exit code. Useful for unit or integration tests
8//! using QEMU.
9//!
10//! ## TL;DR
11//!
12//! ```rust
13//! use qemu_exit::QEMUExit;
14//!
15//! #[cfg(target_arch = "aarch64")]
16//! let qemu_exit_handle = qemu_exit::AArch64::new();
17//!
18//! // addr: The address of sifive_test.
19//! #[cfg(target_arch = "riscv64")]
20//! let qemu_exit_handle = qemu_exit::RISCV64::new(addr);
21//!
22//! // io_base: I/O-base of isa-debug-exit.
23//! // custom_exit_success: A custom success code; Must be an odd number.
24//! #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
25//! let qemu_exit_handle = qemu_exit::X86::new(io_base, custom_exit_success);
26//!
27//! qemu_exit_handle.exit(1337);
28//! qemu_exit_handle.exit_success();
29//! qemu_exit_handle.exit_failure();
30//! ```
31//!
32//! ## Architecture Specific Configuration
33//!
34//! ### AArch64
35//!
36//! Pass the `-semihosting` argument to the QEMU invocation, e.g.:
37//! ```
38//! qemu-system-aarch64 -M raspi3 -serial stdio -semihosting -kernel kernel8.img
39//! ```
40//!
41//! ### RISCV64
42//!
43//! You need to chose a machine with the `sifive_test` device, for exemple `-M virt`:
44//! ```
45//! qemu-system-riscv64 -M virt -nographic -monitor none -serial stdio -kernel kernel.elf
46//! ```
47//!
48//! ### x86_64
49//!
50//! Add the special ISA debug exit device by passing the flags:
51//! ```
52//! -device isa-debug-exit,iobase=0xf4,iosize=0x04
53//! ```
54//!
55//! When instantiating the handle, `iobase` must be given as the first parameter.
56//!
57//! The second parameter must be an `EXIT_SUCCESS` code of your choice that is an odd number, aka
58//! bit number zero must be `1`. This is needed because in QEMU, the provided code is internally
59//! binary-OR'ed with `0x1`. This is hardcoded and therefore, with `isa-debug-exit`, it is not
60//! possible to let QEMU invoke `exit(0)`.
61//!
62//! ```rust
63//! let qemu_exit_handle = qemu_exit::X86::new(io_base, custom_exit_success);
64//! ```
65//!
66//! ## Literature
67//!
68//! - [Semihosting for AArch32 and AArch64](https://static.docs.arm.com/dui0003/b/semihosting.pdf)
69//! - [QEMU isa-debug-exit source](https://git.qemu.org/?p=qemu.git;a=blob;f=hw/misc/debugexit.c)
70//! - [QEMU sifive_test source](https://git.qemu.org/?p=qemu.git;a=blob;f=hw/misc/sifive_test.c)
71
72#![deny(missing_docs)]
73#![no_std]
74
75#[cfg(target_arch = "aarch64")]
76pub mod aarch64;
77
78#[cfg(target_arch = "aarch64")]
79pub use aarch64::*;
80
81#[cfg(target_arch = "riscv64")]
82pub mod riscv64;
83
84#[cfg(target_arch = "riscv64")]
85pub use riscv64::*;
86
87#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
88pub mod x86;
89
90#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
91pub use x86::*;
92
93/// Generic interface for exiting QEMU.
94pub trait QEMUExit {
95 /// Exit with specified return code.
96 ///
97 /// Note: For `X86`, code is binary-OR'ed with `0x1` inside QEMU.
98 fn exit(&self, code: u32) -> !;
99
100 /// Exit QEMU using `EXIT_SUCCESS`, aka `0`, if possible.
101 ///
102 /// Note: Not possible for `X86`.
103 fn exit_success(&self) -> !;
104
105 /// Exit QEMU using `EXIT_FAILURE`, aka `1`.
106 fn exit_failure(&self) -> !;
107}