Skip to content

Commit 20bf713

Browse files
committed
multiboot2-header: moved all related code into the new builder-module
1 parent d9b35e3 commit 20bf713

19 files changed

+223
-231
lines changed

multiboot2-header/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ multiboot2-header = "<latest>"
2929

3030
## Example 1: Builder + Parse
3131
```rust
32-
use multiboot2_header::builder::Multiboot2HeaderBuilder;
33-
use multiboot2_header::{HeaderTagFlag, HeaderTagISA, InformationRequestHeaderTagBuilder, MbiTagType, RelocatableHeaderTag, RelocatableHeaderTagPreference, Multiboot2Header};
32+
use multiboot2_header::builder::{InformationRequestHeaderTagBuilder, Multiboot2HeaderBuilder};
33+
use multiboot2_header::{HeaderTagFlag, HeaderTagISA, MbiTagType, RelocatableHeaderTag, RelocatableHeaderTagPreference, Multiboot2Header};
3434

3535
/// Small example that creates a Multiboot2 header and parses it afterwards.
3636
fn main() {

multiboot2-header/examples/minimal.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
use multiboot2_header::builder::Multiboot2HeaderBuilder;
1+
use multiboot2_header::builder::{InformationRequestHeaderTagBuilder, Multiboot2HeaderBuilder};
22
use multiboot2_header::{
3-
HeaderTagFlag, HeaderTagISA, InformationRequestHeaderTagBuilder, MbiTagType, Multiboot2Header,
4-
RelocatableHeaderTag, RelocatableHeaderTagPreference,
3+
HeaderTagFlag, HeaderTagISA, MbiTagType, Multiboot2Header, RelocatableHeaderTag,
4+
RelocatableHeaderTagPreference,
55
};
66

77
/// Small example that creates a Multiboot2 header and parses it afterwards.

multiboot2-header/src/address.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,3 @@ impl AddressHeaderTag {
6464
self.bss_end_addr
6565
}
6666
}
67-
68-
#[cfg(feature = "builder")]
69-
impl crate::StructAsBytes for AddressHeaderTag {}

multiboot2-header/src/header/builder.rs renamed to multiboot2-header/src/builder/header.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
//! Exports item [`Multiboot2HeaderBuilder`].
22
3+
use crate::builder::information_request::InformationRequestHeaderTagBuilder;
4+
use crate::builder::traits::StructAsBytes;
35
use crate::HeaderTagISA;
46
use crate::{
57
AddressHeaderTag, ConsoleHeaderTag, EfiBootServiceHeaderTag, EndHeaderTag, EntryEfi32HeaderTag,
6-
EntryEfi64HeaderTag, EntryHeaderTag, FramebufferHeaderTag, InformationRequestHeaderTagBuilder,
7-
ModuleAlignHeaderTag, Multiboot2BasicHeader, RelocatableHeaderTag, StructAsBytes,
8+
EntryEfi64HeaderTag, EntryHeaderTag, FramebufferHeaderTag, ModuleAlignHeaderTag,
9+
Multiboot2BasicHeader, RelocatableHeaderTag,
810
};
911
use alloc::vec::Vec;
1012
use core::mem::size_of;
@@ -226,9 +228,10 @@ impl Multiboot2HeaderBuilder {
226228

227229
#[cfg(test)]
228230
mod tests {
231+
use crate::builder::header::Multiboot2HeaderBuilder;
232+
use crate::builder::information_request::InformationRequestHeaderTagBuilder;
229233
use crate::{
230-
HeaderTagFlag, HeaderTagISA, InformationRequestHeaderTagBuilder, MbiTagType,
231-
Multiboot2Header, Multiboot2HeaderBuilder, RelocatableHeaderTag,
234+
HeaderTagFlag, HeaderTagISA, MbiTagType, Multiboot2Header, RelocatableHeaderTag,
232235
RelocatableHeaderTagPreference,
233236
};
234237

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
use super::traits::StructAsBytes;
2+
use crate::InformationRequestHeaderTag;
3+
use crate::{HeaderTagFlag, MbiTagType};
4+
use alloc::collections::BTreeSet;
5+
use alloc::vec::Vec;
6+
use core::fmt::Debug;
7+
use core::mem::size_of;
8+
9+
/// Helper to build the dynamically sized [`InformationRequestHeaderTag`]
10+
/// at runtime. The information request tag has a dedicated builder because this way one
11+
/// can dynamically attach several requests to it. Otherwise, the number of requested tags
12+
/// must be known at compile time.
13+
#[derive(Debug)]
14+
#[cfg(feature = "builder")]
15+
pub struct InformationRequestHeaderTagBuilder {
16+
flag: HeaderTagFlag,
17+
// information requests (irs)
18+
irs: BTreeSet<MbiTagType>,
19+
}
20+
21+
#[cfg(feature = "builder")]
22+
impl InformationRequestHeaderTagBuilder {
23+
/// New builder.
24+
pub fn new(flag: HeaderTagFlag) -> Self {
25+
Self {
26+
irs: BTreeSet::new(),
27+
flag,
28+
}
29+
}
30+
31+
/// Returns the expected length of the information request tag,
32+
/// when the `build`-method gets called.
33+
pub fn expected_len(&self) -> usize {
34+
let basic_header_size = size_of::<InformationRequestHeaderTag<0>>();
35+
let req_tags_size = self.irs.len() * size_of::<MbiTagType>();
36+
basic_header_size + req_tags_size
37+
}
38+
39+
/// Adds an [`MbiTagType`] to the information request.
40+
pub fn add_ir(mut self, tag: MbiTagType) -> Self {
41+
self.irs.insert(tag);
42+
self
43+
}
44+
45+
/// Adds multiple [`MbiTagType`] to the information request.
46+
pub fn add_irs(mut self, tags: &[MbiTagType]) -> Self {
47+
self.irs.extend(tags);
48+
self
49+
}
50+
51+
/// Builds the bytes of the dynamically sized information request header.
52+
pub fn build(self) -> Vec<u8> {
53+
let expected_len = self.expected_len();
54+
let mut data = Vec::with_capacity(expected_len);
55+
56+
let basic_tag = InformationRequestHeaderTag::<0>::new(
57+
self.flag,
58+
[],
59+
// we put the expected length here already, because in the next step we write
60+
// all the tags into the byte array. We can't know this during compile time,
61+
// therefore N is 0.
62+
Some(expected_len as u32),
63+
);
64+
data.extend(basic_tag.struct_as_bytes());
65+
#[cfg(debug_assertions)]
66+
{
67+
let basic_tag_size = size_of::<InformationRequestHeaderTag<0>>();
68+
assert_eq!(
69+
data.len(),
70+
basic_tag_size,
71+
"the vector must be as long as the basic tag!"
72+
);
73+
}
74+
75+
for tag in &self.irs {
76+
let bytes: [u8; 4] = (*tag as u32).to_ne_bytes();
77+
data.extend(&bytes);
78+
}
79+
80+
debug_assert_eq!(
81+
data.len(),
82+
expected_len,
83+
"the byte vector must be as long as the expected size of the struct"
84+
);
85+
86+
data
87+
}
88+
}
89+
#[cfg(test)]
90+
mod tests {
91+
use crate::builder::information_request::InformationRequestHeaderTagBuilder;
92+
use crate::{HeaderTagFlag, InformationRequestHeaderTag, MbiTagType};
93+
94+
#[test]
95+
fn test_builder() {
96+
let builder = InformationRequestHeaderTagBuilder::new(HeaderTagFlag::Required)
97+
.add_ir(MbiTagType::EfiMmap)
98+
.add_ir(MbiTagType::BootLoaderName)
99+
.add_ir(MbiTagType::Cmdline);
100+
// type(u16) + flags(u16) + size(u32) + 3 tags (u32)
101+
assert_eq!(builder.expected_len(), 2 + 2 + 4 + 3 * 4);
102+
let tag = builder.build();
103+
let tag = unsafe {
104+
(tag.as_ptr() as *const InformationRequestHeaderTag<3>)
105+
.as_ref()
106+
.unwrap()
107+
};
108+
assert_eq!(tag.flags(), HeaderTagFlag::Required);
109+
// type(u16) + flags(u16) + size(u32) + 3 tags (u32)
110+
assert_eq!(tag.size(), 2 + 2 + 4 + 3 * 4);
111+
assert_eq!(tag.dynamic_requests_size(), 3);
112+
assert!(tag.requests().contains(&MbiTagType::EfiMmap));
113+
assert!(tag.requests().contains(&MbiTagType::BootLoaderName));
114+
assert!(tag.requests().contains(&MbiTagType::Cmdline));
115+
assert_eq!(tag.requests().len(), 3);
116+
assert!(!tag.requests().contains(&MbiTagType::AcpiV1));
117+
println!("{:#?}", tag);
118+
}
119+
}

multiboot2-header/src/builder/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
//! Module for the builder-feature.
2+
3+
mod header;
4+
mod information_request;
5+
pub(self) mod traits;
6+
7+
pub use header::Multiboot2HeaderBuilder;
8+
pub use information_request::InformationRequestHeaderTagBuilder;
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
use crate::{
2+
AddressHeaderTag, ConsoleHeaderTag, EfiBootServiceHeaderTag, EndHeaderTag, EntryEfi32HeaderTag,
3+
EntryEfi64HeaderTag, EntryHeaderTag, FramebufferHeaderTag, InformationRequestHeaderTag,
4+
ModuleAlignHeaderTag, Multiboot2BasicHeader, RelocatableHeaderTag,
5+
};
6+
use core::mem::size_of;
7+
8+
/// Trait for all tags that creates a byte array from the tag.
9+
/// Useful in builders to construct a byte vector that
10+
/// represents the Multiboot2 header with all its tags.
11+
pub(crate) trait StructAsBytes: Sized {
12+
/// Returns the size in bytes of the struct, as known during compile
13+
/// time. This doesn't use read the "size" field of tags.
14+
fn byte_size(&self) -> usize {
15+
size_of::<Self>()
16+
}
17+
18+
/// Returns a byte pointer to the begin of the struct.
19+
fn as_ptr(&self) -> *const u8 {
20+
self as *const Self as *const u8
21+
}
22+
23+
/// Returns the structure as a vector of its bytes.
24+
/// The length is determined by [`size`].
25+
fn struct_as_bytes(&self) -> alloc::vec::Vec<u8> {
26+
let ptr = self.as_ptr();
27+
let mut vec = alloc::vec::Vec::with_capacity(self.byte_size());
28+
for i in 0..self.byte_size() {
29+
vec.push(unsafe { *ptr.add(i) })
30+
}
31+
vec
32+
}
33+
}
34+
35+
impl StructAsBytes for AddressHeaderTag {}
36+
impl StructAsBytes for ConsoleHeaderTag {}
37+
impl StructAsBytes for EndHeaderTag {}
38+
impl StructAsBytes for EntryEfi32HeaderTag {}
39+
impl StructAsBytes for EntryEfi64HeaderTag {}
40+
impl StructAsBytes for EntryHeaderTag {}
41+
impl StructAsBytes for FramebufferHeaderTag {}
42+
impl StructAsBytes for InformationRequestHeaderTag<0> {}
43+
impl StructAsBytes for ModuleAlignHeaderTag {}
44+
impl StructAsBytes for RelocatableHeaderTag {}
45+
impl StructAsBytes for EfiBootServiceHeaderTag {}
46+
47+
impl StructAsBytes for Multiboot2BasicHeader {}
48+
49+
#[cfg(test)]
50+
mod tests {
51+
use super::*;
52+
53+
#[test]
54+
fn test_as_bytes() {
55+
struct Foobar {
56+
a: u32,
57+
b: u8,
58+
c: u128,
59+
}
60+
impl StructAsBytes for Foobar {}
61+
let foo = Foobar {
62+
a: 11,
63+
b: 22,
64+
c: 33,
65+
};
66+
let bytes = foo.struct_as_bytes();
67+
let foo_from_bytes = unsafe { (bytes.as_ptr() as *const Foobar).as_ref().unwrap() };
68+
assert_eq!(bytes.len(), size_of::<Foobar>());
69+
assert_eq!(foo.a, foo_from_bytes.a);
70+
assert_eq!(foo.b, foo_from_bytes.b);
71+
assert_eq!(foo.c, foo_from_bytes.c);
72+
}
73+
}

multiboot2-header/src/console.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,6 @@ impl ConsoleHeaderTag {
4646
}
4747
}
4848

49-
#[cfg(feature = "builder")]
50-
impl crate::StructAsBytes for ConsoleHeaderTag {}
51-
5249
#[cfg(test)]
5350
mod tests {
5451
use crate::{ConsoleHeaderTag, ConsoleHeaderTagFlags, HeaderTagFlag, HeaderTagType};

multiboot2-header/src/end.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,3 @@ impl EndHeaderTag {
3232
self.size
3333
}
3434
}
35-
36-
#[cfg(feature = "builder")]
37-
impl crate::StructAsBytes for EndHeaderTag {}

multiboot2-header/src/entry_efi_32.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,3 @@ impl Debug for EntryEfi32HeaderTag {
4949
.finish()
5050
}
5151
}
52-
53-
#[cfg(feature = "builder")]
54-
impl crate::StructAsBytes for EntryEfi32HeaderTag {}

multiboot2-header/src/entry_efi_64.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,3 @@ impl Debug for EntryEfi64HeaderTag {
4949
.finish()
5050
}
5151
}
52-
53-
#[cfg(feature = "builder")]
54-
impl crate::StructAsBytes for EntryEfi64HeaderTag {}

multiboot2-header/src/entry_header.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,3 @@ impl Debug for EntryHeaderTag {
4949
.finish()
5050
}
5151
}
52-
53-
#[cfg(feature = "builder")]
54-
impl crate::StructAsBytes for EntryHeaderTag {}

multiboot2-header/src/framebuffer.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,3 @@ impl FramebufferHeaderTag {
4747
self.depth
4848
}
4949
}
50-
51-
#[cfg(feature = "builder")]
52-
impl crate::StructAsBytes for FramebufferHeaderTag {}

multiboot2-header/src/header/mod.rs renamed to multiboot2-header/src/header.rs

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,8 @@
1-
//! Module for the main struct, which marks the begin of a Multiboot2 header.
2-
//! See [`Multiboot2Header`].
3-
4-
pub mod builder;
5-
6-
pub use self::builder::*;
7-
use crate::{AddressHeaderTag, InformationRequestHeaderTag, RelocatableHeaderTag};
8-
use crate::{ConsoleHeaderTag, EntryHeaderTag};
9-
use crate::{EfiBootServiceHeaderTag, FramebufferHeaderTag};
10-
use crate::{EndHeaderTag, HeaderTagType};
11-
use crate::{EntryEfi32HeaderTag, EntryEfi64HeaderTag};
12-
use crate::{HeaderTag, HeaderTagISA};
1+
use crate::{
2+
AddressHeaderTag, ConsoleHeaderTag, EfiBootServiceHeaderTag, EndHeaderTag, EntryEfi32HeaderTag,
3+
EntryEfi64HeaderTag, EntryHeaderTag, FramebufferHeaderTag, HeaderTag, HeaderTagISA,
4+
HeaderTagType, InformationRequestHeaderTag, RelocatableHeaderTag,
5+
};
136
use core::fmt::{Debug, Formatter};
147
use core::mem::size_of;
158

@@ -122,6 +115,7 @@ pub struct Multiboot2BasicHeader {
122115
}
123116

124117
impl Multiboot2BasicHeader {
118+
#[cfg(feature = "builder")]
125119
/// Constructor for the basic header.
126120
pub(crate) const fn new(arch: HeaderTagISA, length: u32) -> Self {
127121
let magic = MULTIBOOT2_HEADER_MAGIC;
@@ -194,9 +188,6 @@ impl Debug for Multiboot2BasicHeader {
194188
}
195189
}
196190

197-
#[cfg(feature = "builder")]
198-
impl crate::StructAsBytes for Multiboot2BasicHeader {}
199-
200191
/// Iterator over all tags of a Multiboot2 header. The number of items is derived
201192
/// by the size/length of the header.
202193
///

0 commit comments

Comments
 (0)