add VIRT_TEST support for qemu exit with exit_code, for CI autotest
This commit is contained in:
parent
a8e8644865
commit
f25fe0431c
3 changed files with 94 additions and 6 deletions
|
@ -1,9 +1,10 @@
|
||||||
pub const CLOCK_FREQ: usize = 12500000;
|
pub const CLOCK_FREQ: usize = 12500000;
|
||||||
|
|
||||||
pub const MMIO: &[(usize, usize)] = &[
|
pub const MMIO: &[(usize, usize)] = &[
|
||||||
(0x1000_0000, 0x1000),
|
(0x1000_0000, 0x1000), // VIRT_UART0 in virt machine
|
||||||
(0x1000_1000, 0x1000),
|
(0x1000_1000, 0x1000), // VIRT_VIRTIO in virt machine
|
||||||
(0xC00_0000, 0x40_0000),
|
(0x0C00_0000, 0x40_0000), // VIRT_PLIC in virt machine
|
||||||
|
(0x0010_0000, 0x00_2000), // VIRT_TEST/RTC in virt machine
|
||||||
];
|
];
|
||||||
|
|
||||||
pub type BlockDeviceImpl = crate::drivers::block::VirtIOBlock;
|
pub type BlockDeviceImpl = crate::drivers::block::VirtIOBlock;
|
||||||
|
@ -43,3 +44,84 @@ pub fn irq_handler() {
|
||||||
}
|
}
|
||||||
plic.complete(0, IntrTargetPriority::Supervisor, intr_src_id);
|
plic.complete(0, IntrTargetPriority::Supervisor, intr_src_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
const EXIT_SUCCESS: u32 = 0x5555; // Equals `exit(0)`. qemu successful exit
|
||||||
|
|
||||||
|
const EXIT_FAILURE_FLAG: u32 = 0x3333;
|
||||||
|
const EXIT_FAILURE: u32 = exit_code_encode(1); // Equals `exit(1)`. qemu failed exit
|
||||||
|
const EXIT_RESET: u32 = 0x7777; // qemu reset
|
||||||
|
|
||||||
|
pub trait QEMUExit {
|
||||||
|
/// Exit with specified return code.
|
||||||
|
///
|
||||||
|
/// Note: For `X86`, code is binary-OR'ed with `0x1` inside QEMU.
|
||||||
|
fn exit(&self, code: u32) -> !;
|
||||||
|
|
||||||
|
/// Exit QEMU using `EXIT_SUCCESS`, aka `0`, if possible.
|
||||||
|
///
|
||||||
|
/// Note: Not possible for `X86`.
|
||||||
|
fn exit_success(&self) -> !;
|
||||||
|
|
||||||
|
/// Exit QEMU using `EXIT_FAILURE`, aka `1`.
|
||||||
|
fn exit_failure(&self) -> !;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// RISCV64 configuration
|
||||||
|
pub struct RISCV64 {
|
||||||
|
/// Address of the sifive_test mapped device.
|
||||||
|
addr: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Encode the exit code using EXIT_FAILURE_FLAG.
|
||||||
|
const fn exit_code_encode(code: u32) -> u32 {
|
||||||
|
(code << 16) | EXIT_FAILURE_FLAG
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RISCV64 {
|
||||||
|
/// Create an instance.
|
||||||
|
pub const fn new(addr: u64) -> Self {
|
||||||
|
RISCV64 { addr }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl QEMUExit for RISCV64 {
|
||||||
|
/// Exit qemu with specified exit code.
|
||||||
|
fn exit(&self, code: u32) -> ! {
|
||||||
|
// If code is not a special value, we need to encode it with EXIT_FAILURE_FLAG.
|
||||||
|
let code_new = match code {
|
||||||
|
EXIT_SUCCESS | EXIT_FAILURE | EXIT_RESET => code,
|
||||||
|
_ => exit_code_encode(code),
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
asm!(
|
||||||
|
"sw {0}, 0({1})",
|
||||||
|
in(reg)code_new, in(reg)self.addr
|
||||||
|
);
|
||||||
|
|
||||||
|
// For the case that the QEMU exit attempt did not work, transition into an infinite
|
||||||
|
// loop. Calling `panic!()` here is unfeasible, since there is a good chance
|
||||||
|
// this function here is the last expression in the `panic!()` handler
|
||||||
|
// itself. This prevents a possible infinite loop.
|
||||||
|
loop {
|
||||||
|
asm!("wfi", options(nomem, nostack));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exit_success(&self) -> ! {
|
||||||
|
self.exit(EXIT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exit_failure(&self) -> ! {
|
||||||
|
self.exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const VIRT_TEST: u64 =0x100000;
|
||||||
|
|
||||||
|
pub const QEMU_EXIT_HANDLE: RISCV64 = RISCV64::new(VIRT_TEST);
|
||||||
|
|
|
@ -39,7 +39,9 @@ pub fn console_getchar() -> usize {
|
||||||
sbi_call(SBI_CONSOLE_GETCHAR, 0, 0, 0)
|
sbi_call(SBI_CONSOLE_GETCHAR, 0, 0, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use crate::board::QEMUExit;
|
||||||
pub fn shutdown(exit_code: usize) -> ! {
|
pub fn shutdown(exit_code: usize) -> ! {
|
||||||
sbi_call(SBI_SHUTDOWN, exit_code, 0, 0);
|
//sbi_call(SBI_SHUTDOWN, exit_code, 0, 0);
|
||||||
|
crate::board::QEMU_EXIT_HANDLE.exit_failure();
|
||||||
panic!("It should shutdown!");
|
panic!("It should shutdown!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,8 @@ pub fn block_current_and_run_next() {
|
||||||
schedule(task_cx_ptr);
|
schedule(task_cx_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use crate::board::QEMUExit;
|
||||||
|
|
||||||
pub fn exit_current_and_run_next(exit_code: i32) {
|
pub fn exit_current_and_run_next(exit_code: i32) {
|
||||||
let task = take_current_task().unwrap();
|
let task = take_current_task().unwrap();
|
||||||
let mut task_inner = task.inner_exclusive_access();
|
let mut task_inner = task.inner_exclusive_access();
|
||||||
|
@ -79,9 +81,11 @@ pub fn exit_current_and_run_next(exit_code: i32) {
|
||||||
exit_code
|
exit_code
|
||||||
);
|
);
|
||||||
if exit_code != 0 {
|
if exit_code != 0 {
|
||||||
crate::sbi::shutdown(255); //255 == -1 for err hint
|
//crate::sbi::shutdown(255); //255 == -1 for err hint
|
||||||
|
crate::board::QEMU_EXIT_HANDLE.exit_failure();
|
||||||
} else {
|
} else {
|
||||||
crate::sbi::shutdown(0); //0 for success hint
|
//crate::sbi::shutdown(0); //0 for success hint
|
||||||
|
crate::board::QEMU_EXIT_HANDLE.exit_success();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
remove_from_pid2process(pid);
|
remove_from_pid2process(pid);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue