Переглянути джерело

crate: move BootInformation to dedicated module

This improves code quality
Philipp Schuster 8 місяців тому
батько
коміт
767eb0ca18
3 змінених файлів з 434 додано та 427 видалено
  1. 430 0
      multiboot2/src/boot_information.rs
  2. 2 425
      multiboot2/src/lib.rs
  3. 2 2
      multiboot2/src/module.rs

+ 430 - 0
multiboot2/src/boot_information.rs

@@ -0,0 +1,430 @@
+//! Module for [`BootInformation`].
+
+#[cfg(feature = "builder")]
+use crate::builder::AsBytes;
+use crate::framebuffer::UnknownFramebufferType;
+use crate::tag::TagIter;
+use crate::{
+    module, BasicMemoryInfoTag, BootLoaderNameTag, CommandLineTag, EFIBootServicesNotExitedTag,
+    EFIImageHandle32Tag, EFIImageHandle64Tag, EFIMemoryMapTag, EFISdt32Tag, EFISdt64Tag,
+    ElfSectionIter, ElfSectionsTag, EndTag, FramebufferTag, ImageLoadPhysAddrTag, MemoryMapTag,
+    ModuleIter, RsdpV1Tag, RsdpV2Tag, SmbiosTag, TagTrait, VBEInfoTag,
+};
+use core::fmt;
+use derive_more::Display;
+
+/// Error type that describes errors while loading/parsing a multiboot2 information structure
+/// from a given address.
+#[derive(Display, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub enum MbiLoadError {
+    /// The address is invalid. Make sure that the address is 8-byte aligned,
+    /// according to the spec.
+    #[display("The address is invalid")]
+    IllegalAddress,
+    /// The total size of the multiboot2 information structure must be not zero
+    /// and a multiple of 8.
+    #[display("The size of the MBI is unexpected")]
+    IllegalTotalSize(u32),
+    /// Missing end tag. Each multiboot2 boot information requires to have an
+    /// end tag.
+    #[display("There is no end tag")]
+    NoEndTag,
+}
+
+#[cfg(feature = "unstable")]
+impl core::error::Error for MbiLoadError {}
+
+/// The basic header of a [`BootInformation`] as sized Rust type.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[repr(C)]
+pub struct BootInformationHeader {
+    // size is multiple of 8
+    pub total_size: u32,
+    _reserved: u32,
+    // Followed by the boot information tags.
+}
+
+#[cfg(feature = "builder")]
+impl BootInformationHeader {
+    pub(crate) fn new(total_size: u32) -> Self {
+        Self {
+            total_size,
+            _reserved: 0,
+        }
+    }
+}
+
+#[cfg(feature = "builder")]
+impl AsBytes for BootInformationHeader {}
+
+/// This type holds the whole data of the MBI. This helps to better satisfy miri
+/// when it checks for memory issues.
+#[derive(ptr_meta::Pointee)]
+#[repr(C)]
+struct BootInformationInner {
+    header: BootInformationHeader,
+    tags: [u8],
+}
+
+impl BootInformationInner {
+    /// Checks if the MBI has a valid end tag by checking the end of the mbi's
+    /// bytes.
+    fn has_valid_end_tag(&self) -> bool {
+        let end_tag_prototype = EndTag::default();
+
+        let self_ptr = unsafe { self.tags.as_ptr().sub(size_of::<BootInformationHeader>()) };
+
+        let end_tag_ptr = unsafe {
+            self_ptr
+                .add(self.header.total_size as usize)
+                .sub(size_of::<EndTag>())
+        };
+        let end_tag = unsafe { &*(end_tag_ptr as *const EndTag) };
+
+        end_tag.typ == end_tag_prototype.typ && end_tag.size == end_tag_prototype.size
+    }
+}
+
+/// A Multiboot 2 Boot Information (MBI) accessor.
+#[repr(transparent)]
+pub struct BootInformation<'a>(&'a BootInformationInner);
+
+impl<'a> BootInformation<'a> {
+    /// Loads the [`BootInformation`] from a pointer. The pointer must be valid
+    /// and aligned to an 8-byte boundary, as defined by the spec.
+    ///
+    /// ## Example
+    ///
+    /// ```rust
+    /// use multiboot2::{BootInformation, BootInformationHeader};
+    ///
+    /// fn kernel_entry(mb_magic: u32, mbi_ptr: u32) {
+    ///     if mb_magic == multiboot2::MAGIC {
+    ///         let boot_info = unsafe { BootInformation::load(mbi_ptr as *const BootInformationHeader).unwrap() };
+    ///         let _cmd = boot_info.command_line_tag();
+    ///     } else { /* Panic or use multiboot1 flow. */ }
+    /// }
+    /// ```
+    ///
+    /// ## Safety
+    /// * `ptr` must be valid for reading. Otherwise this function might cause
+    ///   invalid machine state or crash your binary (kernel). This can be the
+    ///   case in environments with standard environment (segfault), but also in
+    ///   boot environments, such as UEFI.
+    /// * The memory at `ptr` must not be modified after calling `load` or the
+    ///   program may observe unsynchronized mutation.
+    pub unsafe fn load(ptr: *const BootInformationHeader) -> Result<Self, MbiLoadError> {
+        // null or not aligned
+        if ptr.is_null() || ptr.align_offset(8) != 0 {
+            return Err(MbiLoadError::IllegalAddress);
+        }
+
+        // mbi: reference to basic header
+        let mbi = &*ptr;
+
+        // Check if total size is not 0 and a multiple of 8.
+        if mbi.total_size == 0 || mbi.total_size & 0b111 != 0 {
+            return Err(MbiLoadError::IllegalTotalSize(mbi.total_size));
+        }
+
+        let slice_size = mbi.total_size as usize - size_of::<BootInformationHeader>();
+        // mbi: reference to full mbi
+        let mbi = ptr_meta::from_raw_parts::<BootInformationInner>(ptr.cast(), slice_size);
+        let mbi = &*mbi;
+
+        if !mbi.has_valid_end_tag() {
+            return Err(MbiLoadError::NoEndTag);
+        }
+
+        Ok(Self(mbi))
+    }
+
+    /// Get the start address of the boot info.
+    pub fn start_address(&self) -> usize {
+        self.as_ptr() as usize
+    }
+
+    /// Get the start address of the boot info as pointer.
+    pub fn as_ptr(&self) -> *const () {
+        core::ptr::addr_of!(*self.0).cast()
+    }
+
+    /// Get the end address of the boot info.
+    ///
+    /// This is the same as doing:
+    ///
+    /// ```rust,no_run
+    /// # use multiboot2::{BootInformation, BootInformationHeader};
+    /// # let ptr = 0xdeadbeef as *const BootInformationHeader;
+    /// # let boot_info = unsafe { BootInformation::load(ptr).unwrap() };
+    /// let end_addr = boot_info.start_address() + boot_info.total_size();
+    /// ```
+    pub fn end_address(&self) -> usize {
+        self.start_address() + self.total_size()
+    }
+
+    /// Get the total size of the boot info struct.
+    pub fn total_size(&self) -> usize {
+        self.0.header.total_size as usize
+    }
+
+    // ######################################################
+    // ### BEGIN OF TAG GETTERS (in alphabetical order)
+
+    /*fn apm(&self) {
+        // also add to debug output
+        todo!()
+    }*/
+
+    /// Search for the basic memory info tag.
+    pub fn basic_memory_info_tag(&self) -> Option<&BasicMemoryInfoTag> {
+        self.get_tag::<BasicMemoryInfoTag>()
+    }
+
+    /// Search for the BootLoader name tag.
+    pub fn boot_loader_name_tag(&self) -> Option<&BootLoaderNameTag> {
+        self.get_tag::<BootLoaderNameTag>()
+    }
+
+    /*fn bootdev(&self) {
+        // also add to debug output
+        todo!()
+    }*/
+
+    /// Search for the Command line tag.
+    pub fn command_line_tag(&self) -> Option<&CommandLineTag> {
+        self.get_tag::<CommandLineTag>()
+    }
+
+    /// Search for the EFI boot services not exited tag.
+    pub fn efi_bs_not_exited_tag(&self) -> Option<&EFIBootServicesNotExitedTag> {
+        self.get_tag::<EFIBootServicesNotExitedTag>()
+    }
+
+    /// Search for the EFI Memory map tag, if the boot services were exited.
+    /// Otherwise, if the [`TagType::EfiBs`] tag is present, this returns `None`
+    /// as it is strictly recommended to get the memory map from the `uefi`
+    /// services.
+    pub fn efi_memory_map_tag(&self) -> Option<&EFIMemoryMapTag> {
+        // If the EFIBootServicesNotExited is present, then we should not use
+        // the memory map, as it could still be in use.
+        match self.get_tag::<EFIBootServicesNotExitedTag>() {
+            Some(_tag) => {
+                log::debug!("The EFI memory map is present but the UEFI Boot Services Not Existed Tag is present. Returning None.");
+                None
+            }
+            None => self.get_tag::<EFIMemoryMapTag>(),
+        }
+    }
+
+    /// Search for the EFI 32-bit SDT tag.
+    pub fn efi_sdt32_tag(&self) -> Option<&EFISdt32Tag> {
+        self.get_tag::<EFISdt32Tag>()
+    }
+
+    /// Search for the EFI 64-bit SDT tag.
+    pub fn efi_sdt64_tag(&self) -> Option<&EFISdt64Tag> {
+        self.get_tag::<EFISdt64Tag>()
+    }
+
+    /// Search for the EFI 32-bit image handle pointer tag.
+    pub fn efi_ih32_tag(&self) -> Option<&EFIImageHandle32Tag> {
+        self.get_tag::<EFIImageHandle32Tag>()
+    }
+
+    /// Search for the EFI 64-bit image handle pointer tag.
+    pub fn efi_ih64_tag(&self) -> Option<&EFIImageHandle64Tag> {
+        self.get_tag::<EFIImageHandle64Tag>()
+    }
+
+    /// Returns an [`ElfSectionIter`] iterator over the ELF Sections, if the
+    /// [`ElfSectionsTag`] is present.
+    ///
+    /// # Examples
+    ///
+    /// ```rust,no_run
+    /// # use multiboot2::{BootInformation, BootInformationHeader};
+    /// # let ptr = 0xdeadbeef as *const BootInformationHeader;
+    /// # let boot_info = unsafe { BootInformation::load(ptr).unwrap() };
+    /// if let Some(sections) = boot_info.elf_sections() {
+    ///     let mut total = 0;
+    ///     for section in sections {
+    ///         println!("Section: {:?}", section);
+    ///         total += 1;
+    ///     }
+    /// }
+    /// ```
+    pub fn elf_sections(&self) -> Option<ElfSectionIter> {
+        let tag = self.get_tag::<ElfSectionsTag>();
+        tag.map(|t| {
+            assert!((t.entry_size * t.shndx) <= t.size);
+            t.sections()
+        })
+    }
+
+    /// Search for the VBE framebuffer tag. The result is `Some(Err(e))`, if the
+    /// framebuffer type is unknown, while the framebuffer tag is present.
+    pub fn framebuffer_tag(&self) -> Option<Result<&FramebufferTag, UnknownFramebufferType>> {
+        self.get_tag::<FramebufferTag>()
+            .map(|tag| match tag.buffer_type() {
+                Ok(_) => Ok(tag),
+                Err(e) => Err(e),
+            })
+    }
+
+    /// Search for the Image Load Base Physical Address tag.
+    pub fn load_base_addr_tag(&self) -> Option<&ImageLoadPhysAddrTag> {
+        self.get_tag::<ImageLoadPhysAddrTag>()
+    }
+
+    /// Search for the Memory map tag.
+    pub fn memory_map_tag(&self) -> Option<&MemoryMapTag> {
+        self.get_tag::<MemoryMapTag>()
+    }
+
+    /// Get an iterator of all module tags.
+    pub fn module_tags(&self) -> ModuleIter {
+        module::module_iter(self.tags())
+    }
+
+    /*fn network_tag(&self) {
+        // also add to debug output
+        todo!()
+    }*/
+
+    /// Search for the (ACPI 1.0) RSDP tag.
+    pub fn rsdp_v1_tag(&self) -> Option<&RsdpV1Tag> {
+        self.get_tag::<RsdpV1Tag>()
+    }
+
+    /// Search for the (ACPI 2.0 or later) RSDP tag.
+    pub fn rsdp_v2_tag(&self) -> Option<&RsdpV2Tag> {
+        self.get_tag::<RsdpV2Tag>()
+    }
+
+    /// Search for the SMBIOS tag.
+    pub fn smbios_tag(&self) -> Option<&SmbiosTag> {
+        self.get_tag::<SmbiosTag>()
+    }
+
+    /// Search for the VBE information tag.
+    pub fn vbe_info_tag(&self) -> Option<&VBEInfoTag> {
+        self.get_tag::<VBEInfoTag>()
+    }
+
+    // ### END OF TAG GETTERS
+    // ######################################################
+
+    /// Public getter to find any Multiboot tag by its type, including
+    /// specified and custom ones.
+    ///
+    /// # Specified or Custom Tags
+    /// The Multiboot2 specification specifies a list of tags, see [`TagType`].
+    /// However, it doesn't forbid to use custom tags. Because of this, there
+    /// exists the [`TagType`] abstraction. It is recommended to use this
+    /// getter only for custom tags. For specified tags, use getters, such as
+    /// [`Self::efi_ih64_tag`].
+    ///
+    /// ## Use Custom Tags
+    /// The following example shows how you may use this interface to parse
+    /// custom tags from the MBI. If they are dynamically sized (DST), a few more
+    /// special handling is required. This is reflected by code-comments.
+    ///
+    /// ```no_run
+    /// use multiboot2::{BootInformation, BootInformationHeader, StringError, Tag, TagTrait, TagType, TagTypeId};
+    ///
+    /// #[repr(C)]
+    /// #[derive(multiboot2::Pointee)] // Only needed for DSTs.
+    /// struct CustomTag {
+    ///     tag: TagTypeId,
+    ///     size: u32,
+    ///     // begin of inline string
+    ///     name: [u8],
+    /// }
+    ///
+    /// // This implementation is only necessary for tags that are DSTs.
+    /// impl TagTrait for CustomTag {
+    ///     const ID: TagType = TagType::Custom(0x1337);
+    ///
+    ///     fn dst_size(base_tag: &Tag) -> usize {
+    ///         // The size of the sized portion of the custom tag.
+    ///         let tag_base_size = 8; // id + size is 8 byte in size
+    ///         assert!(base_tag.size >= 8);
+    ///         base_tag.size as usize - tag_base_size
+    ///     }
+    /// }
+    ///
+    /// impl CustomTag {
+    ///     fn name(&self) -> Result<&str, StringError> {
+    ///         Tag::parse_slice_as_string(&self.name)
+    ///     }
+    /// }
+    /// let mbi_ptr = 0xdeadbeef as *const BootInformationHeader;
+    /// let mbi = unsafe { BootInformation::load(mbi_ptr).unwrap() };
+    ///
+    /// let tag = mbi
+    ///     .get_tag::<CustomTag>()
+    ///     .unwrap();
+    /// assert_eq!(tag.name(), Ok("name"));
+    /// ```
+    pub fn get_tag<TagT: TagTrait + ?Sized + 'a>(&'a self) -> Option<&'a TagT> {
+        self.tags()
+            .find(|tag| tag.typ == TagT::ID)
+            .map(|tag| tag.cast_tag::<TagT>())
+    }
+
+    /// Returns an iterator over all tags.
+    fn tags(&self) -> TagIter {
+        TagIter::new(&self.0.tags)
+    }
+}
+
+impl fmt::Debug for BootInformation<'_> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        /// Limit how many Elf-Sections should be debug-formatted.
+        /// Can be thousands of sections for a Rust binary => this is useless output.
+        /// If the user really wants this, they should debug-format the field directly.
+        const ELF_SECTIONS_LIMIT: usize = 7;
+
+        let mut debug = f.debug_struct("Multiboot2BootInformation");
+        debug
+            .field("start_address", &self.start_address())
+            .field("end_address", &self.end_address())
+            .field("total_size", &self.total_size())
+            // now tags in alphabetical order
+            .field("basic_memory_info", &(self.basic_memory_info_tag()))
+            .field("boot_loader_name", &self.boot_loader_name_tag())
+            // .field("bootdev", &self.bootdev_tag())
+            .field("command_line", &self.command_line_tag())
+            .field("efi_bs_not_exited", &self.efi_bs_not_exited_tag())
+            .field("efi_memory_map", &self.efi_memory_map_tag())
+            .field("efi_sdt32", &self.efi_sdt32_tag())
+            .field("efi_sdt64", &self.efi_sdt64_tag())
+            .field("efi_ih32", &self.efi_ih32_tag())
+            .field("efi_ih64", &self.efi_ih64_tag());
+
+        // usually this is REALLY big (thousands of tags) => skip it here
+        {
+            let elf_sections_tag_entries_count =
+                self.elf_sections().map(|x| x.count()).unwrap_or(0);
+
+            if elf_sections_tag_entries_count > ELF_SECTIONS_LIMIT {
+                debug.field("elf_sections (count)", &elf_sections_tag_entries_count);
+            } else {
+                debug.field("elf_sections", &self.elf_sections().unwrap_or_default());
+            }
+        }
+
+        debug
+            .field("framebuffer", &self.framebuffer_tag())
+            .field("load_base_addr", &self.load_base_addr_tag())
+            .field("memory_map", &self.memory_map_tag())
+            .field("modules", &self.module_tags())
+            // .field("network", &self.network_tag())
+            .field("rsdp_v1", &self.rsdp_v1_tag())
+            .field("rsdp_v2", &self.rsdp_v2_tag())
+            .field("smbios_tag", &self.smbios_tag())
+            .field("vbe_info_tag", &self.vbe_info_tag())
+            .finish()
+    }
+}

+ 2 - 425
multiboot2/src/lib.rs

@@ -49,6 +49,7 @@ extern crate bitflags;
 #[cfg(feature = "builder")]
 pub mod builder;
 
+mod boot_information;
 mod boot_loader_name;
 mod command_line;
 mod efi;
@@ -65,6 +66,7 @@ mod tag_trait;
 mod tag_type;
 mod vbe_info;
 
+pub use boot_information::{BootInformation, BootInformationHeader, MbiLoadError};
 pub use boot_loader_name::BootLoaderNameTag;
 pub use command_line::CommandLineTag;
 pub use efi::{
@@ -92,436 +94,11 @@ pub use vbe_info::{
     VBEMemoryModel, VBEModeAttributes, VBEModeInfo, VBEWindowAttributes,
 };
 
-use core::fmt;
-use core::mem::size_of;
-use derive_more::Display;
-// Must be public so that custom tags can be DSTs.
-#[cfg(feature = "builder")]
-use crate::builder::AsBytes;
-use crate::framebuffer::UnknownFramebufferType;
-use tag::TagIter;
-
 /// Magic number that a Multiboot2-compliant boot loader will use to identify
 /// the handoff. The location depends on the architecture and the targeted
 /// machine state.
 pub const MAGIC: u32 = 0x36d76289;
 
-/// Error type that describes errors while loading/parsing a multiboot2 information structure
-/// from a given address.
-#[derive(Display, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub enum MbiLoadError {
-    /// The address is invalid. Make sure that the address is 8-byte aligned,
-    /// according to the spec.
-    #[display("The address is invalid")]
-    IllegalAddress,
-    /// The total size of the multiboot2 information structure must be not zero
-    /// and a multiple of 8.
-    #[display("The size of the MBI is unexpected")]
-    IllegalTotalSize(u32),
-    /// Missing end tag. Each multiboot2 boot information requires to have an
-    /// end tag.
-    #[display("There is no end tag")]
-    NoEndTag,
-}
-
-#[cfg(feature = "unstable")]
-impl core::error::Error for MbiLoadError {}
-
-/// The basic header of a boot information.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[repr(C)]
-pub struct BootInformationHeader {
-    // size is multiple of 8
-    pub total_size: u32,
-    _reserved: u32,
-    // Followed by the boot information tags.
-}
-
-#[cfg(feature = "builder")]
-impl BootInformationHeader {
-    fn new(total_size: u32) -> Self {
-        Self {
-            total_size,
-            _reserved: 0,
-        }
-    }
-}
-
-#[cfg(feature = "builder")]
-impl AsBytes for BootInformationHeader {}
-
-/// This type holds the whole data of the MBI. This helps to better satisfy miri
-/// when it checks for memory issues.
-#[derive(ptr_meta::Pointee)]
-#[repr(C)]
-struct BootInformationInner {
-    header: BootInformationHeader,
-    tags: [u8],
-}
-
-impl BootInformationInner {
-    /// Checks if the MBI has a valid end tag by checking the end of the mbi's
-    /// bytes.
-    fn has_valid_end_tag(&self) -> bool {
-        let end_tag_prototype = EndTag::default();
-
-        let self_ptr = unsafe { self.tags.as_ptr().sub(size_of::<BootInformationHeader>()) };
-
-        let end_tag_ptr = unsafe {
-            self_ptr
-                .add(self.header.total_size as usize)
-                .sub(size_of::<EndTag>())
-        };
-        let end_tag = unsafe { &*(end_tag_ptr as *const EndTag) };
-
-        end_tag.typ == end_tag_prototype.typ && end_tag.size == end_tag_prototype.size
-    }
-}
-
-/// A Multiboot 2 Boot Information (MBI) accessor.
-#[repr(transparent)]
-pub struct BootInformation<'a>(&'a BootInformationInner);
-
-impl<'a> BootInformation<'a> {
-    /// Loads the [`BootInformation`] from a pointer. The pointer must be valid
-    /// and aligned to an 8-byte boundary, as defined by the spec.
-    ///
-    /// ## Example
-    ///
-    /// ```rust
-    /// use multiboot2::{BootInformation, BootInformationHeader};
-    ///
-    /// fn kernel_entry(mb_magic: u32, mbi_ptr: u32) {
-    ///     if mb_magic == multiboot2::MAGIC {
-    ///         let boot_info = unsafe { BootInformation::load(mbi_ptr as *const BootInformationHeader).unwrap() };
-    ///         let _cmd = boot_info.command_line_tag();
-    ///     } else { /* Panic or use multiboot1 flow. */ }
-    /// }
-    /// ```
-    ///
-    /// ## Safety
-    /// * `ptr` must be valid for reading. Otherwise this function might cause
-    ///   invalid machine state or crash your binary (kernel). This can be the
-    ///   case in environments with standard environment (segfault), but also in
-    ///   boot environments, such as UEFI.
-    /// * The memory at `ptr` must not be modified after calling `load` or the
-    ///   program may observe unsynchronized mutation.
-    pub unsafe fn load(ptr: *const BootInformationHeader) -> Result<Self, MbiLoadError> {
-        // null or not aligned
-        if ptr.is_null() || ptr.align_offset(8) != 0 {
-            return Err(MbiLoadError::IllegalAddress);
-        }
-
-        // mbi: reference to basic header
-        let mbi = &*ptr;
-
-        // Check if total size is not 0 and a multiple of 8.
-        if mbi.total_size == 0 || mbi.total_size & 0b111 != 0 {
-            return Err(MbiLoadError::IllegalTotalSize(mbi.total_size));
-        }
-
-        let slice_size = mbi.total_size as usize - size_of::<BootInformationHeader>();
-        // mbi: reference to full mbi
-        let mbi = ptr_meta::from_raw_parts::<BootInformationInner>(ptr.cast(), slice_size);
-        let mbi = &*mbi;
-
-        if !mbi.has_valid_end_tag() {
-            return Err(MbiLoadError::NoEndTag);
-        }
-
-        Ok(Self(mbi))
-    }
-
-    /// Get the start address of the boot info.
-    pub fn start_address(&self) -> usize {
-        self.as_ptr() as usize
-    }
-
-    /// Get the start address of the boot info as pointer.
-    pub fn as_ptr(&self) -> *const () {
-        core::ptr::addr_of!(*self.0).cast()
-    }
-
-    /// Get the end address of the boot info.
-    ///
-    /// This is the same as doing:
-    ///
-    /// ```rust,no_run
-    /// # use multiboot2::{BootInformation, BootInformationHeader};
-    /// # let ptr = 0xdeadbeef as *const BootInformationHeader;
-    /// # let boot_info = unsafe { BootInformation::load(ptr).unwrap() };
-    /// let end_addr = boot_info.start_address() + boot_info.total_size();
-    /// ```
-    pub fn end_address(&self) -> usize {
-        self.start_address() + self.total_size()
-    }
-
-    /// Get the total size of the boot info struct.
-    pub fn total_size(&self) -> usize {
-        self.0.header.total_size as usize
-    }
-
-    // ######################################################
-    // ### BEGIN OF TAG GETTERS (in alphabetical order)
-
-    /*fn apm(&self) {
-        // also add to debug output
-        todo!()
-    }*/
-
-    /// Search for the basic memory info tag.
-    pub fn basic_memory_info_tag(&self) -> Option<&BasicMemoryInfoTag> {
-        self.get_tag::<BasicMemoryInfoTag>()
-    }
-
-    /// Search for the BootLoader name tag.
-    pub fn boot_loader_name_tag(&self) -> Option<&BootLoaderNameTag> {
-        self.get_tag::<BootLoaderNameTag>()
-    }
-
-    /*fn bootdev(&self) {
-        // also add to debug output
-        todo!()
-    }*/
-
-    /// Search for the Command line tag.
-    pub fn command_line_tag(&self) -> Option<&CommandLineTag> {
-        self.get_tag::<CommandLineTag>()
-    }
-
-    /// Search for the EFI boot services not exited tag.
-    pub fn efi_bs_not_exited_tag(&self) -> Option<&EFIBootServicesNotExitedTag> {
-        self.get_tag::<EFIBootServicesNotExitedTag>()
-    }
-
-    /// Search for the EFI Memory map tag, if the boot services were exited.
-    /// Otherwise, if the [`TagType::EfiBs`] tag is present, this returns `None`
-    /// as it is strictly recommended to get the memory map from the `uefi`
-    /// services.
-    pub fn efi_memory_map_tag(&self) -> Option<&EFIMemoryMapTag> {
-        // If the EFIBootServicesNotExited is present, then we should not use
-        // the memory map, as it could still be in use.
-        match self.get_tag::<EFIBootServicesNotExitedTag>() {
-            Some(_tag) => {
-                log::debug!("The EFI memory map is present but the UEFI Boot Services Not Existed Tag is present. Returning None.");
-                None
-            }
-            None => self.get_tag::<EFIMemoryMapTag>(),
-        }
-    }
-
-    /// Search for the EFI 32-bit SDT tag.
-    pub fn efi_sdt32_tag(&self) -> Option<&EFISdt32Tag> {
-        self.get_tag::<EFISdt32Tag>()
-    }
-
-    /// Search for the EFI 64-bit SDT tag.
-    pub fn efi_sdt64_tag(&self) -> Option<&EFISdt64Tag> {
-        self.get_tag::<EFISdt64Tag>()
-    }
-
-    /// Search for the EFI 32-bit image handle pointer tag.
-    pub fn efi_ih32_tag(&self) -> Option<&EFIImageHandle32Tag> {
-        self.get_tag::<EFIImageHandle32Tag>()
-    }
-
-    /// Search for the EFI 64-bit image handle pointer tag.
-    pub fn efi_ih64_tag(&self) -> Option<&EFIImageHandle64Tag> {
-        self.get_tag::<EFIImageHandle64Tag>()
-    }
-
-    /// Returns an [`ElfSectionIter`] iterator over the ELF Sections, if the
-    /// [`ElfSectionsTag`] is present.
-    ///
-    /// # Examples
-    ///
-    /// ```rust,no_run
-    /// # use multiboot2::{BootInformation, BootInformationHeader};
-    /// # let ptr = 0xdeadbeef as *const BootInformationHeader;
-    /// # let boot_info = unsafe { BootInformation::load(ptr).unwrap() };
-    /// if let Some(sections) = boot_info.elf_sections() {
-    ///     let mut total = 0;
-    ///     for section in sections {
-    ///         println!("Section: {:?}", section);
-    ///         total += 1;
-    ///     }
-    /// }
-    /// ```
-    pub fn elf_sections(&self) -> Option<ElfSectionIter> {
-        let tag = self.get_tag::<ElfSectionsTag>();
-        tag.map(|t| {
-            assert!((t.entry_size * t.shndx) <= t.size);
-            t.sections()
-        })
-    }
-
-    /// Search for the VBE framebuffer tag. The result is `Some(Err(e))`, if the
-    /// framebuffer type is unknown, while the framebuffer tag is present.
-    pub fn framebuffer_tag(&self) -> Option<Result<&FramebufferTag, UnknownFramebufferType>> {
-        self.get_tag::<FramebufferTag>()
-            .map(|tag| match tag.buffer_type() {
-                Ok(_) => Ok(tag),
-                Err(e) => Err(e),
-            })
-    }
-
-    /// Search for the Image Load Base Physical Address tag.
-    pub fn load_base_addr_tag(&self) -> Option<&ImageLoadPhysAddrTag> {
-        self.get_tag::<ImageLoadPhysAddrTag>()
-    }
-
-    /// Search for the Memory map tag.
-    pub fn memory_map_tag(&self) -> Option<&MemoryMapTag> {
-        self.get_tag::<MemoryMapTag>()
-    }
-
-    /// Get an iterator of all module tags.
-    pub fn module_tags(&self) -> ModuleIter {
-        module::module_iter(self.tags())
-    }
-
-    /*fn network_tag(&self) {
-        // also add to debug output
-        todo!()
-    }*/
-
-    /// Search for the (ACPI 1.0) RSDP tag.
-    pub fn rsdp_v1_tag(&self) -> Option<&RsdpV1Tag> {
-        self.get_tag::<RsdpV1Tag>()
-    }
-
-    /// Search for the (ACPI 2.0 or later) RSDP tag.
-    pub fn rsdp_v2_tag(&self) -> Option<&RsdpV2Tag> {
-        self.get_tag::<RsdpV2Tag>()
-    }
-
-    /// Search for the SMBIOS tag.
-    pub fn smbios_tag(&self) -> Option<&SmbiosTag> {
-        self.get_tag::<SmbiosTag>()
-    }
-
-    /// Search for the VBE information tag.
-    pub fn vbe_info_tag(&self) -> Option<&VBEInfoTag> {
-        self.get_tag::<VBEInfoTag>()
-    }
-
-    // ### END OF TAG GETTERS
-    // ######################################################
-
-    /// Public getter to find any Multiboot tag by its type, including
-    /// specified and custom ones.
-    ///
-    /// # Specified or Custom Tags
-    /// The Multiboot2 specification specifies a list of tags, see [`TagType`].
-    /// However, it doesn't forbid to use custom tags. Because of this, there
-    /// exists the [`TagType`] abstraction. It is recommended to use this
-    /// getter only for custom tags. For specified tags, use getters, such as
-    /// [`Self::efi_ih64_tag`].
-    ///
-    /// ## Use Custom Tags
-    /// The following example shows how you may use this interface to parse
-    /// custom tags from the MBI. If they are dynamically sized (DST), a few more
-    /// special handling is required. This is reflected by code-comments.
-    ///
-    /// ```no_run
-    /// use multiboot2::{BootInformation, BootInformationHeader, StringError, Tag, TagTrait, TagType, TagTypeId};
-    ///
-    /// #[repr(C)]
-    /// #[derive(multiboot2::Pointee)] // Only needed for DSTs.
-    /// struct CustomTag {
-    ///     tag: TagTypeId,
-    ///     size: u32,
-    ///     // begin of inline string
-    ///     name: [u8],
-    /// }
-    ///
-    /// // This implementation is only necessary for tags that are DSTs.
-    /// impl TagTrait for CustomTag {
-    ///     const ID: TagType = TagType::Custom(0x1337);
-    ///
-    ///     fn dst_size(base_tag: &Tag) -> usize {
-    ///         // The size of the sized portion of the custom tag.
-    ///         let tag_base_size = 8; // id + size is 8 byte in size
-    ///         assert!(base_tag.size >= 8);
-    ///         base_tag.size as usize - tag_base_size
-    ///     }
-    /// }
-    ///
-    /// impl CustomTag {
-    ///     fn name(&self) -> Result<&str, StringError> {
-    ///         Tag::parse_slice_as_string(&self.name)
-    ///     }
-    /// }
-    /// let mbi_ptr = 0xdeadbeef as *const BootInformationHeader;
-    /// let mbi = unsafe { BootInformation::load(mbi_ptr).unwrap() };
-    ///
-    /// let tag = mbi
-    ///     .get_tag::<CustomTag>()
-    ///     .unwrap();
-    /// assert_eq!(tag.name(), Ok("name"));
-    /// ```
-    pub fn get_tag<TagT: TagTrait + ?Sized + 'a>(&'a self) -> Option<&'a TagT> {
-        self.tags()
-            .find(|tag| tag.typ == TagT::ID)
-            .map(|tag| tag.cast_tag::<TagT>())
-    }
-
-    /// Returns an iterator over all tags.
-    fn tags(&self) -> TagIter {
-        TagIter::new(&self.0.tags)
-    }
-}
-
-impl fmt::Debug for BootInformation<'_> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        /// Limit how many Elf-Sections should be debug-formatted.
-        /// Can be thousands of sections for a Rust binary => this is useless output.
-        /// If the user really wants this, they should debug-format the field directly.
-        const ELF_SECTIONS_LIMIT: usize = 7;
-
-        let mut debug = f.debug_struct("Multiboot2BootInformation");
-        debug
-            .field("start_address", &self.start_address())
-            .field("end_address", &self.end_address())
-            .field("total_size", &self.total_size())
-            // now tags in alphabetical order
-            .field("basic_memory_info", &(self.basic_memory_info_tag()))
-            .field("boot_loader_name", &self.boot_loader_name_tag())
-            // .field("bootdev", &self.bootdev_tag())
-            .field("command_line", &self.command_line_tag())
-            .field("efi_bs_not_exited", &self.efi_bs_not_exited_tag())
-            .field("efi_memory_map", &self.efi_memory_map_tag())
-            .field("efi_sdt32", &self.efi_sdt32_tag())
-            .field("efi_sdt64", &self.efi_sdt64_tag())
-            .field("efi_ih32", &self.efi_ih32_tag())
-            .field("efi_ih64", &self.efi_ih64_tag());
-
-        // usually this is REALLY big (thousands of tags) => skip it here
-        {
-            let elf_sections_tag_entries_count =
-                self.elf_sections().map(|x| x.count()).unwrap_or(0);
-
-            if elf_sections_tag_entries_count > ELF_SECTIONS_LIMIT {
-                debug.field("elf_sections (count)", &elf_sections_tag_entries_count);
-            } else {
-                debug.field("elf_sections", &self.elf_sections().unwrap_or_default());
-            }
-        }
-
-        debug
-            .field("framebuffer", &self.framebuffer_tag())
-            .field("load_base_addr", &self.load_base_addr_tag())
-            .field("memory_map", &self.memory_map_tag())
-            .field("modules", &self.module_tags())
-            // .field("network", &self.network_tag())
-            .field("rsdp_v1", &self.rsdp_v1_tag())
-            .field("rsdp_v2", &self.rsdp_v2_tag())
-            .field("smbios_tag", &self.smbios_tag())
-            .field("vbe_info_tag", &self.vbe_info_tag())
-            .finish()
-    }
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;

+ 2 - 2
multiboot2/src/module.rs

@@ -1,7 +1,7 @@
 //! Module for [`ModuleTag`].
 
-use crate::tag::StringError;
-use crate::{Tag, TagIter, TagTrait, TagType, TagTypeId};
+use crate::tag::{StringError, TagIter};
+use crate::{Tag, TagTrait, TagType, TagTypeId};
 use core::fmt::{Debug, Formatter};
 use core::mem::size_of;
 #[cfg(feature = "builder")]