Skip to content

Commit d198dce

Browse files
committed
multiboot2: Implement setting memory map tag
1 parent 0320148 commit d198dce

File tree

3 files changed

+49
-19
lines changed

3 files changed

+49
-19
lines changed

multiboot2/src/builder/information.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
use crate::builder::traits::StructAsBytes;
33
use crate::{
44
BasicMemoryInfoTag, BootLoaderNameTag, CommandLineTag, ElfSectionsTag, FramebufferTag,
5-
ModuleTag,
5+
MemoryMapTag, ModuleTag,
66
};
77

88
use alloc::boxed::Box;
@@ -18,6 +18,7 @@ pub struct Multiboot2InformationBuilder {
1818
command_line_tag: Option<Box<CommandLineTag>>,
1919
elf_sections_tag: Option<Box<ElfSectionsTag>>,
2020
framebuffer_tag: Option<Box<FramebufferTag>>,
21+
memory_map_tag: Option<Box<MemoryMapTag>>,
2122
module_tags: Vec<Box<ModuleTag>>,
2223
}
2324

@@ -29,6 +30,7 @@ impl Multiboot2InformationBuilder {
2930
command_line_tag: None,
3031
elf_sections_tag: None,
3132
framebuffer_tag: None,
33+
memory_map_tag: None,
3234
module_tags: Vec::new(),
3335
}
3436
}
@@ -53,6 +55,10 @@ impl Multiboot2InformationBuilder {
5355
self.framebuffer_tag = Some(framebuffer_tag);
5456
}
5557

58+
pub fn memory_map_tag(&mut self, memory_map_tag: Box<MemoryMapTag>) {
59+
self.memory_map_tag = Some(memory_map_tag);
60+
}
61+
5662
pub fn add_module_tag(&mut self, module_tag: Box<ModuleTag>) {
5763
self.module_tags.push(module_tag);
5864
}

multiboot2/src/lib.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,16 +1526,6 @@ mod tests {
15261526
assert!(efi_mmap.is_none());
15271527
}
15281528

1529-
#[test]
1530-
/// Compile time test for `MemoryMapTag`.
1531-
fn e820_memory_map_tag_size() {
1532-
use super::MemoryMapTag;
1533-
unsafe {
1534-
// `MemoryMapTag` is 16 bytes without the 1st entry
1535-
core::mem::transmute::<[u8; 16], MemoryMapTag>([0u8; 16]);
1536-
}
1537-
}
1538-
15391529
#[test]
15401530
/// Compile time test for `EFIMemoryMapTag`.
15411531
fn efi_memory_map_tag_size() {

multiboot2/src/memory_map.rs

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1-
use crate::tag_type::{TagType, TagTypeId};
1+
use crate::{Tag, TagTrait, TagType, TagTypeId};
2+
23
use core::convert::TryInto;
34
use core::marker::PhantomData;
45
use core::mem;
56

7+
#[cfg(feature = "builder")]
8+
use {crate::builder::boxed_dst_tag, crate::builder::traits::StructAsBytes, alloc::boxed::Box};
9+
10+
const METADATA_SIZE: usize = mem::size_of::<TagTypeId>() + 3 * mem::size_of::<u32>();
11+
612
/// This tag provides an initial host memory map.
713
///
814
/// The map provided is guaranteed to list all standard RAM that should be
@@ -13,17 +19,28 @@ use core::mem;
1319
/// This tag may not be provided by some boot loaders on EFI platforms if EFI
1420
/// boot services are enabled and available for the loaded image (The EFI boot
1521
/// services tag may exist in the Multiboot2 boot information structure).
16-
#[derive(Debug)]
22+
#[derive(Debug, ptr_meta::Pointee)]
1723
#[repr(C)]
1824
pub struct MemoryMapTag {
1925
typ: TagTypeId,
2026
size: u32,
2127
entry_size: u32,
2228
entry_version: u32,
23-
first_area: [MemoryArea; 0],
29+
areas: [MemoryArea],
2430
}
2531

2632
impl MemoryMapTag {
33+
#[cfg(feature = "builder")]
34+
pub fn new(areas: &[MemoryArea]) -> Box<Self> {
35+
let entry_size: u32 = mem::size_of::<MemoryArea>().try_into().unwrap();
36+
let entry_version: u32 = 0;
37+
let mut bytes = [entry_size.to_le_bytes(), entry_version.to_le_bytes()].concat();
38+
for area in areas {
39+
bytes.extend(area.struct_as_bytes());
40+
}
41+
boxed_dst_tag(TagType::Mmap, bytes.as_slice())
42+
}
43+
2744
/// Return an iterator over all memory areas that have the type
2845
/// [`MemoryAreaType::Available`].
2946
pub fn available_memory_areas(&self) -> impl Iterator<Item = &MemoryArea> {
@@ -34,21 +51,26 @@ impl MemoryMapTag {
3451
/// Return an iterator over all memory areas.
3552
pub fn memory_areas(&self) -> MemoryAreaIter {
3653
let self_ptr = self as *const MemoryMapTag;
37-
let start_area = self.first_area.as_ptr();
38-
54+
let start_area = (&self.areas[0]) as *const MemoryArea;
3955
MemoryAreaIter {
4056
current_area: start_area as u64,
4157
// NOTE: `last_area` is only a bound, it doesn't necessarily point exactly to the last element
42-
last_area: (self_ptr as u64
43-
+ (self.size as u64 - core::mem::size_of::<MemoryMapTag>() as u64)),
58+
last_area: (self_ptr as *const () as u64 + (self.size - self.entry_size) as u64),
4459
entry_size: self.entry_size,
4560
phantom: PhantomData,
4661
}
4762
}
4863
}
4964

65+
impl TagTrait for MemoryMapTag {
66+
fn dst_size(base_tag: &Tag) -> usize {
67+
assert!(base_tag.size as usize >= METADATA_SIZE);
68+
base_tag.size as usize - METADATA_SIZE
69+
}
70+
}
71+
5072
/// A memory area entry descriptor.
51-
#[derive(Debug)]
73+
#[derive(Debug, Clone)]
5274
#[repr(C)]
5375
pub struct MemoryArea {
5476
base_addr: u64,
@@ -58,6 +80,16 @@ pub struct MemoryArea {
5880
}
5981

6082
impl MemoryArea {
83+
/// Create a new MemoryArea.
84+
pub fn new(base_addr: u64, length: u64, typ: MemoryAreaType) -> Self {
85+
Self {
86+
base_addr,
87+
length,
88+
typ,
89+
_reserved: 0,
90+
}
91+
}
92+
6193
/// The start address of the memory region.
6294
pub fn start_address(&self) -> u64 {
6395
self.base_addr
@@ -79,6 +111,8 @@ impl MemoryArea {
79111
}
80112
}
81113

114+
impl StructAsBytes for MemoryArea {}
115+
82116
/// An enum of possible reported region types.
83117
/// Inside the Multiboot2 spec this is kind of hidden
84118
/// inside the implementation of `struct multiboot_mmap_entry`.

0 commit comments

Comments
 (0)