Skip to content

Commit 727a182

Browse files
committed
multiboot2: memory bug fix
1 parent 1e1ef79 commit 727a182

File tree

3 files changed

+42
-47
lines changed

3 files changed

+42
-47
lines changed

multiboot2/Changelog.md

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
- `EFIMemoryAreaType` was removed and is now an alias of
1515
`uefi_raw::table::boot::MemoryType`
1616
- MSRV is 1.68.0
17+
- **BREAKING** Removed `MemoryAreaIter` and `MemoryMapTag::available_memory_areas`
18+
- Added `MemoryMapTag::entry_size` and `MemoryMapTag::entry_version`
1719

1820
## 0.15.1 (2023-03-18)
1921
- **BREAKING** `MemoryMapTag::all_memory_areas()` was renamed to `memory_areas`

multiboot2/src/lib.rs

+21-7
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ pub use framebuffer::{FramebufferColor, FramebufferField, FramebufferTag, Frameb
5858
pub use image_load_addr::ImageLoadPhysAddr;
5959
pub use memory_map::{
6060
BasicMemoryInfoTag, EFIBootServicesNotExited, EFIMemoryAreaType, EFIMemoryDesc,
61-
EFIMemoryMapTag, MemoryArea, MemoryAreaIter, MemoryAreaType, MemoryMapTag,
61+
EFIMemoryMapTag, MemoryArea, MemoryAreaType, MemoryMapTag,
6262
};
6363
pub use module::{ModuleIter, ModuleTag};
6464
pub use rsdp::{RsdpV1Tag, RsdpV2Tag};
@@ -514,7 +514,10 @@ impl fmt::Debug for BootInformation {
514514
/// This crate uses the [`Pointee`]-abstraction of the [`ptr_meta`] crate to
515515
/// create fat pointers.
516516
pub trait TagTrait: Pointee {
517-
/// Returns
517+
/// Returns the amount of items in the dynamically sized portion of the
518+
/// DST. Note that this is not the amount of bytes. So if the dynamically
519+
/// sized portion is 16 bytes in size and each element is 4 bytes big, then
520+
/// this function must return 4.
518521
fn dst_size(base_tag: &Tag) -> Self::Metadata;
519522

520523
/// Creates a reference to a (dynamically sized) tag type in a safe way.
@@ -1218,27 +1221,33 @@ mod tests {
12181221
let addr = bytes.0.as_ptr() as usize;
12191222
let bi = unsafe { load(addr) };
12201223
let bi = bi.unwrap();
1221-
test_grub2_boot_info(bi, addr, string_addr, &bytes.0, &string_bytes.0);
1224+
1225+
test_grub2_boot_info(&bi, addr, string_addr, &bytes.0, &string_bytes.0);
12221226
let bi = unsafe { load_with_offset(addr, 0) };
12231227
let bi = bi.unwrap();
1224-
test_grub2_boot_info(bi, addr, string_addr, &bytes.0, &string_bytes.0);
1228+
test_grub2_boot_info(&bi, addr, string_addr, &bytes.0, &string_bytes.0);
12251229
let offset = 8usize;
12261230
for i in 0..8 {
12271231
bytes.0[796 + i] = ((string_addr - offset as u64) >> (i * 8)) as u8;
12281232
}
12291233
let bi = unsafe { load_with_offset(addr - offset, offset) };
12301234
let bi = bi.unwrap();
12311235
test_grub2_boot_info(
1232-
bi,
1236+
&bi,
12331237
addr,
12341238
string_addr - offset as u64,
12351239
&bytes.0,
12361240
&string_bytes.0,
12371241
);
1242+
1243+
// Check that the MBI's debug output can be printed without SEGFAULT.
1244+
// If this works, it is a good indicator than transitively a lot of
1245+
// stuff works.
1246+
println!("{bi:#?}");
12381247
}
12391248

12401249
fn test_grub2_boot_info(
1241-
bi: BootInformation,
1250+
bi: &BootInformation,
12421251
addr: usize,
12431252
string_addr: u64,
12441253
bytes: &[u8],
@@ -1317,7 +1326,12 @@ mod tests {
13171326
assert_eq!(ElfSectionFlags::empty(), s8.flags());
13181327
assert_eq!(ElfSectionType::StringTable, s8.section_type());
13191328
assert!(es.next().is_none());
1320-
let mut mm = bi.memory_map_tag().unwrap().available_memory_areas();
1329+
let mut mm = bi
1330+
.memory_map_tag()
1331+
.unwrap()
1332+
.memory_areas()
1333+
.iter()
1334+
.filter(|area| area.typ() == MemoryAreaType::Available);
13211335
let mm1 = mm.next().unwrap();
13221336
assert_eq!(0x00000000, mm1.start_address());
13231337
assert_eq!(0x009_FC00, mm1.end_address());

multiboot2/src/memory_map.rs

+19-40
Original file line numberDiff line numberDiff line change
@@ -44,31 +44,30 @@ impl MemoryMapTag {
4444
boxed_dst_tag(TagType::Mmap, bytes.as_slice())
4545
}
4646

47-
/// Return an iterator over all memory areas that have the type
48-
/// [`MemoryAreaType::Available`].
49-
pub fn available_memory_areas(&self) -> impl Iterator<Item = &MemoryArea> {
50-
self.memory_areas()
51-
.filter(|entry| matches!(entry.typ, MemoryAreaType::Available))
47+
/// Returns the entry size.
48+
pub fn entry_size(&self) -> u32 {
49+
self.entry_size
5250
}
5351

54-
/// Return an iterator over all memory areas.
55-
pub fn memory_areas(&self) -> MemoryAreaIter {
56-
let self_ptr = self as *const MemoryMapTag;
57-
let start_area = (&self.areas[0]) as *const MemoryArea;
58-
MemoryAreaIter {
59-
current_area: start_area as u64,
60-
// NOTE: `last_area` is only a bound, it doesn't necessarily point exactly to the last element
61-
last_area: (self_ptr as *const () as u64 + (self.size - self.entry_size) as u64),
62-
entry_size: self.entry_size,
63-
phantom: PhantomData,
64-
}
52+
/// Returns the entry version.
53+
pub fn entry_version(&self) -> u32 {
54+
self.entry_version
55+
}
56+
57+
/// Return the slice with all memory areas.
58+
pub fn memory_areas(&self) -> &[MemoryArea] {
59+
// If this ever fails, we need to model this differently in this crate.
60+
assert_eq!(self.entry_size as usize, mem::size_of::<MemoryArea>());
61+
&self.areas
6562
}
6663
}
6764

6865
impl TagTrait for MemoryMapTag {
6966
fn dst_size(base_tag: &Tag) -> usize {
7067
assert!(base_tag.size as usize >= METADATA_SIZE);
71-
base_tag.size as usize - METADATA_SIZE
68+
let size = base_tag.size as usize - METADATA_SIZE;
69+
assert_eq!(size % mem::size_of::<MemoryArea>(), 0);
70+
size / mem::size_of::<MemoryArea>()
7271
}
7372
}
7473

@@ -152,28 +151,6 @@ pub enum MemoryAreaType {
152151
Defective = 5,
153152
}
154153

155-
/// An iterator over all memory areas
156-
#[derive(Clone, Debug)]
157-
pub struct MemoryAreaIter<'a> {
158-
current_area: u64,
159-
last_area: u64,
160-
entry_size: u32,
161-
phantom: PhantomData<&'a MemoryArea>,
162-
}
163-
164-
impl<'a> Iterator for MemoryAreaIter<'a> {
165-
type Item = &'a MemoryArea;
166-
fn next(&mut self) -> Option<&'a MemoryArea> {
167-
if self.current_area > self.last_area {
168-
None
169-
} else {
170-
let area = unsafe { &*(self.current_area as *const MemoryArea) };
171-
self.current_area += self.entry_size as u64;
172-
Some(area)
173-
}
174-
}
175-
}
176-
177154
/// Basic memory info
178155
///
179156
/// This tag includes "basic memory information".
@@ -279,7 +256,9 @@ impl EFIMemoryMapTag {
279256
impl TagTrait for EFIMemoryMapTag {
280257
fn dst_size(base_tag: &Tag) -> usize {
281258
assert!(base_tag.size as usize >= EFI_METADATA_SIZE);
282-
base_tag.size as usize - EFI_METADATA_SIZE
259+
let size = base_tag.size as usize - EFI_METADATA_SIZE;
260+
assert_eq!(size % mem::size_of::<MemoryArea>(), 0);
261+
size / mem::size_of::<EFIMemoryDesc>()
283262
}
284263
}
285264

0 commit comments

Comments
 (0)