Skip to content

Commit 9e436af

Browse files
committed
multiboot2: memory bug fix
1 parent 1e1ef79 commit 9e436af

File tree

3 files changed

+53
-59
lines changed

3 files changed

+53
-59
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

+33-19
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.
@@ -706,16 +709,16 @@ mod tests {
706709
FramebufferType::RGB {
707710
red: FramebufferField {
708711
position: 16,
709-
size: 8
712+
size: 8,
710713
},
711714
green: FramebufferField {
712715
position: 8,
713-
size: 8
716+
size: 8,
714717
},
715718
blue: FramebufferField {
716719
position: 0,
717-
size: 8
718-
}
720+
size: 8,
721+
},
719722
}
720723
);
721724
}
@@ -767,22 +770,22 @@ mod tests {
767770
FramebufferColor {
768771
red: 255,
769772
green: 0,
770-
blue: 0
773+
blue: 0,
771774
},
772775
FramebufferColor {
773776
red: 0,
774777
green: 255,
775-
blue: 0
778+
blue: 0,
776779
},
777780
FramebufferColor {
778781
red: 0,
779782
green: 0,
780-
blue: 255
783+
blue: 255,
781784
},
782785
FramebufferColor {
783786
red: 0,
784787
green: 0,
785-
blue: 0
788+
blue: 0,
786789
}
787790
]
788791
),
@@ -915,28 +918,28 @@ mod tests {
915918
vbe.mode_info.red_field,
916919
VBEField {
917920
position: 16,
918-
size: 8
921+
size: 8,
919922
}
920923
);
921924
assert_eq!(
922925
vbe.mode_info.green_field,
923926
VBEField {
924927
position: 8,
925-
size: 8
928+
size: 8,
926929
}
927930
);
928931
assert_eq!(
929932
vbe.mode_info.blue_field,
930933
VBEField {
931934
position: 0,
932-
size: 8
935+
size: 8,
933936
}
934937
);
935938
assert_eq!(
936939
vbe.mode_info.reserved_field,
937940
VBEField {
938941
position: 24,
939-
size: 8
942+
size: 8,
940943
}
941944
);
942945
assert_eq!(
@@ -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

+18-40
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use core::convert::TryInto;
33
use core::fmt::Debug;
44
use core::marker::PhantomData;
55
use core::mem;
6+
use std::mem::size_of;
67

78
pub use uefi_raw::table::boot::MemoryDescriptor as EFIMemoryDesc;
89
pub use uefi_raw::table::boot::MemoryType as EFIMemoryAreaType;
@@ -44,31 +45,29 @@ impl MemoryMapTag {
4445
boxed_dst_tag(TagType::Mmap, bytes.as_slice())
4546
}
4647

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))
48+
/// Returns the entry size.
49+
pub fn entry_size(&self) -> u32 {
50+
self.entry_size
5251
}
5352

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-
}
53+
/// Returns the entry version.
54+
pub fn entry_version(&self) -> u32 {
55+
self.entry_version
56+
}
57+
58+
/// Return the slice with all memory areas.
59+
pub fn memory_areas(&self) -> &[MemoryArea] {
60+
// If this ever fails, we need to model this differently in this crate.
61+
assert_eq!(self.entry_size as usize, size_of::<MemoryArea>());
62+
&self.areas
6563
}
6664
}
6765

6866
impl TagTrait for MemoryMapTag {
6967
fn dst_size(base_tag: &Tag) -> usize {
7068
assert!(base_tag.size as usize >= METADATA_SIZE);
71-
base_tag.size as usize - METADATA_SIZE
69+
let size = base_tag.size as usize - METADATA_SIZE;
70+
size / 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,8 @@ 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+
size / size_of::<EFIMemoryDesc>()
283261
}
284262
}
285263

0 commit comments

Comments
 (0)