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