1 use core::{ops::Deref, ptr::NonNull}; 2 3 /// Describes a physical mapping created by `AcpiHandler::map_physical_region` and unmapped by 4 /// `AcpiHandler::unmap_physical_region`. The region mapped must be at least `size_of::<T>()` 5 /// bytes, but may be bigger. 6 /// 7 /// See `PhysicalMapping::new` for the meaning of each field. 8 #[derive(Debug)] 9 pub struct PhysicalMapping<H, T> 10 where 11 H: AcpiHandler, 12 { 13 physical_start: usize, 14 virtual_start: NonNull<T>, 15 region_length: usize, // Can be equal or larger than size_of::<T>() 16 mapped_length: usize, // Differs from `region_length` if padding is added for alignment 17 handler: H, 18 } 19 20 impl<H, T> PhysicalMapping<H, T> 21 where 22 H: AcpiHandler, 23 { 24 /// Construct a new `PhysicalMapping`. 25 /// 26 /// - `physical_start` should be the physical address of the structure to be mapped. 27 /// - `virtual_start` should be the corresponding virtual address of that structure. It may differ from the 28 /// start of the region mapped due to requirements of the paging system. It must be a valid, non-null 29 /// pointer. 30 /// - `region_length` should be the number of bytes requested to be mapped. It must be equal to or larger than 31 /// `size_of::<T>()`. 32 /// - `mapped_length` should be the number of bytes mapped to fulfill the request. It may be equal to or larger 33 /// than `region_length`, due to requirements of the paging system or other reasoning. 34 /// - `handler` should be the same `AcpiHandler` that created the mapping. When the `PhysicalMapping` is 35 /// dropped, it will be used to unmap the structure. new( physical_start: usize, virtual_start: NonNull<T>, region_length: usize, mapped_length: usize, handler: H, ) -> Self36 pub unsafe fn new( 37 physical_start: usize, 38 virtual_start: NonNull<T>, 39 region_length: usize, 40 mapped_length: usize, 41 handler: H, 42 ) -> Self { 43 Self { physical_start, virtual_start, region_length, mapped_length, handler } 44 } 45 physical_start(&self) -> usize46 pub fn physical_start(&self) -> usize { 47 self.physical_start 48 } 49 virtual_start(&self) -> NonNull<T>50 pub fn virtual_start(&self) -> NonNull<T> { 51 self.virtual_start 52 } 53 region_length(&self) -> usize54 pub fn region_length(&self) -> usize { 55 self.region_length 56 } 57 mapped_length(&self) -> usize58 pub fn mapped_length(&self) -> usize { 59 self.mapped_length 60 } 61 handler(&self) -> &H62 pub fn handler(&self) -> &H { 63 &self.handler 64 } 65 } 66 67 unsafe impl<H: AcpiHandler + Send, T: Send> Send for PhysicalMapping<H, T> {} 68 69 impl<H, T> Deref for PhysicalMapping<H, T> 70 where 71 H: AcpiHandler, 72 { 73 type Target = T; 74 deref(&self) -> &T75 fn deref(&self) -> &T { 76 unsafe { self.virtual_start.as_ref() } 77 } 78 } 79 80 impl<H, T> Drop for PhysicalMapping<H, T> 81 where 82 H: AcpiHandler, 83 { drop(&mut self)84 fn drop(&mut self) { 85 H::unmap_physical_region(self) 86 } 87 } 88 89 /// An implementation of this trait must be provided to allow `acpi` to access platform-specific 90 /// functionality, such as mapping regions of physical memory. You are free to implement these 91 /// however you please, as long as they conform to the documentation of each function. The handler is stored in 92 /// every `PhysicalMapping` so it's able to unmap itself when dropped, so this type needs to be something you can 93 /// clone/move about freely (e.g. a reference, wrapper over `Rc`, marker struct, etc.). 94 pub trait AcpiHandler: Clone { 95 /// Given a physical address and a size, map a region of physical memory that contains `T` (note: the passed 96 /// size may be larger than `size_of::<T>()`). The address is not neccessarily page-aligned, so the 97 /// implementation may need to map more than `size` bytes. The virtual address the region is mapped to does not 98 /// matter, as long as it is accessible to `acpi`. 99 /// 100 /// See the documentation on `PhysicalMapping::new` for an explanation of each field on the `PhysicalMapping` 101 /// return type. 102 /// 103 /// ## Safety 104 /// 105 /// - `physical_address` must point to a valid `T` in physical memory. 106 /// - `size` must be at least `size_of::<T>()`. map_physical_region<T>(&self, physical_address: usize, size: usize) -> PhysicalMapping<Self, T>107 unsafe fn map_physical_region<T>(&self, physical_address: usize, size: usize) -> PhysicalMapping<Self, T>; 108 109 /// Unmap the given physical mapping. This is called when a `PhysicalMapping` is dropped, you should **not** manually call this. 110 /// 111 /// Note: A reference to the handler used to construct `region` can be acquired by calling [`PhysicalMapping::handler`]. unmap_physical_region<T>(region: &PhysicalMapping<Self, T>)112 fn unmap_physical_region<T>(region: &PhysicalMapping<Self, T>); 113 } 114 115 #[cfg(test)] 116 mod tests { 117 use super::*; 118 119 #[test] 120 #[allow(dead_code)] test_send_sync()121 fn test_send_sync() { 122 // verify that PhysicalMapping implements Send and Sync 123 fn test_send_sync<T: Send>() {} 124 fn caller<H: AcpiHandler + Send, T: Send>() { 125 test_send_sync::<PhysicalMapping<H, T>>(); 126 } 127 } 128 } 129