acpi/
handler.rs

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