瀏覽代碼

multiboot2: Implement setting memory map tag

Niklas Sombert 2 年之前
父節點
當前提交
d198dceffe
共有 3 個文件被更改,包括 49 次插入19 次删除
  1. 7 1
      multiboot2/src/builder/information.rs
  2. 0 10
      multiboot2/src/lib.rs
  3. 42 8
      multiboot2/src/memory_map.rs

+ 7 - 1
multiboot2/src/builder/information.rs

@@ -2,7 +2,7 @@
 use crate::builder::traits::StructAsBytes;
 use crate::{
     BasicMemoryInfoTag, BootLoaderNameTag, CommandLineTag, ElfSectionsTag, FramebufferTag,
-    ModuleTag,
+    MemoryMapTag, ModuleTag,
 };
 
 use alloc::boxed::Box;
@@ -18,6 +18,7 @@ pub struct Multiboot2InformationBuilder {
     command_line_tag: Option<Box<CommandLineTag>>,
     elf_sections_tag: Option<Box<ElfSectionsTag>>,
     framebuffer_tag: Option<Box<FramebufferTag>>,
+    memory_map_tag: Option<Box<MemoryMapTag>>,
     module_tags: Vec<Box<ModuleTag>>,
 }
 
@@ -29,6 +30,7 @@ impl Multiboot2InformationBuilder {
             command_line_tag: None,
             elf_sections_tag: None,
             framebuffer_tag: None,
+            memory_map_tag: None,
             module_tags: Vec::new(),
         }
     }
@@ -53,6 +55,10 @@ impl Multiboot2InformationBuilder {
         self.framebuffer_tag = Some(framebuffer_tag);
     }
 
+    pub fn memory_map_tag(&mut self, memory_map_tag: Box<MemoryMapTag>) {
+        self.memory_map_tag = Some(memory_map_tag);
+    }
+
     pub fn add_module_tag(&mut self, module_tag: Box<ModuleTag>) {
         self.module_tags.push(module_tag);
     }

+ 0 - 10
multiboot2/src/lib.rs

@@ -1526,16 +1526,6 @@ mod tests {
         assert!(efi_mmap.is_none());
     }
 
-    #[test]
-    /// Compile time test for `MemoryMapTag`.
-    fn e820_memory_map_tag_size() {
-        use super::MemoryMapTag;
-        unsafe {
-            // `MemoryMapTag` is 16 bytes without the 1st entry
-            core::mem::transmute::<[u8; 16], MemoryMapTag>([0u8; 16]);
-        }
-    }
-
     #[test]
     /// Compile time test for `EFIMemoryMapTag`.
     fn efi_memory_map_tag_size() {

+ 42 - 8
multiboot2/src/memory_map.rs

@@ -1,8 +1,14 @@
-use crate::tag_type::{TagType, TagTypeId};
+use crate::{Tag, TagTrait, TagType, TagTypeId};
+
 use core::convert::TryInto;
 use core::marker::PhantomData;
 use core::mem;
 
+#[cfg(feature = "builder")]
+use {crate::builder::boxed_dst_tag, crate::builder::traits::StructAsBytes, alloc::boxed::Box};
+
+const METADATA_SIZE: usize = mem::size_of::<TagTypeId>() + 3 * mem::size_of::<u32>();
+
 /// This tag provides an initial host memory map.
 ///
 /// The map provided is guaranteed to list all standard RAM that should be
@@ -13,17 +19,28 @@ use core::mem;
 /// This tag may not be provided by some boot loaders on EFI platforms if EFI
 /// boot services are enabled and available for the loaded image (The EFI boot
 /// services tag may exist in the Multiboot2 boot information structure).
-#[derive(Debug)]
+#[derive(Debug, ptr_meta::Pointee)]
 #[repr(C)]
 pub struct MemoryMapTag {
     typ: TagTypeId,
     size: u32,
     entry_size: u32,
     entry_version: u32,
-    first_area: [MemoryArea; 0],
+    areas: [MemoryArea],
 }
 
 impl MemoryMapTag {
+    #[cfg(feature = "builder")]
+    pub fn new(areas: &[MemoryArea]) -> Box<Self> {
+        let entry_size: u32 = mem::size_of::<MemoryArea>().try_into().unwrap();
+        let entry_version: u32 = 0;
+        let mut bytes = [entry_size.to_le_bytes(), entry_version.to_le_bytes()].concat();
+        for area in areas {
+            bytes.extend(area.struct_as_bytes());
+        }
+        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> {
@@ -34,21 +51,26 @@ impl MemoryMapTag {
     /// Return an iterator over all memory areas.
     pub fn memory_areas(&self) -> MemoryAreaIter {
         let self_ptr = self as *const MemoryMapTag;
-        let start_area = self.first_area.as_ptr();
-
+        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 u64
-                + (self.size as u64 - core::mem::size_of::<MemoryMapTag>() as u64)),
+            last_area: (self_ptr as *const () as u64 + (self.size - self.entry_size) as u64),
             entry_size: self.entry_size,
             phantom: PhantomData,
         }
     }
 }
 
+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
+    }
+}
+
 /// A memory area entry descriptor.
-#[derive(Debug)]
+#[derive(Debug, Clone)]
 #[repr(C)]
 pub struct MemoryArea {
     base_addr: u64,
@@ -58,6 +80,16 @@ pub struct MemoryArea {
 }
 
 impl MemoryArea {
+    /// Create a new MemoryArea.
+    pub fn new(base_addr: u64, length: u64, typ: MemoryAreaType) -> Self {
+        Self {
+            base_addr,
+            length,
+            typ,
+            _reserved: 0,
+        }
+    }
+
     /// The start address of the memory region.
     pub fn start_address(&self) -> u64 {
         self.base_addr
@@ -79,6 +111,8 @@ impl MemoryArea {
     }
 }
 
+impl StructAsBytes for MemoryArea {}
+
 /// An enum of possible reported region types.
 /// Inside the Multiboot2 spec this is kind of hidden
 /// inside the implementation of `struct multiboot_mmap_entry`.