use crate::thread::Thread;
use riscv::{
interrupt::supervisor::{Exception, Interrupt},
register::{
scause::{self, Trap},
sie,
},
};
use sbi::HartMask;
#[derive(Clone, Debug)]
pub enum Case {
NotExist,
Begin,
SendIpi,
UnexpectedTrap(Trap<usize, usize>),
Pass,
}
pub fn test(hart_id: usize, mut f: impl FnMut(Case)) {
if sbi::probe_extension(sbi::Timer).is_unavailable() {
f(Case::NotExist);
return;
}
fn ipi(hart_id: usize) -> ! {
sbi::send_ipi(HartMask::from_mask_base(1 << hart_id, 0));
unsafe { core::arch::asm!("unimp", options(noreturn, nomem)) };
}
f(Case::Begin);
let mut stack = [0usize; 32];
let mut thread = Thread::new(ipi as *const () as _);
*thread.sp_mut() = stack.as_mut_ptr_range().end as _;
*thread.a_mut(0) = hart_id;
unsafe {
sie::set_ssoft();
thread.execute();
}
let trap = scause::read().cause();
match trap.try_into::<Interrupt, Exception>() {
Ok(Trap::Interrupt(Interrupt::SupervisorSoft)) => {
f(Case::SendIpi);
f(Case::Pass);
}
_ => {
f(Case::UnexpectedTrap(trap));
}
}
}