diff --git a/multiboot2/CHANGELOG.md b/multiboot2/CHANGELOG.md index cbec0eec..6fe1b347 100644 --- a/multiboot2/CHANGELOG.md +++ b/multiboot2/CHANGELOG.md @@ -4,6 +4,10 @@ - dependency updates - **Breaking:** MSRV is now 1.75 +- Added missing tags: + - `ApmTag` + - `BootdevTag` + - `NetworkTag` ## v0.22.2 (2024-08-24) diff --git a/multiboot2/src/apm.rs b/multiboot2/src/apm.rs new file mode 100644 index 00000000..11211a36 --- /dev/null +++ b/multiboot2/src/apm.rs @@ -0,0 +1,126 @@ +//! Module for [`ApmTag`]. + +use crate::{TagHeader, TagType}; +use core::mem; +use multiboot2_common::{MaybeDynSized, Tag}; + +/// The Advanced Power Management (APM) tag. +#[derive(Debug)] +#[repr(C, align(8))] +pub struct ApmTag { + header: TagHeader, + version: u16, + cseg: u16, + offset: u32, + cset_16: u16, + dseg: u16, + flags: u16, + cseg_len: u16, + cseg_16_len: u16, + dseg_len: u16, +} + +impl ApmTag { + /// Creates a new tag. + #[allow(clippy::too_many_arguments)] + #[must_use] + pub fn new( + version: u16, + cseg: u16, + offset: u32, + cset_16: u16, + dset: u16, + flags: u16, + cseg_len: u16, + cseg_16_len: u16, + dseg_len: u16, + ) -> Self { + Self { + header: TagHeader::new(TagType::Apm, mem::size_of::() as u32), + version, + cseg, + offset, + cset_16, + dseg: dset, + flags, + cseg_len, + cseg_16_len, + dseg_len, + } + } + + /// The version number of the APM BIOS. + #[must_use] + pub const fn version(&self) -> u16 { + self.version + } + + /// Contains the 16-bit code segment (CS) address for the APM entry point. + #[must_use] + pub const fn cseg(&self) -> u16 { + self.cseg + } + + /// Represents the offset address within the code segment (`cseg`) for the + /// APM entry point. + #[must_use] + pub const fn offset(&self) -> u32 { + self.offset + } + + /// Contains the 16-bit code segment (CS) address used for 16-bit protected + /// mode APM functions. + #[must_use] + pub const fn cset_16(&self) -> u16 { + self.cset_16 + } + + /// Holds the 16-bit data segment (DS) address used by the APM BIOS for + /// data operations. + #[must_use] + pub const fn dseg(&self) -> u16 { + self.dseg + } + + /// Indicates the status and characteristics of the APM connection, such as + /// if APM is present and its capabilities. + #[must_use] + pub const fn flags(&self) -> u16 { + self.flags + } + + /// Indicates the length, in bytes, of the data segment (`dseg`) used by + /// the APM BIOS + #[must_use] + pub const fn cseg_len(&self) -> u16 { + self.cseg_len + } + + /// Provides the length, in bytes, of the 16-bit code segment (`cseg_16`) + /// used for APM functions. + #[must_use] + pub const fn cseg_16_len(&self) -> u16 { + self.cseg_16_len + } + + /// Indicates the length, in bytes, of the data segment (`dseg`) used by + /// the APM BIOS. + #[must_use] + pub const fn dseg_len(&self) -> u16 { + self.dseg_len + } +} + +impl MaybeDynSized for ApmTag { + type Header = TagHeader; + + const BASE_SIZE: usize = mem::size_of::(); + + fn dst_len(_: &TagHeader) {} +} + +impl Tag for ApmTag { + type IDType = TagType; + + const ID: TagType = TagType::Apm; +} diff --git a/multiboot2/src/bootdev.rs b/multiboot2/src/bootdev.rs new file mode 100644 index 00000000..14640e16 --- /dev/null +++ b/multiboot2/src/bootdev.rs @@ -0,0 +1,67 @@ +//! Module for [`BootdevTag`]. + +use crate::{TagHeader, TagType}; +use core::mem; +use multiboot2_common::{MaybeDynSized, Tag}; + +/// The end tag ends the information struct. +#[derive(Debug)] +#[repr(C, align(8))] +pub struct BootdevTag { + header: TagHeader, + biosdev: u32, + slice: u32, + part: u32, +} + +impl BootdevTag { + /// Creates a new tag. + #[must_use] + pub fn new(biosdev: u32, slice: u32, part: u32) -> Self { + Self { + header: TagHeader::new(TagType::Apm, mem::size_of::() as u32), + biosdev, + slice, + part, + } + } + + /// Returns the bios device from which the device was booted from. + /// `0x00` represents the first floppy disk. + /// `0x80` represents the first hard disk, 0x81 the second hard disk, and + /// so on. + #[must_use] + pub const fn biosdev(&self) -> u32 { + self.biosdev + } + + /// The slice field identifies the partition (also known as a "slice" in BSD + /// terminology) on the BIOS device from which the operating system was + /// booted. + #[must_use] + pub const fn slice(&self) -> u32 { + self.slice + } + + /// The part field denotes the subpartition or logical partition within the + /// primary partition (if applicable) from which the operating system was + /// booted. + #[must_use] + pub const fn part(&self) -> u32 { + self.part + } +} + +impl MaybeDynSized for BootdevTag { + type Header = TagHeader; + + const BASE_SIZE: usize = mem::size_of::(); + + fn dst_len(_: &TagHeader) {} +} + +impl Tag for BootdevTag { + type IDType = TagType; + + const ID: TagType = TagType::Bootdev; +} diff --git a/multiboot2/src/builder.rs b/multiboot2/src/builder.rs index 6ee4dea6..0ddab5de 100644 --- a/multiboot2/src/builder.rs +++ b/multiboot2/src/builder.rs @@ -1,5 +1,8 @@ //! Module for [`Builder`]. +use crate::apm::ApmTag; +use crate::bootdev::BootdevTag; +use crate::network::NetworkTag; use crate::{ BasicMemoryInfoTag, BootInformationHeader, BootLoaderNameTag, CommandLineTag, EFIBootServicesNotExitedTag, EFIImageHandle32Tag, EFIImageHandle64Tag, EFIMemoryMapTag, @@ -18,18 +21,18 @@ pub struct Builder { bootloader: Option>, modules: Vec>, meminfo: Option, - // missing bootdev: Option + bootdev: Option, mmap: Option>, vbe: Option, framebuffer: Option>, elf_sections: Option>, - // missing apm: + apm: Option, efi32: Option, efi64: Option, smbios: Vec>, rsdpv1: Option, rsdpv2: Option, - // missing: network + network: Option>, efi_mmap: Option>, efi_bs: Option, efi32_ih: Option, @@ -53,16 +56,19 @@ impl Builder { bootloader: None, modules: vec![], meminfo: None, + bootdev: None, mmap: None, vbe: None, framebuffer: None, elf_sections: None, + apm: None, efi32: None, efi64: None, smbios: vec![], rsdpv1: None, rsdpv2: None, efi_mmap: None, + network: None, efi_bs: None, efi32_ih: None, efi64_ih: None, @@ -99,6 +105,13 @@ impl Builder { self } + /// Sets the [`BootdevTag`] tag. + #[must_use] + pub const fn bootdev(mut self, bootdev: BootdevTag) -> Self { + self.bootdev = Some(bootdev); + self + } + /// Sets the [`MemoryMapTag`] tag. #[must_use] pub fn mmap(mut self, mmap: Box) -> Self { @@ -127,6 +140,13 @@ impl Builder { self } + /// Sets the [`ApmTag`] tag. + #[must_use] + pub const fn apm(mut self, apm: ApmTag) -> Self { + self.apm = Some(apm); + self + } + /// Sets the [`EFISdt32Tag`] tag. #[must_use] pub const fn efi32(mut self, efi32: EFISdt32Tag) -> Self { @@ -169,6 +189,13 @@ impl Builder { self } + /// Sets the [`NetworkTag`] tag. + #[must_use] + pub fn network(mut self, network: Box) -> Self { + self.network = Some(network); + self + } + /// Sets the [`EFIBootServicesNotExitedTag`] tag. #[must_use] pub const fn efi_bs(mut self, efi_bs: EFIBootServicesNotExitedTag) -> Self { @@ -226,6 +253,9 @@ impl Builder { if let Some(tag) = self.meminfo.as_ref() { byte_refs.push(tag.as_bytes().as_ref()); } + if let Some(tag) = self.bootdev.as_ref() { + byte_refs.push(tag.as_bytes().as_ref()); + } if let Some(tag) = self.mmap.as_ref() { byte_refs.push(tag.as_bytes().as_ref()); } @@ -238,6 +268,9 @@ impl Builder { if let Some(tag) = self.elf_sections.as_ref() { byte_refs.push(tag.as_bytes().as_ref()); } + if let Some(tag) = self.apm.as_ref() { + byte_refs.push(tag.as_bytes().as_ref()); + } if let Some(tag) = self.efi32.as_ref() { byte_refs.push(tag.as_bytes().as_ref()); } @@ -293,6 +326,7 @@ mod tests { .add_module(ModuleTag::new(0x1000, 0x2000, "module 1")) .add_module(ModuleTag::new(0x3000, 0x4000, "module 2")) .meminfo(BasicMemoryInfoTag::new(0x4000, 0x5000)) + .bootdev(BootdevTag::new(0x00, 0x00, 0x00)) .mmap(MemoryMapTag::new(&[MemoryArea::new( 0x1000000, 0x1000, @@ -316,6 +350,7 @@ mod tests { FramebufferType::Text, )) .elf_sections(ElfSectionsTag::new(0, 32, 0, &[])) + .apm(ApmTag::new(0, 0, 0, 0, 0, 0, 0, 0, 0)) .efi32(EFISdt32Tag::new(0x1000)) .efi64(EFISdt64Tag::new(0x1000)) .add_smbios(SmbiosTag::new(0, 0, &[1, 2, 3])) @@ -326,6 +361,7 @@ mod tests { MemoryDescriptor::default(), MemoryDescriptor::default(), ])) + .network(NetworkTag::new(&[0; 1500])) .efi_bs(EFIBootServicesNotExitedTag::new()) .efi32_ih(EFIImageHandle32Tag::new(0x1000)) .efi64_ih(EFIImageHandle64Tag::new(0x1000)) diff --git a/multiboot2/src/end.rs b/multiboot2/src/end.rs index d8f900c4..23707d0b 100644 --- a/multiboot2/src/end.rs +++ b/multiboot2/src/end.rs @@ -1,6 +1,6 @@ //! Module for [`EndTag`]. -use crate::{TagHeader, TagType, TagTypeId}; +use crate::{TagHeader, TagType}; use core::mem; use multiboot2_common::{MaybeDynSized, Tag}; @@ -8,15 +8,13 @@ use multiboot2_common::{MaybeDynSized, Tag}; #[derive(Debug)] #[repr(C, align(8))] pub struct EndTag { - typ: TagTypeId, - size: u32, + header: TagHeader, } impl Default for EndTag { fn default() -> Self { Self { - typ: TagType::End.into(), - size: 8, + header: TagHeader::new(TagType::End, mem::size_of::() as u32), } } } diff --git a/multiboot2/src/lib.rs b/multiboot2/src/lib.rs index d5ad47c5..cd13f558 100644 --- a/multiboot2/src/lib.rs +++ b/multiboot2/src/lib.rs @@ -66,8 +66,10 @@ pub type TagIter<'a> = multiboot2_common::TagIter<'a, TagHeader>; #[cfg(test)] pub type GenericInfoTag = multiboot2_common::DynSizedStructure; +mod apm; mod boot_information; mod boot_loader_name; +mod bootdev; mod command_line; mod efi; mod elf_sections; @@ -76,6 +78,7 @@ mod framebuffer; mod image_load_addr; mod memory_map; mod module; +mod network; mod rsdp; mod smbios; mod tag; @@ -85,8 +88,10 @@ mod vbe_info; pub use multiboot2_common::{DynSizedStructure, MaybeDynSized, Tag}; +pub use apm::ApmTag; pub use boot_information::{BootInformation, BootInformationHeader, LoadError}; pub use boot_loader_name::BootLoaderNameTag; +pub use bootdev::BootdevTag; #[cfg(feature = "builder")] pub use builder::Builder; pub use command_line::CommandLineTag; @@ -104,6 +109,7 @@ pub use memory_map::{ MemoryArea, MemoryAreaType, MemoryAreaTypeId, MemoryMapTag, }; pub use module::{ModuleIter, ModuleTag}; +pub use network::NetworkTag; pub use ptr_meta::Pointee; pub use rsdp::{RsdpV1Tag, RsdpV2Tag}; pub use smbios::SmbiosTag; diff --git a/multiboot2/src/network.rs b/multiboot2/src/network.rs new file mode 100644 index 00000000..1cea90b7 --- /dev/null +++ b/multiboot2/src/network.rs @@ -0,0 +1,43 @@ +//! Module for [`NetworkTag`]. + +use crate::{TagHeader, TagType, TagTypeId}; +use core::mem; +use multiboot2_common::{MaybeDynSized, Tag}; +use ptr_meta::Pointee; +#[cfg(feature = "builder")] +use {alloc::boxed::Box, multiboot2_common::new_boxed}; + +/// The end tag ends the information struct. +#[derive(Debug, Pointee)] +#[repr(C, align(8))] +pub struct NetworkTag { + typ: TagTypeId, + size: u32, + dhcpack: [u8], +} + +impl NetworkTag { + /// Create a new network tag from the given DHCP package. + #[cfg(feature = "builder")] + #[must_use] + pub fn new(dhcp_pack: &[u8]) -> Box { + let header = TagHeader::new(Self::ID, 0); + new_boxed(header, &[dhcp_pack]) + } +} + +impl MaybeDynSized for NetworkTag { + type Header = TagHeader; + + const BASE_SIZE: usize = mem::size_of::(); + + fn dst_len(header: &TagHeader) -> usize { + header.size as usize - Self::BASE_SIZE + } +} + +impl Tag for NetworkTag { + type IDType = TagType; + + const ID: TagType = TagType::Network; +}