pub mod boot;
pub mod diagnostics;
pub mod fatal;
mod fault;
mod interrupted;
use core::sync::atomic::{AtomicUsize, Ordering};
use ax_memory_addr::VirtAddr;
pub use diagnostics::BacktraceRegisters;
pub use fault::PageFaultFlags;
pub use interrupted::{InterruptedContext, InterruptedPrivilege};
pub use crate::arch::current::{context::TrapFrame as UserRegisters, trap::KernelTrapFrame};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TrapOrigin {
Kernel,
User,
}
pub type IrqHandler = fn(usize, TrapOrigin, Option<InterruptedContext>) -> bool;
pub type PageFaultHandler = fn(VirtAddr, PageFaultFlags) -> bool;
pub type BreakpointHandler = fn(&mut KernelTrapFrame<'_>) -> bool;
pub type DebugHandler = fn(&mut KernelTrapFrame<'_>) -> bool;
fn default_irq_handler(
irq: usize,
_origin: TrapOrigin,
_context: Option<InterruptedContext>,
) -> 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
}
fn default_breakpoint_handler(_tf: &mut KernelTrapFrame<'_>) -> bool {
false
}
fn default_debug_handler(_tf: &mut KernelTrapFrame<'_>) -> bool {
false
}
static IRQ_HANDLER: AtomicUsize = AtomicUsize::new(0);
static PAGE_FAULT_HANDLER: AtomicUsize = AtomicUsize::new(0);
static BREAKPOINT_HANDLER: AtomicUsize = AtomicUsize::new(0);
static DEBUG_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 set_breakpoint_handler(handler: BreakpointHandler) -> BreakpointHandler {
let old = BREAKPOINT_HANDLER.swap(handler as usize, Ordering::AcqRel);
if old == 0 {
default_breakpoint_handler
} else {
unsafe { core::mem::transmute::<usize, BreakpointHandler>(old) }
}
}
pub fn set_debug_handler(handler: DebugHandler) -> DebugHandler {
let old = DEBUG_HANDLER.swap(handler as usize, Ordering::AcqRel);
if old == 0 {
default_debug_handler
} else {
unsafe { core::mem::transmute::<usize, DebugHandler>(old) }
}
}
pub fn dispatch_irq(irq: usize, origin: TrapOrigin, context: Option<InterruptedContext>) -> 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, origin, context)
}
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)
}
pub fn irq_handler(irq: usize) -> bool {
dispatch_irq(irq, TrapOrigin::Kernel, None)
}
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
}
pub fn breakpoint_handler(tf: &mut KernelTrapFrame<'_>) -> bool {
let handler = BREAKPOINT_HANDLER.load(Ordering::Acquire);
let handler = if handler == 0 {
default_breakpoint_handler
} else {
unsafe { core::mem::transmute::<usize, BreakpointHandler>(handler) }
};
handler(tf)
}
pub fn debug_handler(tf: &mut KernelTrapFrame<'_>) -> bool {
let handler = DEBUG_HANDLER.load(Ordering::Acquire);
let handler = if handler == 0 {
default_debug_handler
} else {
unsafe { core::mem::transmute::<usize, DebugHandler>(handler) }
};
handler(tf)
}
#[cfg(target_arch = "loongarch64")]
pub use crate::arch::current::unaligned::{
UnalignedAccess, UnalignedAccessType, UnalignedError, UnalignedPageFault,
};