use crate::data_types::PhysicalAddress;
use crate::mem::memory_map::MemoryType;
use crate::proto::unsafe_protocol;
use crate::{Handle, Result, Status, StatusExt};
use core::ffi::c_void;
use uefi_raw::table::boot::AllocateType;
pub use crate::proto::dma::{DmaBuffer, Mapping};
pub use uefi_raw::protocol::iommu::{
EdkiiIommuAccess, EdkiiIommuAttribute, EdkiiIommuOperation, EdkiiIommuProtocol,
};
#[derive(Debug)]
#[repr(transparent)]
#[unsafe_protocol(EdkiiIommuProtocol::GUID)]
pub struct Iommu(EdkiiIommuProtocol);
impl Iommu {
#[must_use]
pub const fn revision(&self) -> u64 {
self.0.revision
}
pub fn set_attribute(
&self,
device_handle: Handle,
mapping: &mut Mapping<'_, '_>,
iommu_access: EdkiiIommuAccess,
) -> Result {
let mapping_raw = mapping.as_mut_ptr();
let status = unsafe {
(self.0.set_attribute)(&self.0, device_handle.as_ptr(), mapping_raw, iommu_access)
};
status.to_result()
}
pub fn map<'iommu, 'buf>(
&'iommu self,
operation: EdkiiIommuOperation,
host_buffer: &'buf mut DmaBuffer<'iommu>,
number_of_bytes: usize,
) -> Result<(PhysicalAddress, Mapping<'iommu, 'buf>, usize)> {
if number_of_bytes > host_buffer.size() {
return Err(Status::BAD_BUFFER_SIZE.into());
}
let mut number_of_bytes = number_of_bytes;
let mut mapping_raw: *mut c_void = core::ptr::null_mut();
let mut device_address: u64 = 0;
let host_address: *mut c_void = host_buffer.as_mut_ptr();
let status = unsafe {
(self.0.map)(
&self.0,
operation,
host_address,
&mut number_of_bytes,
&mut device_address,
&mut mapping_raw,
)
};
status.to_result_with_val(|| {
let mapping = unsafe { Mapping::from_raw(mapping_raw, self, host_buffer) };
(device_address, mapping, number_of_bytes)
})
}
pub(crate) fn unmap_raw(&self, mapping: *mut c_void) -> Result {
let status = unsafe { (self.0.unmap)(&self.0, mapping) };
status.to_result()
}
pub fn allocate_buffer(
&self,
memory_type: MemoryType,
pages: usize,
attributes: EdkiiIommuAttribute,
) -> Result<DmaBuffer<'_>> {
let mut host_address: *mut c_void = core::ptr::null_mut();
let allocate_type = AllocateType::ANY_PAGES;
let status = unsafe {
(self.0.allocate_buffer)(
&self.0,
allocate_type,
memory_type,
pages,
&mut host_address,
attributes,
)
};
status.to_result_with_val(|| {
unsafe { DmaBuffer::from_raw(host_address, pages, self) }
})
}
pub(crate) fn free_buffer_raw(&self, ptr: *mut c_void, pages: usize) -> Result {
let status = unsafe { (self.0.free_buffer)(&self.0, pages, ptr) };
status.to_result()
}
}