Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita97a62b

Browse files
committed
uefi: MemoryMap now owns the memory
This is an attempt to simplify the overall complex handling of obtaining the UEFI memorymap. We have the following pre-requisites and use-cases all to keep in mind whendesigning the functions and associated helper types:- the memory map itself needs memory; typically on the UEFI heap- acquiring that memory and storing the memory map inside it are two distinct steps- the memory map is not just a slice of [MemoryDescriptor] (desc_size is bigger than size_of)- the required size can be obtained by another boot service function- the needed memory might change due to hidden or asynchronous allocations between the allocation of a buffer and storing the memory map inside it- when boot services are excited, best practise has shown (looking at linux code) that one should use the same buffer (with some extra capacity) and call exit_boot_services with that buffer at most two times in a loopThis makes it hard to come up with an ergonomic solution such as using a Boxor any other high-level Rust type.The main simplification of my design is that the MemoryMap type now doesn'thas a reference to memory anymore but actually owns it. This also models thereal world use case where one typically obtains the memory map once whenboot services are exited. A &'static [u8] on the MemoryMap just creates moreconfusion that it brings any benefit.The MemoryMap now knows whether boot services are still active and freesthat memory, or it doesn't if the boot services are exited. This meansless fiddling with life-times and less cognitive overhead when- reading the code- calling BootService::memory_map independently of exit_boot_services
1 parentbac1911 commita97a62b

File tree

3 files changed

+142
-123
lines changed

3 files changed

+142
-123
lines changed

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

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,17 +63,8 @@ fn alloc_alignment() {
6363
fnmemory_map(bt:&BootServices){
6464
info!("Testing memory map functions");
6565

66-
// Get the memory descriptor size and an estimate of the memory map size
67-
let sizes = bt.memory_map_size();
68-
69-
// 2 extra descriptors should be enough.
70-
let buf_sz = sizes.map_size +2* sizes.desc_size;
71-
72-
// We will use vectors for convenience.
73-
letmut buffer =vec![0_u8; buf_sz];
74-
7566
letmut memory_map = bt
76-
.memory_map(&mut buffer)
67+
.memory_map(MemoryType::LOADER_DATA)
7768
.expect("Failed to retrieve UEFI memory map");
7869

7970
memory_map.sort();

‎uefi/src/table/boot.rs

Lines changed: 132 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -215,37 +215,46 @@ impl BootServices {
215215
}
216216
}
217217

218-
/// Stores the current UEFI memory map in the provided buffer.
219-
///
220-
/// The allocated buffer must be at least aligned to a [`MemoryDescriptor`]
221-
/// and should be big enough to store the whole map. To estimating how big
222-
/// the map will be, you can call [`Self::memory_map_size`].
223-
///
224-
/// The memory map contains entries of type [`MemoryDescriptor`]. However,
225-
/// the relevant step size is always the reported `desc_size` but never
226-
/// `size_of::<MemoryDescriptor>()`.
227-
///
228-
/// The returned key is a unique identifier of the current configuration of
229-
/// memory. Any allocations or such will change the memory map's key.
230-
///
231-
/// If you want to store the resulting memory map without having to keep
232-
/// the buffer around, you can use `.copied().collect()` on the iterator.
233-
/// Note that this will change the current memory map again, if the UEFI
234-
/// allocator is used under the hood.
218+
/// Stores the current UEFI memory map in an UEFI-heap allocated buffer
219+
/// and returns a [`MemoryMap`].
235220
///
236221
/// # Errors
237222
///
238-
/// See section `EFI_BOOT_SERVICES.GetMemoryMap()` in the UEFI Specification for more details.
223+
/// See section `EFI_BOOT_SERVICES.GetMemoryMap()` in the UEFI Specification
224+
/// for more details.
239225
///
240226
/// * [`uefi::Status::BUFFER_TOO_SMALL`]
241227
/// * [`uefi::Status::INVALID_PARAMETER`]
242-
pubfnmemory_map<'buf>(&self,buffer:&'bufmut[u8]) ->Result<MemoryMap<'buf>>{
243-
letmut map_size = buffer.len();
244-
MemoryDescriptor::assert_aligned(buffer);
245-
let map_buffer = buffer.as_mut_ptr().cast::<MemoryDescriptor>();
228+
pubfnmemory_map(&self,mt:MemoryType) ->Result<MemoryMap>{
229+
letmut buffer =MemoryMapBackingMemory::new(mt)?;
230+
231+
letGetMemoryMapResult{
232+
map_size,
233+
map_key,
234+
desc_size,
235+
desc_version,
236+
} =self.get_memory_map(buffer.as_mut_slice())?;
237+
238+
let len = map_size / desc_size;
239+
assert_eq!(map_size % desc_size,0);
240+
assert_eq!(desc_version,MemoryDescriptor::VERSION);
241+
Ok(MemoryMap{
242+
key: map_key,
243+
buf: buffer,
244+
desc_size,
245+
len,
246+
})
247+
}
248+
249+
/// Calls the underlying `GetMemoryMap` function of UEFI. On success,
250+
/// the buffer is mutated and contains the map. The map might be shorter
251+
/// than the buffer, which is reflected by the return value.
252+
pub(crate)fnget_memory_map(&self,buf:&mut[u8]) ->Result<GetMemoryMapResult>{
253+
letmut map_size = buf.len();
254+
let map_buffer = buf.as_mut_ptr().cast::<MemoryDescriptor>();
246255
letmut map_key =MemoryMapKey(0);
247256
letmut desc_size =0;
248-
letmutentry_version =0;
257+
letmutdesc_version =0;
249258

250259
assert_eq!(
251260
(map_bufferasusize) % mem::align_of::<MemoryDescriptor>(),
@@ -259,18 +268,14 @@ impl BootServices {
259268
map_buffer,
260269
&mut map_key.0,
261270
&mut desc_size,
262-
&mutentry_version,
271+
&mutdesc_version,
263272
)
264273
}
265-
.to_result_with_val(move ||{
266-
let len = map_size / desc_size;
267-
268-
MemoryMap{
269-
key: map_key,
270-
buf: buffer,
271-
desc_size,
272-
len,
273-
}
274+
.to_result_with_val(||GetMemoryMapResult{
275+
map_size,
276+
desc_size,
277+
map_key,
278+
desc_version,
274279
})
275280
}
276281

@@ -1637,31 +1642,45 @@ pub struct MemoryMapKey(usize);
16371642
/// When this type is dropped and boot services are not exited yet, the memory
16381643
/// is freed.
16391644
#[derive(Debug)]
1640-
pubstructMemoryMapBackingMemory(NonNull<[u8]>/* buffer on UEFI heap */);
1645+
pubstructMemoryMapBackingMemory(NonNull<[u8]>);
16411646

16421647
implMemoryMapBackingMemory{
16431648
/// Constructs a new [`MemoryMapBackingMemory`].
16441649
///
1645-
/// # Parameters
1650+
/// # Parameters
16461651
/// - `memory_type`: The memory type for the memory map allocation.
16471652
/// Typically, [`MemoryType::LOADER_DATA`] for regular UEFI applications.
16481653
pub(crate)fnnew(memory_type:MemoryType) ->Result<Self>{
16491654
let st =system_table_boot().expect("Should have boot services activated");
16501655
let bs = st.boot_services();
16511656

16521657
let memory_map_size = bs.memory_map_size();
1653-
let alloc_size =Self::allocation_size_hint(memory_map_size);
1654-
let ptr = bs.allocate_pool(memory_type, alloc_size)?;
1658+
let len =Self::allocation_size_hint(memory_map_size);
1659+
let ptr = bs.allocate_pool(memory_type, len)?;
1660+
assert_eq!(ptr.align_offset(mem::align_of::<MemoryDescriptor>()),0);
1661+
Ok(Self::from_raw(ptr, len))
1662+
}
1663+
1664+
fnfrom_raw(ptr:*mutu8,len:usize) ->Self{
16551665
assert_eq!(ptr.align_offset(mem::align_of::<MemoryDescriptor>()),0);
16561666

16571667
let ptr =NonNull::new(ptr).expect("UEFI should never return a null ptr. An error should have been reflected via an Err earlier.");
1658-
let slice =NonNull::slice_from_raw_parts(ptr,alloc_size);
1668+
let slice =NonNull::slice_from_raw_parts(ptr,len);
16591669

1660-
Ok(Self(slice))
1670+
Self(slice)
1671+
}
1672+
1673+
/// Creates an instance from the provided memory, which is not necessarily
1674+
/// on the UEFI heap.
1675+
#[cfg(test)]
1676+
fnfrom_slice(buffer:&mut[u8]) ->Self{
1677+
let len = buffer.len();
1678+
Self::from_raw(buffer.as_mut_ptr(), len)
16611679
}
16621680

16631681
/// Returns a best-effort size hint of the memory map size. This is
16641682
/// especially created with exiting boot services in mind.
1683+
#[must_use]
16651684
pubfnallocation_size_hint(mms:MemoryMapSize) ->usize{
16661685
letMemoryMapSize{
16671686
desc_size,
@@ -1689,16 +1708,34 @@ impl MemoryMapBackingMemory {
16891708
let allocation_size = map_size + extra_size;
16901709
allocation_size
16911710
}
1692-
1693-
/// Returns the raw pointer to the beginning of the allocation.
1694-
pubfnas_ptr_mut(&mutself) ->*mutu8{
1711+
1712+
/// Returns a raw pointer to the beginning of the allocation.
1713+
#[must_use]
1714+
pubfnas_ptr(&self) ->*constu8{
16951715
self.0.as_ptr().cast()
16961716
}
1697-
1717+
1718+
/// Returns a mutable raw pointer to the beginning of the allocation.
1719+
#[must_use]
1720+
pubfnas_mut_ptr(&mutself) ->*mutu8{
1721+
self.0.as_ptr().cast()
1722+
}
1723+
16981724
/// Returns the length of the allocation.
1725+
#[must_use]
16991726
pubfnlen(&self) ->usize{
17001727
self.0.len()
1701-
}
1728+
}
1729+
1730+
/*#[must_use]
1731+
pub fn as_slice(&self) -> &[u8] {
1732+
self.0.as_ref()
1733+
}*/
1734+
1735+
#[must_use]
1736+
pubfnas_mut_slice(&mutself) ->&mut[u8]{
1737+
unsafe{self.0.as_mut()}
1738+
}
17021739
}
17031740

17041741
implDropforMemoryMapBackingMemory{
@@ -1724,6 +1761,14 @@ pub struct MemoryMapSize {
17241761
pubmap_size:usize,
17251762
}
17261763

1764+
#[derive(Copy,Clone,Debug)]
1765+
pubstructGetMemoryMapResult{
1766+
pubmap_size:usize,
1767+
pubdesc_size:usize,
1768+
pubmap_key:MemoryMapKey,
1769+
pubdesc_version:u32,
1770+
}
1771+
17271772
/// An accessory to the memory map that can be either iterated or
17281773
/// indexed like an array.
17291774
///
@@ -1739,35 +1784,36 @@ pub struct MemoryMapSize {
17391784
/// always use `entry_size` as step-size when interfacing with the memory map on
17401785
/// a low level.
17411786
///
1742-
///
1743-
///
17441787
/// [0]: https://github.com/tianocore/edk2/blob/7142e648416ff5d3eac6c6d607874805f5de0ca8/MdeModulePkg/Core/PiSmmCore/Page.c#L1059
17451788
#[derive(Debug)]
1746-
pubstructMemoryMap<'buf>{
1789+
pubstructMemoryMap{
1790+
/// Backing memory, properly initialized at this point.
1791+
buf:MemoryMapBackingMemory,
17471792
key:MemoryMapKey,
1748-
buf:&'bufmut[u8],
17491793
/// Usually bound to the size of a [`MemoryDescriptor`] but can indicate if
17501794
/// this field is ever extended by a new UEFI standard.
17511795
desc_size:usize,
17521796
len:usize,
17531797
}
17541798

1755-
impl<'buf>MemoryMap<'buf>{
1756-
/// Creates a [`MemoryMap`] from the given buffer and entry size.
1757-
/// The entry size is usually bound to the size of a [`MemoryDescriptor`]
1758-
/// but can indicate if this field is ever extended by a new UEFI standard.
1759-
///
1760-
/// This allows parsing a memory map provided by a kernel after boot
1761-
/// services have already exited.
1762-
pubfnfrom_raw(buf:&'bufmut[u8],desc_size:usize) ->Self{
1763-
assert!(!buf.is_empty());
1764-
assert_eq!(
1765-
buf.len() % desc_size,
1766-
0,
1767-
"The buffer length must be a multiple of the desc_size"
1768-
);
1799+
implMemoryMap{
1800+
/*pub fn new() -> Self {
1801+
1802+
}*/
1803+
1804+
/// Creates a [`MemoryMap`] from the give initialized memory map behind
1805+
/// the buffer and the reported `desc_size` from UEFI.
1806+
pub(crate)fnfrom_initialized_mem(
1807+
buf:MemoryMapBackingMemory,
1808+
props:GetMemoryMapResult,
1809+
) ->Self{
1810+
letGetMemoryMapResult{
1811+
map_size,
1812+
desc_size,
1813+
..
1814+
} = props;
17691815
assert!(desc_size >= mem::size_of::<MemoryDescriptor>());
1770-
let len =buf.len() / desc_size;
1816+
let len =map_size / desc_size;
17711817
MemoryMap{
17721818
key:MemoryMapKey(0),
17731819
buf,
@@ -1776,6 +1822,20 @@ impl<'buf> MemoryMap<'buf> {
17761822
}
17771823
}
17781824

1825+
#[cfg(test)]
1826+
fnfrom_raw(buf:&mut[u8],desc_size:usize) ->Self{
1827+
let mem =MemoryMapBackingMemory::from_slice(buf);
1828+
Self::from_initialized_mem(
1829+
mem,
1830+
GetMemoryMapResult{
1831+
map_size: buf.len(),
1832+
desc_size,
1833+
map_key:MemoryMapKey(0),
1834+
desc_version:MemoryDescriptor::VERSION,
1835+
},
1836+
)
1837+
}
1838+
17791839
#[must_use]
17801840
/// Returns the unique [`MemoryMapKey`] associated with the memory map.
17811841
pubfnkey(&self) ->MemoryMapKey{
@@ -1870,7 +1930,7 @@ impl<'buf> MemoryMap<'buf> {
18701930

18711931
/// Returns a reference to the [`MemoryDescriptor`] at `index` or `None` if out of bounds.
18721932
#[must_use]
1873-
pubfnget(&self,index:usize) ->Option<&'bufMemoryDescriptor>{
1933+
pubfnget(&self,index:usize) ->Option<&MemoryDescriptor>{
18741934
if index >=self.len{
18751935
returnNone;
18761936
}
@@ -1888,7 +1948,7 @@ impl<'buf> MemoryMap<'buf> {
18881948

18891949
/// Returns a mut reference to the [`MemoryDescriptor`] at `index` or `None` if out of bounds.
18901950
#[must_use]
1891-
pubfnget_mut(&mutself,index:usize) ->Option<&'bufmutMemoryDescriptor>{
1951+
pubfnget_mut(&mutself,index:usize) ->Option<&mutMemoryDescriptor>{
18921952
if index >=self.len{
18931953
returnNone;
18941954
}
@@ -1905,15 +1965,15 @@ impl<'buf> MemoryMap<'buf> {
19051965
}
19061966
}
19071967

1908-
impl core::ops::Index<usize>forMemoryMap<'_>{
1968+
impl core::ops::Index<usize>forMemoryMap{
19091969
typeOutput =MemoryDescriptor;
19101970

19111971
fnindex(&self,index:usize) ->&Self::Output{
19121972
self.get(index).unwrap()
19131973
}
19141974
}
19151975

1916-
impl core::ops::IndexMut<usize>forMemoryMap<'_>{
1976+
impl core::ops::IndexMut<usize>forMemoryMap{
19171977
fnindex_mut(&mutself,index:usize) ->&mutSelf::Output{
19181978
self.get_mut(index).unwrap()
19191979
}
@@ -1922,13 +1982,13 @@ impl core::ops::IndexMut<usize> for MemoryMap<'_> {
19221982
/// An iterator of [`MemoryDescriptor`]. The underlying memory map is always
19231983
/// associated with a unique [`MemoryMapKey`].
19241984
#[derive(Debug,Clone)]
1925-
pubstructMemoryMapIter<'buf>{
1926-
memory_map:&'bufMemoryMap<'buf>,
1985+
pubstructMemoryMapIter<'a>{
1986+
memory_map:&'aMemoryMap,
19271987
index:usize,
19281988
}
19291989

1930-
impl<'buf>IteratorforMemoryMapIter<'buf>{
1931-
typeItem =&'bufMemoryDescriptor;
1990+
impl<'a>IteratorforMemoryMapIter<'a>{
1991+
typeItem =&'aMemoryDescriptor;
19321992

19331993
fnsize_hint(&self) ->(usize,Option<usize>){
19341994
let sz =self.memory_map.len -self.index;
@@ -2179,7 +2239,7 @@ mod tests {
21792239
}
21802240

21812241
// Added for debug purposes on test failure
2182-
impl core::fmt::DisplayforMemoryMap<'_>{
2242+
impl core::fmt::DisplayforMemoryMap{
21832243
fnfmt(&self,f:&mut core::fmt::Formatter<'_>) -> core::fmt::Result{
21842244
writeln!(f)?;
21852245
for descinself.entries(){

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp