1use 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#[derive(Clone, Debug)]
15pub enum Case {
16 NotExist,
18 Begin,
20 SendIpi,
22 UnexpectedTrap(Trap<usize, usize>),
24 Pass,
26}
27
28pub 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 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}