|
| 1 | +//! Module for the traits [`MemoryMap`] and [`MemoryMapMut`]. |
| 2 | +
|
| 3 | +use super::*; |
| 4 | +use core::fmt::Debug; |
| 5 | +use core::ops::{Index, IndexMut}; |
| 6 | + |
| 7 | +/// An accessory to the UEFI memory map and associated metadata that can be |
| 8 | +/// either iterated or indexed like an array. |
| 9 | +/// |
| 10 | +/// A [`MemoryMap`] is always associated with the unique [`MemoryMapKey`] |
| 11 | +/// bundled with the map. |
| 12 | +/// |
| 13 | +/// To iterate over the entries, call [`MemoryMap::entries`]. |
| 14 | +/// |
| 15 | +/// ## UEFI pitfalls |
| 16 | +/// Note that a MemoryMap can quickly become outdated, as soon as any explicit |
| 17 | +/// or hidden allocation happens. |
| 18 | +/// |
| 19 | +/// As soon as boot services are excited, all previous obtained memory maps must |
| 20 | +/// be considered as outdated, except if the [`MemoryMapKey`] equals the one |
| 21 | +/// returned by `exit_boot_services()`. |
| 22 | +/// |
| 23 | +/// **Please note** that when working with memory maps, the `entry_size` is |
| 24 | +/// usually larger than `size_of::<MemoryDescriptor` [[0]]. So to be safe, |
| 25 | +/// always use `entry_size` as step-size when interfacing with the memory map on |
| 26 | +/// a low level. |
| 27 | +/// |
| 28 | +/// [0]: https://github.com/tianocore/edk2/blob/7142e648416ff5d3eac6c6d607874805f5de0ca8/MdeModulePkg/Core/PiSmmCore/Page.c#L1059 |
| 29 | +pub trait MemoryMap: Debug + Index<usize, Output = MemoryDescriptor> { |
| 30 | + /// Returns the associated [`MemoryMapMeta`]. |
| 31 | + #[must_use] |
| 32 | + fn meta(&self) -> MemoryMapMeta; |
| 33 | + |
| 34 | + /// Returns the associated [`MemoryMapKey`]. |
| 35 | + #[must_use] |
| 36 | + fn key(&self) -> MemoryMapKey; |
| 37 | + |
| 38 | + /// Returns the number of keys in the map. |
| 39 | + #[must_use] |
| 40 | + fn len(&self) -> usize; |
| 41 | + |
| 42 | + /// Returns if the memory map is empty. |
| 43 | + #[must_use] |
| 44 | + fn is_empty(&self) -> bool { |
| 45 | + self.len() == 0 |
| 46 | + } |
| 47 | + |
| 48 | + /// Returns a reference to the [`MemoryDescriptor`] at the given index, if |
| 49 | + /// present. |
| 50 | + #[must_use] |
| 51 | + fn get(&self, index: usize) -> Option<&MemoryDescriptor> { |
| 52 | + if index >= self.len() { |
| 53 | + None |
| 54 | + } else { |
| 55 | + let offset = index * self.meta().desc_size; |
| 56 | + unsafe { |
| 57 | + self.buffer() |
| 58 | + .as_ptr() |
| 59 | + .add(offset) |
| 60 | + .cast::<MemoryDescriptor>() |
| 61 | + .as_ref() |
| 62 | + } |
| 63 | + } |
| 64 | + } |
| 65 | + |
| 66 | + /// Returns a reference to the underlying memory. |
| 67 | + fn buffer(&self) -> &[u8]; |
| 68 | + |
| 69 | + /// Returns an Iterator of type [`MemoryMapIter`]. |
| 70 | + fn entries(&self) -> MemoryMapIter<'_>; |
| 71 | +} |
| 72 | + |
| 73 | +/// Extension to [`MemoryMap`] that adds mutable operations. This also includes |
| 74 | +/// the ability to sort the memory map. |
| 75 | +pub trait MemoryMapMut: MemoryMap + IndexMut<usize> { |
| 76 | + /// Returns a mutable reference to the [`MemoryDescriptor`] at the given |
| 77 | + /// index, if present. |
| 78 | + #[must_use] |
| 79 | + fn get_mut(&mut self, index: usize) -> Option<&mut MemoryDescriptor> { |
| 80 | + if index >= self.len() { |
| 81 | + None |
| 82 | + } else { |
| 83 | + let offset = index * self.meta().desc_size; |
| 84 | + unsafe { |
| 85 | + self.buffer_mut() |
| 86 | + .as_mut_ptr() |
| 87 | + .add(offset) |
| 88 | + .cast::<MemoryDescriptor>() |
| 89 | + .as_mut() |
| 90 | + } |
| 91 | + } |
| 92 | + } |
| 93 | + |
| 94 | + /// Sorts the memory map by physical address in place. This operation is |
| 95 | + /// optional and should be invoked only once. |
| 96 | + fn sort(&mut self); |
| 97 | + |
| 98 | + /// Returns a reference to the underlying memory. |
| 99 | + /// |
| 100 | + /// # Safety |
| 101 | + /// |
| 102 | + /// This is unsafe as there is a potential to create invalid entries. |
| 103 | + unsafe fn buffer_mut(&mut self) -> &mut [u8]; |
| 104 | +} |
0 commit comments