Ver Fonte

multiboot2-header: code improvements

Philipp Schuster há 3 anos atrás
pai
commit
648184d874

+ 13 - 3
multiboot2-header/README.md

@@ -15,10 +15,10 @@ What this library is good for:
 What this library is not optimal for:
 - compiling a Multiboot2 header statically into an object file using only Rust code
 
-## Example
+## Example 1: Builder + Parse
 ```rust
 use multiboot2_header::builder::Multiboot2HeaderBuilder;
-use multiboot2_header::{ConsoleHeaderTag, HeaderTagFlag, HeaderTagISA, InformationRequestHeaderTagBuilder, MbiTagType, Multiboot2Header, RelocatableHeaderTag, RelocatableHeaderTagPreference, load_mb2_header};
+use multiboot2_header::{HeaderTagFlag, HeaderTagISA, InformationRequestHeaderTagBuilder, MbiTagType, RelocatableHeaderTag, RelocatableHeaderTagPreference, Multiboot2Header};
 
 /// Small example that creates a Multiboot2 header and parses it afterwards.
 fn main() {
@@ -39,11 +39,21 @@ fn main() {
         .build();
 
     // Cast bytes in vector to Multiboot2 information structure
-    let mb2_hdr = unsafe { load_mb2_header(mb2_hdr_bytes.as_ptr() as usize) };
+    let mb2_hdr = unsafe { Multiboot2Header::from_addr(mb2_hdr_bytes.as_ptr() as usize) };
     println!("{:#?}", mb2_hdr);
 }
+```
 
+## Example 2: Multiboot2 header as static data in Rust file
+You can use the builder, construct a Multiboot2 header, write it to a file and include it like this:
+```
+#[used]
+#[no_mangle]
+#[link_section = ".text.multiboot2_header"]
+static MULTIBOOT2_HDR: &[u8; 64] = include_bytes!("mb2_hdr_dump.bin");
 ```
+You may need a special linker script to place this in a LOAD segment with a file offset with less than 32768 bytes.
+See specification.
 
 ## License & Contribution
 

+ 5 - 2
multiboot2-header/examples/minimal.rs

@@ -1,5 +1,8 @@
 use multiboot2_header::builder::Multiboot2HeaderBuilder;
-use multiboot2_header::{ConsoleHeaderTag, HeaderTagFlag, HeaderTagISA, InformationRequestHeaderTagBuilder, MbiTagType, Multiboot2Header, RelocatableHeaderTag, RelocatableHeaderTagPreference, load_mb2_header};
+use multiboot2_header::{
+    HeaderTagFlag, HeaderTagISA, InformationRequestHeaderTagBuilder, MbiTagType, Multiboot2Header,
+    RelocatableHeaderTag, RelocatableHeaderTagPreference,
+};
 
 /// Small example that creates a Multiboot2 header and parses it afterwards.
 fn main() {
@@ -20,6 +23,6 @@ fn main() {
         .build();
 
     // Cast bytes in vector to Multiboot2 information structure
-    let mb2_hdr = unsafe { load_mb2_header(mb2_hdr_bytes.as_ptr() as usize) };
+    let mb2_hdr = unsafe { Multiboot2Header::from_addr(mb2_hdr_bytes.as_ptr() as usize) };
     println!("{:#?}", mb2_hdr);
 }

+ 7 - 7
multiboot2-header/src/address.rs

@@ -42,25 +42,25 @@ impl AddressHeaderTag {
         }
     }
 
-    pub fn typ(&self) -> HeaderTagType {
+    pub const fn typ(&self) -> HeaderTagType {
         self.typ
     }
-    pub fn flags(&self) -> HeaderTagFlag {
+    pub const fn flags(&self) -> HeaderTagFlag {
         self.flags
     }
-    pub fn size(&self) -> u32 {
+    pub const fn size(&self) -> u32 {
         self.size
     }
-    pub fn header_addr(&self) -> u32 {
+    pub const fn header_addr(&self) -> u32 {
         self.header_addr
     }
-    pub fn load_addr(&self) -> u32 {
+    pub const fn load_addr(&self) -> u32 {
         self.load_addr
     }
-    pub fn load_end_addr(&self) -> u32 {
+    pub const fn load_end_addr(&self) -> u32 {
         self.load_end_addr
     }
-    pub fn bss_end_addr(&self) -> u32 {
+    pub const fn bss_end_addr(&self) -> u32 {
         self.bss_end_addr
     }
 }

+ 5 - 4
multiboot2-header/src/console.rs

@@ -1,6 +1,7 @@
 use crate::{HeaderTagFlag, HeaderTagType, StructAsBytes};
 use core::mem::size_of;
 
+/// Possible flags for [`ConsoleHeaderTag`].
 #[repr(u32)]
 #[derive(Copy, Clone, Debug)]
 pub enum ConsoleHeaderTagFlags {
@@ -31,16 +32,16 @@ impl ConsoleHeaderTag {
         }
     }
 
-    pub fn typ(&self) -> HeaderTagType {
+    pub const fn typ(&self) -> HeaderTagType {
         self.typ
     }
-    pub fn flags(&self) -> HeaderTagFlag {
+    pub const fn flags(&self) -> HeaderTagFlag {
         self.flags
     }
-    pub fn size(&self) -> u32 {
+    pub const fn size(&self) -> u32 {
         self.size
     }
-    pub fn console_flags(&self) -> ConsoleHeaderTagFlags {
+    pub const fn console_flags(&self) -> ConsoleHeaderTagFlags {
         self.console_flags
     }
 }

+ 4 - 4
multiboot2-header/src/end.rs

@@ -2,7 +2,7 @@ use crate::{HeaderTagFlag, HeaderTagType, StructAsBytes};
 use core::mem::size_of;
 
 /// Terminates a list of optional tags
-/// in a multiboot2 header.
+/// in a Multiboot2 header.
 #[derive(Copy, Clone, Debug)]
 #[repr(C, packed(8))]
 pub struct EndHeaderTag {
@@ -22,13 +22,13 @@ impl EndHeaderTag {
         }
     }
 
-    pub fn typ(&self) -> HeaderTagType {
+    pub const fn typ(&self) -> HeaderTagType {
         self.typ
     }
-    pub fn flags(&self) -> HeaderTagFlag {
+    pub const fn flags(&self) -> HeaderTagFlag {
         self.flags
     }
-    pub fn size(&self) -> u32 {
+    pub const fn size(&self) -> u32 {
         self.size
     }
 }

+ 4 - 4
multiboot2-header/src/entry_efi_32.rs

@@ -25,16 +25,16 @@ impl EntryEfi32HeaderTag {
         }
     }
 
-    pub fn typ(&self) -> HeaderTagType {
+    pub const fn typ(&self) -> HeaderTagType {
         self.typ
     }
-    pub fn flags(&self) -> HeaderTagFlag {
+    pub const fn flags(&self) -> HeaderTagFlag {
         self.flags
     }
-    pub fn size(&self) -> u32 {
+    pub const fn size(&self) -> u32 {
         self.size
     }
-    pub fn entry_addr(&self) -> u32 {
+    pub const fn entry_addr(&self) -> u32 {
         self.entry_addr
     }
 }

+ 4 - 4
multiboot2-header/src/entry_efi_64.rs

@@ -25,16 +25,16 @@ impl EntryEfi64HeaderTag {
         }
     }
 
-    pub fn typ(&self) -> HeaderTagType {
+    pub const fn typ(&self) -> HeaderTagType {
         self.typ
     }
-    pub fn flags(&self) -> HeaderTagFlag {
+    pub const fn flags(&self) -> HeaderTagFlag {
         self.flags
     }
-    pub fn size(&self) -> u32 {
+    pub const fn size(&self) -> u32 {
         self.size
     }
-    pub fn entry_addr(&self) -> u32 {
+    pub const fn entry_addr(&self) -> u32 {
         self.entry_addr
     }
 }

+ 4 - 4
multiboot2-header/src/entry_header.rs

@@ -25,16 +25,16 @@ impl EntryHeaderTag {
         }
     }
 
-    pub fn typ(&self) -> HeaderTagType {
+    pub const fn typ(&self) -> HeaderTagType {
         self.typ
     }
-    pub fn flags(&self) -> HeaderTagFlag {
+    pub const fn flags(&self) -> HeaderTagFlag {
         self.flags
     }
-    pub fn size(&self) -> u32 {
+    pub const fn size(&self) -> u32 {
         self.size
     }
-    pub fn entry_addr(&self) -> u32 {
+    pub const fn entry_addr(&self) -> u32 {
         self.entry_addr
     }
 }

+ 6 - 6
multiboot2-header/src/framebuffer.rs

@@ -28,22 +28,22 @@ impl FramebufferHeaderTag {
         }
     }
 
-    pub fn typ(&self) -> HeaderTagType {
+    pub const fn typ(&self) -> HeaderTagType {
         self.typ
     }
-    pub fn flags(&self) -> HeaderTagFlag {
+    pub const fn flags(&self) -> HeaderTagFlag {
         self.flags
     }
-    pub fn size(&self) -> u32 {
+    pub const fn size(&self) -> u32 {
         self.size
     }
-    pub fn width(&self) -> u32 {
+    pub const fn width(&self) -> u32 {
         self.width
     }
-    pub fn height(&self) -> u32 {
+    pub const fn height(&self) -> u32 {
         self.height
     }
-    pub fn depth(&self) -> u32 {
+    pub const fn depth(&self) -> u32 {
         self.depth
     }
 }

+ 24 - 20
multiboot2-header/src/header/builder.rs

@@ -1,8 +1,10 @@
+//! Exports item [`Multiboot2HeaderBuilder`].
+
 use crate::HeaderTagISA;
 use crate::{
     AddressHeaderTag, ConsoleHeaderTag, EfiBootServiceHeaderTag, EndHeaderTag, EntryEfi32HeaderTag,
     EntryEfi64HeaderTag, EntryHeaderTag, FramebufferHeaderTag, InformationRequestHeaderTagBuilder,
-    ModuleAlignHeaderTag, Multiboot2HeaderInner, RelocatableHeaderTag, StructAsBytes,
+    ModuleAlignHeaderTag, Multiboot2BasicHeader, RelocatableHeaderTag, StructAsBytes,
 };
 use core::mem::size_of;
 
@@ -64,10 +66,10 @@ impl Multiboot2HeaderBuilder {
         }
     }
 
-    /// Returns the expected length of the multiboot2 header,
-    /// when the [`build`]-method gets called.
+    /// Returns the expected length of the Multiboot2 header,
+    /// when the `build()`-method gets called.
     pub fn expected_len(&self) -> usize {
-        let base_len = size_of::<Multiboot2HeaderInner>();
+        let base_len = size_of::<Multiboot2BasicHeader>();
         // size_or_up_aligned not required, because basic header length is 16 and the
         // begin is 8 byte aligned => first tag automatically 8 byte aligned
         let mut len = Self::size_or_up_aligned(base_len);
@@ -109,9 +111,9 @@ impl Multiboot2HeaderBuilder {
         len
     }
 
-    /// Adds the bytes of a tag to the final multiboot2 header byte vector.
+    /// Adds the bytes of a tag to the final Multiboot2 header byte vector.
     /// Align should be true for all tags except the end tag.
-    fn build_add_bytes(dest: &mut Vec<u8>, source: &Vec<u8>, is_end_tag: bool) {
+    fn build_add_bytes(dest: &mut Vec<u8>, source: &[u8], is_end_tag: bool) {
         dest.extend(source);
         if !is_end_tag {
             let size = source.len();
@@ -130,7 +132,7 @@ impl Multiboot2HeaderBuilder {
         Self::build_add_bytes(
             &mut data,
             // important that we write the correct expected length into the header!
-            &Multiboot2HeaderInner::new(self.arch, self.expected_len() as u32).struct_as_bytes(),
+            &Multiboot2BasicHeader::new(self.arch, self.expected_len() as u32).struct_as_bytes(),
             false,
         );
 
@@ -174,6 +176,8 @@ impl Multiboot2HeaderBuilder {
         data
     }
 
+    // clippy thinks this can be a const fn but the compiler denies it
+    #[allow(clippy::missing_const_for_fn)]
     pub fn information_request_tag(
         mut self,
         information_request_tag: InformationRequestHeaderTagBuilder,
@@ -181,39 +185,39 @@ impl Multiboot2HeaderBuilder {
         self.information_request_tag = Some(information_request_tag);
         self
     }
-    pub fn address_tag(mut self, address_tag: AddressHeaderTag) -> Self {
+    pub const fn address_tag(mut self, address_tag: AddressHeaderTag) -> Self {
         self.address_tag = Some(address_tag);
         self
     }
-    pub fn entry_tag(mut self, entry_tag: EntryHeaderTag) -> Self {
+    pub const fn entry_tag(mut self, entry_tag: EntryHeaderTag) -> Self {
         self.entry_tag = Some(entry_tag);
         self
     }
-    pub fn console_tag(mut self, console_tag: ConsoleHeaderTag) -> Self {
+    pub const fn console_tag(mut self, console_tag: ConsoleHeaderTag) -> Self {
         self.console_tag = Some(console_tag);
         self
     }
-    pub fn framebuffer_tag(mut self, framebuffer_tag: FramebufferHeaderTag) -> Self {
+    pub const fn framebuffer_tag(mut self, framebuffer_tag: FramebufferHeaderTag) -> Self {
         self.framebuffer_tag = Some(framebuffer_tag);
         self
     }
-    pub fn module_align_tag(mut self, module_align_tag: ModuleAlignHeaderTag) -> Self {
+    pub const fn module_align_tag(mut self, module_align_tag: ModuleAlignHeaderTag) -> Self {
         self.module_align_tag = Some(module_align_tag);
         self
     }
-    pub fn efi_bs_tag(mut self, efi_bs_tag: EfiBootServiceHeaderTag) -> Self {
+    pub const fn efi_bs_tag(mut self, efi_bs_tag: EfiBootServiceHeaderTag) -> Self {
         self.efi_bs_tag = Some(efi_bs_tag);
         self
     }
-    pub fn efi_32_tag(mut self, efi_32_tag: EntryEfi32HeaderTag) -> Self {
+    pub const fn efi_32_tag(mut self, efi_32_tag: EntryEfi32HeaderTag) -> Self {
         self.efi_32_tag = Some(efi_32_tag);
         self
     }
-    pub fn efi_64_tag(mut self, efi_64_tag: EntryEfi64HeaderTag) -> Self {
+    pub const fn efi_64_tag(mut self, efi_64_tag: EntryEfi64HeaderTag) -> Self {
         self.efi_64_tag = Some(efi_64_tag);
         self
     }
-    pub fn relocatable_tag(mut self, relocatable_tag: RelocatableHeaderTag) -> Self {
+    pub const fn relocatable_tag(mut self, relocatable_tag: RelocatableHeaderTag) -> Self {
         self.relocatable_tag = Some(relocatable_tag);
         self
     }
@@ -222,8 +226,8 @@ impl Multiboot2HeaderBuilder {
 #[cfg(test)]
 mod tests {
     use crate::{
-        load_mb2_header, HeaderTagFlag, HeaderTagISA, InformationRequestHeaderTagBuilder,
-        MbiTagType, Multiboot2HeaderBuilder, RelocatableHeaderTag,
+        HeaderTagFlag, HeaderTagISA, InformationRequestHeaderTagBuilder, MbiTagType,
+        Multiboot2Header, Multiboot2HeaderBuilder, RelocatableHeaderTag,
         RelocatableHeaderTagPreference,
     };
 
@@ -238,7 +242,7 @@ mod tests {
     #[test]
     fn test_size_builder() {
         let builder = Multiboot2HeaderBuilder::new(HeaderTagISA::I386);
-        // multiboot2 basic header + end tag
+        // Multiboot2 basic header + end tag
         let mut expected_len = 16 + 8;
         assert_eq!(builder.expected_len(), expected_len);
 
@@ -272,7 +276,7 @@ mod tests {
 
         let mb2_hdr_data = builder.build();
         let mb2_hdr = mb2_hdr_data.as_ptr() as usize;
-        let mb2_hdr = unsafe { load_mb2_header(mb2_hdr) };
+        let mb2_hdr = unsafe { Multiboot2Header::from_addr(mb2_hdr) };
         println!("{:#?}", mb2_hdr);
 
         /* you can write the binary to a file and a tool such as crate "bootinfo"

+ 91 - 65
multiboot2-header/src/header/mod.rs

@@ -1,10 +1,10 @@
+//! Module for the main struct, which marks the begin of a Multiboot2 header.
+//! See [`Multiboot2Header`].
+
 pub mod builder;
 
 pub use self::builder::*;
-use crate::{
-    AddressHeaderTag, InformationRequestHeaderTag, RelocatableHeaderTag, StructAsBytes,
-    MULTIBOOT2_HEADER_MAGIC,
-};
+use crate::{AddressHeaderTag, InformationRequestHeaderTag, RelocatableHeaderTag, StructAsBytes};
 use crate::{ConsoleHeaderTag, EntryHeaderTag};
 use crate::{EfiBootServiceHeaderTag, FramebufferHeaderTag};
 use crate::{EndHeaderTag, HeaderTagType};
@@ -13,85 +13,106 @@ use crate::{HeaderTag, HeaderTagISA};
 use core::fmt::{Debug, Formatter};
 use core::mem::size_of;
 
+/// Magic value for a [`Multiboot2Header`], as defined in spec.
+pub const MULTIBOOT2_HEADER_MAGIC: u32 = 0xe85250d6;
+
 /// Wrapper type around a pointer to the Multiboot2 header.
+/// The Multiboot2 header is the [`Multiboot2BasicHeader`] followed
+/// by all tags (see [`crate::tags::HeaderTagType`]).
 /// Use this if you get a pointer to the header and just want
 /// to parse it. If you want to construct the type by yourself,
-/// please look at [`Multiboot2HeaderInner`].
+/// please look at [`builder::Multiboot2HeaderBuilder`].
 #[repr(transparent)]
 pub struct Multiboot2Header<'a> {
-    inner: &'a Multiboot2HeaderInner,
+    inner: &'a Multiboot2BasicHeader,
 }
 
 impl<'a> Multiboot2Header<'a> {
-    /// Creates a new [`Multiboot2Header`]. Verifies the checksum.
-    pub fn new(inner: &'a Multiboot2HeaderInner) -> Self {
-        assert!(inner.verify_checksum(), "checksum invalid!");
-        Self { inner }
-    }
-
-    /*
-      Nope, this just results in really ugly code :/
-      I didn't find a nice way to solve this.
-
-    /// * `additional_tag_length`: additional tag length including end tag
-    pub fn new(arch: ISA,
-               additional_tag_length: u32) -> (Multiboot2HeaderInner, Self) {
-        let inner = Multiboot2HeaderInner::new(
-            arch,
-            (size_of::<Multiboot2HeaderInner>() + additional_tag_length as usize) as u32
+    /// Public constructor for this type with various validations. It panics if the address is invalid.
+    /// It panics rather than returning a result, because if this fails, it is
+    /// a fatal, unrecoverable error anyways and a bug in your code.
+    ///
+    /// # Panics
+    /// Panics if one of the following conditions is true:
+    /// - `addr` is a null-pointer
+    /// - `addr` isn't 8-byte aligned
+    /// - the magic value of the header is not present
+    /// - the checksum field is invalid
+    ///
+    /// # Safety
+    /// This function may produce undefined behaviour, if the provided `addr` is not a valid
+    /// Multiboot2 header pointer.
+    pub unsafe fn from_addr(addr: usize) -> Self {
+        assert_ne!(0, addr, "`addr` is null pointer");
+        assert_eq!(
+            addr % 8,
+            0,
+            "`addr` must be 8-byte aligned, see Multiboot2 spec"
         );
-        let inner_ref = &inner;
-        (inner, Self{inner: inner_ref,})
-    }*/
-
-    /// Returns the size a static multiboot2 header without tags has.
-    pub fn static_size() -> u32 {
-        size_of::<Multiboot2HeaderInner>() as u32
+        let ptr = addr as *const Multiboot2BasicHeader;
+        let reference = &*ptr;
+        assert_eq!(
+            reference.header_magic(),
+            MULTIBOOT2_HEADER_MAGIC,
+            "The Multiboot2 header must contain the MULTIBOOT2_HEADER_MAGIC={:x}",
+            MULTIBOOT2_HEADER_MAGIC
+        );
+        assert!(
+            reference.verify_checksum(),
+            "checksum invalid! Is {:x}, expected {:x}",
+            reference.checksum(),
+            Self::calc_checksum(reference.header_magic, reference.arch, reference.length)
+        );
+        Self { inner: reference }
     }
 
-    pub fn verify_checksum(&self) -> bool {
+    /// Wrapper around [`Multiboot2BasicHeader::verify_checksum`].
+    pub const fn verify_checksum(&self) -> bool {
         self.inner.verify_checksum()
     }
-
-    pub fn header_magic(&self) -> u32 {
+    /// Wrapper around [`Multiboot2BasicHeader::header_magic`].
+    pub const fn header_magic(&self) -> u32 {
         self.inner.header_magic()
     }
-    pub fn arch(&self) -> HeaderTagISA {
+    /// Wrapper around [`Multiboot2BasicHeader::arch`].
+    pub const fn arch(&self) -> HeaderTagISA {
         self.inner.arch()
     }
-    pub fn length(&self) -> u32 {
+    /// Wrapper around [`Multiboot2BasicHeader::length`].
+    pub const fn length(&self) -> u32 {
         self.inner.length()
     }
-    pub fn checksum(&self) -> u32 {
+    /// Wrapper around [`Multiboot2BasicHeader::checksum`].
+    pub const fn checksum(&self) -> u32 {
         self.inner.checksum()
     }
+    /// Wrapper around [`Multiboot2BasicHeader::tag_iter`].
     pub fn iter(&self) -> Multiboot2HeaderTagIter {
         self.inner.tag_iter()
     }
 
-    pub fn calc_checksum(magic: u32, arch: HeaderTagISA, length: u32) -> u32 {
-        (0x100000000 - magic as u64 - arch as u64 - length as u64) as u32
+    /// Wrapper around [`Multiboot2BasicHeader::calc_checksum`].
+    pub const fn calc_checksum(magic: u32, arch: HeaderTagISA, length: u32) -> u32 {
+        Multiboot2BasicHeader::calc_checksum(magic, arch, length)
     }
 }
 
 impl<'a> Debug for Multiboot2Header<'a> {
     fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
         // For debug fmt we only output the inner field
-        let reference = unsafe { &*(self.inner as *const Multiboot2HeaderInner) };
+        let reference = unsafe { &*(self.inner as *const Multiboot2BasicHeader) };
         Debug::fmt(reference, f)
     }
 }
 
-/// The actual multiboot2 header. The size is not known at
-/// compile time and can only be derived during runtime from
-/// the iteration of the tags until the end tag.
+/// **Use this only if you know what you do. You probably want to use
+/// [`Multiboot2Header`] instead.**
 ///
-/// Use this only if you know what you do. You probably want to use
-/// [`Multiboot2Header`]. If you want to construct a Multiboot2 header at
-/// runtime, see [`builder::Multiboot2HeaderBuilder`].
+/// The "basic" Multiboot2 header. This means only the properties, that are known during
+/// compile time. All other information are derived during runtime from the size property.
 #[derive(Copy, Clone)]
 #[repr(C, packed(8))]
-pub struct Multiboot2HeaderInner {
+pub struct Multiboot2BasicHeader {
     /// Must be the value of [`MULTIBOOT2_HEADER_MAGIC`].
     header_magic: u32,
     arch: HeaderTagISA,
@@ -101,12 +122,12 @@ pub struct Multiboot2HeaderInner {
     // at minimum the end tag
 }
 
-impl Multiboot2HeaderInner {
-    /// Constructs a new
-    pub const fn new(arch: HeaderTagISA, length: u32) -> Self {
+impl Multiboot2BasicHeader {
+    /// Constructor for the basic header.
+    pub(crate) const fn new(arch: HeaderTagISA, length: u32) -> Self {
         let magic = MULTIBOOT2_HEADER_MAGIC;
         let checksum = Self::calc_checksum(magic, arch, length);
-        Multiboot2HeaderInner {
+        Multiboot2BasicHeader {
             header_magic: magic,
             arch,
             length,
@@ -114,41 +135,44 @@ impl Multiboot2HeaderInner {
         }
     }
 
-    /// Verifies that a multiboot2 header is valid
-    pub(super) fn verify_checksum(&self) -> bool {
+    /// Verifies that a Multiboot2 header is valid.
+    pub const fn verify_checksum(&self) -> bool {
         let check = Self::calc_checksum(self.header_magic, self.arch, self.length);
         check == self.checksum
     }
 
-    const fn calc_checksum(magic: u32, arch: HeaderTagISA, length: u32) -> u32 {
+    /// Calculates the checksum as described in the spec.
+    pub const fn calc_checksum(magic: u32, arch: HeaderTagISA, length: u32) -> u32 {
         (0x100000000 - magic as u64 - arch as u64 - length as u64) as u32
     }
 
-    fn header_magic(&self) -> u32 {
+    /// Returns
+    pub const fn header_magic(&self) -> u32 {
         self.header_magic
     }
-    fn arch(&self) -> HeaderTagISA {
+    pub const fn arch(&self) -> HeaderTagISA {
         self.arch
     }
-    fn length(&self) -> u32 {
+    pub const fn length(&self) -> u32 {
         self.length
     }
-    fn checksum(&self) -> u32 {
+    pub const fn checksum(&self) -> u32 {
         self.checksum
     }
 
-    fn tag_iter(&self) -> Multiboot2HeaderTagIter {
-        let base_hdr_size = size_of::<Multiboot2HeaderInner>();
+    /// Returns a [`Multiboot2HeaderTagIter`].
+    pub fn tag_iter(&self) -> Multiboot2HeaderTagIter {
+        let base_hdr_size = size_of::<Multiboot2BasicHeader>();
         if base_hdr_size == self.length as usize {
             panic!("No end tag!");
         }
-        let tag_base_addr = self as *const Multiboot2HeaderInner;
+        let tag_base_addr = self as *const Multiboot2BasicHeader;
         // cast to u8 so that the offset in bytes works correctly
         let tag_base_addr = tag_base_addr as *const u8;
         // tag_base_addr should now point behind the "static" members
-        let tag_base_addr = unsafe { tag_base_addr.offset(base_hdr_size as isize) };
+        let tag_base_addr = unsafe { tag_base_addr.add(base_hdr_size) };
         // align pointer to 8 byte according to spec
-        let tag_base_addr = unsafe { tag_base_addr.offset(tag_base_addr.align_offset(8) as isize) };
+        let tag_base_addr = unsafe { tag_base_addr.add(tag_base_addr.align_offset(8)) };
         // cast back
         let tag_base_addr = tag_base_addr as *const HeaderTag;
         let tags_len = self.length as usize - base_hdr_size;
@@ -156,7 +180,7 @@ impl Multiboot2HeaderInner {
     }
 }
 
-impl Debug for Multiboot2HeaderInner {
+impl Debug for Multiboot2BasicHeader {
     fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
         f.debug_struct("Multiboot2Header")
             .field("header_magic", &{ self.header_magic })
@@ -168,8 +192,10 @@ impl Debug for Multiboot2HeaderInner {
     }
 }
 
-impl StructAsBytes for Multiboot2HeaderInner {}
+impl StructAsBytes for Multiboot2BasicHeader {}
 
+/// Iterator over all tags of a Multiboot2 header. The number of items is derived
+/// by the size/length of the header.
 #[derive(Clone)]
 pub struct Multiboot2HeaderTagIter {
     /// 8-byte aligned base address
@@ -185,7 +211,7 @@ impl Multiboot2HeaderTagIter {
     fn new(base: *const HeaderTag, size: u32) -> Self {
         // transform to byte pointer => offset works properly
         let base = base as *const u8;
-        let base = unsafe { base.offset(base.align_offset(8) as isize) };
+        let base = unsafe { base.add(base.align_offset(8)) };
         let base = base as *const HeaderTag;
         Self { base, n: 0, size }
     }
@@ -198,7 +224,7 @@ impl Iterator for Multiboot2HeaderTagIter {
         if self.n < self.size {
             // transform to byte ptr => offset works correctly
             let ptr = self.base as *const u8;
-            let ptr = unsafe { ptr.offset(self.n as isize) };
+            let ptr = unsafe { ptr.add(self.n as usize) };
             let ptr = ptr as *const HeaderTag;
             assert_eq!(ptr as usize % 8, 0, "must be 8-byte aligned");
             let tag = unsafe { &*ptr };

+ 17 - 14
multiboot2-header/src/information_request.rs

@@ -32,29 +32,29 @@ impl<const N: usize> InformationRequestHeaderTag<N> {
         }
     }
 
-    pub fn typ(&self) -> HeaderTagType {
+    pub const fn typ(&self) -> HeaderTagType {
         self.typ
     }
-    pub fn flags(&self) -> HeaderTagFlag {
+    pub const fn flags(&self) -> HeaderTagFlag {
         self.flags
     }
-    pub fn size(&self) -> u32 {
+    pub const fn size(&self) -> u32 {
         self.size
     }
 
     /// Returns the requests as array. Only works if the number of requests
     /// is known at compile time. For safety and correctness during runtime,
-    /// you should use [`req_iter`].
-    pub fn requests(&self) -> [MbiTagType; N] {
-        // cheap to clone, otherwise difficult with lifetime
-        { self.requests }.clone()
+    /// you should use `req_iter()`.
+    pub const fn requests(&self) -> [MbiTagType; N] {
+        // cheap to copy, otherwise difficult with lifetime
+        self.requests
     }
 
     /// Returns the number of [`MbiTagType`]-requests derived
-    /// from the [`size`]-property. This method is useful
+    /// from the `size`-property. This method is useful
     /// because this struct uses a const generic, but during runtime
     /// we don't know the value in almost any case.
-    pub fn dynamic_requests_size(&self) -> u32 {
+    pub const fn dynamic_requests_size(&self) -> u32 {
         let base_struct_size = size_of::<InformationRequestHeaderTag<0>>();
         let size_diff = self.size - base_struct_size as u32;
         if size_diff > 0 {
@@ -70,7 +70,7 @@ impl<const N: usize> InformationRequestHeaderTag<N> {
         let count = self.dynamic_requests_size();
         let base_ptr = self as *const InformationRequestHeaderTag<N>;
         let base_ptr = base_ptr as *const u8;
-        let base_ptr = unsafe { base_ptr.offset(base_struct_size as isize) };
+        let base_ptr = unsafe { base_ptr.add(base_struct_size) };
         let base_ptr = base_ptr as *const MbiTagType;
         InformationRequestHeaderTagIter::new(count, base_ptr)
     }
@@ -107,7 +107,7 @@ impl InformationRequestHeaderTagBuilder {
     }
 
     /// Returns the expected length of the information request tag,
-    /// when the [`build`]-method gets called.
+    /// when the `build`-method gets called.
     pub fn expected_len(&self) -> usize {
         let basic_header_size = size_of::<InformationRequestHeaderTag<0>>();
         let req_tags_size = self.irs.len() * size_of::<MbiTagType>();
@@ -203,7 +203,7 @@ impl<'a> Iterator for InformationRequestHeaderTagIter<'a> {
 impl<'a> Debug for InformationRequestHeaderTagIter<'a> {
     fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
         let mut debug = f.debug_list();
-        self.clone().for_each(|e| {
+        (*self).for_each(|e| {
             debug.entry(e);
         });
         debug.finish()
@@ -225,8 +225,11 @@ mod tests {
         // type(u16) + flags(u16) + size(u32) + 3 tags (u32)
         assert_eq!(builder.expected_len(), 2 + 2 + 4 + 3 * 4);
         let tag = builder.build();
-        let tag = tag.as_ptr() as *const InformationRequestHeaderTag<3>;
-        let tag = unsafe { core::ptr::read(tag) };
+        let tag = unsafe {
+            (tag.as_ptr() as *const InformationRequestHeaderTag<3>)
+                .as_ref()
+                .unwrap()
+        };
         assert_eq!(tag.flags, HeaderTagFlag::Required);
         // type(u16) + flags(u16) + size(u32) + 3 tags (u32)
         assert_eq!(tag.size, 2 + 2 + 4 + 3 * 4);

+ 27 - 39
multiboot2-header/src/lib.rs

@@ -4,33 +4,34 @@
 //! # Example
 //! ```rust
 //! use multiboot2_header::builder::Multiboot2HeaderBuilder;
-//! use multiboot2_header::{ConsoleHeaderTag, HeaderTagFlag, HeaderTagISA, InformationRequestHeaderTagBuilder, MbiTagType, Multiboot2Header, RelocatableHeaderTag, RelocatableHeaderTagPreference, load_mb2_header};
+//! use multiboot2_header::{HeaderTagFlag, HeaderTagISA, InformationRequestHeaderTagBuilder, MbiTagType, RelocatableHeaderTag, RelocatableHeaderTagPreference, Multiboot2Header};
 //!
-//! /// Small example that creates a Multiboot2 header and parses it afterwards.
-//! fn main() {
-//!     // We create a Multiboot2 header during runtime here. A practical example is that your
-//!     // program gets the header from a file and parses it afterwards.
-//!     let mb2_hdr_bytes = Multiboot2HeaderBuilder::new(HeaderTagISA::I386)
-//!        .relocatable_tag(RelocatableHeaderTag::new(
-//!            HeaderTagFlag::Required,
-//!            0x1337,
-//!            0xdeadbeef,
-//!            4096,
-//!            RelocatableHeaderTagPreference::None,
-//!        ))
-//!        .information_request_tag(
-//!            InformationRequestHeaderTagBuilder::new(HeaderTagFlag::Required)
-//!                .add_irs(&[MbiTagType::Cmdline, MbiTagType::BootLoaderName]),
-//!        )
-//!        .build();
+//! // Small example that creates a Multiboot2 header and parses it afterwards.
+//!
+//! // We create a Multiboot2 header during runtime here. A practical example is that your
+//! // program gets the header from a file and parses it afterwards.
+//! let mb2_hdr_bytes = Multiboot2HeaderBuilder::new(HeaderTagISA::I386)
+//!     .relocatable_tag(RelocatableHeaderTag::new(
+//!         HeaderTagFlag::Required,
+//!         0x1337,
+//!         0xdeadbeef,
+//!         4096,
+//!         RelocatableHeaderTagPreference::None,
+//!     ))
+//!     .information_request_tag(
+//!         InformationRequestHeaderTagBuilder::new(HeaderTagFlag::Required)
+//!             .add_irs(&[MbiTagType::Cmdline, MbiTagType::BootLoaderName]),
+//!     )
+//!     .build();
+//!
+//! // Cast bytes in vector to Multiboot2 information structure
+//! let mb2_hdr = unsafe { Multiboot2Header::from_addr(mb2_hdr_bytes.as_ptr() as usize) };
+//! println!("{:#?}", mb2_hdr);
 //!
-//!     // Cast bytes in vector to Multiboot2 information structure
-//!     let mb2_hdr = unsafe { load_mb2_header(mb2_hdr_bytes.as_ptr() as usize) };
-//!     println!("{:#?}", mb2_hdr);
-//! }
 //! ```
 
 #![deny(rustdoc::all)]
+#![allow(rustdoc::missing_doc_code_examples)]
 #![deny(clippy::all)]
 #![deny(clippy::missing_const_for_fn)]
 #![deny(missing_debug_implementations)]
@@ -72,22 +73,9 @@ pub use self::uefi_bs::*;
 pub use multiboot2::TagType as MbiTagType;
 use std::mem::size_of;
 
-/// Value must be present in multiboot2 header.
-pub const MULTIBOOT2_HEADER_MAGIC: u32 = 0xe85250d6;
-
-/// Loads the data on the given address as Multiboot2 header.
-/// The address must be 8-byte aligned (see specification).
-pub unsafe fn load_mb2_header<'a>(addr: usize) -> Multiboot2Header<'a> {
-    assert_ne!(0, addr, "null pointer");
-    assert_eq!(addr % 8, 0, "must be 8-byte aligned, see multiboot spec");
-    let ptr = addr as *const Multiboot2HeaderInner;
-    let reference = &*ptr;
-    Multiboot2Header::new(reference)
-}
-
-/// Trait for all tags that creates a byte array from a tag.
-/// Useful in Builder-classes to construct a byte vector that
-/// represents the Multiboot2 header.
+/// Trait for all tags that creates a byte array from the tag.
+/// Useful in builders to construct a byte vector that
+/// represents the Multiboot2 header with all its tags.
 pub(crate) trait StructAsBytes: Sized {
     /// Returns the size in bytes of the struct, as known during compile
     /// time. This doesn't use read the "size" field of tags.
@@ -130,7 +118,7 @@ mod tests {
             c: 33,
         };
         let bytes = foo.struct_as_bytes();
-        let foo_from_bytes = unsafe { core::ptr::read(bytes.as_ptr() as *const Foobar) };
+        let foo_from_bytes = unsafe { (bytes.as_ptr() as *const Foobar).as_ref().unwrap() };
         assert_eq!(bytes.len(), size_of::<Foobar>());
         assert_eq!(foo.a, foo_from_bytes.a);
         assert_eq!(foo.b, foo_from_bytes.b);

+ 3 - 3
multiboot2-header/src/module_alignment.rs

@@ -19,13 +19,13 @@ impl ModuleAlignHeaderTag {
         }
     }
 
-    pub fn typ(&self) -> HeaderTagType {
+    pub const fn typ(&self) -> HeaderTagType {
         self.typ
     }
-    pub fn flags(&self) -> HeaderTagFlag {
+    pub const fn flags(&self) -> HeaderTagFlag {
         self.flags
     }
-    pub fn size(&self) -> u32 {
+    pub const fn size(&self) -> u32 {
         self.size
     }
 }

+ 7 - 7
multiboot2-header/src/relocatable.rs

@@ -53,25 +53,25 @@ impl RelocatableHeaderTag {
         }
     }
 
-    pub fn typ(&self) -> HeaderTagType {
+    pub const fn typ(&self) -> HeaderTagType {
         self.typ
     }
-    pub fn flags(&self) -> HeaderTagFlag {
+    pub const fn flags(&self) -> HeaderTagFlag {
         self.flags
     }
-    pub fn size(&self) -> u32 {
+    pub const fn size(&self) -> u32 {
         self.size
     }
-    pub fn min_addr(&self) -> u32 {
+    pub const fn min_addr(&self) -> u32 {
         self.min_addr
     }
-    pub fn max_addr(&self) -> u32 {
+    pub const fn max_addr(&self) -> u32 {
         self.max_addr
     }
-    pub fn align(&self) -> u32 {
+    pub const fn align(&self) -> u32 {
         self.align
     }
-    pub fn preference(&self) -> RelocatableHeaderTagPreference {
+    pub const fn preference(&self) -> RelocatableHeaderTagPreference {
         self.preference
     }
 }

+ 13 - 26
multiboot2-header/src/tags.rs

@@ -1,31 +1,25 @@
-//! Type definitions for "multiboot2 header tags". These tags occur in a binary if it
-//! is multiboot2-compliant, for example a kernel.
-//!
-//! The values are taken from the example C code at the end of the official multiboot2 spec.
-//!
-//! This type definitions are only beneficial to parse such a structure. They can't be used
-//! to construct a multiboot2 header as a static global variable. To write a multiboot2
-//! header, it is highly recommended to do this directly in assembly, because of the
-//! unknown size of structs or some addresses are not known yet (keyword: relocations).
+//! Definition for all types of "Multiboot2 header tags". The values are taken from the example C
+//! code at the end of the official Multiboot2 spec. These tags follow in memory right after
+//! [`crate::Multiboot2BasicHeader`].
 
-use crate::StructAsBytes;
 use core::fmt::Debug;
 
-/// ISA/ARCH in multiboot2 header.
+/// ISA/ARCH in Multiboot2 header.
 #[repr(u32)]
 #[derive(Copy, Clone, Debug)]
 pub enum HeaderTagISA {
     /// Spec: "means 32-bit (protected) mode of i386".
     /// Caution: This is confusing. If you use the EFI64-tag
     /// on an UEFI system, you get into `64-bit long mode`.
-    /// Therefore this tag should be understood as "arch=x86".
+    /// Therefore this tag should be understood as "arch=x86|x86_64".
     I386 = 0,
     /// 32-bit MIPS
     MIPS32 = 4,
 }
 
-/// Possible types for header tags of a multiboot2 header. The names and values are taken
-/// from the example C code at the bottom of the Multiboot2 specification.
+/// Possible types for header tags of a Multiboot2 header. The names and values are taken
+/// from the example C code at the bottom of the Multiboot2 specification. This value
+/// stands in the `typ` property of [`crate::tags::HeaderTag`].
 #[repr(u16)]
 #[derive(Copy, Clone, Debug, PartialEq)]
 pub enum HeaderTagType {
@@ -61,7 +55,8 @@ pub enum HeaderTagFlag {
     Optional = 1,
 }
 
-/// Common structure for all header tags.
+/// Common properties for all header tags. Other tags may have additional fields
+/// that depend on the `typ` and the `size` field.
 #[derive(Copy, Clone, Debug)]
 #[repr(C, packed(8))]
 pub struct HeaderTag {
@@ -74,21 +69,13 @@ pub struct HeaderTag {
 }
 
 impl HeaderTag {
-    // never needed to construct this publicly
-    /*
-    pub fn new(typ: HeaderTagType, flags: HeaderTagFlag, size: u32) -> Self {
-        HeaderTag { typ, flags, size }
-    }*/
-
-    pub fn typ(&self) -> HeaderTagType {
+    pub const fn typ(&self) -> HeaderTagType {
         self.typ
     }
-    pub fn flags(&self) -> HeaderTagFlag {
+    pub const fn flags(&self) -> HeaderTagFlag {
         self.flags
     }
-    pub fn size(&self) -> u32 {
+    pub const fn size(&self) -> u32 {
         self.size
     }
 }
-
-impl StructAsBytes for HeaderTag {}

+ 3 - 3
multiboot2-header/src/uefi_bs.rs

@@ -20,13 +20,13 @@ impl EfiBootServiceHeaderTag {
         }
     }
 
-    pub fn typ(&self) -> HeaderTagType {
+    pub const fn typ(&self) -> HeaderTagType {
         self.typ
     }
-    pub fn flags(&self) -> HeaderTagFlag {
+    pub const fn flags(&self) -> HeaderTagFlag {
         self.flags
     }
-    pub fn size(&self) -> u32 {
+    pub const fn size(&self) -> u32 {
         self.size
     }
 }

+ 1 - 1
multiboot2/src/lib.rs

@@ -389,7 +389,7 @@ impl Reader {
 
     pub(crate) fn read_u8(&mut self) -> u8 {
         self.off += 1;
-        unsafe { core::ptr::read(self.ptr.add(self.off - 1)) }
+        unsafe { *self.ptr.add(self.off - 1) }
     }
 
     pub(crate) fn read_u16(&mut self) -> u16 {