Skip to content

Commit c277fb8

Browse files
committed
multiboot2: Get a mutable reference to the memory map
1 parent 714905b commit c277fb8

File tree

3 files changed

+111
-1
lines changed

3 files changed

+111
-1
lines changed

multiboot2/src/lib.rs

+33-1
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ pub use memory_map::{
6363
pub use module::{ModuleIter, ModuleTag};
6464
pub use rsdp::{RsdpV1Tag, RsdpV2Tag};
6565
pub use smbios::SmbiosTag;
66-
use tag_type::TagIter;
6766
pub use tag_type::{EndTag, Tag, TagType, TagTypeId};
67+
use tag_type::{TagIter, TagIterMut};
6868
pub use vbe_info::{
6969
VBECapabilities, VBEControlInfo, VBEDirectColorAttributes, VBEField, VBEInfoTag,
7070
VBEMemoryModel, VBEModeAttributes, VBEModeInfo, VBEWindowAttributes,
@@ -276,6 +276,11 @@ impl BootInformation {
276276
self.get_tag::<MemoryMapTag, _>(TagType::Mmap)
277277
}
278278

279+
/// Search for the Memory map tag, return a mutable reference.
280+
pub fn memory_map_tag_mut(&mut self) -> Option<&mut MemoryMapTag> {
281+
self.get_tag_mut::<MemoryMapTag, _>(TagType::Mmap)
282+
}
283+
279284
/// Get an iterator of all module tags.
280285
pub fn module_tags(&self) -> ModuleIter {
281286
module::module_iter(self.tags())
@@ -427,9 +432,23 @@ impl BootInformation {
427432
.map(|tag| tag.cast_tag::<TagT>())
428433
}
429434

435+
fn get_tag_mut<TagT: TagTrait + ?Sized, TagType: Into<TagTypeId>>(
436+
&mut self,
437+
typ: TagType,
438+
) -> Option<&mut TagT> {
439+
let typ = typ.into();
440+
self.tags_mut()
441+
.find(|tag| tag.typ == typ)
442+
.map(|tag| tag.cast_tag_mut::<TagT>())
443+
}
444+
430445
fn tags(&self) -> TagIter {
431446
TagIter::new(unsafe { self.inner.offset(1) } as *const _)
432447
}
448+
449+
fn tags_mut(&mut self) -> TagIterMut {
450+
TagIterMut::new(unsafe { self.inner.offset(1) } as *mut _)
451+
}
433452
}
434453

435454
impl BootInformationInner {
@@ -567,6 +586,19 @@ pub trait TagTrait: Pointee {
567586
let ptr = ptr_meta::from_raw_parts(ptr, Self::dst_size(tag));
568587
&*ptr
569588
}
589+
590+
/// Creates a mutable reference to a (dynamically sized) tag type in a safe way.
591+
/// DST tags need to implement a proper [`Self::dst_size`] implementation.
592+
///
593+
/// # Safety
594+
/// Callers must be sure that the "size" field of the provided [`Tag`] is
595+
/// sane and the underlying memory valid. The implementation of this trait
596+
/// **must have** a correct [`Self::dst_size`] implementation.
597+
unsafe fn from_base_tag_mut<'a>(tag: &mut Tag) -> &'a mut Self {
598+
let ptr = tag as *mut _ as *mut ();
599+
let ptr = ptr_meta::from_raw_parts_mut(ptr, Self::dst_size(tag));
600+
&mut *ptr
601+
}
570602
}
571603

572604
// All sized tags automatically have a Pointee implementation where

multiboot2/src/memory_map.rs

+34
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,18 @@ impl MemoryMapTag {
6161
phantom: PhantomData,
6262
}
6363
}
64+
65+
/// Return a mutable iterator over all marked memory areas.
66+
pub fn all_memory_areas_mut(&mut self) -> impl Iterator<Item = &mut MemoryArea> {
67+
let self_ptr = self as *mut MemoryMapTag;
68+
let start_area = (&mut self.areas[0]) as *mut MemoryArea;
69+
MemoryAreaIterMut {
70+
current_area: start_area as u64,
71+
last_area: (self_ptr as *const () as u64 + (self.size - self.entry_size) as u64),
72+
entry_size: self.entry_size,
73+
phantom: PhantomData,
74+
}
75+
}
6476
}
6577

6678
impl TagTrait for MemoryMapTag {
@@ -172,6 +184,28 @@ impl<'a> Iterator for MemoryAreaIter<'a> {
172184
}
173185
}
174186

187+
/// A mutable iterator over all memory areas
188+
#[derive(Clone, Debug)]
189+
pub struct MemoryAreaIterMut<'a> {
190+
current_area: u64,
191+
last_area: u64,
192+
entry_size: u32,
193+
phantom: PhantomData<&'a MemoryArea>,
194+
}
195+
196+
impl<'a> Iterator for MemoryAreaIterMut<'a> {
197+
type Item = &'a mut MemoryArea;
198+
fn next(&mut self) -> Option<&'a mut MemoryArea> {
199+
if self.current_area > self.last_area {
200+
None
201+
} else {
202+
let area = unsafe { &mut *(self.current_area as *mut MemoryArea) };
203+
self.current_area += self.entry_size as u64;
204+
Some(area)
205+
}
206+
}
207+
}
208+
175209
/// Basic memory info
176210
///
177211
/// This tag includes "basic memory information".

multiboot2/src/tag_type.rs

+44
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,13 @@ impl Tag {
310310
unsafe { TagTrait::from_base_tag(self) }
311311
}
312312

313+
/// Casts the base tag to the specific tag type, but mutably.
314+
pub(crate) fn cast_tag_mut<'a, T: TagTrait + ?Sized>(&mut self) -> &'a mut T {
315+
// Safety: At this point, we trust that "self.size" and the size hint
316+
// for DST tags are sane.
317+
unsafe { TagTrait::from_base_tag_mut(self) }
318+
}
319+
313320
/// Some multiboot2 tags are a DST as they end with a dynamically sized byte
314321
/// slice. This function parses this slice as [`str`] so that either a valid
315322
/// UTF-8 Rust string slice without a terminating null byte or an error is
@@ -414,6 +421,43 @@ impl<'a> Iterator for TagIter<'a> {
414421
}
415422
}
416423

424+
#[derive(Clone, Debug)]
425+
pub struct TagIterMut<'a> {
426+
pub current: *mut Tag,
427+
phantom: PhantomData<&'a mut Tag>,
428+
}
429+
430+
impl<'a> TagIterMut<'a> {
431+
pub fn new(first: *mut Tag) -> Self {
432+
TagIterMut {
433+
current: first,
434+
phantom: PhantomData,
435+
}
436+
}
437+
}
438+
439+
impl<'a> Iterator for TagIterMut<'a> {
440+
type Item = &'a mut Tag;
441+
442+
fn next(&mut self) -> Option<&'a mut Tag> {
443+
match unsafe { &mut *self.current } {
444+
&mut Tag {
445+
// END-Tag
446+
typ: TagTypeId(0),
447+
size: 8,
448+
} => None, // end tag
449+
tag => {
450+
// go to next tag
451+
let mut tag_addr = self.current as usize;
452+
tag_addr += ((tag.size + 7) & !7) as usize; //align at 8 byte
453+
self.current = tag_addr as *mut _;
454+
455+
Some(tag)
456+
}
457+
}
458+
}
459+
}
460+
417461
#[cfg(test)]
418462
mod tests {
419463
use super::*;

0 commit comments

Comments
 (0)