Skip to content

fix memory issue in memory-map #149

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions multiboot2/Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
- `EFIMemoryAreaType` was removed and is now an alias of
`uefi_raw::table::boot::MemoryType`
- MSRV is 1.68.0
- **BREAKING** Removed `MemoryAreaIter` and `MemoryMapTag::available_memory_areas`
- Added `MemoryMapTag::entry_size` and `MemoryMapTag::entry_version`

## 0.15.1 (2023-03-18)
- **BREAKING** `MemoryMapTag::all_memory_areas()` was renamed to `memory_areas`
Expand Down
28 changes: 21 additions & 7 deletions multiboot2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ pub use framebuffer::{FramebufferColor, FramebufferField, FramebufferTag, Frameb
pub use image_load_addr::ImageLoadPhysAddr;
pub use memory_map::{
BasicMemoryInfoTag, EFIBootServicesNotExited, EFIMemoryAreaType, EFIMemoryDesc,
EFIMemoryMapTag, MemoryArea, MemoryAreaIter, MemoryAreaType, MemoryMapTag,
EFIMemoryMapTag, MemoryArea, MemoryAreaType, MemoryMapTag,
};
pub use module::{ModuleIter, ModuleTag};
pub use rsdp::{RsdpV1Tag, RsdpV2Tag};
Expand Down Expand Up @@ -514,7 +514,10 @@ impl fmt::Debug for BootInformation {
/// This crate uses the [`Pointee`]-abstraction of the [`ptr_meta`] crate to
/// create fat pointers.
pub trait TagTrait: Pointee {
/// Returns
/// Returns the amount of items in the dynamically sized portion of the
/// DST. Note that this is not the amount of bytes. So if the dynamically
/// sized portion is 16 bytes in size and each element is 4 bytes big, then
/// this function must return 4.
fn dst_size(base_tag: &Tag) -> Self::Metadata;

/// Creates a reference to a (dynamically sized) tag type in a safe way.
Expand Down Expand Up @@ -1218,27 +1221,33 @@ mod tests {
let addr = bytes.0.as_ptr() as usize;
let bi = unsafe { load(addr) };
let bi = bi.unwrap();
test_grub2_boot_info(bi, addr, string_addr, &bytes.0, &string_bytes.0);

test_grub2_boot_info(&bi, addr, string_addr, &bytes.0, &string_bytes.0);
let bi = unsafe { load_with_offset(addr, 0) };
let bi = bi.unwrap();
test_grub2_boot_info(bi, addr, string_addr, &bytes.0, &string_bytes.0);
test_grub2_boot_info(&bi, addr, string_addr, &bytes.0, &string_bytes.0);
let offset = 8usize;
for i in 0..8 {
bytes.0[796 + i] = ((string_addr - offset as u64) >> (i * 8)) as u8;
}
let bi = unsafe { load_with_offset(addr - offset, offset) };
let bi = bi.unwrap();
test_grub2_boot_info(
bi,
&bi,
addr,
string_addr - offset as u64,
&bytes.0,
&string_bytes.0,
);

// Check that the MBI's debug output can be printed without SEGFAULT.
// If this works, it is a good indicator than transitively a lot of
// stuff works.
println!("{bi:#?}");
}

fn test_grub2_boot_info(
bi: BootInformation,
bi: &BootInformation,
addr: usize,
string_addr: u64,
bytes: &[u8],
Expand Down Expand Up @@ -1317,7 +1326,12 @@ mod tests {
assert_eq!(ElfSectionFlags::empty(), s8.flags());
assert_eq!(ElfSectionType::StringTable, s8.section_type());
assert!(es.next().is_none());
let mut mm = bi.memory_map_tag().unwrap().available_memory_areas();
let mut mm = bi
.memory_map_tag()
.unwrap()
.memory_areas()
.iter()
.filter(|area| area.typ() == MemoryAreaType::Available);
let mm1 = mm.next().unwrap();
assert_eq!(0x00000000, mm1.start_address());
assert_eq!(0x009_FC00, mm1.end_address());
Expand Down
59 changes: 19 additions & 40 deletions multiboot2/src/memory_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,31 +44,30 @@ impl MemoryMapTag {
boxed_dst_tag(TagType::Mmap, bytes.as_slice())
}

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

/// Return an iterator over all memory areas.
pub fn memory_areas(&self) -> MemoryAreaIter {
let self_ptr = self as *const MemoryMapTag;
let start_area = (&self.areas[0]) as *const MemoryArea;
MemoryAreaIter {
current_area: start_area as u64,
// NOTE: `last_area` is only a bound, it doesn't necessarily point exactly to the last element
last_area: (self_ptr as *const () as u64 + (self.size - self.entry_size) as u64),
entry_size: self.entry_size,
phantom: PhantomData,
}
/// Returns the entry version.
pub fn entry_version(&self) -> u32 {
self.entry_version
}

/// Return the slice with all memory areas.
pub fn memory_areas(&self) -> &[MemoryArea] {
// If this ever fails, we need to model this differently in this crate.
assert_eq!(self.entry_size as usize, mem::size_of::<MemoryArea>());
&self.areas
}
}

impl TagTrait for MemoryMapTag {
fn dst_size(base_tag: &Tag) -> usize {
assert!(base_tag.size as usize >= METADATA_SIZE);
base_tag.size as usize - METADATA_SIZE
let size = base_tag.size as usize - METADATA_SIZE;
assert_eq!(size % mem::size_of::<MemoryArea>(), 0);
size / mem::size_of::<MemoryArea>()
}
}

Expand Down Expand Up @@ -152,28 +151,6 @@ pub enum MemoryAreaType {
Defective = 5,
}

/// An iterator over all memory areas
#[derive(Clone, Debug)]
pub struct MemoryAreaIter<'a> {
current_area: u64,
last_area: u64,
entry_size: u32,
phantom: PhantomData<&'a MemoryArea>,
}

impl<'a> Iterator for MemoryAreaIter<'a> {
type Item = &'a MemoryArea;
fn next(&mut self) -> Option<&'a MemoryArea> {
if self.current_area > self.last_area {
None
} else {
let area = unsafe { &*(self.current_area as *const MemoryArea) };
self.current_area += self.entry_size as u64;
Some(area)
}
}
}

/// Basic memory info
///
/// This tag includes "basic memory information".
Expand Down Expand Up @@ -279,7 +256,9 @@ impl EFIMemoryMapTag {
impl TagTrait for EFIMemoryMapTag {
fn dst_size(base_tag: &Tag) -> usize {
assert!(base_tag.size as usize >= EFI_METADATA_SIZE);
base_tag.size as usize - EFI_METADATA_SIZE
let size = base_tag.size as usize - EFI_METADATA_SIZE;
assert_eq!(size % mem::size_of::<EFIMemoryDesc>(), 0);
size / mem::size_of::<EFIMemoryDesc>()
}
}

Expand Down