Skip to content

Commit f2ace36

Browse files
Merge pull request #1263 from phip1611/memory-map
Finalize memory_map module refactoring
2 parents 990a2c0 + daeaaf5 commit f2ace36

File tree

6 files changed

+288
-63
lines changed

6 files changed

+288
-63
lines changed

uefi/CHANGELOG.md

+8-4
Original file line numberDiff line numberDiff line change
@@ -11,24 +11,28 @@
1111
- `PcrEvent`/`PcrEventInputs` impl `Align`, `Eq`, and `PartialEq`.
1212
- Added `PcrEvent::new_in_box` and `PcrEventInputs::new_in_box`.
1313
- `VariableKey` impls `Clone`, `Eq`, `PartialEq`, `Ord`, `PartialOrd`, and `Hash`.
14+
- The traits `MemoryMap` and `MemoryMapMut` have been introduced together with
15+
the implementations `MemoryMapRef`, `MemoryMapRefMut`, and `MemoryMapOwned`.
16+
This comes with some changes. Read below. We recommend to directly use the
17+
implementations instead of the traits.
1418

1519
## Changed
1620
- **Breaking:** `uefi::helpers::init` no longer takes an argument.
1721
- The lifetime of the `SearchType` returned from
1822
`BootServices::register_protocol_notify` is now tied to the protocol GUID.
19-
- The traits `MemoryMap` and `MemoryMapMut` have been introduced together with
20-
the implementations `MemoryMapRef`, `MemoryMapRefMut`, and `MemoryMapOwned`.
2123
The old `MemoryMap` was renamed to `MemoryMapOwned`.
2224
- `pub fn memory_map(&self, mt: MemoryType) -> Result<MemoryMap>` now returns
2325
a `MemoryMapOwned`.
2426
- **Breaking:** `PcrEvent::new_in_buffer` and `PcrEventInputs::new_in_buffer`
2527
now take an initialized buffer (`[u8`] instead of `[MaybeUninit<u8>]`), and if
2628
the buffer is too small the required size is returned in the error data.
27-
- **Breaking** Exports of Memory Map-related types from `uefi::table::boot` are
29+
- **Breaking:** The type `MemoryMap` was renamed to `MemoryMapOwned`. `MemoryMap`
30+
is now a trait. Read the [documentation](https://docs.rs/uefi/latest/uefi/) of the
31+
`uefi > mem > memory_map` module to learn more.
32+
- **Breaking:** Exports of Memory Map-related types from `uefi::table::boot` are
2833
now removed. Use `uefi::mem::memory_map` instead. The patch you have to apply
2934
to the `use` statements of your code might look as follows:
3035
```diff
31-
1c1,2
3236
< use uefi::table::boot::{BootServices, MemoryMap, MemoryMapMut, MemoryType};
3337
---
3438
> use uefi::mem::memory_map::{MemoryMap, MemoryMapMut, MemoryType};

uefi/src/mem/memory_map/api.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ pub trait MemoryMap: Debug + Index<usize, Output = MemoryDescriptor> {
3131
#[must_use]
3232
fn meta(&self) -> MemoryMapMeta;
3333

34-
/// Returns the associated [`MemoryMapKey`].
34+
/// Returns the associated [`MemoryMapKey`]. Note that this isn't
35+
/// necessarily the key of the latest valid UEFI memory map.
3536
#[must_use]
3637
fn key(&self) -> MemoryMapKey;
3738

@@ -64,10 +65,28 @@ pub trait MemoryMap: Debug + Index<usize, Output = MemoryDescriptor> {
6465
}
6566

6667
/// Returns a reference to the underlying memory.
68+
#[must_use]
6769
fn buffer(&self) -> &[u8];
6870

6971
/// Returns an Iterator of type [`MemoryMapIter`].
72+
#[must_use]
7073
fn entries(&self) -> MemoryMapIter<'_>;
74+
75+
/// Returns if the underlying memory map is sorted regarding the physical
76+
/// address start.
77+
#[must_use]
78+
fn is_sorted(&self) -> bool {
79+
let iter = self.entries();
80+
let iter = iter.clone().zip(iter.skip(1));
81+
82+
for (curr, next) in iter {
83+
if next.phys_start < curr.phys_start {
84+
log::debug!("next.phys_start < curr.phys_start: curr={curr:?}, next={next:?}");
85+
return false;
86+
}
87+
}
88+
true
89+
}
7190
}
7291

7392
/// Extension to [`MemoryMap`] that adds mutable operations. This also includes

uefi/src/mem/memory_map/impl_.rs

+176-31
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,67 @@
33
44
use super::*;
55
use crate::table::system_table_boot;
6+
use core::fmt::{Debug, Display, Formatter};
67
use core::ops::{Index, IndexMut};
78
use core::ptr::NonNull;
89
use core::{mem, ptr};
910
use uefi_raw::PhysicalAddress;
1011

12+
/// Errors that may happen when constructing a [`MemoryMapRef`] or
13+
/// [`MemoryMapRefMut`].
14+
#[derive(Copy, Clone, Debug)]
15+
pub enum MemoryMapError {
16+
/// The buffer is not 8-byte aligned.
17+
Misaligned,
18+
/// The memory map size is invalid.
19+
InvalidSize,
20+
}
21+
22+
impl Display for MemoryMapError {
23+
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
24+
Debug::fmt(self, f)
25+
}
26+
}
27+
28+
#[cfg(feature = "unstable")]
29+
impl core::error::Error for MemoryMapError {}
30+
1131
/// Implementation of [`MemoryMap`] for the given buffer.
1232
#[derive(Debug)]
13-
#[allow(dead_code)] // TODO: github.com/rust-osdev/uefi-rs/issues/1247
1433
pub struct MemoryMapRef<'a> {
1534
buf: &'a [u8],
16-
key: MemoryMapKey,
1735
meta: MemoryMapMeta,
1836
len: usize,
1937
}
2038

39+
impl<'a> MemoryMapRef<'a> {
40+
/// Constructs a new [`MemoryMapRef`].
41+
///
42+
/// The underlying memory might contain an invalid/malformed memory map
43+
/// which can't be checked during construction of this type. The entry
44+
/// iterator might yield unexpected results.
45+
pub fn new(buffer: &'a [u8], meta: MemoryMapMeta) -> Result<Self, MemoryMapError> {
46+
if buffer.as_ptr().align_offset(8) != 0 {
47+
return Err(MemoryMapError::Misaligned);
48+
}
49+
if buffer.len() < meta.map_size {
50+
return Err(MemoryMapError::InvalidSize);
51+
}
52+
Ok(Self {
53+
buf: buffer,
54+
meta,
55+
len: meta.entry_count(),
56+
})
57+
}
58+
}
59+
2160
impl<'a> MemoryMap for MemoryMapRef<'a> {
2261
fn meta(&self) -> MemoryMapMeta {
2362
self.meta
2463
}
2564

2665
fn key(&self) -> MemoryMapKey {
27-
self.key
66+
self.meta.map_key
2867
}
2968

3069
fn len(&self) -> usize {
@@ -55,18 +94,38 @@ impl Index<usize> for MemoryMapRef<'_> {
5594
#[derive(Debug)]
5695
pub struct MemoryMapRefMut<'a> {
5796
buf: &'a mut [u8],
58-
key: MemoryMapKey,
5997
meta: MemoryMapMeta,
6098
len: usize,
6199
}
62100

101+
impl<'a> MemoryMapRefMut<'a> {
102+
/// Constructs a new [`MemoryMapRefMut`].
103+
///
104+
/// The underlying memory might contain an invalid/malformed memory map
105+
/// which can't be checked during construction of this type. The entry
106+
/// iterator might yield unexpected results.
107+
pub fn new(buffer: &'a mut [u8], meta: MemoryMapMeta) -> Result<Self, MemoryMapError> {
108+
if buffer.as_ptr().align_offset(8) != 0 {
109+
return Err(MemoryMapError::Misaligned);
110+
}
111+
if buffer.len() < meta.map_size {
112+
return Err(MemoryMapError::InvalidSize);
113+
}
114+
Ok(Self {
115+
buf: buffer,
116+
meta,
117+
len: meta.entry_count(),
118+
})
119+
}
120+
}
121+
63122
impl<'a> MemoryMap for MemoryMapRefMut<'a> {
64123
fn meta(&self) -> MemoryMapMeta {
65124
self.meta
66125
}
67126

68127
fn key(&self) -> MemoryMapKey {
69-
self.key
128+
self.meta.map_key
70129
}
71130

72131
fn len(&self) -> usize {
@@ -241,10 +300,12 @@ impl MemoryMapBackingMemory {
241300
Self(slice)
242301
}
243302

303+
/// INTERNAL, for unit tests.
304+
///
244305
/// Creates an instance from the provided memory, which is not necessarily
245306
/// on the UEFI heap.
246307
#[cfg(test)]
247-
fn from_slice(buffer: &mut [u8]) -> Self {
308+
pub(crate) fn from_slice(buffer: &mut [u8]) -> Self {
248309
let len = buffer.len();
249310
unsafe { Self::from_raw(buffer.as_mut_ptr(), len) }
250311
}
@@ -287,6 +348,10 @@ impl Drop for MemoryMapBackingMemory {
287348
log::error!("Failed to deallocate memory map: {e:?}");
288349
}
289350
} else {
351+
#[cfg(test)]
352+
log::debug!("Boot services are not available in unit tests.");
353+
354+
#[cfg(not(test))]
290355
log::debug!("Boot services are excited. Memory map won't be freed using the UEFI boot services allocator.");
291356
}
292357
}
@@ -297,37 +362,18 @@ impl Drop for MemoryMapBackingMemory {
297362
pub struct MemoryMapOwned {
298363
/// Backing memory, properly initialized at this point.
299364
pub(crate) buf: MemoryMapBackingMemory,
300-
pub(crate) key: MemoryMapKey,
301365
pub(crate) meta: MemoryMapMeta,
302366
pub(crate) len: usize,
303367
}
304368

305369
impl MemoryMapOwned {
306-
/// Creates a [`MemoryMapOwned`] from the give initialized memory map behind
307-
/// the buffer and the reported `desc_size` from UEFI.
370+
/// Creates a [`MemoryMapOwned`] from the given **initialized** memory map
371+
/// (stored inside the provided buffer) and the corresponding
372+
/// [`MemoryMapMeta`].
308373
pub(crate) fn from_initialized_mem(buf: MemoryMapBackingMemory, meta: MemoryMapMeta) -> Self {
309374
assert!(meta.desc_size >= mem::size_of::<MemoryDescriptor>());
310375
let len = meta.entry_count();
311-
MemoryMapOwned {
312-
key: MemoryMapKey(0),
313-
buf,
314-
meta,
315-
len,
316-
}
317-
}
318-
319-
#[cfg(test)]
320-
pub(super) fn from_raw(buf: &mut [u8], desc_size: usize) -> Self {
321-
let mem = MemoryMapBackingMemory::from_slice(buf);
322-
Self::from_initialized_mem(
323-
mem,
324-
MemoryMapMeta {
325-
map_size: buf.len(),
326-
desc_size,
327-
map_key: MemoryMapKey(0),
328-
desc_version: MemoryDescriptor::VERSION,
329-
},
330-
)
376+
MemoryMapOwned { buf, meta, len }
331377
}
332378
}
333379

@@ -337,7 +383,7 @@ impl MemoryMap for MemoryMapOwned {
337383
}
338384

339385
fn key(&self) -> MemoryMapKey {
340-
self.key
386+
self.meta.map_key
341387
}
342388

343389
fn len(&self) -> usize {
@@ -360,7 +406,6 @@ impl MemoryMapMut for MemoryMapOwned {
360406
fn sort(&mut self) {
361407
let mut reference = MemoryMapRefMut {
362408
buf: self.buf.as_mut_slice(),
363-
key: self.key,
364409
meta: self.meta,
365410
len: self.len,
366411
};
@@ -385,3 +430,103 @@ impl IndexMut<usize> for MemoryMapOwned {
385430
self.get_mut(index).unwrap()
386431
}
387432
}
433+
434+
#[cfg(test)]
435+
mod tests {
436+
use super::*;
437+
use alloc::vec::Vec;
438+
use core::mem::size_of;
439+
440+
const BASE_MMAP_UNSORTED: [MemoryDescriptor; 3] = [
441+
MemoryDescriptor {
442+
ty: MemoryType::CONVENTIONAL,
443+
phys_start: 0x3000,
444+
virt_start: 0x3000,
445+
page_count: 1,
446+
att: MemoryAttribute::WRITE_BACK,
447+
},
448+
MemoryDescriptor {
449+
ty: MemoryType::CONVENTIONAL,
450+
phys_start: 0x2000,
451+
virt_start: 0x2000,
452+
page_count: 1,
453+
att: MemoryAttribute::WRITE_BACK,
454+
},
455+
MemoryDescriptor {
456+
ty: MemoryType::CONVENTIONAL,
457+
phys_start: 0x1000,
458+
virt_start: 0x1000,
459+
page_count: 1,
460+
att: MemoryAttribute::WRITE_BACK,
461+
},
462+
];
463+
464+
/// Returns a copy of [`BASE_MMAP_UNSORTED`] owned on the stack.
465+
fn new_mmap_memory() -> [MemoryDescriptor; 3] {
466+
BASE_MMAP_UNSORTED
467+
}
468+
469+
fn mmap_raw<'a>(memory: &mut [MemoryDescriptor]) -> (&'a mut [u8], MemoryMapMeta) {
470+
let desc_size = size_of::<MemoryDescriptor>();
471+
let len = memory.len() * desc_size;
472+
let ptr = memory.as_mut_ptr().cast::<u8>();
473+
let slice = unsafe { core::slice::from_raw_parts_mut(ptr, len) };
474+
let meta = MemoryMapMeta {
475+
map_size: len,
476+
desc_size,
477+
map_key: Default::default(),
478+
desc_version: MemoryDescriptor::VERSION,
479+
};
480+
(slice, meta)
481+
}
482+
483+
/// Basic sanity checks for the type [`MemoryMapRef`].
484+
#[test]
485+
fn memory_map_ref() {
486+
let mut memory = new_mmap_memory();
487+
let (mmap, meta) = mmap_raw(&mut memory);
488+
let mmap = MemoryMapRef::new(mmap, meta).unwrap();
489+
490+
assert_eq!(mmap.entries().count(), 3);
491+
assert_eq!(
492+
mmap.entries().copied().collect::<Vec<_>>().as_slice(),
493+
&BASE_MMAP_UNSORTED
494+
);
495+
assert!(!mmap.is_sorted());
496+
}
497+
498+
/// Basic sanity checks for the type [`MemoryMapRefMut`].
499+
#[test]
500+
fn memory_map_ref_mut() {
501+
let mut memory = new_mmap_memory();
502+
let (mmap, meta) = mmap_raw(&mut memory);
503+
let mut mmap = MemoryMapRefMut::new(mmap, meta).unwrap();
504+
505+
assert_eq!(mmap.entries().count(), 3);
506+
assert_eq!(
507+
mmap.entries().copied().collect::<Vec<_>>().as_slice(),
508+
&BASE_MMAP_UNSORTED
509+
);
510+
assert!(!mmap.is_sorted());
511+
mmap.sort();
512+
assert!(mmap.is_sorted());
513+
}
514+
515+
/// Basic sanity checks for the type [`MemoryMapOwned`].
516+
#[test]
517+
fn memory_map_owned() {
518+
let mut memory = new_mmap_memory();
519+
let (mmap, meta) = mmap_raw(&mut memory);
520+
let mmap = MemoryMapBackingMemory::from_slice(mmap);
521+
let mut mmap = MemoryMapOwned::from_initialized_mem(mmap, meta);
522+
523+
assert_eq!(mmap.entries().count(), 3);
524+
assert_eq!(
525+
mmap.entries().copied().collect::<Vec<_>>().as_slice(),
526+
&BASE_MMAP_UNSORTED
527+
);
528+
assert!(!mmap.is_sorted());
529+
mmap.sort();
530+
assert!(mmap.is_sorted());
531+
}
532+
}

uefi/src/mem/memory_map/iter.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
use super::*;
22

3-
/// An iterator of [`MemoryDescriptor`]. The underlying memory map is always
4-
/// associated with a unique [`MemoryMapKey`].
3+
/// An iterator for [`MemoryMap`].
4+
///
5+
/// The underlying memory might contain an invalid/malformed memory map
6+
/// which can't be checked during construction of this type. The iterator
7+
/// might yield unexpected results.
58
#[derive(Debug, Clone)]
69
pub struct MemoryMapIter<'a> {
710
pub(crate) memory_map: &'a dyn MemoryMap,

0 commit comments

Comments
 (0)