From 4888d5576dc5d48e8ce0f1549cc20fd84818f409 Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Wed, 14 Aug 2024 08:15:41 +0200 Subject: [PATCH 1/8] ci: also run doc tests cargo nextest still can't run doctests. --- .github/workflows/_build-rust.yml | 15 ++------------- multiboot2/Changelog.md | 1 + multiboot2/src/lib.rs | 5 ++--- 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/.github/workflows/_build-rust.yml b/.github/workflows/_build-rust.yml index 2c834c64..27c01a2f 100644 --- a/.github/workflows/_build-rust.yml +++ b/.github/workflows/_build-rust.yml @@ -94,19 +94,8 @@ jobs: run: | cargo doc --no-deps --document-private-items --features ${{ inputs.features }} --no-default-features cargo clippy --all-targets --features ${{ inputs.features }} --no-default-features - - name: Unit Test (UNIX) - if: inputs.do-test && runner.os != 'Windows' - run: | - curl -LsSf https://get.nexte.st/latest/linux | tar zxf - - chmod u+x cargo-nextest - ./cargo-nextest nextest run --features ${{ inputs.features }} --no-default-features - - name: Unit Test (Windows) - if: inputs.do-test && runner.os == 'Windows' - run: | - Invoke-WebRequest https://get.nexte.st/latest/windows -OutFile cargo-nextest.zip - Expand-Archive .\cargo-nextest.zip - cp .\cargo-nextest/cargo-nextest.exe . - .\cargo-nextest.exe nextest run --features ${{ inputs.features }} --no-default-features + - name: Unit Test + run: cargo test --verbose - name: Unit Test with Miri if: inputs.do-miri # "--tests" so that the doctests are skipped. Currently, the doctest diff --git a/multiboot2/Changelog.md b/multiboot2/Changelog.md index f949feaa..1a5cfe99 100644 --- a/multiboot2/Changelog.md +++ b/multiboot2/Changelog.md @@ -4,6 +4,7 @@ - updated dependencies - MSRV is 1.75 +- doc fixes ## 0.20.2 (2024-05-26) diff --git a/multiboot2/src/lib.rs b/multiboot2/src/lib.rs index f9b07f35..384473de 100644 --- a/multiboot2/src/lib.rs +++ b/multiboot2/src/lib.rs @@ -424,8 +424,7 @@ impl<'a> BootInformation<'a> { /// special handling is required. This is reflected by code-comments. /// /// ```no_run - /// use std::str::Utf8Error; - /// use multiboot2::{BootInformation, BootInformationHeader, Tag, TagTrait, TagType, TagTypeId}; + /// use multiboot2::{BootInformation, BootInformationHeader, StringError, Tag, TagTrait, TagType, TagTypeId}; /// /// #[repr(C)] /// #[derive(multiboot2::Pointee)] // Only needed for DSTs. @@ -449,7 +448,7 @@ impl<'a> BootInformation<'a> { /// } /// /// impl CustomTag { - /// fn name(&self) -> Result<&str, Utf8Error> { + /// fn name(&self) -> Result<&str, StringError> { /// Tag::parse_slice_as_string(&self.name) /// } /// } From 767eb0ca18c4255653a210f9dbfc8d2ea14d7738 Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Wed, 14 Aug 2024 13:42:28 +0200 Subject: [PATCH 2/8] crate: move BootInformation to dedicated module This improves code quality --- multiboot2/src/boot_information.rs | 430 +++++++++++++++++++++++++++++ multiboot2/src/lib.rs | 427 +--------------------------- multiboot2/src/module.rs | 4 +- 3 files changed, 434 insertions(+), 427 deletions(-) create mode 100644 multiboot2/src/boot_information.rs diff --git a/multiboot2/src/boot_information.rs b/multiboot2/src/boot_information.rs new file mode 100644 index 00000000..8effbc71 --- /dev/null +++ b/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::()) }; + + let end_tag_ptr = unsafe { + self_ptr + .add(self.header.total_size as usize) + .sub(size_of::()) + }; + 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 { + // 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::(); + // mbi: reference to full mbi + let mbi = ptr_meta::from_raw_parts::(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::() + } + + /// Search for the BootLoader name tag. + pub fn boot_loader_name_tag(&self) -> Option<&BootLoaderNameTag> { + self.get_tag::() + } + + /*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::() + } + + /// Search for the EFI boot services not exited tag. + pub fn efi_bs_not_exited_tag(&self) -> Option<&EFIBootServicesNotExitedTag> { + self.get_tag::() + } + + /// 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::() { + 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::(), + } + } + + /// Search for the EFI 32-bit SDT tag. + pub fn efi_sdt32_tag(&self) -> Option<&EFISdt32Tag> { + self.get_tag::() + } + + /// Search for the EFI 64-bit SDT tag. + pub fn efi_sdt64_tag(&self) -> Option<&EFISdt64Tag> { + self.get_tag::() + } + + /// Search for the EFI 32-bit image handle pointer tag. + pub fn efi_ih32_tag(&self) -> Option<&EFIImageHandle32Tag> { + self.get_tag::() + } + + /// Search for the EFI 64-bit image handle pointer tag. + pub fn efi_ih64_tag(&self) -> Option<&EFIImageHandle64Tag> { + self.get_tag::() + } + + /// 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 { + let tag = self.get_tag::(); + 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> { + self.get_tag::() + .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::() + } + + /// Search for the Memory map tag. + pub fn memory_map_tag(&self) -> Option<&MemoryMapTag> { + self.get_tag::() + } + + /// 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::() + } + + /// Search for the (ACPI 2.0 or later) RSDP tag. + pub fn rsdp_v2_tag(&self) -> Option<&RsdpV2Tag> { + self.get_tag::() + } + + /// Search for the SMBIOS tag. + pub fn smbios_tag(&self) -> Option<&SmbiosTag> { + self.get_tag::() + } + + /// Search for the VBE information tag. + pub fn vbe_info_tag(&self) -> Option<&VBEInfoTag> { + self.get_tag::() + } + + // ### 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::() + /// .unwrap(); + /// assert_eq!(tag.name(), Ok("name")); + /// ``` + pub fn get_tag(&'a self) -> Option<&'a TagT> { + self.tags() + .find(|tag| tag.typ == TagT::ID) + .map(|tag| tag.cast_tag::()) + } + + /// 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() + } +} diff --git a/multiboot2/src/lib.rs b/multiboot2/src/lib.rs index 384473de..436a632c 100644 --- a/multiboot2/src/lib.rs +++ b/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::()) }; - - let end_tag_ptr = unsafe { - self_ptr - .add(self.header.total_size as usize) - .sub(size_of::()) - }; - 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 { - // 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::(); - // mbi: reference to full mbi - let mbi = ptr_meta::from_raw_parts::(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::() - } - - /// Search for the BootLoader name tag. - pub fn boot_loader_name_tag(&self) -> Option<&BootLoaderNameTag> { - self.get_tag::() - } - - /*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::() - } - - /// Search for the EFI boot services not exited tag. - pub fn efi_bs_not_exited_tag(&self) -> Option<&EFIBootServicesNotExitedTag> { - self.get_tag::() - } - - /// 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::() { - 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::(), - } - } - - /// Search for the EFI 32-bit SDT tag. - pub fn efi_sdt32_tag(&self) -> Option<&EFISdt32Tag> { - self.get_tag::() - } - - /// Search for the EFI 64-bit SDT tag. - pub fn efi_sdt64_tag(&self) -> Option<&EFISdt64Tag> { - self.get_tag::() - } - - /// Search for the EFI 32-bit image handle pointer tag. - pub fn efi_ih32_tag(&self) -> Option<&EFIImageHandle32Tag> { - self.get_tag::() - } - - /// Search for the EFI 64-bit image handle pointer tag. - pub fn efi_ih64_tag(&self) -> Option<&EFIImageHandle64Tag> { - self.get_tag::() - } - - /// 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 { - let tag = self.get_tag::(); - 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> { - self.get_tag::() - .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::() - } - - /// Search for the Memory map tag. - pub fn memory_map_tag(&self) -> Option<&MemoryMapTag> { - self.get_tag::() - } - - /// 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::() - } - - /// Search for the (ACPI 2.0 or later) RSDP tag. - pub fn rsdp_v2_tag(&self) -> Option<&RsdpV2Tag> { - self.get_tag::() - } - - /// Search for the SMBIOS tag. - pub fn smbios_tag(&self) -> Option<&SmbiosTag> { - self.get_tag::() - } - - /// Search for the VBE information tag. - pub fn vbe_info_tag(&self) -> Option<&VBEInfoTag> { - self.get_tag::() - } - - // ### 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::() - /// .unwrap(); - /// assert_eq!(tag.name(), Ok("name")); - /// ``` - pub fn get_tag(&'a self) -> Option<&'a TagT> { - self.tags() - .find(|tag| tag.typ == TagT::ID) - .map(|tag| tag.cast_tag::()) - } - - /// 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::*; diff --git a/multiboot2/src/module.rs b/multiboot2/src/module.rs index b5098beb..e8a74bce 100644 --- a/multiboot2/src/module.rs +++ b/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")] From ec05bf5663335259dd1a17e4410f52e2fd11e087 Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Wed, 14 Aug 2024 15:00:13 +0200 Subject: [PATCH 3/8] multiboot2: introduce new TagHeader type This is a preparation for following refactorings. --- multiboot2/Changelog.md | 2 ++ multiboot2/src/boot_loader_name.rs | 9 ++++---- multiboot2/src/command_line.rs | 10 ++++----- multiboot2/src/efi.rs | 32 ++++++++++------------------- multiboot2/src/framebuffer.rs | 33 +++++++++++++++--------------- multiboot2/src/image_load_addr.rs | 9 ++++---- multiboot2/src/memory_map.rs | 17 +++++++-------- multiboot2/src/module.rs | 9 ++++---- multiboot2/src/rsdp.rs | 15 ++++++-------- multiboot2/src/smbios.rs | 14 ++++++------- multiboot2/src/tag.rs | 23 +++++++++++++++++++++ 11 files changed, 88 insertions(+), 85 deletions(-) diff --git a/multiboot2/Changelog.md b/multiboot2/Changelog.md index 1a5cfe99..5d269291 100644 --- a/multiboot2/Changelog.md +++ b/multiboot2/Changelog.md @@ -5,6 +5,8 @@ - updated dependencies - MSRV is 1.75 - doc fixes +- Introduced new `TagHeader` type as replacement for the `Tag` type that will + be changed in the next step. ## 0.20.2 (2024-05-26) diff --git a/multiboot2/src/boot_loader_name.rs b/multiboot2/src/boot_loader_name.rs index 93b12e0d..3cd2ac5c 100644 --- a/multiboot2/src/boot_loader_name.rs +++ b/multiboot2/src/boot_loader_name.rs @@ -1,6 +1,6 @@ //! Module for [`BootLoaderNameTag`]. -use crate::tag::StringError; +use crate::tag::{StringError, TagHeader}; use crate::{Tag, TagTrait, TagType, TagTypeId}; use core::fmt::{Debug, Formatter}; use core::mem::size_of; @@ -13,8 +13,7 @@ const METADATA_SIZE: usize = size_of::() + size_of::(); #[derive(ptr_meta::Pointee, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct BootLoaderNameTag { - typ: TagTypeId, - size: u32, + header: TagHeader, /// Null-terminated UTF-8 string name: [u8], } @@ -55,8 +54,8 @@ impl BootLoaderNameTag { impl Debug for BootLoaderNameTag { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("BootLoaderNameTag") - .field("typ", &{ self.typ }) - .field("size", &{ self.size }) + .field("typ", &self.header.typ) + .field("size", &self.header.size) .field("name", &self.name()) .finish() } diff --git a/multiboot2/src/command_line.rs b/multiboot2/src/command_line.rs index e2b168f8..25bd884a 100644 --- a/multiboot2/src/command_line.rs +++ b/multiboot2/src/command_line.rs @@ -1,8 +1,7 @@ //! Module for [`CommandLineTag`]. +use crate::tag::{StringError, TagHeader}; use crate::{Tag, TagTrait, TagType, TagTypeId}; - -use crate::tag::StringError; use core::fmt::{Debug, Formatter}; use core::mem; use core::str; @@ -18,8 +17,7 @@ pub(crate) const METADATA_SIZE: usize = mem::size_of::() + mem::size_ #[derive(ptr_meta::Pointee, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct CommandLineTag { - typ: TagTypeId, - size: u32, + header: TagHeader, /// Null-terminated UTF-8 string cmdline: [u8], } @@ -63,8 +61,8 @@ impl CommandLineTag { impl Debug for CommandLineTag { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("CommandLineTag") - .field("typ", &{ self.typ }) - .field("size", &{ self.size }) + .field("typ", &self.header.typ) + .field("size", &self.header.size) .field("cmdline", &self.cmdline()) .finish() } diff --git a/multiboot2/src/efi.rs b/multiboot2/src/efi.rs index 230b1bd8..acc8fbed 100644 --- a/multiboot2/src/efi.rs +++ b/multiboot2/src/efi.rs @@ -6,7 +6,7 @@ //! - [`EFIImageHandle64Tag`] //! - [`EFIBootServicesNotExitedTag`] -use crate::TagTypeId; +use crate::tag::TagHeader; use crate::{Tag, TagTrait, TagType}; use core::mem::size_of; @@ -14,8 +14,7 @@ use core::mem::size_of; #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct EFISdt32Tag { - typ: TagTypeId, - size: u32, + header: TagHeader, pointer: u32, } @@ -23,8 +22,7 @@ impl EFISdt32Tag { /// Create a new tag to pass the EFI32 System Table pointer. pub fn new(pointer: u32) -> Self { Self { - typ: Self::ID.into(), - size: size_of::().try_into().unwrap(), + header: TagHeader::new(Self::ID, size_of::().try_into().unwrap()), pointer, } } @@ -45,8 +43,7 @@ impl TagTrait for EFISdt32Tag { #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct EFISdt64Tag { - typ: TagTypeId, - size: u32, + header: TagHeader, pointer: u64, } @@ -54,8 +51,7 @@ impl EFISdt64Tag { /// Create a new tag to pass the EFI64 System Table pointer. pub fn new(pointer: u64) -> Self { Self { - typ: Self::ID.into(), - size: size_of::().try_into().unwrap(), + header: TagHeader::new(Self::ID, size_of::().try_into().unwrap()), pointer, } } @@ -77,8 +73,7 @@ impl TagTrait for EFISdt64Tag { #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct EFIImageHandle32Tag { - typ: TagTypeId, - size: u32, + header: TagHeader, pointer: u32, } @@ -86,8 +81,7 @@ impl EFIImageHandle32Tag { #[cfg(feature = "builder")] pub fn new(pointer: u32) -> Self { Self { - typ: Self::ID.into(), - size: size_of::().try_into().unwrap(), + header: TagHeader::new(Self::ID, size_of::().try_into().unwrap()), pointer, } } @@ -109,8 +103,7 @@ impl TagTrait for EFIImageHandle32Tag { #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct EFIImageHandle64Tag { - typ: TagTypeId, - size: u32, + header: TagHeader, pointer: u64, } @@ -118,8 +111,7 @@ impl EFIImageHandle64Tag { #[cfg(feature = "builder")] pub fn new(pointer: u64) -> Self { Self { - typ: Self::ID.into(), - size: size_of::().try_into().unwrap(), + header: TagHeader::new(Self::ID, size_of::().try_into().unwrap()), pointer, } } @@ -140,8 +132,7 @@ impl TagTrait for EFIImageHandle64Tag { #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct EFIBootServicesNotExitedTag { - typ: TagTypeId, - size: u32, + header: TagHeader, } impl EFIBootServicesNotExitedTag { @@ -155,8 +146,7 @@ impl EFIBootServicesNotExitedTag { impl Default for EFIBootServicesNotExitedTag { fn default() -> Self { Self { - typ: TagType::EfiBs.into(), - size: core::mem::size_of::().try_into().unwrap(), + header: TagHeader::new(Self::ID, size_of::().try_into().unwrap()), } } } diff --git a/multiboot2/src/framebuffer.rs b/multiboot2/src/framebuffer.rs index 5a92b8c4..96b1c32b 100644 --- a/multiboot2/src/framebuffer.rs +++ b/multiboot2/src/framebuffer.rs @@ -1,5 +1,6 @@ //! Module for [`FramebufferTag`]. +use crate::tag::TagHeader; use crate::{Tag, TagTrait, TagType, TagTypeId}; use core::fmt::Debug; use core::mem::size_of; @@ -51,8 +52,7 @@ const METADATA_SIZE: usize = size_of::() #[derive(ptr_meta::Pointee, Eq)] #[repr(C)] pub struct FramebufferTag { - typ: TagTypeId, - size: u32, + header: TagHeader, /// Contains framebuffer physical address. /// @@ -185,13 +185,13 @@ impl TagTrait for FramebufferTag { impl Debug for FramebufferTag { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("FramebufferTag") - .field("typ", &{ self.typ }) - .field("size", &{ self.size }) + .field("typ", &self.header.typ) + .field("size", &self.header.size) .field("buffer_type", &self.buffer_type()) - .field("address", &{ self.address }) - .field("pitch", &{ self.pitch }) - .field("width", &{ self.width }) - .field("height", &{ self.height }) + .field("address", &self.address) + .field("pitch", &self.pitch) + .field("width", &self.width) + .field("height", &self.height) .field("bpp", &self.bpp) .finish() } @@ -199,15 +199,14 @@ impl Debug for FramebufferTag { impl PartialEq for FramebufferTag { fn eq(&self, other: &Self) -> bool { - ({ self.typ } == { other.typ } - && { self.size } == { other.size } - && { self.address } == { other.address } - && { self.pitch } == { other.pitch } - && { self.width } == { other.width } - && { self.height } == { other.height } - && { self.bpp } == { other.bpp } - && { self.type_no } == { other.type_no } - && self.buffer == other.buffer) + self.header == other.header + && self.address == { other.address } + && self.pitch == { other.pitch } + && self.width == { other.width } + && self.height == { other.height } + && self.bpp == { other.bpp } + && self.type_no == { other.type_no } + && self.buffer == other.buffer } } diff --git a/multiboot2/src/image_load_addr.rs b/multiboot2/src/image_load_addr.rs index fbc6645d..ae2fe995 100644 --- a/multiboot2/src/image_load_addr.rs +++ b/multiboot2/src/image_load_addr.rs @@ -1,6 +1,7 @@ //! Module for [`ImageLoadPhysAddrTag`]. -use crate::{Tag, TagTrait, TagType, TagTypeId}; +use crate::tag::TagHeader; +use crate::{Tag, TagTrait, TagType}; #[cfg(feature = "builder")] use core::mem::size_of; @@ -10,8 +11,7 @@ use core::mem::size_of; #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct ImageLoadPhysAddrTag { - typ: TagTypeId, - size: u32, + header: TagHeader, load_base_addr: u32, } @@ -19,8 +19,7 @@ impl ImageLoadPhysAddrTag { #[cfg(feature = "builder")] pub fn new(load_base_addr: u32) -> Self { Self { - typ: Self::ID.into(), - size: size_of::().try_into().unwrap(), + header: TagHeader::new(Self::ID, size_of::().try_into().unwrap()), load_base_addr, } } diff --git a/multiboot2/src/memory_map.rs b/multiboot2/src/memory_map.rs index 3b005c09..f7989898 100644 --- a/multiboot2/src/memory_map.rs +++ b/multiboot2/src/memory_map.rs @@ -5,6 +5,7 @@ pub use uefi_raw::table::boot::MemoryAttribute as EFIMemoryAttribute; pub use uefi_raw::table::boot::MemoryDescriptor as EFIMemoryDesc; pub use uefi_raw::table::boot::MemoryType as EFIMemoryAreaType; +use crate::tag::TagHeader; use crate::{Tag, TagTrait, TagType, TagTypeId}; use core::fmt::{Debug, Formatter}; use core::marker::PhantomData; @@ -27,8 +28,7 @@ const METADATA_SIZE: usize = mem::size_of::() + 3 * mem::size_of:: for MemoryAreaType { #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct BasicMemoryInfoTag { - typ: TagTypeId, - size: u32, + header: TagHeader, memory_lower: u32, memory_upper: u32, } @@ -255,8 +254,7 @@ pub struct BasicMemoryInfoTag { impl BasicMemoryInfoTag { pub fn new(memory_lower: u32, memory_upper: u32) -> Self { Self { - typ: Self::ID.into(), - size: mem::size_of::().try_into().unwrap(), + header: TagHeader::new(Self::ID, size_of::().try_into().unwrap()), memory_lower, memory_upper, } @@ -287,8 +285,7 @@ impl AsBytes for EFIMemoryDesc {} #[derive(ptr_meta::Pointee, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct EFIMemoryMapTag { - typ: TagTypeId, - size: u32, + header: TagHeader, /// Most likely a little more than the size of a [`EFIMemoryDesc`]. /// This is always the reference, and `size_of` never. /// See . @@ -380,8 +377,8 @@ impl EFIMemoryMapTag { impl Debug for EFIMemoryMapTag { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("EFIMemoryMapTag") - .field("typ", &self.typ) - .field("size", &self.size) + .field("typ", &self.header.typ) + .field("size", &self.header.size) .field("desc_size", &self.desc_size) .field("buf", &self.memory_map.as_ptr()) .field("buf_len", &self.memory_map.len()) diff --git a/multiboot2/src/module.rs b/multiboot2/src/module.rs index e8a74bce..8359cbc5 100644 --- a/multiboot2/src/module.rs +++ b/multiboot2/src/module.rs @@ -1,6 +1,6 @@ //! Module for [`ModuleTag`]. -use crate::tag::{StringError, TagIter}; +use crate::tag::{StringError, TagHeader, TagIter}; use crate::{Tag, TagTrait, TagType, TagTypeId}; use core::fmt::{Debug, Formatter}; use core::mem::size_of; @@ -15,8 +15,7 @@ const METADATA_SIZE: usize = size_of::() + 3 * size_of::(); #[derive(ptr_meta::Pointee, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct ModuleTag { - typ: TagTypeId, - size: u32, + header: TagHeader, mod_start: u32, mod_end: u32, /// Null-terminated UTF-8 string @@ -81,8 +80,8 @@ impl TagTrait for ModuleTag { impl Debug for ModuleTag { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("ModuleTag") - .field("type", &{ self.typ }) - .field("size", &{ self.size }) + .field("type", &self.header.typ) + .field("size", &self.header.size) // Trick to print as hex. .field("mod_start", &self.mod_start) .field("mod_end", &self.mod_end) diff --git a/multiboot2/src/rsdp.rs b/multiboot2/src/rsdp.rs index d8526157..4d9ca2aa 100644 --- a/multiboot2/src/rsdp.rs +++ b/multiboot2/src/rsdp.rs @@ -12,7 +12,8 @@ //! signature should be manually verified. //! -use crate::{Tag, TagTrait, TagType, TagTypeId}; +use crate::tag::TagHeader; +use crate::{Tag, TagTrait, TagType}; #[cfg(feature = "builder")] use core::mem::size_of; use core::slice; @@ -25,8 +26,7 @@ const RSDPV1_LENGTH: usize = 20; #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct RsdpV1Tag { - typ: TagTypeId, - size: u32, + header: TagHeader, signature: [u8; 8], checksum: u8, oem_id: [u8; 6], @@ -44,8 +44,7 @@ impl RsdpV1Tag { rsdt_address: u32, ) -> Self { Self { - typ: Self::ID.into(), - size: size_of::().try_into().unwrap(), + header: TagHeader::new(Self::ID, size_of::().try_into().unwrap()), signature, checksum, oem_id, @@ -97,8 +96,7 @@ impl TagTrait for RsdpV1Tag { #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct RsdpV2Tag { - typ: TagTypeId, - size: u32, + header: TagHeader, signature: [u8; 8], checksum: u8, oem_id: [u8; 6], @@ -125,8 +123,7 @@ impl RsdpV2Tag { ext_checksum: u8, ) -> Self { Self { - typ: Self::ID.into(), - size: size_of::().try_into().unwrap(), + header: TagHeader::new(Self::ID, size_of::().try_into().unwrap()), signature, checksum, oem_id, diff --git a/multiboot2/src/smbios.rs b/multiboot2/src/smbios.rs index 5c34c7d8..46f1ad33 100644 --- a/multiboot2/src/smbios.rs +++ b/multiboot2/src/smbios.rs @@ -2,6 +2,7 @@ #[cfg(feature = "builder")] use crate::builder::BoxedDst; +use crate::tag::TagHeader; use crate::{Tag, TagTrait, TagType, TagTypeId}; use core::fmt::Debug; @@ -13,8 +14,7 @@ const METADATA_SIZE: usize = core::mem::size_of::() #[derive(ptr_meta::Pointee, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct SmbiosTag { - typ: TagTypeId, - size: u32, + header: TagHeader, pub major: u8, pub minor: u8, _reserved: [u8; 6], @@ -42,10 +42,10 @@ impl TagTrait for SmbiosTag { impl Debug for SmbiosTag { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("BootLoaderNameTag") - .field("typ", &{ self.typ }) - .field("size", &{ self.size }) - .field("major", &{ self.major }) - .field("minor", &{ self.minor }) + .field("typ", &self.header.typ) + .field("size", &self.header.size) + .field("major", &self.major) + .field("minor", &self.minor) .finish() } } @@ -76,7 +76,7 @@ mod tests { let tag = get_bytes(); let tag = unsafe { &*tag.as_ptr().cast::() }; let tag = tag.cast_tag::(); - assert_eq!({ tag.typ }, TagType::Smbios); + assert_eq!(tag.header.typ, TagType::Smbios); assert_eq!(tag.major, 3); assert_eq!(tag.minor, 0); assert_eq!(tag.tables, [0xabu8; 24]); diff --git a/multiboot2/src/tag.rs b/multiboot2/src/tag.rs index 0002d59f..8909e6ee 100644 --- a/multiboot2/src/tag.rs +++ b/multiboot2/src/tag.rs @@ -34,6 +34,29 @@ impl core::error::Error for StringError { } } +/// The common header that all tags have in common. This type is ABI compatible. +/// +/// Not to be confused with Multiboot header tags, which are something +/// different. +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[repr(C)] +pub struct TagHeader { + pub typ: TagTypeId, /* u32 */ + pub size: u32, + // Followed by additional, tag specific fields. +} + +impl TagHeader { + /// Creates a new header. + #[cfg(feature = "builder")] + pub fn new(typ: impl Into, size: u32) -> Self { + Self { + typ: typ.into(), + size, + } + } +} + /// Common base structure for all tags that can be passed via the Multiboot2 /// Information Structure (MBI) to a Multiboot2 payload/program/kernel. /// From 34abe94b4afe995b429d3e89ecd26ced532e102a Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Wed, 14 Aug 2024 15:07:45 +0200 Subject: [PATCH 4/8] multiboot2: apply latest clippy code style guidelines --- multiboot2/Changelog.md | 1 + multiboot2/src/boot_information.rs | 41 +++++++++++++++----- multiboot2/src/boot_loader_name.rs | 3 +- multiboot2/src/builder/boxed_dst.rs | 2 +- multiboot2/src/builder/information.rs | 22 ++++++++++- multiboot2/src/command_line.rs | 5 ++- multiboot2/src/efi.rs | 17 +++++++-- multiboot2/src/elf_sections.rs | 13 ++++++- multiboot2/src/framebuffer.rs | 20 ++++++---- multiboot2/src/image_load_addr.rs | 4 +- multiboot2/src/lib.rs | 20 +++++++--- multiboot2/src/memory_map.rs | 32 +++++++++++----- multiboot2/src/module.rs | 14 ++++--- multiboot2/src/rsdp.rs | 27 +++++++++----- multiboot2/src/smbios.rs | 1 + multiboot2/src/tag.rs | 6 ++- multiboot2/src/tag_trait.rs | 1 + multiboot2/src/tag_type.rs | 54 ++++++++++++++------------- 18 files changed, 198 insertions(+), 85 deletions(-) diff --git a/multiboot2/Changelog.md b/multiboot2/Changelog.md index 5d269291..6e28ec80 100644 --- a/multiboot2/Changelog.md +++ b/multiboot2/Changelog.md @@ -2,6 +2,7 @@ ## Unreleased +- **Breaking** All functions that returns something useful are now `#[must_use]` - updated dependencies - MSRV is 1.75 - doc fixes diff --git a/multiboot2/src/boot_information.rs b/multiboot2/src/boot_information.rs index 8effbc71..affd4e9d 100644 --- a/multiboot2/src/boot_information.rs +++ b/multiboot2/src/boot_information.rs @@ -46,7 +46,7 @@ pub struct BootInformationHeader { #[cfg(feature = "builder")] impl BootInformationHeader { - pub(crate) fn new(total_size: u32) -> Self { + pub(crate) const fn new(total_size: u32) -> Self { Self { total_size, _reserved: 0, @@ -140,12 +140,14 @@ impl<'a> BootInformation<'a> { } /// Get the start address of the boot info. + #[must_use] 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 () { + #[must_use] + pub const fn as_ptr(&self) -> *const () { core::ptr::addr_of!(*self.0).cast() } @@ -159,12 +161,14 @@ impl<'a> BootInformation<'a> { /// # let boot_info = unsafe { BootInformation::load(ptr).unwrap() }; /// let end_addr = boot_info.start_address() + boot_info.total_size(); /// ``` + #[must_use] 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 { + #[must_use] + pub const fn total_size(&self) -> usize { self.0.header.total_size as usize } @@ -177,11 +181,13 @@ impl<'a> BootInformation<'a> { }*/ /// Search for the basic memory info tag. + #[must_use] pub fn basic_memory_info_tag(&self) -> Option<&BasicMemoryInfoTag> { self.get_tag::() } /// Search for the BootLoader name tag. + #[must_use] pub fn boot_loader_name_tag(&self) -> Option<&BootLoaderNameTag> { self.get_tag::() } @@ -192,11 +198,13 @@ impl<'a> BootInformation<'a> { }*/ /// Search for the Command line tag. + #[must_use] pub fn command_line_tag(&self) -> Option<&CommandLineTag> { self.get_tag::() } /// Search for the EFI boot services not exited tag. + #[must_use] pub fn efi_bs_not_exited_tag(&self) -> Option<&EFIBootServicesNotExitedTag> { self.get_tag::() } @@ -205,34 +213,37 @@ impl<'a> BootInformation<'a> { /// 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. + #[must_use] 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::() { - 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::(), - } + self.get_tag::().map_or_else( + || self.get_tag::(), |_tag| { + log::debug!("The EFI memory map is present but the UEFI Boot Services Not Existed Tag is present. Returning None."); + None + }) } /// Search for the EFI 32-bit SDT tag. + #[must_use] pub fn efi_sdt32_tag(&self) -> Option<&EFISdt32Tag> { self.get_tag::() } /// Search for the EFI 64-bit SDT tag. + #[must_use] pub fn efi_sdt64_tag(&self) -> Option<&EFISdt64Tag> { self.get_tag::() } /// Search for the EFI 32-bit image handle pointer tag. + #[must_use] pub fn efi_ih32_tag(&self) -> Option<&EFIImageHandle32Tag> { self.get_tag::() } /// Search for the EFI 64-bit image handle pointer tag. + #[must_use] pub fn efi_ih64_tag(&self) -> Option<&EFIImageHandle64Tag> { self.get_tag::() } @@ -254,6 +265,7 @@ impl<'a> BootInformation<'a> { /// } /// } /// ``` + #[must_use] pub fn elf_sections(&self) -> Option { let tag = self.get_tag::(); tag.map(|t| { @@ -264,6 +276,7 @@ impl<'a> BootInformation<'a> { /// Search for the VBE framebuffer tag. The result is `Some(Err(e))`, if the /// framebuffer type is unknown, while the framebuffer tag is present. + #[must_use] pub fn framebuffer_tag(&self) -> Option> { self.get_tag::() .map(|tag| match tag.buffer_type() { @@ -273,16 +286,19 @@ impl<'a> BootInformation<'a> { } /// Search for the Image Load Base Physical Address tag. + #[must_use] pub fn load_base_addr_tag(&self) -> Option<&ImageLoadPhysAddrTag> { self.get_tag::() } /// Search for the Memory map tag. + #[must_use] pub fn memory_map_tag(&self) -> Option<&MemoryMapTag> { self.get_tag::() } /// Get an iterator of all module tags. + #[must_use] pub fn module_tags(&self) -> ModuleIter { module::module_iter(self.tags()) } @@ -293,21 +309,25 @@ impl<'a> BootInformation<'a> { }*/ /// Search for the (ACPI 1.0) RSDP tag. + #[must_use] pub fn rsdp_v1_tag(&self) -> Option<&RsdpV1Tag> { self.get_tag::() } /// Search for the (ACPI 2.0 or later) RSDP tag. + #[must_use] pub fn rsdp_v2_tag(&self) -> Option<&RsdpV2Tag> { self.get_tag::() } /// Search for the SMBIOS tag. + #[must_use] pub fn smbios_tag(&self) -> Option<&SmbiosTag> { self.get_tag::() } /// Search for the VBE information tag. + #[must_use] pub fn vbe_info_tag(&self) -> Option<&VBEInfoTag> { self.get_tag::() } @@ -367,6 +387,7 @@ impl<'a> BootInformation<'a> { /// .unwrap(); /// assert_eq!(tag.name(), Ok("name")); /// ``` + #[must_use] pub fn get_tag(&'a self) -> Option<&'a TagT> { self.tags() .find(|tag| tag.typ == TagT::ID) diff --git a/multiboot2/src/boot_loader_name.rs b/multiboot2/src/boot_loader_name.rs index 3cd2ac5c..4e0851c8 100644 --- a/multiboot2/src/boot_loader_name.rs +++ b/multiboot2/src/boot_loader_name.rs @@ -20,6 +20,7 @@ pub struct BootLoaderNameTag { impl BootLoaderNameTag { #[cfg(feature = "builder")] + #[must_use] pub fn new(name: &str) -> BoxedDst { let mut bytes: Vec<_> = name.bytes().collect(); if !bytes.ends_with(&[0]) { @@ -100,7 +101,7 @@ mod tests { let tag = get_bytes(); let tag = unsafe { &*tag.as_ptr().cast::() }; let tag = tag.cast_tag::(); - assert_eq!({ tag.typ }, TagType::BootLoaderName); + assert_eq!(tag.header.typ, TagType::BootLoaderName); assert_eq!(tag.name().expect("must be valid UTF-8"), MSG); } diff --git a/multiboot2/src/builder/boxed_dst.rs b/multiboot2/src/builder/boxed_dst.rs index bafb8df3..f433104e 100644 --- a/multiboot2/src/builder/boxed_dst.rs +++ b/multiboot2/src/builder/boxed_dst.rs @@ -144,7 +144,7 @@ mod tests { #[test] fn can_hold_tag_trait() { - fn consume(_: &T) {} + const fn consume(_: &T) {} let content = b"hallo\0"; let tag = BoxedDst::::new(content); diff --git a/multiboot2/src/builder/information.rs b/multiboot2/src/builder/information.rs index 8d16a903..91b70eff 100644 --- a/multiboot2/src/builder/information.rs +++ b/multiboot2/src/builder/information.rs @@ -73,6 +73,7 @@ impl Default for InformationBuilder { impl InformationBuilder { /// Creates a new builder. + #[must_use] pub const fn new() -> Self { Self(Vec::new()) } @@ -87,6 +88,7 @@ impl InformationBuilder { /// [`Self::build`]-method is called. This function assumes that the begin /// of the boot information is 8-byte aligned and automatically adds padding /// between tags to ensure that each tag is 8-byte aligned. + #[must_use] pub fn expected_len(&self) -> usize { let tag_size_iter = self.0.iter().map(|(_, bytes)| bytes.len()); @@ -118,6 +120,7 @@ impl InformationBuilder { } /// Constructs the bytes for a valid Multiboot2 information with the given properties. + #[must_use] pub fn build(self) -> BootInformationBytes { const ALIGN: usize = 8; @@ -202,92 +205,109 @@ impl InformationBuilder { } /// Adds a 'basic memory information' tag (represented by [`BasicMemoryInfoTag`]) to the builder. + #[must_use] pub fn basic_memory_info_tag(self, tag: BasicMemoryInfoTag) -> Self { self.add_tag(&tag).unwrap() } /// Adds a 'bootloader name' tag (represented by [`BootLoaderNameTag`]) to the builder. + #[must_use] pub fn bootloader_name_tag(self, tag: BoxedDst) -> Self { self.add_tag(&*tag).unwrap() } /// Adds a 'command line' tag (represented by [`CommandLineTag`]) to the builder. + #[must_use] pub fn command_line_tag(self, tag: BoxedDst) -> Self { self.add_tag(&*tag).unwrap() } /// Adds a 'EFI 32-bit system table pointer' tag (represented by [`EFISdt32Tag`]) to the builder. + #[must_use] pub fn efisdt32_tag(self, tag: EFISdt32Tag) -> Self { self.add_tag(&tag).unwrap() } /// Adds a 'EFI 64-bit system table pointer' tag (represented by [`EFISdt64Tag`]) to the builder. + #[must_use] pub fn efisdt64_tag(self, tag: EFISdt64Tag) -> Self { self.add_tag(&tag).unwrap() } /// Adds a 'EFI boot services not terminated' tag (represented by [`EFIBootServicesNotExitedTag`]) to the builder. + #[must_use] pub fn efi_boot_services_not_exited_tag(self) -> Self { self.add_tag(&EFIBootServicesNotExitedTag::new()).unwrap() } /// Adds a 'EFI 32-bit image handle pointer' tag (represented by [`EFIImageHandle32Tag`]) to the builder. + #[must_use] pub fn efi_image_handle32(self, tag: EFIImageHandle32Tag) -> Self { self.add_tag(&tag).unwrap() } /// Adds a 'EFI 64-bit image handle pointer' tag (represented by [`EFIImageHandle64Tag`]) to the builder. + #[must_use] pub fn efi_image_handle64(self, tag: EFIImageHandle64Tag) -> Self { self.add_tag(&tag).unwrap() } /// Adds a 'EFI Memory map' tag (represented by [`EFIMemoryMapTag`]) to the builder. + #[must_use] pub fn efi_memory_map_tag(self, tag: BoxedDst) -> Self { self.add_tag(&*tag).unwrap() } /// Adds a 'ELF-Symbols' tag (represented by [`ElfSectionsTag`]) to the builder. + #[must_use] pub fn elf_sections_tag(self, tag: BoxedDst) -> Self { self.add_tag(&*tag).unwrap() } /// Adds a 'Framebuffer info' tag (represented by [`FramebufferTag`]) to the builder. + #[must_use] pub fn framebuffer_tag(self, tag: BoxedDst) -> Self { self.add_tag(&*tag).unwrap() } /// Adds a 'Image load base physical address' tag (represented by [`ImageLoadPhysAddrTag`]) to the builder. + #[must_use] pub fn image_load_addr(self, tag: ImageLoadPhysAddrTag) -> Self { self.add_tag(&tag).unwrap() } /// Adds a (*none EFI*) 'memory map' tag (represented by [`MemoryMapTag`]) to the builder. + #[must_use] pub fn memory_map_tag(self, tag: BoxedDst) -> Self { self.add_tag(&*tag).unwrap() } /// Adds a 'Modules' tag (represented by [`ModuleTag`]) to the builder. /// This tag can occur multiple times in boot information. + #[must_use] pub fn add_module_tag(self, tag: BoxedDst) -> Self { self.add_tag(&*tag).unwrap() } /// Adds a 'ACPI old RSDP' tag (represented by [`RsdpV1Tag`]) to the builder. + #[must_use] pub fn rsdp_v1_tag(self, tag: RsdpV1Tag) -> Self { self.add_tag(&tag).unwrap() } /// Adds a 'ACPI new RSDP' tag (represented by [`RsdpV2Tag`]) to the builder. + #[must_use] pub fn rsdp_v2_tag(self, tag: RsdpV2Tag) -> Self { self.add_tag(&tag).unwrap() } /// Adds a 'SMBIOS tables' tag (represented by [`SmbiosTag`]) to the builder. + #[must_use] pub fn smbios_tag(self, tag: BoxedDst) -> Self { self.add_tag(&*tag).unwrap() } - fn tag_is_allowed_multiple_times(tag_type: TagType) -> bool { + const fn tag_is_allowed_multiple_times(tag_type: TagType) -> bool { matches!( tag_type, TagType::Module | TagType::Smbios | TagType::Custom(_) diff --git a/multiboot2/src/command_line.rs b/multiboot2/src/command_line.rs index 25bd884a..91466ef5 100644 --- a/multiboot2/src/command_line.rs +++ b/multiboot2/src/command_line.rs @@ -8,7 +8,7 @@ use core::str; #[cfg(feature = "builder")] use {crate::builder::BoxedDst, alloc::vec::Vec}; -pub(crate) const METADATA_SIZE: usize = mem::size_of::() + mem::size_of::(); +pub const METADATA_SIZE: usize = mem::size_of::() + mem::size_of::(); /// This tag contains the command line string. /// @@ -25,6 +25,7 @@ pub struct CommandLineTag { impl CommandLineTag { /// Create a new command line tag from the given string. #[cfg(feature = "builder")] + #[must_use] pub fn new(command_line: &str) -> BoxedDst { let mut bytes: Vec<_> = command_line.bytes().collect(); if !bytes.ends_with(&[0]) { @@ -107,7 +108,7 @@ mod tests { let tag = get_bytes(); let tag = unsafe { &*tag.as_ptr().cast::() }; let tag = tag.cast_tag::(); - assert_eq!({ tag.typ }, TagType::Cmdline); + assert_eq!(tag.header.typ, TagType::Cmdline); assert_eq!(tag.cmdline().expect("must be valid UTF-8"), MSG); } diff --git a/multiboot2/src/efi.rs b/multiboot2/src/efi.rs index acc8fbed..9b2e5975 100644 --- a/multiboot2/src/efi.rs +++ b/multiboot2/src/efi.rs @@ -20,6 +20,7 @@ pub struct EFISdt32Tag { impl EFISdt32Tag { /// Create a new tag to pass the EFI32 System Table pointer. + #[must_use] pub fn new(pointer: u32) -> Self { Self { header: TagHeader::new(Self::ID, size_of::().try_into().unwrap()), @@ -28,7 +29,8 @@ impl EFISdt32Tag { } /// The physical address of a i386 EFI system table. - pub fn sdt_address(&self) -> usize { + #[must_use] + pub const fn sdt_address(&self) -> usize { self.pointer as usize } } @@ -49,6 +51,7 @@ pub struct EFISdt64Tag { impl EFISdt64Tag { /// Create a new tag to pass the EFI64 System Table pointer. + #[must_use] pub fn new(pointer: u64) -> Self { Self { header: TagHeader::new(Self::ID, size_of::().try_into().unwrap()), @@ -57,7 +60,8 @@ impl EFISdt64Tag { } /// The physical address of a x86_64 EFI system table. - pub fn sdt_address(&self) -> usize { + #[must_use] + pub const fn sdt_address(&self) -> usize { self.pointer as usize } } @@ -79,6 +83,7 @@ pub struct EFIImageHandle32Tag { impl EFIImageHandle32Tag { #[cfg(feature = "builder")] + #[must_use] pub fn new(pointer: u32) -> Self { Self { header: TagHeader::new(Self::ID, size_of::().try_into().unwrap()), @@ -87,7 +92,8 @@ impl EFIImageHandle32Tag { } /// Returns the physical address of the EFI image handle. - pub fn image_handle(&self) -> usize { + #[must_use] + pub const fn image_handle(&self) -> usize { self.pointer as usize } } @@ -109,6 +115,7 @@ pub struct EFIImageHandle64Tag { impl EFIImageHandle64Tag { #[cfg(feature = "builder")] + #[must_use] pub fn new(pointer: u64) -> Self { Self { header: TagHeader::new(Self::ID, size_of::().try_into().unwrap()), @@ -117,7 +124,8 @@ impl EFIImageHandle64Tag { } /// Returns the physical address of the EFI image handle. - pub fn image_handle(&self) -> usize { + #[must_use] + pub const fn image_handle(&self) -> usize { self.pointer as usize } } @@ -137,6 +145,7 @@ pub struct EFIBootServicesNotExitedTag { impl EFIBootServicesNotExitedTag { #[cfg(feature = "builder")] + #[must_use] pub fn new() -> Self { Self::default() } diff --git a/multiboot2/src/elf_sections.rs b/multiboot2/src/elf_sections.rs index 00579359..eac63e7d 100644 --- a/multiboot2/src/elf_sections.rs +++ b/multiboot2/src/elf_sections.rs @@ -26,6 +26,7 @@ pub struct ElfSectionsTag { impl ElfSectionsTag { /// Create a new ElfSectionsTag with the given data. #[cfg(feature = "builder")] + #[must_use] pub fn new( number_of_sections: u32, entry_size: u32, @@ -43,7 +44,7 @@ impl ElfSectionsTag { } /// Get an iterator of loaded ELF sections. - pub(crate) fn sections(&self) -> ElfSectionIter { + pub(crate) const fn sections(&self) -> ElfSectionIter { let string_section_offset = (self.shndx * self.entry_size) as isize; let string_section_ptr = unsafe { self.first_section().offset(string_section_offset) as *const _ }; @@ -55,7 +56,7 @@ impl ElfSectionsTag { } } - fn first_section(&self) -> *const u8 { + const fn first_section(&self) -> *const u8 { &(self.sections[0]) as *const _ } } @@ -174,6 +175,7 @@ struct ElfSectionInner64 { impl ElfSection { /// Get the section type as a `ElfSectionType` enum variant. + #[must_use] pub fn section_type(&self) -> ElfSectionType { match self.get().typ() { 0 => ElfSectionType::Unused, @@ -201,6 +203,7 @@ impl ElfSection { } /// Get the "raw" section type as a `u32` + #[must_use] pub fn section_type_raw(&self) -> u32 { self.get().typ() } @@ -224,6 +227,7 @@ impl ElfSection { } /// Get the physical start address of the section. + #[must_use] pub fn start_address(&self) -> u64 { self.get().addr() } @@ -231,11 +235,13 @@ impl ElfSection { /// Get the physical end address of the section. /// /// This is the same as doing `section.start_address() + section.size()` + #[must_use] pub fn end_address(&self) -> u64 { self.get().addr() + self.get().size() } /// Get the section's size in bytes. + #[must_use] pub fn size(&self) -> u64 { self.get().size() } @@ -246,16 +252,19 @@ impl ElfSection { /// modulo the value of `addrlign`. Currently, only 0 and positive /// integral powers of two are allowed. Values 0 and 1 mean the section has no /// alignment constraints. + #[must_use] pub fn addralign(&self) -> u64 { self.get().addralign() } /// Get the section's flags. + #[must_use] pub fn flags(&self) -> ElfSectionFlags { ElfSectionFlags::from_bits_truncate(self.get().flags()) } /// Check if the `ALLOCATED` flag is set in the section flags. + #[must_use] pub fn is_allocated(&self) -> bool { self.flags().contains(ElfSectionFlags::ALLOCATED) } diff --git a/multiboot2/src/framebuffer.rs b/multiboot2/src/framebuffer.rs index 96b1c32b..a5d7b49c 100644 --- a/multiboot2/src/framebuffer.rs +++ b/multiboot2/src/framebuffer.rs @@ -17,8 +17,8 @@ struct Reader { } impl Reader { - fn new(ptr: *const T) -> Reader { - Reader { + const fn new(ptr: *const T) -> Self { + Self { ptr: ptr as *const u8, off: 0, } @@ -85,6 +85,7 @@ pub struct FramebufferTag { impl FramebufferTag { #[cfg(feature = "builder")] + #[must_use] pub fn new( address: u64, pitch: u32, @@ -107,27 +108,32 @@ impl FramebufferTag { /// This field is 64-bit wide but bootloader should set it under 4GiB if /// possible for compatibility with payloads which aren’t aware of PAE or /// amd64. - pub fn address(&self) -> u64 { + #[must_use] + pub const fn address(&self) -> u64 { self.address } /// Contains the pitch in bytes. - pub fn pitch(&self) -> u32 { + #[must_use] + pub const fn pitch(&self) -> u32 { self.pitch } /// Contains framebuffer width in pixels. - pub fn width(&self) -> u32 { + #[must_use] + pub const fn width(&self) -> u32 { self.width } /// Contains framebuffer height in pixels. - pub fn height(&self) -> u32 { + #[must_use] + pub const fn height(&self) -> u32 { self.height } /// Contains number of bits per pixel. - pub fn bpp(&self) -> u8 { + #[must_use] + pub const fn bpp(&self) -> u8 { self.bpp } diff --git a/multiboot2/src/image_load_addr.rs b/multiboot2/src/image_load_addr.rs index ae2fe995..1f9be8f3 100644 --- a/multiboot2/src/image_load_addr.rs +++ b/multiboot2/src/image_load_addr.rs @@ -17,6 +17,7 @@ pub struct ImageLoadPhysAddrTag { impl ImageLoadPhysAddrTag { #[cfg(feature = "builder")] + #[must_use] pub fn new(load_base_addr: u32) -> Self { Self { header: TagHeader::new(Self::ID, size_of::().try_into().unwrap()), @@ -25,7 +26,8 @@ impl ImageLoadPhysAddrTag { } /// Returns the load base address. - pub fn load_base_addr(&self) -> u32 { + #[must_use] + pub const fn load_base_addr(&self) -> u32 { self.load_base_addr } } diff --git a/multiboot2/src/lib.rs b/multiboot2/src/lib.rs index 436a632c..a2abeadd 100644 --- a/multiboot2/src/lib.rs +++ b/multiboot2/src/lib.rs @@ -1,12 +1,20 @@ #![no_std] #![cfg_attr(feature = "unstable", feature(error_in_core))] -#![deny(missing_debug_implementations)] // --- BEGIN STYLE CHECKS --- -// These checks are optional in CI for PRs, as discussed in -// https://github.com/rust-osdev/multiboot2/pull/92 -#![deny(clippy::all)] +#![deny( + clippy::all, + clippy::cargo, + clippy::nursery, + clippy::must_use_candidate, + // clippy::restriction, + // clippy::pedantic +)] +// now allow a few rules which are denied by the above statement +// --> They are either ridiculous, not necessary, or we can't fix them. +#![allow(clippy::multiple_crate_versions)] +// #![deny(missing_docs)] +#![deny(missing_debug_implementations)] #![deny(rustdoc::all)] -#![allow(rustdoc::private_doc_tests)] // --- END STYLE CHECKS --- //! Library that assists parsing the Multiboot2 Information Structure (MBI) from @@ -372,6 +380,7 @@ mod tests { #[test] #[cfg_attr(miri, ignore)] + #[allow(clippy::cognitive_complexity)] fn vbe_info_tag() { //Taken from GRUB2 running in QEMU. #[repr(C, align(8))] @@ -813,6 +822,7 @@ mod tests { } /// Helper for [`grub2`]. + #[allow(clippy::cognitive_complexity)] fn test_grub2_boot_info( bi: &BootInformation, addr: usize, diff --git a/multiboot2/src/memory_map.rs b/multiboot2/src/memory_map.rs index f7989898..f087dde4 100644 --- a/multiboot2/src/memory_map.rs +++ b/multiboot2/src/memory_map.rs @@ -36,6 +36,7 @@ pub struct MemoryMapTag { impl MemoryMapTag { #[cfg(feature = "builder")] + #[must_use] pub fn new(areas: &[MemoryArea]) -> BoxedDst { let entry_size: u32 = mem::size_of::().try_into().unwrap(); let entry_version: u32 = 0; @@ -47,12 +48,14 @@ impl MemoryMapTag { } /// Returns the entry size. - pub fn entry_size(&self) -> u32 { + #[must_use] + pub const fn entry_size(&self) -> u32 { self.entry_size } /// Returns the entry version. - pub fn entry_version(&self) -> u32 { + #[must_use] + pub const fn entry_version(&self) -> u32 { self.entry_version } @@ -60,6 +63,7 @@ impl MemoryMapTag { /// /// Usually, this should already reflect the memory consumed by the /// code running this. + #[must_use] pub fn memory_areas(&self) -> &[MemoryArea] { // If this ever fails, we need to model this differently in this crate. assert_eq!(self.entry_size as usize, mem::size_of::()); @@ -100,22 +104,26 @@ impl MemoryArea { } /// The start address of the memory region. - pub fn start_address(&self) -> u64 { + #[must_use] + pub const fn start_address(&self) -> u64 { self.base_addr } /// The end address of the memory region. - pub fn end_address(&self) -> u64 { + #[must_use] + pub const fn end_address(&self) -> u64 { self.base_addr + self.length } /// The size, in bytes, of the memory region. - pub fn size(&self) -> u64 { + #[must_use] + pub const fn size(&self) -> u64 { self.length } /// The type of the memory region. - pub fn typ(&self) -> MemoryAreaTypeId { + #[must_use] + pub const fn typ(&self) -> MemoryAreaTypeId { self.typ } } @@ -215,7 +223,7 @@ impl From for MemoryAreaTypeId { impl PartialEq for MemoryAreaTypeId { fn eq(&self, other: &MemoryAreaType) -> bool { - let val: MemoryAreaTypeId = (*other).into(); + let val: Self = (*other).into(); let val: u32 = val.0; self.0.eq(&val) } @@ -252,6 +260,7 @@ pub struct BasicMemoryInfoTag { } impl BasicMemoryInfoTag { + #[must_use] pub fn new(memory_lower: u32, memory_upper: u32) -> Self { Self { header: TagHeader::new(Self::ID, size_of::().try_into().unwrap()), @@ -260,11 +269,13 @@ impl BasicMemoryInfoTag { } } - pub fn memory_lower(&self) -> u32 { + #[must_use] + pub const fn memory_lower(&self) -> u32 { self.memory_lower } - pub fn memory_upper(&self) -> u32 { + #[must_use] + pub const fn memory_upper(&self) -> u32 { self.memory_upper } } @@ -310,6 +321,7 @@ impl EFIMemoryMapTag { /// Create a new EFI memory map tag with the given memory descriptors. /// Version and size can't be set because you're passing a slice of /// EFIMemoryDescs, not the ones you might have gotten from the firmware. + #[must_use] pub fn new_from_descs(descs: &[EFIMemoryDesc]) -> BoxedDst { // TODO replace this EfiMemorydesc::uefi_desc_size() in the next uefi_raw // release. @@ -337,6 +349,7 @@ impl EFIMemoryMapTag { #[cfg(feature = "builder")] /// Create a new EFI memory map tag from the given EFI memory map. + #[must_use] pub fn new_from_map(desc_size: u32, desc_version: u32, efi_mmap: &[u8]) -> BoxedDst { assert!(desc_size > 0); assert_eq!(efi_mmap.len() % desc_size as usize, 0); @@ -359,6 +372,7 @@ impl EFIMemoryMapTag { /// /// Usually, this should already reflect the memory consumed by the /// code running this. + #[must_use] pub fn memory_areas(&self) -> EFIMemoryAreaIter { // If this ever fails, this needs to be refactored in a joint-effort // with the uefi-rs project to have all corresponding typings. diff --git a/multiboot2/src/module.rs b/multiboot2/src/module.rs index 8359cbc5..fcd43421 100644 --- a/multiboot2/src/module.rs +++ b/multiboot2/src/module.rs @@ -24,6 +24,7 @@ pub struct ModuleTag { impl ModuleTag { #[cfg(feature = "builder")] + #[must_use] pub fn new(start: u32, end: u32, cmdline: &str) -> BoxedDst { assert!(end > start, "must have a size"); @@ -53,17 +54,20 @@ impl ModuleTag { } /// Start address of the module. - pub fn start_address(&self) -> u32 { + #[must_use] + pub const fn start_address(&self) -> u32 { self.mod_start } /// End address of the module - pub fn end_address(&self) -> u32 { + #[must_use] + pub const fn end_address(&self) -> u32 { self.mod_end } /// The size of the module/the BLOB in memory. - pub fn module_size(&self) -> u32 { + #[must_use] + pub const fn module_size(&self) -> u32 { self.mod_end - self.mod_start } } @@ -91,7 +95,7 @@ impl Debug for ModuleTag { } } -pub fn module_iter(iter: TagIter) -> ModuleIter { +pub const fn module_iter(iter: TagIter) -> ModuleIter { ModuleIter { iter } } @@ -154,7 +158,7 @@ mod tests { let tag = get_bytes(); let tag = unsafe { &*tag.as_ptr().cast::() }; let tag = tag.cast_tag::(); - assert_eq!({ tag.typ }, TagType::Module); + assert_eq!(tag.header.typ, TagType::Module); assert_eq!(tag.cmdline().expect("must be valid UTF-8"), MSG); } diff --git a/multiboot2/src/rsdp.rs b/multiboot2/src/rsdp.rs index 4d9ca2aa..29ff6ea6 100644 --- a/multiboot2/src/rsdp.rs +++ b/multiboot2/src/rsdp.rs @@ -36,6 +36,7 @@ pub struct RsdpV1Tag { impl RsdpV1Tag { #[cfg(feature = "builder")] + #[must_use] pub fn new( signature: [u8; 8], checksum: u8, @@ -56,11 +57,12 @@ impl RsdpV1Tag { /// The "RSD PTR " marker signature. /// /// This is originally a 8-byte C string (not null terminated!) that must contain "RSD PTR " - pub fn signature(&self) -> Result<&str, Utf8Error> { + pub const fn signature(&self) -> Result<&str, Utf8Error> { str::from_utf8(&self.signature) } /// Validation of the RSDPv1 checksum + #[must_use] pub fn checksum_is_valid(&self) -> bool { let bytes = unsafe { slice::from_raw_parts(self as *const _ as *const u8, RSDPV1_LENGTH + 8) }; @@ -71,17 +73,19 @@ impl RsdpV1Tag { } /// An OEM-supplied string that identifies the OEM. - pub fn oem_id(&self) -> Result<&str, Utf8Error> { + pub const fn oem_id(&self) -> Result<&str, Utf8Error> { str::from_utf8(&self.oem_id) } /// The revision of the ACPI. - pub fn revision(&self) -> u8 { + #[must_use] + pub const fn revision(&self) -> u8 { self.revision } /// The physical (I repeat: physical) address of the RSDT table. - pub fn rsdt_address(&self) -> usize { + #[must_use] + pub const fn rsdt_address(&self) -> usize { self.rsdt_address as usize } } @@ -112,6 +116,7 @@ pub struct RsdpV2Tag { impl RsdpV2Tag { #[cfg(feature = "builder")] #[allow(clippy::too_many_arguments)] + #[must_use] pub fn new( signature: [u8; 8], checksum: u8, @@ -139,11 +144,12 @@ impl RsdpV2Tag { /// The "RSD PTR " marker signature. /// /// This is originally a 8-byte C string (not null terminated!) that must contain "RSD PTR ". - pub fn signature(&self) -> Result<&str, Utf8Error> { + pub const fn signature(&self) -> Result<&str, Utf8Error> { str::from_utf8(&self.signature) } /// Validation of the RSDPv2 extended checksum + #[must_use] pub fn checksum_is_valid(&self) -> bool { let bytes = unsafe { slice::from_raw_parts(self as *const _ as *const u8, self.length as usize + 8) @@ -155,24 +161,27 @@ impl RsdpV2Tag { } /// An OEM-supplied string that identifies the OEM. - pub fn oem_id(&self) -> Result<&str, Utf8Error> { + pub const fn oem_id(&self) -> Result<&str, Utf8Error> { str::from_utf8(&self.oem_id) } /// The revision of the ACPI. - pub fn revision(&self) -> u8 { + #[must_use] + pub const fn revision(&self) -> u8 { self.revision } /// Physical address of the XSDT table. /// /// On x86, this is truncated from 64-bit to 32-bit. - pub fn xsdt_address(&self) -> usize { + #[must_use] + pub const fn xsdt_address(&self) -> usize { self.xsdt_address as usize } /// This field is used to calculate the checksum of the entire table, including both checksum fields. - pub fn ext_checksum(&self) -> u8 { + #[must_use] + pub const fn ext_checksum(&self) -> u8 { self.ext_checksum } } diff --git a/multiboot2/src/smbios.rs b/multiboot2/src/smbios.rs index 46f1ad33..f092ed3a 100644 --- a/multiboot2/src/smbios.rs +++ b/multiboot2/src/smbios.rs @@ -23,6 +23,7 @@ pub struct SmbiosTag { impl SmbiosTag { #[cfg(feature = "builder")] + #[must_use] pub fn new(major: u8, minor: u8, tables: &[u8]) -> BoxedDst { let mut bytes = [major, minor, 0, 0, 0, 0, 0, 0].to_vec(); bytes.extend(tables); diff --git a/multiboot2/src/tag.rs b/multiboot2/src/tag.rs index 8909e6ee..3c249632 100644 --- a/multiboot2/src/tag.rs +++ b/multiboot2/src/tag.rs @@ -28,8 +28,8 @@ impl Display for StringError { impl core::error::Error for StringError { fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { match self { - StringError::MissingNul(e) => Some(e), - StringError::Utf8(e) => Some(e), + Self::MissingNul(e) => Some(e), + Self::Utf8(e) => Some(e), } } } @@ -75,11 +75,13 @@ pub struct Tag { impl Tag { /// Returns the underlying type of the tag. + #[must_use] pub fn typ(&self) -> TagType { self.typ.into() } /// Casts the base tag to the specific tag type. + #[must_use] pub fn cast_tag<'a, T: TagTrait + ?Sized + 'a>(&'a self) -> &'a T { assert_eq!(self.typ, T::ID); // Safety: At this point, we trust that "self.size" and the size hint diff --git a/multiboot2/src/tag_trait.rs b/multiboot2/src/tag_trait.rs index 2a073da7..c13b63d1 100644 --- a/multiboot2/src/tag_trait.rs +++ b/multiboot2/src/tag_trait.rs @@ -51,6 +51,7 @@ pub trait TagTrait: Pointee { /// Callers must be sure that the "size" field of the provided [`Tag`] is /// sane and the underlying memory valid. The implementation of this trait /// **must have** a correct [`Self::dst_size`] implementation. + #[must_use] unsafe fn from_base_tag(tag: &Tag) -> &Self { let ptr = core::ptr::addr_of!(*tag); let ptr = ptr_meta::from_raw_parts(ptr.cast(), Self::dst_size(tag)); diff --git a/multiboot2/src/tag_type.rs b/multiboot2/src/tag_type.rs index 49d32d25..9c47c089 100644 --- a/multiboot2/src/tag_type.rs +++ b/multiboot2/src/tag_type.rs @@ -17,7 +17,8 @@ pub struct TagTypeId(u32); impl TagTypeId { /// Constructor. - pub fn new(val: u32) -> Self { + #[must_use] + pub const fn new(val: u32) -> Self { Self(val) } } @@ -135,6 +136,7 @@ pub enum TagType { impl TagType { /// Convenient wrapper to get the underlying `u32` representation of the tag. + #[must_use] pub fn val(&self) -> u32 { u32::from(*self) } @@ -161,29 +163,29 @@ mod primitive_conversion_impls { impl From for TagType { fn from(value: u32) -> Self { match value { - 0 => TagType::End, - 1 => TagType::Cmdline, - 2 => TagType::BootLoaderName, - 3 => TagType::Module, - 4 => TagType::BasicMeminfo, - 5 => TagType::Bootdev, - 6 => TagType::Mmap, - 7 => TagType::Vbe, - 8 => TagType::Framebuffer, - 9 => TagType::ElfSections, - 10 => TagType::Apm, - 11 => TagType::Efi32, - 12 => TagType::Efi64, - 13 => TagType::Smbios, - 14 => TagType::AcpiV1, - 15 => TagType::AcpiV2, - 16 => TagType::Network, - 17 => TagType::EfiMmap, - 18 => TagType::EfiBs, - 19 => TagType::Efi32Ih, - 20 => TagType::Efi64Ih, - 21 => TagType::LoadBaseAddr, - c => TagType::Custom(c), + 0 => Self::End, + 1 => Self::Cmdline, + 2 => Self::BootLoaderName, + 3 => Self::Module, + 4 => Self::BasicMeminfo, + 5 => Self::Bootdev, + 6 => Self::Mmap, + 7 => Self::Vbe, + 8 => Self::Framebuffer, + 9 => Self::ElfSections, + 10 => Self::Apm, + 11 => Self::Efi32, + 12 => Self::Efi64, + 13 => Self::Smbios, + 14 => Self::AcpiV1, + 15 => Self::AcpiV2, + 16 => Self::Network, + 17 => Self::EfiMmap, + 18 => Self::EfiBs, + 19 => Self::Efi32Ih, + 20 => Self::Efi64Ih, + 21 => Self::LoadBaseAddr, + c => Self::Custom(c), } } } @@ -226,14 +228,14 @@ mod intermediate_conversion_impls { impl From for TagType { fn from(value: TagTypeId) -> Self { let value = u32::from(value); - TagType::from(value) + Self::from(value) } } impl From for TagTypeId { fn from(value: TagType) -> Self { let value = u32::from(value); - TagTypeId::from(value) + Self::from(value) } } } From 776a980570690a8f632941e41beb9689d9a9603e Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Wed, 14 Aug 2024 15:25:59 +0200 Subject: [PATCH 5/8] multiboot2: add missing docs --- multiboot2/Changelog.md | 4 +++- multiboot2/src/boot_information.rs | 28 ++++++++++++++++++---------- multiboot2/src/boot_loader_name.rs | 13 +++++++++++++ multiboot2/src/builder/mod.rs | 5 ++++- multiboot2/src/efi.rs | 3 +++ multiboot2/src/end.rs | 4 ++-- multiboot2/src/framebuffer.rs | 1 + multiboot2/src/image_load_addr.rs | 1 + multiboot2/src/lib.rs | 2 +- multiboot2/src/memory_map.rs | 10 +++++++--- multiboot2/src/module.rs | 1 + multiboot2/src/rsdp.rs | 2 ++ multiboot2/src/smbios.rs | 25 ++++++++++++++++++++++--- multiboot2/src/tag.rs | 6 ++++-- 14 files changed, 82 insertions(+), 23 deletions(-) diff --git a/multiboot2/Changelog.md b/multiboot2/Changelog.md index 6e28ec80..ecb0b7a4 100644 --- a/multiboot2/Changelog.md +++ b/multiboot2/Changelog.md @@ -3,9 +3,11 @@ ## Unreleased - **Breaking** All functions that returns something useful are now `#[must_use]` +- **Breaking** More public fields in tags were replaced by public getters, such + as `SmbiosTag::major()` - updated dependencies - MSRV is 1.75 -- doc fixes +- documentation enhancements - Introduced new `TagHeader` type as replacement for the `Tag` type that will be changed in the next step. diff --git a/multiboot2/src/boot_information.rs b/multiboot2/src/boot_information.rs index affd4e9d..550842db 100644 --- a/multiboot2/src/boot_information.rs +++ b/multiboot2/src/boot_information.rs @@ -3,7 +3,7 @@ #[cfg(feature = "builder")] use crate::builder::AsBytes; use crate::framebuffer::UnknownFramebufferType; -use crate::tag::TagIter; +use crate::tag::{TagHeader, TagIter}; use crate::{ module, BasicMemoryInfoTag, BootLoaderNameTag, CommandLineTag, EFIBootServicesNotExitedTag, EFIImageHandle32Tag, EFIImageHandle64Tag, EFIMemoryMapTag, EFISdt32Tag, EFISdt64Tag, @@ -11,6 +11,8 @@ use crate::{ ModuleIter, RsdpV1Tag, RsdpV2Tag, SmbiosTag, TagTrait, VBEInfoTag, }; use core::fmt; +use core::mem; +use core::ptr; use derive_more::Display; /// Error type that describes errors while loading/parsing a multiboot2 information structure @@ -39,19 +41,25 @@ impl core::error::Error for MbiLoadError {} #[repr(C)] pub struct BootInformationHeader { // size is multiple of 8 - pub total_size: u32, + total_size: u32, _reserved: u32, // Followed by the boot information tags. } -#[cfg(feature = "builder")] impl BootInformationHeader { + #[cfg(feature = "builder")] pub(crate) const fn new(total_size: u32) -> Self { Self { total_size, _reserved: 0, } } + + /// Returns the total size of the structure. + #[must_use] + pub const fn total_size(&self) -> u32 { + self.total_size + } } #[cfg(feature = "builder")] @@ -70,18 +78,18 @@ 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::()) }; + let self_ptr = ptr::addr_of!(*self); let end_tag_ptr = unsafe { self_ptr + .cast::() .add(self.header.total_size as usize) - .sub(size_of::()) + .sub(mem::size_of::()) + .cast::() }; - let end_tag = unsafe { &*(end_tag_ptr as *const EndTag) }; + let end_tag = unsafe { &*end_tag_ptr }; - end_tag.typ == end_tag_prototype.typ && end_tag.size == end_tag_prototype.size + end_tag.typ == EndTag::ID && end_tag.size as usize == mem::size_of::() } } @@ -127,7 +135,7 @@ impl<'a> BootInformation<'a> { return Err(MbiLoadError::IllegalTotalSize(mbi.total_size)); } - let slice_size = mbi.total_size as usize - size_of::(); + let slice_size = mbi.total_size as usize - mem::size_of::(); // mbi: reference to full mbi let mbi = ptr_meta::from_raw_parts::(ptr.cast(), slice_size); let mbi = &*mbi; diff --git a/multiboot2/src/boot_loader_name.rs b/multiboot2/src/boot_loader_name.rs index 4e0851c8..4ce15d5b 100644 --- a/multiboot2/src/boot_loader_name.rs +++ b/multiboot2/src/boot_loader_name.rs @@ -19,6 +19,7 @@ pub struct BootLoaderNameTag { } impl BootLoaderNameTag { + /// Constructs a new tag. #[cfg(feature = "builder")] #[must_use] pub fn new(name: &str) -> BoxedDst { @@ -30,6 +31,18 @@ impl BootLoaderNameTag { BoxedDst::new(&bytes) } + /// Returns the underlying [`TagType`]. + #[must_use] + pub fn typ(&self) -> TagType { + self.header.typ.into() + } + + /// Returns the underlying tag size. + #[must_use] + pub const fn size(&self) -> usize { + self.header.size as usize + } + /// Reads the name of the bootloader that is booting the kernel as Rust /// string slice without the null-byte. /// diff --git a/multiboot2/src/builder/mod.rs b/multiboot2/src/builder/mod.rs index 93b68528..7d06c425 100644 --- a/multiboot2/src/builder/mod.rs +++ b/multiboot2/src/builder/mod.rs @@ -8,8 +8,11 @@ pub use boxed_dst::BoxedDst; pub use information::InformationBuilder; /// Helper trait for all structs that need to be serialized that do not -/// implement `TagTrait`. +/// implement [`TagTrait`]. +/// +/// [`TagTrait`]: crate::TagTrait pub trait AsBytes: Sized { + /// Returns the raw bytes of the type. fn as_bytes(&self) -> &[u8] { let ptr = core::ptr::addr_of!(*self); let size = core::mem::size_of::(); diff --git a/multiboot2/src/efi.rs b/multiboot2/src/efi.rs index 9b2e5975..863b8535 100644 --- a/multiboot2/src/efi.rs +++ b/multiboot2/src/efi.rs @@ -82,6 +82,7 @@ pub struct EFIImageHandle32Tag { } impl EFIImageHandle32Tag { + /// Constructs a new tag. #[cfg(feature = "builder")] #[must_use] pub fn new(pointer: u32) -> Self { @@ -114,6 +115,7 @@ pub struct EFIImageHandle64Tag { } impl EFIImageHandle64Tag { + /// Constructs a new tag. #[cfg(feature = "builder")] #[must_use] pub fn new(pointer: u64) -> Self { @@ -144,6 +146,7 @@ pub struct EFIBootServicesNotExitedTag { } impl EFIBootServicesNotExitedTag { + /// Constructs a new tag. #[cfg(feature = "builder")] #[must_use] pub fn new() -> Self { diff --git a/multiboot2/src/end.rs b/multiboot2/src/end.rs index f32351cf..e48b2238 100644 --- a/multiboot2/src/end.rs +++ b/multiboot2/src/end.rs @@ -6,8 +6,8 @@ use crate::{Tag, TagTrait, TagType, TagTypeId}; #[repr(C)] #[derive(Debug)] pub struct EndTag { - pub typ: TagTypeId, - pub size: u32, + typ: TagTypeId, + size: u32, } impl Default for EndTag { diff --git a/multiboot2/src/framebuffer.rs b/multiboot2/src/framebuffer.rs index a5d7b49c..ae69d844 100644 --- a/multiboot2/src/framebuffer.rs +++ b/multiboot2/src/framebuffer.rs @@ -84,6 +84,7 @@ pub struct FramebufferTag { } impl FramebufferTag { + /// Constructs a new tag. #[cfg(feature = "builder")] #[must_use] pub fn new( diff --git a/multiboot2/src/image_load_addr.rs b/multiboot2/src/image_load_addr.rs index 1f9be8f3..b11127d4 100644 --- a/multiboot2/src/image_load_addr.rs +++ b/multiboot2/src/image_load_addr.rs @@ -16,6 +16,7 @@ pub struct ImageLoadPhysAddrTag { } impl ImageLoadPhysAddrTag { + /// Constructs a new tag. #[cfg(feature = "builder")] #[must_use] pub fn new(load_base_addr: u32) -> Self { diff --git a/multiboot2/src/lib.rs b/multiboot2/src/lib.rs index a2abeadd..46a41d5e 100644 --- a/multiboot2/src/lib.rs +++ b/multiboot2/src/lib.rs @@ -12,7 +12,7 @@ // now allow a few rules which are denied by the above statement // --> They are either ridiculous, not necessary, or we can't fix them. #![allow(clippy::multiple_crate_versions)] -// #![deny(missing_docs)] +#![deny(missing_docs)] #![deny(missing_debug_implementations)] #![deny(rustdoc::all)] // --- END STYLE CHECKS --- diff --git a/multiboot2/src/memory_map.rs b/multiboot2/src/memory_map.rs index f087dde4..b246de56 100644 --- a/multiboot2/src/memory_map.rs +++ b/multiboot2/src/memory_map.rs @@ -35,6 +35,7 @@ pub struct MemoryMapTag { } impl MemoryMapTag { + /// Constructs a new tag. #[cfg(feature = "builder")] #[must_use] pub fn new(areas: &[MemoryArea]) -> BoxedDst { @@ -260,21 +261,24 @@ pub struct BasicMemoryInfoTag { } impl BasicMemoryInfoTag { + /// Constructs a new tag. #[must_use] pub fn new(memory_lower: u32, memory_upper: u32) -> Self { Self { - header: TagHeader::new(Self::ID, size_of::().try_into().unwrap()), + header: TagHeader::new(Self::ID, mem::size_of::().try_into().unwrap()), memory_lower, memory_upper, } } #[must_use] + /// Returns the lower memory bound. pub const fn memory_lower(&self) -> u32 { self.memory_lower } #[must_use] + /// Returns the upper memory bound. pub const fn memory_upper(&self) -> u32 { self.memory_upper } @@ -317,10 +321,10 @@ pub struct EFIMemoryMapTag { } impl EFIMemoryMapTag { - #[cfg(feature = "builder")] /// Create a new EFI memory map tag with the given memory descriptors. /// Version and size can't be set because you're passing a slice of /// EFIMemoryDescs, not the ones you might have gotten from the firmware. + #[cfg(feature = "builder")] #[must_use] pub fn new_from_descs(descs: &[EFIMemoryDesc]) -> BoxedDst { // TODO replace this EfiMemorydesc::uefi_desc_size() in the next uefi_raw @@ -347,8 +351,8 @@ impl EFIMemoryMapTag { ) } - #[cfg(feature = "builder")] /// Create a new EFI memory map tag from the given EFI memory map. + #[cfg(feature = "builder")] #[must_use] pub fn new_from_map(desc_size: u32, desc_version: u32, efi_mmap: &[u8]) -> BoxedDst { assert!(desc_size > 0); diff --git a/multiboot2/src/module.rs b/multiboot2/src/module.rs index fcd43421..ac8c0a41 100644 --- a/multiboot2/src/module.rs +++ b/multiboot2/src/module.rs @@ -23,6 +23,7 @@ pub struct ModuleTag { } impl ModuleTag { + /// Constructs a new tag. #[cfg(feature = "builder")] #[must_use] pub fn new(start: u32, end: u32, cmdline: &str) -> BoxedDst { diff --git a/multiboot2/src/rsdp.rs b/multiboot2/src/rsdp.rs index 29ff6ea6..8a4c289b 100644 --- a/multiboot2/src/rsdp.rs +++ b/multiboot2/src/rsdp.rs @@ -35,6 +35,7 @@ pub struct RsdpV1Tag { } impl RsdpV1Tag { + /// Constructs a new tag. #[cfg(feature = "builder")] #[must_use] pub fn new( @@ -114,6 +115,7 @@ pub struct RsdpV2Tag { } impl RsdpV2Tag { + /// Constructs a new tag. #[cfg(feature = "builder")] #[allow(clippy::too_many_arguments)] #[must_use] diff --git a/multiboot2/src/smbios.rs b/multiboot2/src/smbios.rs index f092ed3a..900d6ba6 100644 --- a/multiboot2/src/smbios.rs +++ b/multiboot2/src/smbios.rs @@ -15,13 +15,14 @@ const METADATA_SIZE: usize = core::mem::size_of::() #[repr(C)] pub struct SmbiosTag { header: TagHeader, - pub major: u8, - pub minor: u8, + major: u8, + minor: u8, _reserved: [u8; 6], - pub tables: [u8], + tables: [u8], } impl SmbiosTag { + /// Constructs a new tag. #[cfg(feature = "builder")] #[must_use] pub fn new(major: u8, minor: u8, tables: &[u8]) -> BoxedDst { @@ -29,6 +30,24 @@ impl SmbiosTag { bytes.extend(tables); BoxedDst::new(&bytes) } + + /// Returns the major number. + #[must_use] + pub const fn major(&self) -> u8 { + self.major + } + + /// Returns the major number. + #[must_use] + pub const fn minor(&self) -> u8 { + self.minor + } + + /// Returns the raw tables. + #[must_use] + pub const fn tables(&self) -> &[u8] { + &self.tables + } } impl TagTrait for SmbiosTag { diff --git a/multiboot2/src/tag.rs b/multiboot2/src/tag.rs index 3c249632..7764fc57 100644 --- a/multiboot2/src/tag.rs +++ b/multiboot2/src/tag.rs @@ -41,14 +41,15 @@ impl core::error::Error for StringError { #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] #[repr(C)] pub struct TagHeader { + /// The ABI-compatible [`TagType`]. pub typ: TagTypeId, /* u32 */ + /// The total size of the tag including the header. pub size: u32, - // Followed by additional, tag specific fields. + // Followed by optional additional tag specific fields. } impl TagHeader { /// Creates a new header. - #[cfg(feature = "builder")] pub fn new(typ: impl Into, size: u32) -> Self { Self { typ: typ.into(), @@ -67,6 +68,7 @@ impl TagHeader { /// different. #[derive(Clone, Copy)] #[repr(C)] +#[allow(missing_docs)] // type will be removed soon anyway in its form pub struct Tag { pub typ: TagTypeId, // u32 pub size: u32, From a9d93eee6bf95abd3972bf108e3386e23ca0e218 Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Wed, 14 Aug 2024 15:47:49 +0200 Subject: [PATCH 6/8] multiboot2: streamline code style --- multiboot2/src/boot_loader_name.rs | 4 ++-- multiboot2/src/command_line.rs | 2 +- multiboot2/src/elf_sections.rs | 4 ++-- multiboot2/src/framebuffer.rs | 14 +++++++------- multiboot2/src/module.rs | 4 ++-- multiboot2/src/smbios.rs | 6 +++--- 6 files changed, 17 insertions(+), 17 deletions(-) diff --git a/multiboot2/src/boot_loader_name.rs b/multiboot2/src/boot_loader_name.rs index 4ce15d5b..e6817d26 100644 --- a/multiboot2/src/boot_loader_name.rs +++ b/multiboot2/src/boot_loader_name.rs @@ -3,11 +3,11 @@ use crate::tag::{StringError, TagHeader}; use crate::{Tag, TagTrait, TagType, TagTypeId}; use core::fmt::{Debug, Formatter}; -use core::mem::size_of; +use core::mem; #[cfg(feature = "builder")] use {crate::builder::BoxedDst, alloc::vec::Vec}; -const METADATA_SIZE: usize = size_of::() + size_of::(); +const METADATA_SIZE: usize = mem::size_of::() + mem::size_of::(); /// The bootloader name tag. #[derive(ptr_meta::Pointee, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/multiboot2/src/command_line.rs b/multiboot2/src/command_line.rs index 91466ef5..b48eeddb 100644 --- a/multiboot2/src/command_line.rs +++ b/multiboot2/src/command_line.rs @@ -8,7 +8,7 @@ use core::str; #[cfg(feature = "builder")] use {crate::builder::BoxedDst, alloc::vec::Vec}; -pub const METADATA_SIZE: usize = mem::size_of::() + mem::size_of::(); +const METADATA_SIZE: usize = mem::size_of::() + mem::size_of::(); /// This tag contains the command line string. /// diff --git a/multiboot2/src/elf_sections.rs b/multiboot2/src/elf_sections.rs index eac63e7d..849b08e5 100644 --- a/multiboot2/src/elf_sections.rs +++ b/multiboot2/src/elf_sections.rs @@ -4,10 +4,10 @@ use crate::builder::BoxedDst; use crate::{Tag, TagTrait, TagType, TagTypeId}; use core::fmt::{Debug, Formatter}; -use core::mem::size_of; +use core::mem; use core::str::Utf8Error; -const METADATA_SIZE: usize = size_of::() + 4 * size_of::(); +const METADATA_SIZE: usize = mem::size_of::() + 4 * mem::size_of::(); /// This tag contains the section header table from an ELF binary. // The sections iterator is provided via the [`ElfSectionsTag::sections`] diff --git a/multiboot2/src/framebuffer.rs b/multiboot2/src/framebuffer.rs index ae69d844..50167b88 100644 --- a/multiboot2/src/framebuffer.rs +++ b/multiboot2/src/framebuffer.rs @@ -3,7 +3,7 @@ use crate::tag::TagHeader; use crate::{Tag, TagTrait, TagType, TagTypeId}; use core::fmt::Debug; -use core::mem::size_of; +use core::mem; use core::slice; use derive_more::Display; #[cfg(feature = "builder")] @@ -42,11 +42,11 @@ impl Reader { } } -const METADATA_SIZE: usize = size_of::() - + 4 * size_of::() - + size_of::() - + size_of::() - + 2 * size_of::(); +const METADATA_SIZE: usize = mem::size_of::() + + 4 * mem::size_of::() + + mem::size_of::() + + mem::size_of::() + + 2 * mem::size_of::(); /// The VBE Framebuffer information tag. #[derive(ptr_meta::Pointee, Eq)] @@ -343,6 +343,6 @@ mod tests { // Compile time test #[test] fn test_size() { - assert_eq!(size_of::(), 3) + assert_eq!(mem::size_of::(), 3) } } diff --git a/multiboot2/src/module.rs b/multiboot2/src/module.rs index ac8c0a41..5dd65047 100644 --- a/multiboot2/src/module.rs +++ b/multiboot2/src/module.rs @@ -3,11 +3,11 @@ use crate::tag::{StringError, TagHeader, TagIter}; use crate::{Tag, TagTrait, TagType, TagTypeId}; use core::fmt::{Debug, Formatter}; -use core::mem::size_of; +use core::mem; #[cfg(feature = "builder")] use {crate::builder::BoxedDst, alloc::vec::Vec}; -const METADATA_SIZE: usize = size_of::() + 3 * size_of::(); +const METADATA_SIZE: usize = mem::size_of::() + 3 * mem::size_of::(); /// The module tag can occur multiple times and specifies passed boot modules /// (blobs in memory). The tag itself doesn't include the blog, but references diff --git a/multiboot2/src/smbios.rs b/multiboot2/src/smbios.rs index 900d6ba6..e66b732e 100644 --- a/multiboot2/src/smbios.rs +++ b/multiboot2/src/smbios.rs @@ -5,10 +5,10 @@ use crate::builder::BoxedDst; use crate::tag::TagHeader; use crate::{Tag, TagTrait, TagType, TagTypeId}; use core::fmt::Debug; +use core::mem; -const METADATA_SIZE: usize = core::mem::size_of::() - + core::mem::size_of::() - + core::mem::size_of::() * 8; +const METADATA_SIZE: usize = + mem::size_of::() + mem::size_of::() + mem::size_of::() * 8; /// This tag contains a copy of SMBIOS tables as well as their version. #[derive(ptr_meta::Pointee, PartialEq, Eq, PartialOrd, Ord, Hash)] From b2966736b78a61465125d39187b6b63e7fc49323 Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Wed, 14 Aug 2024 16:12:36 +0200 Subject: [PATCH 7/8] multiboot2-header: improve code style --- multiboot2-header/Changelog.md | 3 +- multiboot2-header/src/address.rs | 41 +++++++--- multiboot2-header/src/builder/header.rs | 40 +++++++++- .../src/builder/information_request.rs | 4 + multiboot2-header/src/builder/traits.rs | 2 +- multiboot2-header/src/console.rs | 33 +++++--- multiboot2-header/src/end.rs | 35 +++++---- multiboot2-header/src/entry_address.rs | 40 ++++++---- multiboot2-header/src/entry_efi_32.rs | 41 ++++++---- multiboot2-header/src/entry_efi_64.rs | 41 ++++++---- multiboot2-header/src/framebuffer.rs | 46 ++++++++---- multiboot2-header/src/header.rs | 75 +++++++++++++------ multiboot2-header/src/information_request.rs | 46 +++++++----- multiboot2-header/src/lib.rs | 18 ++++- multiboot2-header/src/module_align.rs | 30 +++++--- multiboot2-header/src/relocatable.rs | 48 ++++++++---- multiboot2-header/src/tags.rs | 40 +++++++--- multiboot2-header/src/uefi_bs.rs | 29 ++++--- 18 files changed, 419 insertions(+), 193 deletions(-) diff --git a/multiboot2-header/Changelog.md b/multiboot2-header/Changelog.md index 55986349..df9f05e8 100644 --- a/multiboot2-header/Changelog.md +++ b/multiboot2-header/Changelog.md @@ -2,8 +2,9 @@ ## Unreleased +- **Breaking** All functions that returns something useful are now `#[must_use]` - updated dependencies -- MSRV is 1.75 +- documentation enhancements ## 0.4.0 (2024-05-01) diff --git a/multiboot2-header/src/address.rs b/multiboot2-header/src/address.rs index e15e5035..7a450e9e 100644 --- a/multiboot2-header/src/address.rs +++ b/multiboot2-header/src/address.rs @@ -1,4 +1,4 @@ -use crate::{HeaderTagFlag, HeaderTagType}; +use crate::{HeaderTagFlag, HeaderTagHeader, HeaderTagType}; use core::mem::size_of; /// This information does not need to be provided if the kernel image is in ELF @@ -8,9 +8,7 @@ use core::mem::size_of; #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct AddressHeaderTag { - typ: HeaderTagType, - flags: HeaderTagFlag, - size: u32, + header: HeaderTagHeader, /// Contains the address corresponding to the beginning of the Multiboot2 header — the physical memory location at which the magic value is supposed to be loaded. This field serves to synchronize the mapping between OS image offsets and physical memory addresses. header_addr: u32, /// Contains the physical address of the beginning of the text segment. The offset in the OS image file at which to start loading is defined by the offset at which the header was found, minus (header_addr - load_addr). load_addr must be less than or equal to header_addr. @@ -24,6 +22,8 @@ pub struct AddressHeaderTag { } impl AddressHeaderTag { + /// Constructs a new tag. + #[must_use] pub const fn new( flags: HeaderTagFlag, header_addr: u32, @@ -31,10 +31,9 @@ impl AddressHeaderTag { load_end_addr: u32, bss_end_addr: u32, ) -> Self { - AddressHeaderTag { - typ: HeaderTagType::Address, - flags, - size: size_of::() as u32, + let header = HeaderTagHeader::new(HeaderTagType::Address, flags, size_of::() as u32); + Self { + header, header_addr, load_addr, load_end_addr, @@ -42,24 +41,44 @@ impl AddressHeaderTag { } } + /// Returns the [`HeaderTagType`]. + #[must_use] pub const fn typ(&self) -> HeaderTagType { - self.typ + self.header.typ() } + + /// Returns the [`HeaderTagFlag`]s. + #[must_use] pub const fn flags(&self) -> HeaderTagFlag { - self.flags + self.header.flags() } + + /// Returns the size. + #[must_use] pub const fn size(&self) -> u32 { - self.size + self.header.size() } + + /// Returns the header address. + #[must_use] pub const fn header_addr(&self) -> u32 { self.header_addr } + + /// Returns the load begin address. + #[must_use] pub const fn load_addr(&self) -> u32 { self.load_addr } + + /// Returns the load end address. + #[must_use] pub const fn load_end_addr(&self) -> u32 { self.load_end_addr } + + /// Returns the bss end address. + #[must_use] pub const fn bss_end_addr(&self) -> u32 { self.bss_end_addr } diff --git a/multiboot2-header/src/builder/header.rs b/multiboot2-header/src/builder/header.rs index 0ab65d28..ff6ba7bb 100644 --- a/multiboot2-header/src/builder/header.rs +++ b/multiboot2-header/src/builder/header.rs @@ -72,6 +72,8 @@ pub struct HeaderBuilder { } impl HeaderBuilder { + /// Creates a new builder. + #[must_use] pub const fn new(arch: HeaderTagISA) -> Self { Self { arch, @@ -98,6 +100,7 @@ impl HeaderBuilder { /// Returns the expected length of the Multiboot2 header, when the /// [`Self::build`]-method gets called. + #[must_use] pub fn expected_len(&self) -> usize { let base_len = size_of::(); // size_or_up_aligned not required, because basic header length is 16 and the @@ -159,7 +162,8 @@ impl HeaderBuilder { } /// Constructs the bytes for a valid Multiboot2 header with the given properties. - pub fn build(mut self) -> HeaderBytes { + #[must_use] + pub fn build(self) -> HeaderBytes { const ALIGN: usize = 8; // PHASE 1/2: Prepare Vector @@ -205,7 +209,7 @@ impl HeaderBuilder { } /// Helper method that adds all the tags to the given vector. - fn build_add_tags(&mut self, bytes: &mut Vec) { + fn build_add_tags(&self, bytes: &mut Vec) { Self::build_add_bytes( bytes, // important that we write the correct expected length into the header! @@ -247,7 +251,10 @@ impl HeaderBuilder { } // clippy thinks this can be a const fn but the compiler denies it - #[allow(clippy::missing_const_for_fn)] + // #[allow(clippy::missing_const_for_fn)] + /// Adds information requests from the + /// [`InformationRequestHeaderTagBuilder`] to the builder. + #[must_use] pub fn information_request_tag( mut self, information_request_tag: InformationRequestHeaderTagBuilder, @@ -255,38 +262,65 @@ impl HeaderBuilder { self.information_request_tag = Some(information_request_tag); self } + + /// Adds a [`AddressHeaderTag`] to the builder. + #[must_use] pub const fn address_tag(mut self, address_tag: AddressHeaderTag) -> Self { self.address_tag = Some(address_tag); self } + + /// Adds a [`EntryAddressHeaderTag`] to the builder. + #[must_use] pub const fn entry_tag(mut self, entry_tag: EntryAddressHeaderTag) -> Self { self.entry_tag = Some(entry_tag); self } + + /// Adds a [`ConsoleHeaderTag`] to the builder. + #[must_use] pub const fn console_tag(mut self, console_tag: ConsoleHeaderTag) -> Self { self.console_tag = Some(console_tag); self } + + /// Adds a [`FramebufferHeaderTag`] to the builder. + #[must_use] pub const fn framebuffer_tag(mut self, framebuffer_tag: FramebufferHeaderTag) -> Self { self.framebuffer_tag = Some(framebuffer_tag); self } + + /// Adds a [`ModuleAlignHeaderTag`] to the builder. + #[must_use] pub const fn module_align_tag(mut self, module_align_tag: ModuleAlignHeaderTag) -> Self { self.module_align_tag = Some(module_align_tag); self } + + /// Adds a [`EfiBootServiceHeaderTag`] to the builder. + #[must_use] pub const fn efi_bs_tag(mut self, efi_bs_tag: EfiBootServiceHeaderTag) -> Self { self.efi_bs_tag = Some(efi_bs_tag); self } + + /// Adds a [`EntryEfi32HeaderTag`] to the builder. + #[must_use] pub const fn efi_32_tag(mut self, efi_32_tag: EntryEfi32HeaderTag) -> Self { self.efi_32_tag = Some(efi_32_tag); self } + + /// Adds a [`EntryEfi64HeaderTag`] to the builder. + #[must_use] pub const fn efi_64_tag(mut self, efi_64_tag: EntryEfi64HeaderTag) -> Self { self.efi_64_tag = Some(efi_64_tag); self } + + /// Adds a [`RelocatableHeaderTag`] to the builder. + #[must_use] pub const fn relocatable_tag(mut self, relocatable_tag: RelocatableHeaderTag) -> Self { self.relocatable_tag = Some(relocatable_tag); self diff --git a/multiboot2-header/src/builder/information_request.rs b/multiboot2-header/src/builder/information_request.rs index 543e7cc9..f5448541 100644 --- a/multiboot2-header/src/builder/information_request.rs +++ b/multiboot2-header/src/builder/information_request.rs @@ -22,6 +22,7 @@ pub struct InformationRequestHeaderTagBuilder { #[cfg(feature = "builder")] impl InformationRequestHeaderTagBuilder { /// New builder. + #[must_use] pub const fn new(flag: HeaderTagFlag) -> Self { Self { irs: BTreeSet::new(), @@ -31,6 +32,7 @@ impl InformationRequestHeaderTagBuilder { /// Returns the expected length of the information request tag, /// when the `build`-method gets called. + #[must_use] pub fn expected_len(&self) -> usize { let basic_header_size = size_of::>(); let req_tags_size = self.irs.len() * size_of::(); @@ -38,12 +40,14 @@ impl InformationRequestHeaderTagBuilder { } /// Adds an [`MbiTagType`] to the information request. + #[must_use] pub fn add_ir(mut self, tag: MbiTagType) -> Self { self.irs.insert(tag); self } /// Adds multiple [`MbiTagType`] to the information request. + #[must_use] pub fn add_irs(mut self, tags: &[MbiTagType]) -> Self { self.irs.extend(tags); self diff --git a/multiboot2-header/src/builder/traits.rs b/multiboot2-header/src/builder/traits.rs index f936c4e8..cea09fdf 100644 --- a/multiboot2-header/src/builder/traits.rs +++ b/multiboot2-header/src/builder/traits.rs @@ -11,7 +11,7 @@ use core::mem::size_of; /// Trait for all tags that helps to create 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 { +pub 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. fn byte_size(&self) -> usize { diff --git a/multiboot2-header/src/console.rs b/multiboot2-header/src/console.rs index 6307201d..392a6c07 100644 --- a/multiboot2-header/src/console.rs +++ b/multiboot2-header/src/console.rs @@ -1,4 +1,4 @@ -use crate::{HeaderTagFlag, HeaderTagType}; +use crate::{HeaderTagFlag, HeaderTagHeader, HeaderTagType}; use core::mem::size_of; /// Possible flags for [`ConsoleHeaderTag`]. @@ -16,31 +16,42 @@ pub enum ConsoleHeaderTagFlags { #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct ConsoleHeaderTag { - typ: HeaderTagType, - flags: HeaderTagFlag, - size: u32, + header: HeaderTagHeader, console_flags: ConsoleHeaderTagFlags, } impl ConsoleHeaderTag { + /// Constructs a new tag. + #[must_use] pub const fn new(flags: HeaderTagFlag, console_flags: ConsoleHeaderTagFlags) -> Self { - ConsoleHeaderTag { - typ: HeaderTagType::ConsoleFlags, - flags, - size: size_of::() as u32, + let header = + HeaderTagHeader::new(HeaderTagType::ConsoleFlags, flags, size_of::() as u32); + Self { + header, console_flags, } } + /// Returns the [`HeaderTagType`]. + #[must_use] pub const fn typ(&self) -> HeaderTagType { - self.typ + self.header.typ() } + + /// Returns the [`HeaderTagFlag`]s. + #[must_use] pub const fn flags(&self) -> HeaderTagFlag { - self.flags + self.header.flags() } + + /// Returns the size. + #[must_use] pub const fn size(&self) -> u32 { - self.size + self.header.size() } + + /// Returns the [`ConsoleHeaderTagFlags`]. + #[must_use] pub const fn console_flags(&self) -> ConsoleHeaderTagFlags { self.console_flags } diff --git a/multiboot2-header/src/end.rs b/multiboot2-header/src/end.rs index 15f8c76f..1e806460 100644 --- a/multiboot2-header/src/end.rs +++ b/multiboot2-header/src/end.rs @@ -1,15 +1,11 @@ -use crate::{HeaderTagFlag, HeaderTagType}; +use crate::{HeaderTagFlag, HeaderTagHeader, HeaderTagType}; use core::mem::size_of; /// Terminates a list of optional tags in a Multiboot2 header. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct EndHeaderTag { - // u16 value - typ: HeaderTagType, - // u16 value - flags: HeaderTagFlag, - size: u32, + header: HeaderTagHeader, } impl Default for EndHeaderTag { @@ -19,22 +15,33 @@ impl Default for EndHeaderTag { } impl EndHeaderTag { + /// Constructs a new tag. + #[must_use] pub const fn new() -> Self { - EndHeaderTag { - typ: HeaderTagType::End, - flags: HeaderTagFlag::Required, - size: size_of::() as u32, - } + let header = HeaderTagHeader::new( + HeaderTagType::EntryAddress, + HeaderTagFlag::Required, + size_of::() as u32, + ); + Self { header } } + /// Returns the [`HeaderTagType`]. + #[must_use] pub const fn typ(&self) -> HeaderTagType { - self.typ + self.header.typ() } + + /// Returns the [`HeaderTagFlag`]s. + #[must_use] pub const fn flags(&self) -> HeaderTagFlag { - self.flags + self.header.flags() } + + /// Returns the size. + #[must_use] pub const fn size(&self) -> u32 { - self.size + self.header.size() } } diff --git a/multiboot2-header/src/entry_address.rs b/multiboot2-header/src/entry_address.rs index 513e7b35..cef429e3 100644 --- a/multiboot2-header/src/entry_address.rs +++ b/multiboot2-header/src/entry_address.rs @@ -1,4 +1,4 @@ -use crate::{HeaderTagFlag, HeaderTagType}; +use crate::{HeaderTagFlag, HeaderTagHeader, HeaderTagType}; use core::fmt; use core::fmt::{Debug, Formatter}; use core::mem::size_of; @@ -8,31 +8,39 @@ use core::mem::size_of; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct EntryAddressHeaderTag { - typ: HeaderTagType, - flags: HeaderTagFlag, - size: u32, + header: HeaderTagHeader, entry_addr: u32, } impl EntryAddressHeaderTag { + /// Constructs a new tag. + #[must_use] pub const fn new(flags: HeaderTagFlag, entry_addr: u32) -> Self { - EntryAddressHeaderTag { - typ: HeaderTagType::EntryAddress, - flags, - size: size_of::() as u32, - entry_addr, - } + let header = + HeaderTagHeader::new(HeaderTagType::EntryAddress, flags, size_of::() as u32); + Self { header, entry_addr } } + /// Returns the [`HeaderTagType`]. + #[must_use] pub const fn typ(&self) -> HeaderTagType { - self.typ + self.header.typ() } + + /// Returns the [`HeaderTagFlag`]s. + #[must_use] pub const fn flags(&self) -> HeaderTagFlag { - self.flags + self.header.flags() } + + /// Returns the size. + #[must_use] pub const fn size(&self) -> u32 { - self.size + self.header.size() } + + /// Returns the entry address. + #[must_use] pub const fn entry_addr(&self) -> u32 { self.entry_addr } @@ -41,9 +49,9 @@ impl EntryAddressHeaderTag { impl Debug for EntryAddressHeaderTag { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("EntryAddressHeaderTag") - .field("type", &{ self.typ }) - .field("flags", &{ self.flags }) - .field("size", &{ self.size }) + .field("type", &self.typ()) + .field("flags", &self.flags()) + .field("size", &self.size()) .field("entry_addr", &(self.entry_addr as *const u32)) .finish() } diff --git a/multiboot2-header/src/entry_efi_32.rs b/multiboot2-header/src/entry_efi_32.rs index 5f6818c1..c6ca3a71 100644 --- a/multiboot2-header/src/entry_efi_32.rs +++ b/multiboot2-header/src/entry_efi_32.rs @@ -1,4 +1,4 @@ -use crate::{HeaderTagFlag, HeaderTagType}; +use crate::{HeaderTagFlag, HeaderTagHeader, HeaderTagType}; use core::fmt; use core::fmt::{Debug, Formatter}; use core::mem::size_of; @@ -12,31 +12,42 @@ use core::mem::size_of; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct EntryEfi32HeaderTag { - typ: HeaderTagType, - flags: HeaderTagFlag, - size: u32, + header: HeaderTagHeader, entry_addr: u32, } impl EntryEfi32HeaderTag { + /// Constructs a new tag. + #[must_use] pub const fn new(flags: HeaderTagFlag, entry_addr: u32) -> Self { - EntryEfi32HeaderTag { - typ: HeaderTagType::EntryAddressEFI32, + let header = HeaderTagHeader::new( + HeaderTagType::EntryAddressEFI32, flags, - size: size_of::() as u32, - entry_addr, - } + size_of::() as u32, + ); + Self { header, entry_addr } } + /// Returns the [`HeaderTagType`]. + #[must_use] pub const fn typ(&self) -> HeaderTagType { - self.typ + self.header.typ() } + + /// Returns the [`HeaderTagFlag`]s. + #[must_use] pub const fn flags(&self) -> HeaderTagFlag { - self.flags + self.header.flags() } + + /// Returns the size. + #[must_use] pub const fn size(&self) -> u32 { - self.size + self.header.size() } + + /// Returns the entry address. + #[must_use] pub const fn entry_addr(&self) -> u32 { self.entry_addr } @@ -45,9 +56,9 @@ impl EntryEfi32HeaderTag { impl Debug for EntryEfi32HeaderTag { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("EntryEfi32HeaderTag") - .field("type", &{ self.typ }) - .field("flags", &{ self.flags }) - .field("size", &{ self.size }) + .field("type", &self.typ()) + .field("flags", &self.flags()) + .field("size", &self.size()) .field("entry_addr", &(self.entry_addr as *const u32)) .finish() } diff --git a/multiboot2-header/src/entry_efi_64.rs b/multiboot2-header/src/entry_efi_64.rs index dea41a95..e145f5cf 100644 --- a/multiboot2-header/src/entry_efi_64.rs +++ b/multiboot2-header/src/entry_efi_64.rs @@ -1,4 +1,4 @@ -use crate::{HeaderTagFlag, HeaderTagType}; +use crate::{HeaderTagFlag, HeaderTagHeader, HeaderTagType}; use core::fmt; use core::fmt::{Debug, Formatter}; use core::mem::size_of; @@ -12,31 +12,42 @@ use core::mem::size_of; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct EntryEfi64HeaderTag { - typ: HeaderTagType, - flags: HeaderTagFlag, - size: u32, + header: HeaderTagHeader, entry_addr: u32, } impl EntryEfi64HeaderTag { + /// Constructs a new tag. + #[must_use] pub const fn new(flags: HeaderTagFlag, entry_addr: u32) -> Self { - EntryEfi64HeaderTag { - typ: HeaderTagType::EntryAddressEFI64, + let header = HeaderTagHeader::new( + HeaderTagType::EntryAddressEFI64, flags, - size: size_of::() as u32, - entry_addr, - } + size_of::() as u32, + ); + Self { header, entry_addr } } + /// Returns the [`HeaderTagType`]. + #[must_use] pub const fn typ(&self) -> HeaderTagType { - self.typ + self.header.typ() } + + /// Returns the [`HeaderTagFlag`]s. + #[must_use] pub const fn flags(&self) -> HeaderTagFlag { - self.flags + self.header.flags() } + + /// Returns the size. + #[must_use] pub const fn size(&self) -> u32 { - self.size + self.header.size() } + + /// Returns the entry address. + #[must_use] pub const fn entry_addr(&self) -> u32 { self.entry_addr } @@ -45,9 +56,9 @@ impl EntryEfi64HeaderTag { impl Debug for EntryEfi64HeaderTag { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("EntryEfi64HeaderTag") - .field("type", &{ self.typ }) - .field("flags", &{ self.flags }) - .field("size", &{ self.size }) + .field("type", &self.typ()) + .field("flags", &self.flags()) + .field("size", &self.size()) .field("entry_addr", &(self.entry_addr as *const u32)) .finish() } diff --git a/multiboot2-header/src/framebuffer.rs b/multiboot2-header/src/framebuffer.rs index 1b9d1772..dfddb2d8 100644 --- a/multiboot2-header/src/framebuffer.rs +++ b/multiboot2-header/src/framebuffer.rs @@ -1,5 +1,5 @@ -use crate::{HeaderTagFlag, HeaderTagType}; -use core::mem::size_of; +use crate::{HeaderTagFlag, HeaderTagHeader, HeaderTagType}; +use core::mem; /// Specifies the preferred graphics mode. If this tag /// is present the bootloader assumes that the payload @@ -8,41 +8,61 @@ use core::mem::size_of; #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct FramebufferHeaderTag { - typ: HeaderTagType, - flags: HeaderTagFlag, - size: u32, + header: HeaderTagHeader, width: u32, height: u32, depth: u32, } impl FramebufferHeaderTag { + /// Constructs a new tag. + #[must_use] pub const fn new(flags: HeaderTagFlag, width: u32, height: u32, depth: u32) -> Self { - FramebufferHeaderTag { - typ: HeaderTagType::Framebuffer, + let header = HeaderTagHeader::new( + HeaderTagType::Framebuffer, flags, - size: size_of::() as u32, + mem::size_of::() as u32, + ); + Self { + header, width, height, depth, } } + /// Returns the [`HeaderTagType`]. + #[must_use] pub const fn typ(&self) -> HeaderTagType { - self.typ + self.header.typ() } + + /// Returns the [`HeaderTagFlag`]s. + #[must_use] pub const fn flags(&self) -> HeaderTagFlag { - self.flags + self.header.flags() } + + /// Returns the size. + #[must_use] pub const fn size(&self) -> u32 { - self.size + self.header.size() } + + /// Returns the width. + #[must_use] pub const fn width(&self) -> u32 { self.width } + + /// Returns the height. + #[must_use] pub const fn height(&self) -> u32 { self.height } + + /// Returns the depth. + #[must_use] pub const fn depth(&self) -> u32 { self.depth } @@ -50,12 +70,12 @@ impl FramebufferHeaderTag { #[cfg(test)] mod tests { - use crate::FramebufferHeaderTag; + use super::*; #[test] fn test_assert_size() { assert_eq!( - core::mem::size_of::(), + mem::size_of::(), 2 + 2 + 4 + 4 + 4 + 4 ); } diff --git a/multiboot2-header/src/header.rs b/multiboot2-header/src/header.rs index cb256f92..4c3c988b 100644 --- a/multiboot2-header/src/header.rs +++ b/multiboot2-header/src/header.rs @@ -1,8 +1,8 @@ use crate::{ AddressHeaderTag, ConsoleHeaderTag, EfiBootServiceHeaderTag, EndHeaderTag, EntryAddressHeaderTag, EntryEfi32HeaderTag, EntryEfi64HeaderTag, FramebufferHeaderTag, - HeaderTag, HeaderTagISA, HeaderTagType, InformationRequestHeaderTag, ModuleAlignHeaderTag, - RelocatableHeaderTag, + HeaderTagHeader, HeaderTagISA, HeaderTagType, InformationRequestHeaderTag, + ModuleAlignHeaderTag, RelocatableHeaderTag, }; use core::fmt::{Debug, Formatter}; use core::mem::size_of; @@ -103,89 +103,106 @@ impl<'a> Multiboot2Header<'a> { } /// Wrapper around [`Multiboot2BasicHeader::verify_checksum`]. + #[must_use] pub const fn verify_checksum(&self) -> bool { self.0.verify_checksum() } /// Wrapper around [`Multiboot2BasicHeader::header_magic`]. + #[must_use] pub const fn header_magic(&self) -> u32 { self.0.header_magic() } /// Wrapper around [`Multiboot2BasicHeader::arch`]. + #[must_use] pub const fn arch(&self) -> HeaderTagISA { self.0.arch() } /// Wrapper around [`Multiboot2BasicHeader::length`]. + #[must_use] pub const fn length(&self) -> u32 { self.0.length() } /// Wrapper around [`Multiboot2BasicHeader::checksum`]. + #[must_use] pub const fn checksum(&self) -> u32 { self.0.checksum() } /// Wrapper around [`Multiboot2BasicHeader::tag_iter`]. + #[must_use] pub fn iter(&self) -> Multiboot2HeaderTagIter { self.0.tag_iter() } /// Wrapper around [`Multiboot2BasicHeader::calc_checksum`]. + #[must_use] pub const fn calc_checksum(magic: u32, arch: HeaderTagISA, length: u32) -> u32 { Multiboot2BasicHeader::calc_checksum(magic, arch, length) } /// Search for the address header tag. + #[must_use] pub fn address_tag(&self) -> Option<&AddressHeaderTag> { self.get_tag(HeaderTagType::Address) - .map(|tag| unsafe { &*(tag as *const HeaderTag as *const AddressHeaderTag) }) + .map(|tag| unsafe { &*(tag as *const HeaderTagHeader as *const AddressHeaderTag) }) } /// Search for the entry address header tag. + #[must_use] pub fn entry_address_tag(&self) -> Option<&EntryAddressHeaderTag> { self.get_tag(HeaderTagType::EntryAddress) - .map(|tag| unsafe { &*(tag as *const HeaderTag as *const EntryAddressHeaderTag) }) + .map(|tag| unsafe { &*(tag as *const HeaderTagHeader as *const EntryAddressHeaderTag) }) } /// Search for the EFI32 entry address header tag. + #[must_use] pub fn entry_address_efi32_tag(&self) -> Option<&EntryEfi32HeaderTag> { self.get_tag(HeaderTagType::EntryAddressEFI32) - .map(|tag| unsafe { &*(tag as *const HeaderTag as *const EntryEfi32HeaderTag) }) + .map(|tag| unsafe { &*(tag as *const HeaderTagHeader as *const EntryEfi32HeaderTag) }) } /// Search for the EFI64 entry address header tag. + #[must_use] pub fn entry_address_efi64_tag(&self) -> Option<&EntryEfi64HeaderTag> { self.get_tag(HeaderTagType::EntryAddressEFI64) - .map(|tag| unsafe { &*(tag as *const HeaderTag as *const EntryEfi64HeaderTag) }) + .map(|tag| unsafe { &*(tag as *const HeaderTagHeader as *const EntryEfi64HeaderTag) }) } /// Search for the console flags header tag. + #[must_use] pub fn console_flags_tag(&self) -> Option<&ConsoleHeaderTag> { self.get_tag(HeaderTagType::ConsoleFlags) - .map(|tag| unsafe { &*(tag as *const HeaderTag as *const ConsoleHeaderTag) }) + .map(|tag| unsafe { &*(tag as *const HeaderTagHeader as *const ConsoleHeaderTag) }) } /// Search for the framebuffer header tag. + #[must_use] pub fn framebuffer_tag(&self) -> Option<&FramebufferHeaderTag> { self.get_tag(HeaderTagType::Framebuffer) - .map(|tag| unsafe { &*(tag as *const HeaderTag as *const FramebufferHeaderTag) }) + .map(|tag| unsafe { &*(tag as *const HeaderTagHeader as *const FramebufferHeaderTag) }) } /// Search for the module align header tag. + #[must_use] pub fn module_align_tag(&self) -> Option<&ModuleAlignHeaderTag> { self.get_tag(HeaderTagType::ModuleAlign) - .map(|tag| unsafe { &*(tag as *const HeaderTag as *const ModuleAlignHeaderTag) }) + .map(|tag| unsafe { &*(tag as *const HeaderTagHeader as *const ModuleAlignHeaderTag) }) } /// Search for the EFI Boot Services header tag. + #[must_use] pub fn efi_boot_services_tag(&self) -> Option<&EfiBootServiceHeaderTag> { - self.get_tag(HeaderTagType::EfiBS) - .map(|tag| unsafe { &*(tag as *const HeaderTag as *const EfiBootServiceHeaderTag) }) + self.get_tag(HeaderTagType::EfiBS).map(|tag| unsafe { + &*(tag as *const HeaderTagHeader as *const EfiBootServiceHeaderTag) + }) } /// Search for the EFI32 entry address header tag. + #[must_use] pub fn relocatable_tag(&self) -> Option<&RelocatableHeaderTag> { self.get_tag(HeaderTagType::Relocatable) - .map(|tag| unsafe { &*(tag as *const HeaderTag as *const RelocatableHeaderTag) }) + .map(|tag| unsafe { &*(tag as *const HeaderTagHeader as *const RelocatableHeaderTag) }) } - fn get_tag(&self, typ: HeaderTagType) -> Option<&HeaderTag> { + fn get_tag(&self, typ: HeaderTagType) -> Option<&HeaderTagHeader> { self.iter() .map(|tag| unsafe { tag.as_ref() }.unwrap()) .find(|tag| tag.typ() == typ) @@ -229,7 +246,7 @@ impl Multiboot2BasicHeader { pub(crate) const fn new(arch: HeaderTagISA, length: u32) -> Self { let magic = MAGIC; let checksum = Self::calc_checksum(magic, arch, length); - Multiboot2BasicHeader { + Self { header_magic: magic, arch, length, @@ -238,25 +255,38 @@ impl Multiboot2BasicHeader { } /// Verifies that a Multiboot2 header is valid. + #[must_use] pub const fn verify_checksum(&self) -> bool { let check = Self::calc_checksum(self.header_magic, self.arch, self.length); check == self.checksum } /// Calculates the checksum as described in the spec. + #[must_use] pub const fn calc_checksum(magic: u32, arch: HeaderTagISA, length: u32) -> u32 { (0x100000000 - magic as u64 - arch as u64 - length as u64) as u32 } + /// Returns the header magic. + #[must_use] pub const fn header_magic(&self) -> u32 { self.header_magic } + + /// Returns the [`HeaderTagISA`]. + #[must_use] pub const fn arch(&self) -> HeaderTagISA { self.arch } + + /// Returns the length. + #[must_use] pub const fn length(&self) -> u32 { self.length } + + /// Returns the checksum. + #[must_use] pub const fn checksum(&self) -> u32 { self.checksum } @@ -265,12 +295,13 @@ impl Multiboot2BasicHeader { /// /// # Panics /// See doc of [`Multiboot2HeaderTagIter`]. + #[must_use] pub fn tag_iter(&self) -> Multiboot2HeaderTagIter { - let base_hdr_size = size_of::(); + let base_hdr_size = size_of::(); if base_hdr_size == self.length as usize { panic!("No end tag!"); } - let tag_base_addr = self as *const Multiboot2BasicHeader; + let tag_base_addr = self as *const Self; // 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 @@ -278,7 +309,7 @@ impl Multiboot2BasicHeader { // align pointer to 8 byte according to spec 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 tag_base_addr = tag_base_addr as *const HeaderTagHeader; let tags_len = self.length as usize - base_hdr_size; Multiboot2HeaderTagIter::new(tag_base_addr, tags_len as u32) } @@ -307,7 +338,7 @@ impl Debug for Multiboot2BasicHeader { #[derive(Clone)] pub struct Multiboot2HeaderTagIter { /// 8-byte aligned base address - base: *const HeaderTag, + base: *const HeaderTagHeader, /// Offset in bytes from the base address. /// Always <= than size. n: u32, @@ -324,11 +355,11 @@ pub struct Multiboot2HeaderTagIter { } impl Multiboot2HeaderTagIter { - fn new(base: *const HeaderTag, size: u32) -> Self { + fn new(base: *const HeaderTagHeader, size: u32) -> Self { // transform to byte pointer => offset works properly let base = base as *const u8; let base = unsafe { base.add(base.align_offset(8)) }; - let base = base as *const HeaderTag; + let base = base as *const HeaderTagHeader; Self { base, n: 0, @@ -340,7 +371,7 @@ impl Multiboot2HeaderTagIter { } impl Iterator for Multiboot2HeaderTagIter { - type Item = *const HeaderTag; + type Item = *const HeaderTagHeader; fn next(&mut self) -> Option { // no more bytes left to check; length reached @@ -351,7 +382,7 @@ impl Iterator for Multiboot2HeaderTagIter { // transform to byte ptr => offset works correctly let ptr = self.base as *const u8; let ptr = unsafe { ptr.add(self.n as usize) }; - let ptr = ptr as *const HeaderTag; + let ptr = ptr as *const HeaderTagHeader; assert_eq!(ptr as usize % 8, 0, "must be 8-byte aligned"); let tag = unsafe { &*ptr }; assert!( diff --git a/multiboot2-header/src/information_request.rs b/multiboot2-header/src/information_request.rs index c5bb1d6c..f19e15bc 100644 --- a/multiboot2-header/src/information_request.rs +++ b/multiboot2-header/src/information_request.rs @@ -1,4 +1,4 @@ -use crate::{HeaderTagFlag, MbiTagType}; +use crate::{HeaderTagFlag, HeaderTagHeader, MbiTagType}; use crate::{HeaderTagType, MbiTagTypeId}; use core::fmt; use core::fmt::{Debug, Formatter}; @@ -11,9 +11,7 @@ use multiboot2::TagType; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct InformationRequestHeaderTag { - typ: HeaderTagType, - flags: HeaderTagFlag, - size: u32, + header: HeaderTagHeader, // Length is determined by size. // Must be parsed during runtime with unsafe pointer magic and the size field. requests: [MbiTagTypeId; N], @@ -23,28 +21,38 @@ impl InformationRequestHeaderTag { /// Creates a new object. The size parameter is the value of the size property. /// It doesn't have to match with `N` necessarily, because during compile time we /// can't know the size of the tag in all runtime situations. + #[must_use] pub fn new(flags: HeaderTagFlag, requests: [MbiTagTypeId; N], size: Option) -> Self { - InformationRequestHeaderTag { - typ: HeaderTagType::InformationRequest, + let header = HeaderTagHeader::new( + HeaderTagType::InformationRequest, flags, - size: size.unwrap_or(size_of::() as u32), - requests, - } + size.unwrap_or(size_of::() as u32), + ); + Self { header, requests } } + /// Returns the [`HeaderTagType`]. + #[must_use] pub const fn typ(&self) -> HeaderTagType { - self.typ + self.header.typ() } + + /// Returns the [`HeaderTagFlag`]s. + #[must_use] pub const fn flags(&self) -> HeaderTagFlag { - self.flags + self.header.flags() } + + /// Returns the size. + #[must_use] pub const fn size(&self) -> u32 { - self.size + self.header.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()`. + #[must_use] pub const fn requests(&self) -> [MbiTagTypeId; N] { // cheap to copy, otherwise difficult with lifetime self.requests @@ -54,9 +62,10 @@ impl InformationRequestHeaderTag { /// 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. + #[must_use] pub const fn dynamic_requests_size(&self) -> u32 { let base_struct_size = size_of::>(); - let size_diff = self.size - base_struct_size as u32; + let size_diff = self.size() - base_struct_size as u32; if size_diff > 0 { size_diff / size_of::() as u32 } else { @@ -65,10 +74,11 @@ impl InformationRequestHeaderTag { } /// Returns an [`InformationRequestHeaderTagIter`]. + #[must_use] pub const fn req_iter(&self) -> InformationRequestHeaderTagIter { let base_struct_size = size_of::>(); let count = self.dynamic_requests_size(); - let base_ptr = self as *const InformationRequestHeaderTag; + let base_ptr = self as *const Self; let base_ptr = base_ptr as *const u8; let base_ptr = unsafe { base_ptr.add(base_struct_size) }; let base_ptr = base_ptr as *const MbiTagTypeId; @@ -79,10 +89,10 @@ impl InformationRequestHeaderTag { impl Debug for InformationRequestHeaderTag { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("InformationRequestHeaderTag") - .field("type", &{ self.typ }) - .field("flags", &{ self.flags }) - .field("size", &{ self.size }) - .field("requests", &{ self.req_iter() }) + .field("type", &self.typ()) + .field("flags", &self.flags()) + .field("size", &self.size()) + .field("requests", &self.req_iter()) .finish() } } diff --git a/multiboot2-header/src/lib.rs b/multiboot2-header/src/lib.rs index 165bace8..578511e8 100644 --- a/multiboot2-header/src/lib.rs +++ b/multiboot2-header/src/lib.rs @@ -38,10 +38,22 @@ #![no_std] #![cfg_attr(feature = "unstable", feature(error_in_core))] -#![deny(rustdoc::all)] -#![deny(clippy::all)] -#![deny(clippy::missing_const_for_fn)] +// --- BEGIN STYLE CHECKS --- +#![deny( + clippy::all, + clippy::cargo, + clippy::nursery, + clippy::must_use_candidate, + // clippy::restriction, + // clippy::pedantic +)] +// now allow a few rules which are denied by the above statement +// --> They are either ridiculous, not necessary, or we can't fix them. +#![allow(clippy::multiple_crate_versions)] +#![deny(missing_docs)] #![deny(missing_debug_implementations)] +#![deny(rustdoc::all)] +// --- END STYLE CHECKS --- #[cfg(feature = "builder")] extern crate alloc; diff --git a/multiboot2-header/src/module_align.rs b/multiboot2-header/src/module_align.rs index 0ec2eb4b..c67acc58 100644 --- a/multiboot2-header/src/module_align.rs +++ b/multiboot2-header/src/module_align.rs @@ -1,32 +1,38 @@ -use crate::{HeaderTagFlag, HeaderTagType}; +use crate::{HeaderTagFlag, HeaderTagHeader, HeaderTagType}; use core::mem::size_of; /// If this tag is present, provided boot modules must be page aligned. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct ModuleAlignHeaderTag { - typ: HeaderTagType, - flags: HeaderTagFlag, - size: u32, + header: HeaderTagHeader, } impl ModuleAlignHeaderTag { + /// Constructs a new tag. + #[must_use] pub const fn new(flags: HeaderTagFlag) -> Self { - ModuleAlignHeaderTag { - typ: HeaderTagType::ModuleAlign, - flags, - size: size_of::() as u32, - } + let header = + HeaderTagHeader::new(HeaderTagType::ModuleAlign, flags, size_of::() as u32); + Self { header } } + /// Returns the [`HeaderTagType`]. + #[must_use] pub const fn typ(&self) -> HeaderTagType { - self.typ + self.header.typ() } + + /// Returns the [`HeaderTagFlag`]s. + #[must_use] pub const fn flags(&self) -> HeaderTagFlag { - self.flags + self.header.flags() } + + /// Returns the size. + #[must_use] pub const fn size(&self) -> u32 { - self.size + self.header.size() } } diff --git a/multiboot2-header/src/relocatable.rs b/multiboot2-header/src/relocatable.rs index ca8aea49..80cfaf96 100644 --- a/multiboot2-header/src/relocatable.rs +++ b/multiboot2-header/src/relocatable.rs @@ -1,4 +1,4 @@ -use crate::{HeaderTagFlag, HeaderTagType}; +use crate::{HeaderTagFlag, HeaderTagHeader, HeaderTagType}; use core::fmt; use core::fmt::{Debug, Formatter}; use core::mem::size_of; @@ -22,9 +22,7 @@ pub enum RelocatableHeaderTagPreference { #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct RelocatableHeaderTag { - typ: HeaderTagType, - flags: HeaderTagFlag, - size: u32, + header: HeaderTagHeader, /// Lowest possible physical address at which image should be loaded. The bootloader cannot load any part of image below this address min_addr: u32, /// Highest possible physical address at which loaded image should end. The bootloader cannot load any part of image above this address. @@ -35,6 +33,8 @@ pub struct RelocatableHeaderTag { } impl RelocatableHeaderTag { + /// Constructs a new tag. + #[must_use] pub const fn new( flags: HeaderTagFlag, min_addr: u32, @@ -42,10 +42,10 @@ impl RelocatableHeaderTag { align: u32, preference: RelocatableHeaderTagPreference, ) -> Self { - RelocatableHeaderTag { - typ: HeaderTagType::Relocatable, - flags, - size: size_of::() as u32, + let header = + HeaderTagHeader::new(HeaderTagType::Relocatable, flags, size_of::() as u32); + Self { + header, min_addr, max_addr, align, @@ -53,24 +53,44 @@ impl RelocatableHeaderTag { } } + /// Returns the [`HeaderTagType`]. + #[must_use] pub const fn typ(&self) -> HeaderTagType { - self.typ + self.header.typ() } + + /// Returns the [`HeaderTagFlag`]s. + #[must_use] pub const fn flags(&self) -> HeaderTagFlag { - self.flags + self.header.flags() } + + /// Returns the size. + #[must_use] pub const fn size(&self) -> u32 { - self.size + self.header.size() } + + /// Return the minimum address. + #[must_use] pub const fn min_addr(&self) -> u32 { self.min_addr } + + /// Return the maximum address. + #[must_use] pub const fn max_addr(&self) -> u32 { self.max_addr } + + /// Return the alignment. + #[must_use] pub const fn align(&self) -> u32 { self.align } + + /// Return the preference. + #[must_use] pub const fn preference(&self) -> RelocatableHeaderTagPreference { self.preference } @@ -79,9 +99,9 @@ impl RelocatableHeaderTag { impl Debug for RelocatableHeaderTag { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("RelocatableHeaderTag") - .field("type", &{ self.typ }) - .field("flags", &{ self.flags }) - .field("size", &{ self.size }) + .field("type", &self.typ()) + .field("flags", &self.flags()) + .field("size", &self.size()) // trick to print this as hexadecimal pointer .field("min_addr", &(self.min_addr as *const u32)) .field("max_addr", &(self.max_addr as *const u32)) diff --git a/multiboot2-header/src/tags.rs b/multiboot2-header/src/tags.rs index 51242697..c51aedc0 100644 --- a/multiboot2-header/src/tags.rs +++ b/multiboot2-header/src/tags.rs @@ -17,7 +17,7 @@ pub enum HeaderTagISA { /// 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`]. +/// stands in the `typ` property of [`HeaderTagHeader`]. #[repr(u16)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum HeaderTagType { @@ -47,6 +47,7 @@ pub enum HeaderTagType { impl HeaderTagType { /// Returns the number of possible variants. + #[must_use] pub const fn count() -> u32 { 11 } @@ -56,31 +57,46 @@ impl HeaderTagType { #[repr(u16)] #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum HeaderTagFlag { + /// Bootloader must provide this tag. If this is not possible, the + /// bootloader will fail loading the kernel. Required = 0, + /// Bootloader should provide the tag if possible. Optional = 1, } -/// Common properties for all header tags. Other tags may have additional fields -/// that depend on the `typ` and the `size` field. All tags share the same beginning of the -/// struct. +/// The common header that all header tags share. Specific tags may have +/// additional fields that depend on the `typ` and the `size` field. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] -pub struct HeaderTag { +pub struct HeaderTagHeader { + typ: HeaderTagType, /* u16 */ // u16 value - typ: HeaderTagType, - // u16 value - flags: HeaderTagFlag, + flags: HeaderTagFlag, /* u16 */ size: u32, - // maybe additional fields (tag specific) + // Followed by optional additional tag specific fields. } -impl HeaderTag { +impl HeaderTagHeader { + /// Creates a new header. + #[must_use] + pub const fn new(typ: HeaderTagType, flags: HeaderTagFlag, size: u32) -> Self { + Self { typ, flags, size } + } + + /// Returns the [`HeaderTagType`]. + #[must_use] pub const fn typ(&self) -> HeaderTagType { self.typ } + + /// Returns the [`HeaderTagFlag`]s. + #[must_use] pub const fn flags(&self) -> HeaderTagFlag { self.flags } + + /// Returns the size. + #[must_use] pub const fn size(&self) -> u32 { self.size } @@ -88,10 +104,10 @@ impl HeaderTag { #[cfg(test)] mod tests { - use crate::HeaderTag; + use crate::HeaderTagHeader; #[test] fn test_assert_size() { - assert_eq!(core::mem::size_of::(), 2 + 2 + 4); + assert_eq!(core::mem::size_of::(), 2 + 2 + 4); } } diff --git a/multiboot2-header/src/uefi_bs.rs b/multiboot2-header/src/uefi_bs.rs index 93204b3f..ce8b0a32 100644 --- a/multiboot2-header/src/uefi_bs.rs +++ b/multiboot2-header/src/uefi_bs.rs @@ -1,4 +1,4 @@ -use crate::{HeaderTagFlag, HeaderTagType}; +use crate::{HeaderTagFlag, HeaderTagHeader, HeaderTagType}; use core::mem::size_of; /// This tag indicates that payload supports starting without terminating UEFI boot services. @@ -6,28 +6,33 @@ use core::mem::size_of; #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(C)] pub struct EfiBootServiceHeaderTag { - typ: HeaderTagType, - flags: HeaderTagFlag, - size: u32, + header: HeaderTagHeader, } impl EfiBootServiceHeaderTag { + /// Constructs a new tag. + #[must_use] pub const fn new(flags: HeaderTagFlag) -> Self { - EfiBootServiceHeaderTag { - typ: HeaderTagType::EfiBS, - flags, - size: size_of::() as u32, - } + let header = HeaderTagHeader::new(HeaderTagType::EfiBS, flags, size_of::() as u32); + Self { header } } + /// Returns the [`HeaderTagType`]. + #[must_use] pub const fn typ(&self) -> HeaderTagType { - self.typ + self.header.typ() } + + /// Returns the [`HeaderTagFlag`]s. + #[must_use] pub const fn flags(&self) -> HeaderTagFlag { - self.flags + self.header.flags() } + + /// Returns the size. + #[must_use] pub const fn size(&self) -> u32 { - self.size + self.header.size() } } From 9b2532dc6ecc030740800789651f61770b515df0 Mon Sep 17 00:00:00 2001 From: Philipp Schuster Date: Wed, 14 Aug 2024 16:24:58 +0200 Subject: [PATCH 8/8] ci: cancel previous runs when new pushes were made This is more what is naturally expected. It saves CI time and it often prevents many already started runs that will fail anyway from running longer than necessary. See https://stackoverflow.com/questions/66335225 --- .github/workflows/rust.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index e0a81671..3c914f55 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -11,6 +11,10 @@ name: "Cargo workspace" # Run on every push (tag, branch) and pull_request on: [ pull_request, push, workflow_dispatch, merge_group ] +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + env: CARGO_TERM_COLOR: always