handler.rs 4.0 KB

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