handler.rs 4.0 KB

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