use core::ops::{Deref, DerefMut};
use patina::{error::EfiError, pi::protocol::cpu_arch::EfiSystemContext, standard};
mod exception_handling;
#[cfg_attr(coverage, coverage(off))]
#[cfg(any(target_arch = "aarch64", test))]
mod aarch64;
#[cfg_attr(coverage, coverage(off))]
#[cfg(not(target_os = "uefi"))]
mod stub;
#[cfg(any(target_arch = "x86_64", test))]
mod x64;
#[cfg(target_arch = "aarch64")]
pub use aarch64::gic_manager;
cfg_if::cfg_if! {
if #[cfg(not(target_os = "uefi"))] {
pub type Interrupts = stub::InterruptsStub;
} else if #[cfg(target_arch = "x86_64")] {
pub type Interrupts = x64::InterruptsX64;
} else if #[cfg(target_arch = "aarch64")] {
pub type Interrupts = aarch64::InterruptsAarch64;
}
}
pub type ExceptionContextX64 = standard::efi::protocols::debug_support::SystemContextX64;
pub type ExceptionContextAArch64 = standard::efi::protocols::debug_support::SystemContextAArch64;
cfg_if::cfg_if! {
if #[cfg(any(test, doc))] {
pub type ExceptionContextArch = stub::ExceptionContextStub;
} else if #[cfg(target_arch = "x86_64")] {
pub type ExceptionContextArch = ExceptionContextX64;
} else if #[cfg(target_arch = "aarch64")] {
pub type ExceptionContextArch = ExceptionContextAArch64;
}
}
#[derive(Debug, Clone, Copy)]
pub struct ExceptionContext<T = ExceptionContextArch>(T);
impl<T> Deref for ExceptionContext<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<T> DerefMut for ExceptionContext<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
pub type ExceptionType = usize;
#[macro_export]
macro_rules! log_registers {
( $( $name:expr, $value:expr ),+ $(,)? ) => {
let registers = [$(($name, $value),)+];
for chunk in registers.chunks(4) {
match chunk {
[c1, c2, c3, c4] => {
log::error!(
"{:>4}: {:#018X} {:>4}: {:#018X} {:>4}: {:#018X} {:>4}: {:#018X}",
c1.0, c1.1, c2.0, c2.1, c3.0, c3.1, c4.0, c4.1
);
},
[c1, c2, c3] => {
log::error!(
"{:>4}: {:#018X} {:>4}: {:#018X} {:>4}: {:#018X}",
c1.0, c1.1, c2.0, c2.1, c3.0, c3.1
);
},
[c1, c2] => {
log::error!(
"{:>4}: {:#018X} {:>4}: {:#018X}",
c1.0, c1.1, c2.0, c2.1,
);
},
[c1] => {
log::error!(
"{:>4}: {:#018X}",
c1.0, c1.1
);
},
_ => {
log::error!("");
}
}
}
};
}
pub(crate) trait EfiSystemContextFactory {
fn create_efi_system_context(&mut self) -> EfiSystemContext;
}
pub(crate) trait EfiExceptionInfoDump {
fn dump_stack_trace(&self);
fn dump_system_context_registers(&self);
}
pub trait InterruptManager {
fn register_exception_handler(&self, exception_type: ExceptionType, handler: HandlerType) -> Result<(), EfiError> {
exception_handling::register_exception_handler(exception_type, handler)
}
fn unregister_exception_handler(&self, exception_type: ExceptionType) -> Result<(), EfiError> {
exception_handling::unregister_exception_handler(exception_type)
}
}
pub enum HandlerType {
None,
UefiRoutine(patina::pi::protocol::cpu_arch::InterruptHandler),
Handler(&'static dyn InterruptHandler),
}
impl HandlerType {
fn is_none(&self) -> bool {
matches!(self, HandlerType::None)
}
}
pub trait InterruptHandler<T = ExceptionContextArch>: Sync {
fn handle_interrupt(&'static self, exception_type: ExceptionType, context: &mut ExceptionContext<T>);
}
#[cfg_attr(coverage, coverage(off))]
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_exception_context_deref() {
let mut exception_context = ExceptionContext(0u64);
*exception_context = 42;
let exception_context = exception_context;
assert_eq!(*exception_context, 42u64);
}
}