use core::ffi::c_void;
use crate::proto::unsafe_protocol;
use crate::{Result, Status, StatusExt};
pub use context::SystemContext;
pub use exception::ExceptionType;
mod context;
mod exception;
#[derive(Debug)]
#[repr(C)]
#[unsafe_protocol("2755590c-6f3c-42fa-9ea4-a3ba543cda25")]
pub struct DebugSupport {
isa: ProcessorArch,
get_maximum_processor_index:
extern "efiapi" fn(this: &mut Self, max_processor_index: &mut usize) -> Status,
register_periodic_callback: unsafe extern "efiapi" fn(
this: &mut Self,
processor_index: usize,
periodic_callback: Option<unsafe extern "efiapi" fn(SystemContext)>,
) -> Status,
register_exception_callback: unsafe extern "efiapi" fn(
this: &mut Self,
processor_index: usize,
exception_callback: Option<unsafe extern "efiapi" fn(ExceptionType, SystemContext)>,
exception_type: ExceptionType,
) -> Status,
invalidate_instruction_cache: unsafe extern "efiapi" fn(
this: &mut Self,
processor_index: usize,
start: *mut c_void,
length: u64,
) -> Status,
}
impl DebugSupport {
#[must_use]
pub const fn arch(&self) -> ProcessorArch {
self.isa
}
pub fn get_maximum_processor_index(&mut self) -> usize {
let mut max_processor_index: usize = usize::MAX;
let _ = (self.get_maximum_processor_index)(self, &mut max_processor_index);
max_processor_index
}
pub unsafe fn register_periodic_callback(
&mut self,
processor_index: usize,
callback: Option<unsafe extern "efiapi" fn(SystemContext)>,
) -> Result {
if processor_index > self.get_maximum_processor_index() {
return Err(Status::INVALID_PARAMETER.into());
}
unsafe { (self.register_periodic_callback)(self, processor_index, callback) }.to_result()
}
pub unsafe fn register_exception_callback(
&mut self,
processor_index: usize,
callback: Option<unsafe extern "efiapi" fn(ExceptionType, SystemContext)>,
exception_type: ExceptionType,
) -> Result {
if processor_index > self.get_maximum_processor_index() {
return Err(Status::INVALID_PARAMETER.into());
}
unsafe {
(self.register_exception_callback)(self, processor_index, callback, exception_type)
}
.to_result()
}
pub unsafe fn invalidate_instruction_cache(
&mut self,
processor_index: usize,
start: *mut c_void,
length: u64,
) -> Result {
if processor_index > self.get_maximum_processor_index() {
return Err(Status::INVALID_PARAMETER.into());
}
unsafe { (self.invalidate_instruction_cache)(self, processor_index, start, length) }
.to_result()
}
}
newtype_enum! {
pub enum ProcessorArch: u32 => {
X86_32 = 0x014C,
X86_64 = 0x8664,
ITANIUM = 0x200,
EBC = 0x0EBC,
ARM = 0x01C2,
AARCH_64 = 0xAA64,
RISCV_32 = 0x5032,
RISCV_64 = 0x5064,
RISCV_128 = 0x5128,
}}
#[derive(Debug)]
#[repr(C)]
#[unsafe_protocol("eba4e8d2-3858-41ec-a281-2647ba9660d0")]
pub struct DebugPort {
reset: extern "efiapi" fn(this: &Self) -> Status,
write: extern "efiapi" fn(
this: &Self,
timeout: u32,
buffer_size: &mut usize,
buffer: *const c_void,
) -> Status,
read: extern "efiapi" fn(
this: &Self,
timeout: u32,
buffer_size: &mut usize,
buffer: *mut c_void,
) -> Status,
poll: extern "efiapi" fn(this: &Self) -> Status,
}
impl DebugPort {
pub fn reset(&self) -> Result {
(self.reset)(self).to_result()
}
pub fn write(&self, timeout: u32, data: &[u8]) -> Result<(), usize> {
let mut buffer_size = data.len();
(self.write)(
self,
timeout,
&mut buffer_size,
data.as_ptr().cast::<c_void>(),
)
.to_result_with(
|| debug_assert_eq!(buffer_size, data.len()),
|_| buffer_size,
)
}
pub fn read(&self, timeout: u32, data: &mut [u8]) -> Result<(), usize> {
let mut buffer_size = data.len();
(self.read)(
self,
timeout,
&mut buffer_size,
data.as_mut_ptr().cast::<c_void>(),
)
.to_result_with(
|| debug_assert_eq!(buffer_size, data.len()),
|_| buffer_size,
)
}
pub fn poll(&self) -> Result {
(self.poll)(self).to_result()
}
}