2
0
Эх сурвалжийг харах

Store the handler in each PhysicalMapping so we can unmap on drop

This is something we've wanted for a while, as it removes the human error
of forgetting to unmap a physical mapping. Having to store the `H` does make
some things a bit janky, but we seem to have been able to work around it
so far.
Isaac Woods 4 жил өмнө
parent
commit
7d6653de7e
1 өөрчлөгдсөн 49 нэмэгдсэн , 14 устгасан
  1. 49 14
      acpi/src/handler.rs

+ 49 - 14
acpi/src/handler.rs

@@ -1,16 +1,42 @@
-use core::{ops::Deref, ptr::NonNull};
+use core::{mem, 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.
-pub struct PhysicalMapping<T> {
+pub struct PhysicalMapping<H, T>
+where
+    H: AcpiHandler,
+{
     pub physical_start: usize,
     pub virtual_start: NonNull<T>,
     pub region_length: usize, // Can be equal or larger than size_of::<T>()
     pub mapped_length: usize, // Differs from `region_length` if padding is added for alignment
+    /*
+     * NOTE: we store an `Option<H>` here to make the implementation of `coerce_type` easier - if we can find a
+     * better way, that would be better. Other than that, this should never be `None`, so is fine to unwrap.
+     */
+    handler: Option<H>,
 }
 
-impl<T> Deref for PhysicalMapping<T> {
+impl<H, T> PhysicalMapping<H, T>
+where
+    H: AcpiHandler,
+{
+    pub fn new(
+        physical_start: usize,
+        virtual_start: NonNull<T>,
+        region_length: usize,
+        mapped_length: usize,
+        handler: H,
+    ) -> PhysicalMapping<H, T> {
+        PhysicalMapping { physical_start, virtual_start, region_length, mapped_length, handler: Some(handler) }
+    }
+}
+
+impl<H, T> Deref for PhysicalMapping<H, T>
+where
+    H: AcpiHandler,
+{
     type Target = T;
 
     fn deref(&self) -> &T {
@@ -18,18 +44,27 @@ impl<T> Deref for PhysicalMapping<T> {
     }
 }
 
+impl<H, T> Drop for PhysicalMapping<H, T>
+where
+    H: AcpiHandler,
+{
+    fn drop(&mut self) {
+        self.handler.as_ref().unwrap().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.
-pub trait AcpiHandler {
-    /// Given a starting physical address and a size, map a region of physical memory that contains
-    /// a `T` (but may be bigger than `size_of::<T>()`). The address doesn't have to be
-    /// page-aligned, so the implementation may have to add padding to either end. The given
-    /// size must be greater or equal to the size of a `T`. The virtual address the memory is
-    /// mapped to does not matter, as long as it is accessible from `acpi`.
-    unsafe fn map_physical_region<T>(&mut self, physical_address: usize, size: usize) -> PhysicalMapping<T>;
+/// 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: Sized {
+    /// 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`.
+    unsafe fn map_physical_region<T>(&self, physical_address: usize, size: usize) -> PhysicalMapping<Self, T>;
 
-    /// Unmap the given physical mapping. Safe because we consume the mapping, and so it can't be
-    /// used after being passed to this function.
-    fn unmap_physical_region<T>(&mut self, region: PhysicalMapping<T>);
+    /// Unmap the given physical mapping. This is called when a `PhysicalMapping` is dropped.
+    fn unmap_physical_region<T>(&self, region: &PhysicalMapping<Self, T>);
 }