diff --git a/integration-test/bins/multiboot2_chainloader/src/loader.rs b/integration-test/bins/multiboot2_chainloader/src/loader.rs index 97150722..fa613b85 100644 --- a/integration-test/bins/multiboot2_chainloader/src/loader.rs +++ b/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"); diff --git a/integration-test/bins/rust-toolchain.toml b/integration-test/bins/rust-toolchain.toml index 0f7ffde2..0aa1490d 100644 --- a/integration-test/bins/rust-toolchain.toml +++ b/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", ] diff --git a/multiboot2-header/src/builder/mod.rs b/multiboot2-header/src/builder/mod.rs index 20306965..9f4037dd 100644 --- a/multiboot2-header/src/builder/mod.rs +++ b/multiboot2-header/src/builder/mod.rs @@ -2,7 +2,7 @@ mod header; mod information_request; -pub(self) mod traits; +pub(crate) mod traits; pub use header::HeaderBuilder; pub use information_request::InformationRequestHeaderTagBuilder; diff --git a/multiboot2/Changelog.md b/multiboot2/Changelog.md index ed335659..f87715ad 100644 --- a/multiboot2/Changelog.md +++ b/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` diff --git a/multiboot2/src/lib.rs b/multiboot2/src/lib.rs index ab5c1731..de1b669e 100644 --- a/multiboot2/src/lib.rs +++ b/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> TagTrait for T { #[cfg(test)] mod tests { use super::*; + use crate::memory_map::MemoryAreaType; use core::str::Utf8Error; #[test] diff --git a/multiboot2/src/memory_map.rs b/multiboot2/src/memory_map.rs index 888e42fb..e6a885c1 100644 --- a/multiboot2/src/memory_map.rs +++ b/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) -> 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 for MemoryAreaTypeId { + fn from(value: u32) -> Self { + Self(value) + } +} + +impl From 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 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 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 for MemoryAreaTypeId { + fn eq(&self, other: &MemoryAreaType) -> bool { + let val: MemoryAreaTypeId = (*other).into(); + let val: u32 = val.0; + self.0.eq(&val) + } +} + +impl PartialEq 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. diff --git a/multiboot2/src/tag_type.rs b/multiboot2/src/tag_type.rs index d36b0589..7b68a9dc 100644 --- a/multiboot2/src/tag_type.rs +++ b/multiboot2/src/tag_type.rs @@ -19,7 +19,7 @@ use core::str::Utf8Error; /// Multiboot2 [`Tag`]. This type can easily be created from or converted to /// [`TagType`]. #[repr(transparent)] -#[derive(Copy, Clone, Debug, PartialOrd, PartialEq, Eq, Ord, Hash)] +#[derive(Copy, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)] pub struct TagTypeId(u32); impl TagTypeId { @@ -29,6 +29,13 @@ impl TagTypeId { } } +impl Debug for TagTypeId { + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + let tag_type = TagType::from(*self); + Debug::fmt(&tag_type, f) + } +} + /// Higher level abstraction for [`TagTypeId`] that assigns each possible value /// to a specific semantic according to the specification. Additionally, it /// allows to use the [`TagType::Custom`] variant. It is **not binary compatible**