| use core::{fmt, ops::Deref, ptr::NonNull}; | |
| /// Describes a physical mapping created by `AcpiHandler::map_physical_region` and unmapped by | |
| /// `AcpiHandler::unmap_physical_region`. The region mapped must be at least `size_of::<T>()` | |
| /// bytes, but may be bigger. | |
| /// | |
| /// See `PhysicalMapping::new` for the meaning of each field. | |
| pub struct PhysicalMapping<H, T> | |
| where | |
| H: AcpiHandler, | |
| { | |
| physical_start: usize, | |
| virtual_start: NonNull<T>, | |
| region_length: usize, // Can be equal or larger than size_of::<T>() | |
| mapped_length: usize, // Differs from `region_length` if padding is added for alignment | |
| handler: H, | |
| } | |
| impl<H, T> fmt::Debug for PhysicalMapping<H, T> | |
| where | |
| H: AcpiHandler + fmt::Debug, | |
| { | |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| f.debug_struct("PhysicalMapping") | |
| .field("physical_start", &self.physical_start) | |
| .field("virtual_start", &self.virtual_start) | |
| .field("region_length", &self.region_length) | |
| .field("mapped_length", &self.mapped_length) | |
| .field("handler", &self.handler) | |
| .finish() | |
| } | |
| } | |
| impl<H, T> PhysicalMapping<H, T> | |
| where | |
| H: AcpiHandler, | |
| { | |
| /// Construct a new `PhysicalMapping`. | |
| /// | |
| /// - `physical_start` should be the physical address of the structure to be mapped. | |
| /// - `virtual_start` should be the corresponding virtual address of that structure. It may differ from the | |
| /// start of the region mapped due to requirements of the paging system. It must be a valid, non-null | |
| /// pointer. | |
| /// - `region_length` should be the number of bytes requested to be mapped. It must be equal to or larger than | |
| /// `size_of::<T>()`. | |
| /// - `mapped_length` should be the number of bytes mapped to fulfill the request. It may be equal to or larger | |
| /// than `region_length`, due to requirements of the paging system or other reasoning. | |
| /// - `handler` should be the same `AcpiHandler` that created the mapping. When the `PhysicalMapping` is | |
| /// dropped, it will be used to unmap the structure. | |
| pub unsafe fn new( | |
| physical_start: usize, | |
| virtual_start: NonNull<T>, | |
| region_length: usize, | |
| mapped_length: usize, | |
| handler: H, | |
| ) -> Self { | |
| Self { physical_start, virtual_start, region_length, mapped_length, handler } | |
| } | |
| pub fn physical_start(&self) -> usize { | |
| self.physical_start | |
| } | |
| pub fn virtual_start(&self) -> NonNull<T> { | |
| self.virtual_start | |
| } | |
| pub fn region_length(&self) -> usize { | |
| self.region_length | |
| } | |
| pub fn mapped_length(&self) -> usize { | |
| self.mapped_length | |
| } | |
| pub fn handler(&self) -> &H { | |
| &self.handler | |
| } | |
| } | |
| unsafe impl<H: AcpiHandler + Send, T: Send> Send for PhysicalMapping<H, T> {} | |
| impl<H, T> Deref for PhysicalMapping<H, T> | |
| where | |
| H: AcpiHandler, | |
| { | |
| type Target = T; | |
| fn deref(&self) -> &T { | |
| unsafe { self.virtual_start.as_ref() } | |
| } | |
| } | |
| impl<H, T> Drop for PhysicalMapping<H, T> | |
| where | |
| H: AcpiHandler, | |
| { | |
| fn drop(&mut self) { | |
| H::unmap_physical_region(self) | |
| } | |
| } | |
| /// An implementation of this trait must be provided to allow `acpi` to access platform-specific | |
| /// functionality, such as mapping regions of physical memory. You are free to implement these | |
| /// however you please, as long as they conform to the documentation of each function. The handler is stored in | |
| /// every `PhysicalMapping` so it's able to unmap itself when dropped, so this type needs to be something you can | |
| /// clone/move about freely (e.g. a reference, wrapper over `Rc`, marker struct, etc.). | |
| pub trait AcpiHandler: Clone { | |
| /// Given a physical address and a size, map a region of physical memory that contains `T` (note: the passed | |
| /// size may be larger than `size_of::<T>()`). The address is not neccessarily page-aligned, so the | |
| /// implementation may need to map more than `size` bytes. The virtual address the region is mapped to does not | |
| /// matter, as long as it is accessible to `acpi`. | |
| /// | |
| /// See the documentation on `PhysicalMapping::new` for an explanation of each field on the `PhysicalMapping` | |
| /// return type. | |
| /// | |
| /// ## Safety | |
| /// | |
| /// - `physical_address` must point to a valid `T` in physical memory. | |
| /// - `size` must be at least `size_of::<T>()`. | |
| unsafe fn map_physical_region<T>(&self, physical_address: usize, size: usize) -> PhysicalMapping<Self, T>; | |
| /// Unmap the given physical mapping. This is called when a `PhysicalMapping` is dropped, you should **not** manually call this. | |
| /// | |
| /// Note: A reference to the handler used to construct `region` can be acquired by calling [`PhysicalMapping::handler`]. | |
| fn unmap_physical_region<T>(region: &PhysicalMapping<Self, T>); | |
| } | |
| #[cfg(test)] | |
| mod tests { | |
| use super::*; | |
| #[test] | |
| #[allow(dead_code)] | |
| fn test_send_sync() { | |
| // verify that PhysicalMapping implements Send and Sync | |
| fn test_send_sync<T: Send>() {} | |
| fn caller<H: AcpiHandler + Send, T: Send>() { | |
| test_send_sync::<PhysicalMapping<H, T>>(); | |
| } | |
| } | |
| } |