Skip to content

Commit 9f23150

Browse files
committed
uefi: introduce types MemoryMapOwned, MemoryMapRef, and MemoryMapRefMut
This provides API users all the flexibility they need. The main motivation for the addition is that one can use a chunk of memory in a kernel (provided by a bootloader) and parse it as EFI memory map. The main motivation for the specific implementation (via traits) is code reduction.
1 parent a2b5544 commit 9f23150

File tree

3 files changed

+135
-131
lines changed

3 files changed

+135
-131
lines changed

uefi-test-runner/src/boot/memory.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use uefi::table::boot::{AllocateType, BootServices, MemoryType};
1+
use uefi::table::boot::{AllocateType, BootServices, MemoryMap, MemoryMapMut, MemoryType};
22

33
use alloc::vec::Vec;
44

uefi-test-runner/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use uefi::prelude::*;
1212
use uefi::proto::console::serial::Serial;
1313
use uefi::proto::device_path::build::{self, DevicePathBuilder};
1414
use uefi::proto::device_path::messaging::Vendor;
15-
use uefi::table::boot::MemoryType;
15+
use uefi::table::boot::{MemoryMap, MemoryType};
1616
use uefi::{print, println, Result};
1717

1818
mod boot;

uefi/src/table/boot.rs

Lines changed: 133 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use core::{ptr, slice};
1818

1919
#[cfg(feature = "alloc")]
2020
use alloc::vec::Vec;
21+
use core::fmt::Debug;
2122

2223
pub use uefi_raw::table::boot::{
2324
EventType, InterfaceType, MemoryAttribute, MemoryDescriptor, MemoryType, Tpl,
@@ -1723,18 +1724,6 @@ impl MemoryMapBackingMemory {
17231724
mmm.map_size + extra_size
17241725
}
17251726

1726-
/// Returns a raw pointer to the beginning of the allocation.
1727-
#[must_use]
1728-
pub fn as_ptr(&self) -> *const u8 {
1729-
self.0.as_ptr().cast()
1730-
}
1731-
1732-
/// Returns a mutable raw pointer to the beginning of the allocation.
1733-
#[must_use]
1734-
pub fn as_mut_ptr(&mut self) -> *mut u8 {
1735-
self.0.as_ptr().cast()
1736-
}
1737-
17381727
/// Returns a slice to the underlying memory.
17391728
#[must_use]
17401729
pub fn as_slice(&self) -> &[u8] {
@@ -1819,7 +1808,7 @@ impl MemoryMapMeta {
18191808
/// a low level.
18201809
///
18211810
/// [0]: https://github.com/tianocore/edk2/blob/7142e648416ff5d3eac6c6d607874805f5de0ca8/MdeModulePkg/Core/PiSmmCore/Page.c#L1059
1822-
pub trait MemoryMap: Index<usize, Output = MemoryDescriptor> {
1811+
pub trait MemoryMap: Debug {
18231812
// TODO also require IntoIterator?! :)
18241813

18251814
/// Returns the associated [`MemoryMapMeta`].
@@ -1861,7 +1850,7 @@ pub trait MemoryMap: Index<usize, Output = MemoryDescriptor> {
18611850

18621851
/// Extension to [`MemoryMap`] that adds mutable operations. This also includes
18631852
/// the ability to sort the memory map.
1864-
pub trait MemoryMapMut: MemoryMap + IndexMut<usize> {
1853+
pub trait MemoryMapMut: MemoryMap {
18651854
/// Returns a mutable reference to the [`MemoryDescriptor`] at the given
18661855
/// index, if present.
18671856
#[must_use]
@@ -1882,84 +1871,97 @@ pub trait MemoryMapMut: MemoryMap + IndexMut<usize> {
18821871

18831872
/// Sorts the memory map by physical address in place. This operation is
18841873
/// optional and should be invoked only once.
1885-
#[must_use]
18861874
fn sort(&mut self);
18871875

18881876
/// Returns a reference to the underlying memory.
18891877
///
18901878
/// # Safety
18911879
///
18921880
/// This is unsafe as there is a potential to create invalid entries.
1893-
unsafe fn buffer_mut(&self) -> &mut [u8];
1881+
unsafe fn buffer_mut(&mut self) -> &mut [u8];
18941882
}
18951883

1896-
/// An accessory to the memory map that can be either iterated or
1897-
/// indexed like an array.
1898-
///
1899-
/// A [`MemoryMapOwned`] is always associated with the unique [`MemoryMapKey`]
1900-
/// contained in the struct.
1901-
///
1902-
/// To iterate over the entries, call [`MemoryMapOwned::entries`]. To get a sorted
1903-
/// map, you manually have to call [`MemoryMapOwned::sort`] first.
1904-
///
1905-
/// ## UEFI pitfalls
1906-
/// **Please note** that when working with memory maps, the `entry_size` is
1907-
/// usually larger than `size_of::<MemoryDescriptor` [[0]]. So to be safe,
1908-
/// always use `entry_size` as step-size when interfacing with the memory map on
1909-
/// a low level.
1910-
///
1911-
/// [0]: https://github.com/tianocore/edk2/blob/7142e648416ff5d3eac6c6d607874805f5de0ca8/MdeModulePkg/Core/PiSmmCore/Page.c#L1059
1884+
/// Implementation of [`MemoryMap`] for the given buffer.
19121885
#[derive(Debug)]
1913-
pub struct MemoryMapOwned {
1914-
/// Backing memory, properly initialized at this point.
1915-
buf: MemoryMapBackingMemory,
1886+
pub struct MemoryMapRef<'a> {
1887+
buf: &'a [u8],
19161888
key: MemoryMapKey,
19171889
meta: MemoryMapMeta,
19181890
len: usize,
19191891
}
19201892

1921-
impl MemoryMapOwned {
1922-
/// Creates a [`MemoryMapOwned`] from the give initialized memory map behind
1923-
/// the buffer and the reported `desc_size` from UEFI.
1924-
pub(crate) fn from_initialized_mem(buf: MemoryMapBackingMemory, meta: MemoryMapMeta) -> Self {
1925-
assert!(meta.desc_size >= mem::size_of::<MemoryDescriptor>());
1926-
let len = meta.entry_count();
1927-
MemoryMapOwned {
1928-
key: MemoryMapKey(0),
1929-
buf,
1930-
meta,
1931-
len,
1893+
impl<'a> MemoryMap for MemoryMapRef<'a> {
1894+
fn meta(&self) -> MemoryMapMeta {
1895+
self.meta
1896+
}
1897+
1898+
fn key(&self) -> MemoryMapKey {
1899+
self.key
1900+
}
1901+
1902+
fn len(&self) -> usize {
1903+
self.len
1904+
}
1905+
1906+
fn buffer(&self) -> &[u8] {
1907+
self.buf
1908+
}
1909+
1910+
fn entries(&self) -> MemoryMapIter<'_> {
1911+
MemoryMapIter {
1912+
memory_map: self,
1913+
index: 0,
19321914
}
19331915
}
1916+
}
19341917

1935-
#[cfg(test)]
1936-
fn from_raw(buf: &mut [u8], desc_size: usize) -> Self {
1937-
let mem = MemoryMapBackingMemory::from_slice(buf);
1938-
Self::from_initialized_mem(
1939-
mem,
1940-
MemoryMapMeta {
1941-
map_size: buf.len(),
1942-
desc_size,
1943-
map_key: MemoryMapKey(0),
1944-
desc_version: MemoryDescriptor::VERSION,
1945-
},
1946-
)
1918+
/// Implementation of [`MemoryMapMut`] for the given buffer.
1919+
#[derive(Debug)]
1920+
pub struct MemoryMapRefMut<'a> {
1921+
buf: &'a mut [u8],
1922+
key: MemoryMapKey,
1923+
meta: MemoryMapMeta,
1924+
len: usize,
1925+
}
1926+
1927+
impl<'a> MemoryMap for MemoryMapRefMut<'a> {
1928+
fn meta(&self) -> MemoryMapMeta {
1929+
self.meta
19471930
}
19481931

1949-
#[must_use]
1950-
/// Returns the unique [`MemoryMapKey`] associated with the memory map.
1951-
pub fn key(&self) -> MemoryMapKey {
1932+
fn key(&self) -> MemoryMapKey {
19521933
self.key
19531934
}
19541935

1955-
/// Sorts the memory map by physical address in place.
1956-
/// This operation is optional and should be invoked only once.
1957-
pub fn sort(&mut self) {
1936+
fn len(&self) -> usize {
1937+
self.len
1938+
}
1939+
1940+
fn buffer(&self) -> &[u8] {
1941+
self.buf
1942+
}
1943+
1944+
fn entries(&self) -> MemoryMapIter<'_> {
1945+
MemoryMapIter {
1946+
memory_map: self,
1947+
index: 0,
1948+
}
1949+
}
1950+
}
1951+
1952+
impl<'a> MemoryMapMut for MemoryMapRefMut<'a> {
1953+
fn sort(&mut self) {
19581954
unsafe {
19591955
self.qsort(0, self.len - 1);
19601956
}
19611957
}
19621958

1959+
unsafe fn buffer_mut(&mut self) -> &mut [u8] {
1960+
self.buf
1961+
}
1962+
}
1963+
1964+
impl<'a> MemoryMapRefMut<'a> {
19631965
/// Hoare partition scheme for quicksort.
19641966
/// Must be called with `low` and `high` being indices within bounds.
19651967
unsafe fn qsort(&mut self, low: usize, high: usize) {
@@ -2021,96 +2023,101 @@ impl MemoryMapOwned {
20212023
let elem = unsafe { &*self.buf.as_ptr().add(offset).cast::<MemoryDescriptor>() };
20222024
elem.phys_start
20232025
}
2026+
}
20242027

2025-
/// Returns an [`MemoryMapIter`] emitting [`MemoryDescriptor`]s.
2026-
///
2027-
/// To get a sorted map, call [`MemoryMapOwned::sort`] first.
2028-
///
2029-
/// # UEFI pitfalls
2030-
/// Currently, only the descriptor version specified in
2031-
/// [`MemoryDescriptor`] is supported. This is going to change if the UEFI
2032-
/// spec ever introduces a new memory descriptor version.
2033-
#[must_use]
2034-
pub fn entries(&self) -> MemoryMapIter {
2035-
MemoryMapIter {
2036-
memory_map: self,
2037-
index: 0,
2038-
}
2039-
}
2028+
/// Implementation of [`MemoryMapMut`] that owns the buffer on the UEFI heap.
2029+
#[derive(Debug)]
2030+
pub struct MemoryMapOwned {
2031+
/// Backing memory, properly initialized at this point.
2032+
buf: MemoryMapBackingMemory,
2033+
key: MemoryMapKey,
2034+
meta: MemoryMapMeta,
2035+
len: usize,
2036+
}
20402037

2041-
/// Returns a reference to the [`MemoryDescriptor`] at `index` or `None` if out of bounds.
2042-
#[must_use]
2043-
pub fn get(&self, index: usize) -> Option<&MemoryDescriptor> {
2044-
if index >= self.len {
2045-
return None;
2038+
impl MemoryMapOwned {
2039+
/// Creates a [`MemoryMapOwned`] from the give initialized memory map behind
2040+
/// the buffer and the reported `desc_size` from UEFI.
2041+
pub(crate) fn from_initialized_mem(buf: MemoryMapBackingMemory, meta: MemoryMapMeta) -> Self {
2042+
assert!(meta.desc_size >= mem::size_of::<MemoryDescriptor>());
2043+
let len = meta.entry_count();
2044+
MemoryMapOwned {
2045+
key: MemoryMapKey(0),
2046+
buf,
2047+
meta,
2048+
len,
20462049
}
2050+
}
20472051

2048-
let desc = unsafe {
2049-
&*self
2050-
.buf
2051-
.as_ptr()
2052-
.add(self.meta.desc_size * index)
2053-
.cast::<MemoryDescriptor>()
2054-
};
2052+
#[cfg(test)]
2053+
fn from_raw(buf: &mut [u8], desc_size: usize) -> Self {
2054+
let mem = MemoryMapBackingMemory::from_slice(buf);
2055+
Self::from_initialized_mem(
2056+
mem,
2057+
MemoryMapMeta {
2058+
map_size: buf.len(),
2059+
desc_size,
2060+
map_key: MemoryMapKey(0),
2061+
desc_version: MemoryDescriptor::VERSION,
2062+
},
2063+
)
2064+
}
2065+
}
20552066

2056-
Some(desc)
2067+
impl MemoryMap for MemoryMapOwned {
2068+
fn meta(&self) -> MemoryMapMeta {
2069+
self.meta
20572070
}
20582071

2059-
/// Returns a mut reference to the [`MemoryDescriptor`] at `index` or `None` if out of bounds.
2060-
#[must_use]
2061-
pub fn get_mut(&mut self, index: usize) -> Option<&mut MemoryDescriptor> {
2062-
if index >= self.len {
2063-
return None;
2064-
}
2072+
fn key(&self) -> MemoryMapKey {
2073+
self.key
2074+
}
20652075

2066-
let desc = unsafe {
2067-
&mut *self
2068-
.buf
2069-
.as_mut_ptr()
2070-
.add(self.meta.desc_size * index)
2071-
.cast::<MemoryDescriptor>()
2072-
};
2076+
fn len(&self) -> usize {
2077+
self.len
2078+
}
20732079

2074-
Some(desc)
2080+
fn buffer(&self) -> &[u8] {
2081+
self.buf.as_slice()
20752082
}
20762083

2077-
/// Provides access to the raw memory map.
2078-
///
2079-
/// This is for example useful if you want to embed the memory map into
2080-
/// another data structure, such as a Multiboot2 boot information.
2081-
#[must_use]
2082-
pub fn as_raw(&self) -> (&[u8], MemoryMapMeta) {
2083-
(self.buf.as_slice(), self.meta)
2084+
fn entries(&self) -> MemoryMapIter<'_> {
2085+
MemoryMapIter {
2086+
memory_map: self,
2087+
index: 0,
2088+
}
20842089
}
20852090
}
20862091

2087-
impl core::ops::Index<usize> for MemoryMapOwned {
2088-
type Output = MemoryDescriptor;
2089-
2090-
fn index(&self, index: usize) -> &Self::Output {
2091-
self.get(index).unwrap()
2092+
impl MemoryMapMut for MemoryMapOwned {
2093+
fn sort(&mut self) {
2094+
let mut reference = MemoryMapRefMut {
2095+
buf: self.buf.as_mut_slice(),
2096+
key: self.key,
2097+
meta: self.meta,
2098+
len: self.len,
2099+
};
2100+
reference.sort();
20922101
}
2093-
}
20942102

2095-
impl core::ops::IndexMut<usize> for MemoryMapOwned {
2096-
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
2097-
self.get_mut(index).unwrap()
2103+
unsafe fn buffer_mut(&mut self) -> &mut [u8] {
2104+
self.buf.as_mut_slice()
20982105
}
20992106
}
21002107

21012108
/// An iterator of [`MemoryDescriptor`]. The underlying memory map is always
21022109
/// associated with a unique [`MemoryMapKey`].
21032110
#[derive(Debug, Clone)]
21042111
pub struct MemoryMapIter<'a> {
2105-
memory_map: &'a MemoryMapOwned,
2112+
memory_map: &'a dyn MemoryMap,
21062113
index: usize,
21072114
}
21082115

21092116
impl<'a> Iterator for MemoryMapIter<'a> {
21102117
type Item = &'a MemoryDescriptor;
21112118

21122119
fn size_hint(&self) -> (usize, Option<usize>) {
2113-
let sz = self.memory_map.len - self.index;
2120+
let sz = self.memory_map.len() - self.index;
21142121

21152122
(sz, Some(sz))
21162123
}
@@ -2126,7 +2133,7 @@ impl<'a> Iterator for MemoryMapIter<'a> {
21262133

21272134
impl ExactSizeIterator for MemoryMapIter<'_> {
21282135
fn len(&self) -> usize {
2129-
self.memory_map.len
2136+
self.memory_map.len()
21302137
}
21312138
}
21322139

@@ -2257,12 +2264,9 @@ pub struct ProtocolSearchKey(NonNull<c_void>);
22572264

22582265
#[cfg(test)]
22592266
mod tests_mmap_artificial {
2267+
use super::*;
22602268
use core::mem::{size_of, size_of_val};
22612269

2262-
use crate::table::boot::{MemoryAttribute, MemoryMapOwned, MemoryType};
2263-
2264-
use super::{MemoryDescriptor, MemoryMapIter};
2265-
22662270
fn buffer_to_map(buffer: &mut [MemoryDescriptor]) -> MemoryMapOwned {
22672271
let byte_buffer = {
22682272
unsafe {

0 commit comments

Comments
 (0)