Browse Source

memory_map: support non-standard types

Philipp Schuster 1 year ago
parent
commit
39eb08e4ba

+ 2 - 2
integration-test/bins/multiboot2_chainloader/src/loader.rs

@@ -1,6 +1,7 @@
 use elf_rs::{ElfFile, ProgramHeaderEntry, ProgramType};
 use multiboot2::{
-    BootLoaderNameTag, CommandLineTag, MemoryArea, MemoryAreaType, MemoryMapTag, ModuleTag,
+    BootLoaderNameTag, CommandLineTag, MemoryArea, MemoryAreaType, MemoryMapTag,
+    ModuleTag,
 };
 
 /// Loads the first module into memory. Assumes that the module is a ELF file.
@@ -26,7 +27,6 @@ pub fn load_module(mut modules: multiboot::information::ModuleIter) -> ! {
         log::info!("Multiboot2 header:\n{hdr:#?}");
     }
 
-
     // Map the load segments into memory (at their corresponding link).
     {
         let elf = elf_rs::Elf32::from_bytes(elf_bytes).expect("Should be valid ELF");

+ 3 - 2
integration-test/bins/rust-toolchain.toml

@@ -1,6 +1,7 @@
 [toolchain]
 channel = "nightly-2023-06-22"
-profile = "minimal"
+profile = "default"
 components = [
-    "rust-src"
+    "rust-src",
+    "rustfmt",
 ]

+ 3 - 1
multiboot2/Changelog.md

@@ -1,6 +1,8 @@
 # CHANGELOG for crate `multiboot2`
 ## Unreleased
-- **Breaking** Make functions of `InformationBuilder` chainable. They now consume the builder.
+- **BREAKING** Make functions of `InformationBuilder` chainable. They now consume the builder.
+- **BREAKING** Allow non-standard memory area types by using new pair of
+  corresponding types: `MemoryAreaTypeId` and `MemoryAreaType`.
 
 ## 0.16.0 (2023-06-23)
 - **BREAKING** renamed `MULTIBOOT2_BOOTLOADER_MAGIC` to `MAGIC`

+ 2 - 1
multiboot2/src/lib.rs

@@ -62,7 +62,7 @@ pub use framebuffer::{FramebufferColor, FramebufferField, FramebufferTag, Frameb
 pub use image_load_addr::ImageLoadPhysAddrTag;
 pub use memory_map::{
     BasicMemoryInfoTag, EFIBootServicesNotExitedTag, EFIMemoryAreaType, EFIMemoryDesc,
-    EFIMemoryMapTag, MemoryArea, MemoryAreaType, MemoryMapTag,
+    EFIMemoryMapTag, MemoryArea, MemoryAreaType, MemoryAreaTypeId, MemoryMapTag,
 };
 pub use module::{ModuleIter, ModuleTag};
 pub use rsdp::{RsdpV1Tag, RsdpV2Tag};
@@ -583,6 +583,7 @@ impl<T: Pointee<Metadata = ()>> TagTrait for T {
 #[cfg(test)]
 mod tests {
     use super::*;
+    use crate::memory_map::MemoryAreaType;
     use core::str::Utf8Error;
 
     #[test]

+ 86 - 14
multiboot2/src/memory_map.rs

@@ -1,6 +1,6 @@
 use crate::{Tag, TagTrait, TagType, TagTypeId};
 use core::convert::TryInto;
-use core::fmt::Debug;
+use core::fmt::{Debug, Formatter};
 use core::marker::PhantomData;
 use core::mem;
 
@@ -84,17 +84,17 @@ impl StructAsBytes for MemoryMapTag {
 pub struct MemoryArea {
     base_addr: u64,
     length: u64,
-    typ: MemoryAreaType,
+    typ: MemoryAreaTypeId,
     _reserved: u32,
 }
 
 impl MemoryArea {
     /// Create a new MemoryArea.
-    pub fn new(base_addr: u64, length: u64, typ: MemoryAreaType) -> Self {
+    pub fn new(base_addr: u64, length: u64, typ: impl Into<MemoryAreaTypeId>) -> Self {
         Self {
             base_addr,
             length,
-            typ,
+            typ: typ.into(),
             _reserved: 0,
         }
     }
@@ -115,7 +115,7 @@ impl MemoryArea {
     }
 
     /// The type of the memory region.
-    pub fn typ(&self) -> MemoryAreaType {
+    pub fn typ(&self) -> MemoryAreaTypeId {
         self.typ
     }
 }
@@ -127,28 +127,100 @@ 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`.
+/// ABI-friendly version of [`MemoryAreaType`].
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[repr(C)]
+pub struct MemoryAreaTypeId(u32);
+
+impl From<u32> for MemoryAreaTypeId {
+    fn from(value: u32) -> Self {
+        Self(value)
+    }
+}
+
+impl From<MemoryAreaTypeId> for u32 {
+    fn from(value: MemoryAreaTypeId) -> Self {
+        value.0
+    }
+}
+
+impl Debug for MemoryAreaTypeId {
+    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
+        let mt = MemoryAreaType::from(*self);
+        Debug::fmt(&mt, f)
+    }
+}
+
+/// Abstraction over defined memory types for the memory map as well as custom
+/// ones. Types 1 to 5 are defined in the Multiboot2 spec and correspond to the
+/// entry types of e820 memory maps.
+///
+/// This is not binary compatible with the Multiboot2 spec. Please use
+/// [`MemoryAreaTypeId`] instead.
 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[repr(u32)]
 pub enum MemoryAreaType {
     /// Available memory free to be used by the OS.
-    Available = 1,
+    Available, /* 1 */
 
     /// A reserved area that must not be used.
-    Reserved = 2,
+    Reserved, /* 2, */
 
     /// Usable memory holding ACPI information.
-    AcpiAvailable = 3,
+    AcpiAvailable, /* 3, */
 
     /// Reserved memory which needs to be preserved on hibernation.
     /// Also called NVS in spec, which stands for "Non-Volatile Sleep/Storage",
     /// which is part of ACPI specification.
-    ReservedHibernate = 4,
+    ReservedHibernate, /* 4, */
 
     /// Memory which is occupied by defective RAM modules.
-    Defective = 5,
+    Defective, /* = 5, */
+
+    /// Custom memory map type.
+    Custom(u32),
+}
+
+impl From<MemoryAreaTypeId> for MemoryAreaType {
+    fn from(value: MemoryAreaTypeId) -> Self {
+        match value.0 {
+            1 => Self::Available,
+            2 => Self::Reserved,
+            3 => Self::AcpiAvailable,
+            4 => Self::ReservedHibernate,
+            5 => Self::Defective,
+            val => Self::Custom(val),
+        }
+    }
+}
+
+impl From<MemoryAreaType> for MemoryAreaTypeId {
+    fn from(value: MemoryAreaType) -> Self {
+        let integer = match value {
+            MemoryAreaType::Available => 1,
+            MemoryAreaType::Reserved => 2,
+            MemoryAreaType::AcpiAvailable => 3,
+            MemoryAreaType::ReservedHibernate => 4,
+            MemoryAreaType::Defective => 5,
+            MemoryAreaType::Custom(val) => val,
+        };
+        integer.into()
+    }
+}
+
+impl PartialEq<MemoryAreaType> for MemoryAreaTypeId {
+    fn eq(&self, other: &MemoryAreaType) -> bool {
+        let val: MemoryAreaTypeId = (*other).into();
+        let val: u32 = val.0;
+        self.0.eq(&val)
+    }
+}
+
+impl PartialEq<MemoryAreaTypeId> for MemoryAreaType {
+    fn eq(&self, other: &MemoryAreaTypeId) -> bool {
+        let val: MemoryAreaTypeId = (*self).into();
+        let val: u32 = val.0;
+        other.0.eq(&val)
+    }
 }
 
 /// Basic memory info tag.