Skip to content

Commit 5ba7c5e

Browse files
committed
multiboot2-header: refactor to use common abstractions
This especially significantly changes the builder. The normal public API however is only slightly affected. multiboot2-header
1 parent b523748 commit 5ba7c5e

21 files changed

+593
-1078
lines changed

multiboot2-header/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ unstable = []
4141

4242
[dependencies]
4343
derive_more.workspace = true
44+
log.workspace = true
45+
ptr_meta.workspace = true
4446
multiboot2 = { version = "0.21.0", default-features = false }
47+
multiboot2-common = "0.1.0"
4548

4649
[package.metadata.docs.rs]
4750
all-features = true

multiboot2-header/examples/minimal.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,35 @@
1-
use multiboot2_header::builder::{HeaderBuilder, InformationRequestHeaderTagBuilder};
1+
use multiboot2_common::MaybeDynSized;
2+
use multiboot2_header::Builder;
23
use multiboot2_header::{
3-
HeaderTagFlag, HeaderTagISA, MbiTagType, Multiboot2Header, RelocatableHeaderTag,
4-
RelocatableHeaderTagPreference,
4+
HeaderTagFlag, HeaderTagISA, InformationRequestHeaderTag, MbiTagType, Multiboot2Header,
5+
RelocatableHeaderTag, RelocatableHeaderTagPreference,
56
};
67

78
/// Small example that creates a Multiboot2 header and parses it afterwards.
89
fn main() {
9-
// We create a Multiboot2 header during runtime here. A practical example is that your
10-
// program gets the header from a file and parses it afterwards.
11-
let mb2_hdr_bytes = HeaderBuilder::new(HeaderTagISA::I386)
10+
// We create a Multiboot2 header during runtime here. A more practical
11+
// example, however, would be that you parse the header from kernel binary
12+
// at runtime.
13+
let mb2_hdr_bytes = Builder::new(HeaderTagISA::I386)
1214
.relocatable_tag(RelocatableHeaderTag::new(
1315
HeaderTagFlag::Required,
1416
0x1337,
1517
0xdeadbeef,
1618
4096,
1719
RelocatableHeaderTagPreference::None,
1820
))
19-
.information_request_tag(
20-
InformationRequestHeaderTagBuilder::new(HeaderTagFlag::Required)
21-
.add_irs(&[MbiTagType::Cmdline, MbiTagType::BootLoaderName]),
22-
)
21+
.information_request_tag(InformationRequestHeaderTag::new(
22+
HeaderTagFlag::Required,
23+
&[
24+
MbiTagType::Cmdline.into(),
25+
MbiTagType::BootLoaderName.into(),
26+
],
27+
))
2328
.build();
2429

2530
// Cast bytes in vector to Multiboot2 information structure
26-
let mb2_hdr = unsafe { Multiboot2Header::load(mb2_hdr_bytes.as_ptr().cast()) };
31+
let ptr = mb2_hdr_bytes.as_bytes().as_ptr();
32+
let mb2_hdr = unsafe { Multiboot2Header::load(ptr.cast()) };
33+
let mb2_hdr = mb2_hdr.unwrap();
2734
println!("{:#?}", mb2_hdr);
2835
}

multiboot2-header/src/address.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
use crate::{HeaderTagFlag, HeaderTagHeader, HeaderTagType};
22
use core::mem::size_of;
3+
use multiboot2_common::{MaybeDynSized, Tag};
34

45
/// This information does not need to be provided if the kernel image is in ELF
56
/// format, but it must be provided if the image is in a.out format or in some
67
/// other format. Required for legacy boot (BIOS).
78
/// Determines load addresses.
89
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
9-
#[repr(C)]
10+
#[repr(C, align(8))]
1011
pub struct AddressHeaderTag {
1112
header: HeaderTagHeader,
1213
/// 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.
@@ -84,6 +85,19 @@ impl AddressHeaderTag {
8485
}
8586
}
8687

88+
impl MaybeDynSized for AddressHeaderTag {
89+
type Header = HeaderTagHeader;
90+
91+
const BASE_SIZE: usize = size_of::<Self>();
92+
93+
fn dst_len(_header: &Self::Header) -> Self::Metadata {}
94+
}
95+
96+
impl Tag for AddressHeaderTag {
97+
type IDType = HeaderTagType;
98+
const ID: HeaderTagType = HeaderTagType::Address;
99+
}
100+
87101
#[cfg(test)]
88102
mod tests {
89103
use crate::AddressHeaderTag;

multiboot2-header/src/builder.rs

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
//! Exports a builder [`Builder`].
2+
3+
use crate::{
4+
AddressHeaderTag, ConsoleHeaderTag, EfiBootServiceHeaderTag, EntryAddressHeaderTag,
5+
EntryEfi32HeaderTag, EntryEfi64HeaderTag, FramebufferHeaderTag, HeaderTagISA,
6+
InformationRequestHeaderTag, ModuleAlignHeaderTag, Multiboot2BasicHeader, RelocatableHeaderTag,
7+
};
8+
use alloc::boxed::Box;
9+
use alloc::vec::Vec;
10+
use multiboot2_common::{new_boxed, DynSizedStructure, MaybeDynSized};
11+
12+
/// Builder for a Multiboot2 header information.
13+
#[derive(Debug)]
14+
pub struct Builder {
15+
arch: HeaderTagISA,
16+
information_request_tag: Option<Box<InformationRequestHeaderTag>>,
17+
address_tag: Option<AddressHeaderTag>,
18+
entry_tag: Option<EntryAddressHeaderTag>,
19+
console_tag: Option<ConsoleHeaderTag>,
20+
framebuffer_tag: Option<FramebufferHeaderTag>,
21+
module_align_tag: Option<ModuleAlignHeaderTag>,
22+
efi_bs_tag: Option<EfiBootServiceHeaderTag>,
23+
efi_32_tag: Option<EntryEfi32HeaderTag>,
24+
efi_64_tag: Option<EntryEfi64HeaderTag>,
25+
relocatable_tag: Option<RelocatableHeaderTag>,
26+
// TODO add support for custom tags once someone requests it.
27+
}
28+
29+
impl Builder {
30+
/// Set the [`RelocatableHeaderTag`] tag.
31+
#[must_use]
32+
pub const fn new(arch: HeaderTagISA) -> Self {
33+
Self {
34+
arch,
35+
information_request_tag: None,
36+
address_tag: None,
37+
entry_tag: None,
38+
console_tag: None,
39+
framebuffer_tag: None,
40+
module_align_tag: None,
41+
efi_bs_tag: None,
42+
efi_32_tag: None,
43+
efi_64_tag: None,
44+
relocatable_tag: None,
45+
}
46+
}
47+
48+
/// Set the [`InformationRequestHeaderTag`] tag.
49+
#[must_use]
50+
pub fn information_request_tag(
51+
mut self,
52+
information_request_tag: Box<InformationRequestHeaderTag>,
53+
) -> Self {
54+
self.information_request_tag = Some(information_request_tag);
55+
self
56+
}
57+
58+
/// Set the [`AddressHeaderTag`] tag.
59+
#[must_use]
60+
pub const fn address_tag(mut self, address_tag: AddressHeaderTag) -> Self {
61+
self.address_tag = Some(address_tag);
62+
self
63+
}
64+
65+
/// Set the [`EntryAddressHeaderTag`] tag.
66+
#[must_use]
67+
pub const fn entry_tag(mut self, entry_tag: EntryAddressHeaderTag) -> Self {
68+
self.entry_tag = Some(entry_tag);
69+
self
70+
}
71+
72+
/// Set the [`ConsoleHeaderTag`] tag.
73+
#[must_use]
74+
pub const fn console_tag(mut self, console_tag: ConsoleHeaderTag) -> Self {
75+
self.console_tag = Some(console_tag);
76+
self
77+
}
78+
79+
/// Set the [`FramebufferHeaderTag`] tag.
80+
#[must_use]
81+
pub const fn framebuffer_tag(mut self, framebuffer_tag: FramebufferHeaderTag) -> Self {
82+
self.framebuffer_tag = Some(framebuffer_tag);
83+
self
84+
}
85+
86+
/// Set the [`ModuleAlignHeaderTag`] tag.
87+
#[must_use]
88+
pub const fn module_align_tag(mut self, module_align_tag: ModuleAlignHeaderTag) -> Self {
89+
self.module_align_tag = Some(module_align_tag);
90+
self
91+
}
92+
93+
/// Set the [`EfiBootServiceHeaderTag`] tag.
94+
#[must_use]
95+
pub const fn efi_bs_tag(mut self, efi_bs_tag: EfiBootServiceHeaderTag) -> Self {
96+
self.efi_bs_tag = Some(efi_bs_tag);
97+
self
98+
}
99+
100+
/// Set the [`EntryEfi32HeaderTag`] tag.
101+
#[must_use]
102+
pub const fn efi_32_tag(mut self, efi_32_tag: EntryEfi32HeaderTag) -> Self {
103+
self.efi_32_tag = Some(efi_32_tag);
104+
self
105+
}
106+
107+
/// Set the [`EntryEfi64HeaderTag`] tag.
108+
#[must_use]
109+
pub const fn efi_64_tag(mut self, efi_64_tag: EntryEfi64HeaderTag) -> Self {
110+
self.efi_64_tag = Some(efi_64_tag);
111+
self
112+
}
113+
114+
/// Set the [`RelocatableHeaderTag`] tag.
115+
#[must_use]
116+
pub const fn relocatable_tag(mut self, relocatable_tag: RelocatableHeaderTag) -> Self {
117+
self.relocatable_tag = Some(relocatable_tag);
118+
self
119+
}
120+
121+
/// Returns properly aligned bytes on the heap representing a valid
122+
/// Multiboot2 header structure.
123+
#[must_use]
124+
pub fn build(self) -> Box<DynSizedStructure<Multiboot2BasicHeader>> {
125+
let header = Multiboot2BasicHeader::new(self.arch, 0);
126+
let mut byte_refs = Vec::new();
127+
if let Some(tag) = self.information_request_tag.as_ref() {
128+
byte_refs.push(tag.as_bytes().as_ref());
129+
}
130+
if let Some(tag) = self.address_tag.as_ref() {
131+
byte_refs.push(tag.as_bytes().as_ref());
132+
}
133+
if let Some(tag) = self.entry_tag.as_ref() {
134+
byte_refs.push(tag.as_bytes().as_ref());
135+
}
136+
if let Some(tag) = self.console_tag.as_ref() {
137+
byte_refs.push(tag.as_bytes().as_ref());
138+
}
139+
if let Some(tag) = self.framebuffer_tag.as_ref() {
140+
byte_refs.push(tag.as_bytes().as_ref());
141+
}
142+
if let Some(tag) = self.module_align_tag.as_ref() {
143+
byte_refs.push(tag.as_bytes().as_ref());
144+
}
145+
if let Some(tag) = self.efi_bs_tag.as_ref() {
146+
byte_refs.push(tag.as_bytes().as_ref());
147+
}
148+
if let Some(tag) = self.efi_32_tag.as_ref() {
149+
byte_refs.push(tag.as_bytes().as_ref());
150+
}
151+
if let Some(tag) = self.efi_64_tag.as_ref() {
152+
byte_refs.push(tag.as_bytes().as_ref());
153+
}
154+
if let Some(tag) = self.relocatable_tag.as_ref() {
155+
byte_refs.push(tag.as_bytes().as_ref());
156+
}
157+
// TODO add support for custom tags once someone requests it.
158+
new_boxed(header, byte_refs.as_slice())
159+
}
160+
}
161+
162+
#[cfg(test)]
163+
mod tests {
164+
use super::*;
165+
use crate::ConsoleHeaderTagFlags::ConsoleRequired;
166+
use crate::HeaderTagFlag::{Optional, Required};
167+
use crate::RelocatableHeaderTagPreference::High;
168+
use crate::{MbiTagType, Multiboot2Header};
169+
170+
#[test]
171+
fn build_and_parse() {
172+
let builder = Builder::new(HeaderTagISA::I386)
173+
.information_request_tag(InformationRequestHeaderTag::new(
174+
Optional,
175+
&[
176+
MbiTagType::Cmdline.into(),
177+
MbiTagType::BootLoaderName.into(),
178+
MbiTagType::Module.into(),
179+
MbiTagType::BasicMeminfo.into(),
180+
MbiTagType::Bootdev.into(),
181+
MbiTagType::Mmap.into(),
182+
MbiTagType::Vbe.into(),
183+
MbiTagType::Framebuffer.into(),
184+
MbiTagType::ElfSections.into(),
185+
MbiTagType::Apm.into(),
186+
MbiTagType::Efi32.into(),
187+
MbiTagType::Efi64.into(),
188+
MbiTagType::Smbios.into(),
189+
MbiTagType::AcpiV1.into(),
190+
MbiTagType::AcpiV2.into(),
191+
MbiTagType::Network.into(),
192+
MbiTagType::EfiMmap.into(),
193+
MbiTagType::EfiBs.into(),
194+
MbiTagType::Efi32Ih.into(),
195+
MbiTagType::Efi64Ih.into(),
196+
MbiTagType::LoadBaseAddr.into(),
197+
MbiTagType::Custom(0x1337).into(),
198+
],
199+
))
200+
.address_tag(AddressHeaderTag::new(
201+
Required, 0x1000, 0x2000, 0x3000, 0x4000,
202+
))
203+
.entry_tag(EntryAddressHeaderTag::new(Required, 0x5000))
204+
.console_tag(ConsoleHeaderTag::new(Required, ConsoleRequired))
205+
.framebuffer_tag(FramebufferHeaderTag::new(Optional, 720, 1024, 8))
206+
.module_align_tag(ModuleAlignHeaderTag::new(Required))
207+
.efi_bs_tag(EfiBootServiceHeaderTag::new(Optional))
208+
.efi_32_tag(EntryEfi32HeaderTag::new(Required, 0x7000))
209+
.efi_64_tag(EntryEfi64HeaderTag::new(Required, 0x8000))
210+
.relocatable_tag(RelocatableHeaderTag::new(
211+
Required, 0x9000, 0x10000, 4096, High,
212+
));
213+
214+
let structure = builder.build();
215+
let header =
216+
unsafe { Multiboot2Header::load(structure.as_bytes().as_ref().as_ptr().cast()) }
217+
.unwrap();
218+
219+
assert!(header.verify_checksum());
220+
221+
for tag in header.iter() {
222+
dbg!(tag);
223+
}
224+
225+
dbg!(header.arch());
226+
dbg!(header.checksum());
227+
dbg!(header.information_request_tag());
228+
dbg!(header.address_tag());
229+
dbg!(header.entry_address_tag());
230+
dbg!(header.console_flags_tag());
231+
dbg!(header.framebuffer_tag());
232+
dbg!(header.module_align_tag());
233+
dbg!(header.efi_boot_services_tag());
234+
dbg!(header.entry_address_efi32_tag());
235+
dbg!(header.entry_address_efi64_tag());
236+
dbg!(header.relocatable_tag());
237+
}
238+
}

0 commit comments

Comments
 (0)