Skip to main content

sbi_testing/
spi.rs

1//! Inter-processor interrupt extension test suite.
2
3use crate::thread::Thread;
4use riscv::{
5    interrupt::supervisor::{Exception, Interrupt},
6    register::{
7        scause::{self, Trap},
8        sie,
9    },
10};
11use sbi::HartMask;
12
13/// Inter-processor Interrupt extension test cases.
14#[derive(Clone, Debug)]
15pub enum Case {
16    /// Can't proceed test for inter-processor interrupt extension does not exist.
17    NotExist,
18    /// Test begin.
19    Begin,
20    /// Test process for an inter-processor interrupt has been received.
21    SendIpi,
22    /// Test failed for unexpected trap occurred upon tests.
23    UnexpectedTrap(Trap<usize, usize>),
24    /// All test cases on inter-processor interrupt extension has passed.
25    Pass,
26}
27
28/// Test inter-processor interrupt extension.
29pub fn test(hart_id: usize, mut f: impl FnMut(Case)) {
30    if sbi::probe_extension(sbi::Timer).is_unavailable() {
31        f(Case::NotExist);
32        return;
33    }
34
35    fn ipi(hart_id: usize) -> ! {
36        sbi::send_ipi(HartMask::from_mask_base(1 << hart_id, 0));
37        // 必须立即触发中断,即使是一个指令的延迟,也会触发另一个异常
38        unsafe { core::arch::asm!("unimp", options(noreturn, nomem)) };
39    }
40
41    f(Case::Begin);
42    let mut stack = [0usize; 32];
43    let mut thread = Thread::new(ipi as *const () as _);
44    *thread.sp_mut() = stack.as_mut_ptr_range().end as _;
45    *thread.a_mut(0) = hart_id;
46    unsafe {
47        sie::set_ssoft();
48        thread.execute();
49    }
50    let trap = scause::read().cause();
51    match trap.try_into::<Interrupt, Exception>() {
52        Ok(Trap::Interrupt(Interrupt::SupervisorSoft)) => {
53            f(Case::SendIpi);
54            f(Case::Pass);
55        }
56        _ => {
57            f(Case::UnexpectedTrap(trap));
58        }
59    }
60}