use super::vcpu::LocalIrqs;
use crate::registers::{read_csr, read_guest_csr, write_csr, write_guest_csr};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct GuestInterrupt(u8);
impl GuestInterrupt {
pub const fn new(source: u8) -> Option<Self> {
if source <= 12 {
Some(Self(source))
} else {
None
}
}
pub const fn source(self) -> u8 {
self.0
}
pub unsafe fn pulse(self) {
let _irqs = LocalIrqs::disable();
unsafe {
if (2..=9).contains(&self.0) {
let bit = 1usize << (self.0 - 2);
let current = read_csr::<0x52>();
let pending = (read_guest_csr::<5>() >> 2) & 0xff;
let cleared = (current & !0xff) | (pending & !bit);
write_csr::<0x52>(cleared);
write_csr::<0x52>(cleared | bit);
} else {
let current = read_guest_csr::<5>();
write_guest_csr::<5>(current | (1usize << self.0));
}
}
}
}
pub unsafe fn set_hwi_pending(mask: u8) {
let _irqs = LocalIrqs::disable();
unsafe {
let current = read_csr::<0x52>();
write_csr::<0x52>((current & !0xff) | usize::from(mask));
}
}
pub unsafe fn set_hwi_passthrough(mask: u8) {
let _irqs = LocalIrqs::disable();
unsafe {
let current = read_csr::<0x52>();
let pending = (read_guest_csr::<5>() >> 2) & 0xff;
write_csr::<0x52>((current & !0xffff) | pending | (usize::from(mask) << 8));
}
}