use core::sync::atomic::{AtomicUsize, Ordering};
use ax_memory_addr::VirtAddr;
pub use ax_page_table_entry::MappingFlags as PageFaultFlags;
pub use crate::TrapFrame;
pub type IrqHandler = fn(usize) -> bool;
pub type PageFaultHandler = fn(VirtAddr, PageFaultFlags) -> bool;
fn default_irq_handler(irq: usize) -> bool {
trace!("IRQ {} triggered", irq);
false
}
fn default_page_fault_handler(addr: VirtAddr, flags: PageFaultFlags) -> bool {
warn!("Page fault at {:#x} with flags {:?}", addr, flags);
false
}
static IRQ_HANDLER: AtomicUsize = AtomicUsize::new(0);
static PAGE_FAULT_HANDLER: AtomicUsize = AtomicUsize::new(0);
pub fn set_irq_handler(handler: IrqHandler) -> IrqHandler {
let old = IRQ_HANDLER.swap(handler as usize, Ordering::AcqRel);
if old == 0 {
default_irq_handler
} else {
unsafe { core::mem::transmute::<usize, IrqHandler>(old) }
}
}
pub fn set_page_fault_handler(handler: PageFaultHandler) -> PageFaultHandler {
let old = PAGE_FAULT_HANDLER.swap(handler as usize, Ordering::AcqRel);
if old == 0 {
default_page_fault_handler
} else {
unsafe { core::mem::transmute::<usize, PageFaultHandler>(old) }
}
}
pub fn dispatch_irq(irq: usize) -> bool {
let handler = IRQ_HANDLER.load(Ordering::Acquire);
let handler = if handler == 0 {
default_irq_handler
} else {
unsafe { core::mem::transmute::<usize, IrqHandler>(handler) }
};
handler(irq)
}
pub fn dispatch_page_fault(addr: VirtAddr, flags: PageFaultFlags) -> bool {
let handler = PAGE_FAULT_HANDLER.load(Ordering::Acquire);
let handler = if handler == 0 {
default_page_fault_handler
} else {
unsafe { core::mem::transmute::<usize, PageFaultHandler>(handler) }
};
handler(addr, flags)
}
#[eii]
pub fn irq_handler(irq: usize) -> bool {
default_irq_handler(irq)
}
#[eii]
pub fn page_fault_handler(addr: VirtAddr, flags: PageFaultFlags) -> bool {
dispatch_page_fault(addr, flags)
}
#[inline]
pub(crate) fn call_page_fault_handler_with_parent_irqs(
addr: VirtAddr,
flags: PageFaultFlags,
parent_irqs_enabled: bool,
) -> bool {
if parent_irqs_enabled {
crate::asm::enable_irqs();
}
let handled = page_fault_handler(addr, flags);
if parent_irqs_enabled {
crate::asm::disable_irqs();
}
handled
}
#[eii]
pub fn breakpoint_handler(_tf: &mut TrapFrame) -> bool {
false
}
#[cfg(target_arch = "x86_64")]
#[eii]
pub fn debug_handler(_tf: &mut TrapFrame) -> bool {
false
}