Skip to content

Commit 3d250eb

Browse files
committed
multiboot2: Trait unification + API adjustments
This commit unifies the StructAsBytes and the TagTrait traits. Furthermore, it adds an associated constant to the TagTrait. This way, the get_tag function can get the ID from directly from the type and the user doesn't have to provide a parameter anymore.
1 parent c0d0d6e commit 3d250eb

17 files changed

+247
-359
lines changed

multiboot2/Changelog.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# CHANGELOG for crate `multiboot2`
22

3+
## 0.18.0 (2023-xx-xx)
4+
- **BREAKING** The `TagTrait` was enhanced and now has an associated `ID`
5+
constant. This is only breaking to users that used `BootInformation::get_tag`
6+
or that implement custom tags. `BootInformation::get_tag` doesn't need the
7+
`typ` parameter anymore, as it can be deduced from the provided type.
8+
39
## 0.17.0 (2023-07-12)
410
- **BREAKING** Make functions of `InformationBuilder` chainable. They now consume the builder.
511
- **BREAKING** Allow non-standard memory area types by using new pair of

multiboot2/src/boot_loader_name.rs

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
1-
use crate::{Tag, TagTrait, TagTypeId};
1+
use crate::{Tag, TagTrait, TagType, TagTypeId};
22
use core::fmt::{Debug, Formatter};
33
use core::mem::size_of;
44
use core::str::Utf8Error;
5-
65
#[cfg(feature = "builder")]
7-
use {
8-
crate::builder::traits::StructAsBytes, crate::builder::BoxedDst, crate::TagType,
9-
alloc::vec::Vec,
10-
};
6+
use {crate::builder::BoxedDst, alloc::vec::Vec};
117

128
const METADATA_SIZE: usize = size_of::<TagTypeId>() + size_of::<u32>();
139

@@ -63,22 +59,17 @@ impl Debug for BootLoaderNameTag {
6359
}
6460

6561
impl TagTrait for BootLoaderNameTag {
62+
const ID: TagType = TagType::BootLoaderName;
63+
6664
fn dst_size(base_tag: &Tag) -> usize {
6765
assert!(base_tag.size as usize >= METADATA_SIZE);
6866
base_tag.size as usize - METADATA_SIZE
6967
}
7068
}
7169

72-
#[cfg(feature = "builder")]
73-
impl StructAsBytes for BootLoaderNameTag {
74-
fn byte_size(&self) -> usize {
75-
self.size.try_into().unwrap()
76-
}
77-
}
78-
7970
#[cfg(test)]
8071
mod tests {
81-
use crate::{BootLoaderNameTag, Tag, TagType};
72+
use crate::{BootLoaderNameTag, Tag, TagTrait, TagType};
8273

8374
const MSG: &str = "hello";
8475

@@ -114,10 +105,8 @@ mod tests {
114105
#[test]
115106
#[cfg(feature = "builder")]
116107
fn test_build_str() {
117-
use crate::builder::traits::StructAsBytes;
118-
119108
let tag = BootLoaderNameTag::new(MSG);
120-
let bytes = tag.struct_as_bytes();
109+
let bytes = tag.as_bytes();
121110
assert_eq!(bytes, get_bytes());
122111
assert_eq!(tag.name(), Ok(MSG));
123112

multiboot2/src/builder/information.rs

Lines changed: 53 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,26 @@
11
//! Exports item [`InformationBuilder`].
2-
use crate::builder::traits::StructAsBytes;
32
use crate::{
43
BasicMemoryInfoTag, BootInformationHeader, BootLoaderNameTag, CommandLineTag,
54
EFIBootServicesNotExitedTag, EFIImageHandle32Tag, EFIImageHandle64Tag, EFIMemoryMapTag,
65
EFISdt32Tag, EFISdt64Tag, ElfSectionsTag, EndTag, FramebufferTag, ImageLoadPhysAddrTag,
7-
MemoryMapTag, ModuleTag, RsdpV1Tag, RsdpV2Tag, SmbiosTag,
6+
MemoryMapTag, ModuleTag, RsdpV1Tag, RsdpV2Tag, SmbiosTag, TagTrait, TagType,
87
};
98

109
use crate::builder::BoxedDst;
1110
use alloc::vec::Vec;
1211
use core::mem::size_of;
1312
use core::ops::Deref;
1413

14+
/// Helper trait for all structs that need to be serialized that do not
15+
/// implement `TagTrait`.
16+
pub trait AsBytes: Sized {
17+
fn as_bytes(&self) -> &[u8] {
18+
let ptr = core::ptr::addr_of!(*self);
19+
let size = core::mem::size_of::<Self>();
20+
unsafe { core::slice::from_raw_parts(ptr.cast(), size) }
21+
}
22+
}
23+
1524
/// Holds the raw bytes of a boot information built with [`InformationBuilder`]
1625
/// on the heap. The bytes returned by [`BootInformationBytes::as_bytes`] are
1726
/// guaranteed to be properly aligned.
@@ -107,71 +116,74 @@ impl InformationBuilder {
107116
let mut len = Self::size_or_up_aligned(base_len);
108117
if let Some(tag) = &self.basic_memory_info_tag {
109118
// we use size_or_up_aligned, because each tag will start at an 8 byte aligned address
110-
len += Self::size_or_up_aligned(tag.byte_size())
119+
len += Self::size_or_up_aligned(tag.size())
111120
}
112121
if let Some(tag) = &self.boot_loader_name_tag {
113-
len += Self::size_or_up_aligned(tag.byte_size())
122+
len += Self::size_or_up_aligned(tag.size())
114123
}
115124
if let Some(tag) = &self.command_line_tag {
116-
len += Self::size_or_up_aligned(tag.byte_size())
125+
len += Self::size_or_up_aligned(tag.size())
117126
}
118127
if let Some(tag) = &self.efisdt32_tag {
119-
len += Self::size_or_up_aligned(tag.byte_size())
128+
len += Self::size_or_up_aligned(tag.size())
120129
}
121130
if let Some(tag) = &self.efisdt64_tag {
122-
len += Self::size_or_up_aligned(tag.byte_size())
131+
len += Self::size_or_up_aligned(tag.size())
123132
}
124133
if let Some(tag) = &self.efi_boot_services_not_exited_tag {
125-
len += Self::size_or_up_aligned(tag.byte_size())
134+
len += Self::size_or_up_aligned(tag.size())
126135
}
127136
if let Some(tag) = &self.efi_image_handle32 {
128-
len += Self::size_or_up_aligned(tag.byte_size())
137+
len += Self::size_or_up_aligned(tag.size())
129138
}
130139
if let Some(tag) = &self.efi_image_handle64 {
131-
len += Self::size_or_up_aligned(tag.byte_size())
140+
len += Self::size_or_up_aligned(tag.size())
132141
}
133142
if let Some(tag) = &self.efi_memory_map_tag {
134-
len += Self::size_or_up_aligned(tag.byte_size())
143+
len += Self::size_or_up_aligned(tag.size())
135144
}
136145
if let Some(tag) = &self.elf_sections_tag {
137-
len += Self::size_or_up_aligned(tag.byte_size())
146+
len += Self::size_or_up_aligned(tag.size())
138147
}
139148
if let Some(tag) = &self.framebuffer_tag {
140-
len += Self::size_or_up_aligned(tag.byte_size())
149+
len += Self::size_or_up_aligned(tag.size())
141150
}
142151
if let Some(tag) = &self.image_load_addr {
143-
len += Self::size_or_up_aligned(tag.byte_size())
152+
len += Self::size_or_up_aligned(tag.size())
144153
}
145154
if let Some(tag) = &self.memory_map_tag {
146-
len += Self::size_or_up_aligned(tag.byte_size())
155+
len += Self::size_or_up_aligned(tag.size())
147156
}
148157
for tag in &self.module_tags {
149-
len += Self::size_or_up_aligned(tag.byte_size())
158+
len += Self::size_or_up_aligned(tag.size())
150159
}
151160
if let Some(tag) = &self.rsdp_v1_tag {
152-
len += Self::size_or_up_aligned(tag.byte_size())
161+
len += Self::size_or_up_aligned(tag.size())
153162
}
154163
if let Some(tag) = &self.rsdp_v2_tag {
155-
len += Self::size_or_up_aligned(tag.byte_size())
164+
len += Self::size_or_up_aligned(tag.size())
156165
}
157166
for tag in &self.smbios_tags {
158-
len += Self::size_or_up_aligned(tag.byte_size())
167+
len += Self::size_or_up_aligned(tag.size())
159168
}
160169
// only here size_or_up_aligned is not important, because it is the last tag
161170
len += size_of::<EndTag>();
162171
len
163172
}
164173

165174
/// Adds the bytes of a tag to the final Multiboot2 information byte vector.
166-
fn build_add_bytes(dest: &mut Vec<u8>, source: &[u8], is_end_tag: bool) {
175+
fn build_add_tag<T: TagTrait + ?Sized>(dest: &mut Vec<u8>, source: &T) {
167176
let vec_next_write_ptr = unsafe { dest.as_ptr().add(dest.len()) };
168177
// At this point, the alignment is guaranteed. If not, something is
169178
// broken fundamentally.
170179
assert_eq!(vec_next_write_ptr.align_offset(8), 0);
171180

172-
dest.extend(source);
181+
dest.extend(source.as_bytes());
182+
183+
let is_end_tag = source.as_base_tag().typ == TagType::End;
184+
173185
if !is_end_tag {
174-
let size = source.len();
186+
let size = source.size();
175187
let size_to_8_align = Self::size_or_up_aligned(size);
176188
let size_to_8_align_diff = size_to_8_align - size;
177189
// fill zeroes so that next data block is 8-byte aligned
@@ -205,6 +217,7 @@ impl InformationBuilder {
205217

206218
// -----------------------------------------------
207219
// PHASE 2/2: Add Tags
220+
bytes.extend(BootInformationHeader::new(self.expected_len() as u32).as_bytes());
208221
self.build_add_tags(&mut bytes);
209222

210223
assert_eq!(
@@ -227,64 +240,58 @@ impl InformationBuilder {
227240

228241
/// Helper method that adds all the tags to the given vector.
229242
fn build_add_tags(&self, bytes: &mut Vec<u8>) {
230-
Self::build_add_bytes(
231-
bytes,
232-
// important that we write the correct expected length into the header!
233-
&BootInformationHeader::new(self.expected_len() as u32).struct_as_bytes(),
234-
false,
235-
);
236243
if let Some(tag) = self.basic_memory_info_tag.as_ref() {
237-
Self::build_add_bytes(bytes, &tag.struct_as_bytes(), false)
244+
Self::build_add_tag(bytes, tag)
238245
}
239246
if let Some(tag) = self.boot_loader_name_tag.as_ref() {
240-
Self::build_add_bytes(bytes, &tag.struct_as_bytes(), false)
247+
Self::build_add_tag(bytes, &**tag)
241248
}
242249
if let Some(tag) = self.command_line_tag.as_ref() {
243-
Self::build_add_bytes(bytes, &tag.struct_as_bytes(), false)
250+
Self::build_add_tag(bytes, &**tag)
244251
}
245252
if let Some(tag) = self.efisdt32_tag.as_ref() {
246-
Self::build_add_bytes(bytes, &tag.struct_as_bytes(), false)
253+
Self::build_add_tag(bytes, tag)
247254
}
248255
if let Some(tag) = self.efisdt64_tag.as_ref() {
249-
Self::build_add_bytes(bytes, &tag.struct_as_bytes(), false)
256+
Self::build_add_tag(bytes, tag)
250257
}
251258
if let Some(tag) = self.efi_boot_services_not_exited_tag.as_ref() {
252-
Self::build_add_bytes(bytes, &tag.struct_as_bytes(), false)
259+
Self::build_add_tag(bytes, tag)
253260
}
254261
if let Some(tag) = self.efi_image_handle32.as_ref() {
255-
Self::build_add_bytes(bytes, &tag.struct_as_bytes(), false)
262+
Self::build_add_tag(bytes, tag)
256263
}
257264
if let Some(tag) = self.efi_image_handle64.as_ref() {
258-
Self::build_add_bytes(bytes, &tag.struct_as_bytes(), false)
265+
Self::build_add_tag(bytes, tag)
259266
}
260267
if let Some(tag) = self.efi_memory_map_tag.as_ref() {
261-
Self::build_add_bytes(bytes, &tag.struct_as_bytes(), false)
268+
Self::build_add_tag(bytes, &**tag)
262269
}
263270
if let Some(tag) = self.elf_sections_tag.as_ref() {
264-
Self::build_add_bytes(bytes, &tag.struct_as_bytes(), false)
271+
Self::build_add_tag(bytes, &**tag)
265272
}
266273
if let Some(tag) = self.framebuffer_tag.as_ref() {
267-
Self::build_add_bytes(bytes, &tag.struct_as_bytes(), false)
274+
Self::build_add_tag(bytes, &**tag)
268275
}
269276
if let Some(tag) = self.image_load_addr.as_ref() {
270-
Self::build_add_bytes(bytes, &tag.struct_as_bytes(), false)
277+
Self::build_add_tag(bytes, tag)
271278
}
272279
if let Some(tag) = self.memory_map_tag.as_ref() {
273-
Self::build_add_bytes(bytes, &tag.struct_as_bytes(), false)
280+
Self::build_add_tag(bytes, &**tag)
274281
}
275282
for tag in &self.module_tags {
276-
Self::build_add_bytes(bytes, &tag.struct_as_bytes(), false)
283+
Self::build_add_tag(bytes, &**tag)
277284
}
278285
if let Some(tag) = self.rsdp_v1_tag.as_ref() {
279-
Self::build_add_bytes(bytes, &tag.struct_as_bytes(), false)
286+
Self::build_add_tag(bytes, tag)
280287
}
281288
if let Some(tag) = self.rsdp_v2_tag.as_ref() {
282-
Self::build_add_bytes(bytes, &tag.struct_as_bytes(), false)
289+
Self::build_add_tag(bytes, tag)
283290
}
284291
for tag in &self.smbios_tags {
285-
Self::build_add_bytes(bytes, &tag.struct_as_bytes(), false)
292+
Self::build_add_tag(bytes, &**tag)
286293
}
287-
Self::build_add_bytes(bytes, &EndTag::default().struct_as_bytes(), true);
294+
Self::build_add_tag(bytes, &EndTag::default());
288295
}
289296

290297
/// Adds a 'basic memory information' tag (represented by [`BasicMemoryInfoTag`]) to the builder.

multiboot2/src/builder/mod.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! Module for the builder-feature.
22
33
mod information;
4-
pub(crate) mod traits;
54

5+
pub(crate) use information::AsBytes;
66
pub use information::InformationBuilder;
77

88
use alloc::alloc::alloc;
@@ -110,6 +110,7 @@ impl<T: ?Sized + PartialEq> PartialEq for BoxedDst<T> {
110110
#[cfg(test)]
111111
mod tests {
112112
use super::*;
113+
use crate::TagType;
113114

114115
const METADATA_SIZE: usize = 8;
115116

@@ -128,6 +129,8 @@ mod tests {
128129
}
129130

130131
impl TagTrait for CustomTag {
132+
const ID: TagType = TagType::Custom(0x1337);
133+
131134
fn dst_size(base_tag: &Tag) -> usize {
132135
assert!(base_tag.size as usize >= METADATA_SIZE);
133136
base_tag.size as usize - METADATA_SIZE

multiboot2/src/builder/traits.rs

Lines changed: 0 additions & 26 deletions
This file was deleted.

multiboot2/src/command_line.rs

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
//! Module for [CommandLineTag].
22
3-
use crate::{Tag, TagTrait, TagTypeId};
3+
use crate::{Tag, TagTrait, TagType, TagTypeId};
44

55
use core::fmt::{Debug, Formatter};
66
use core::mem;
77
use core::str;
88

99
#[cfg(feature = "builder")]
10-
use {
11-
crate::builder::traits::StructAsBytes, crate::builder::BoxedDst, crate::TagType,
12-
alloc::vec::Vec, core::convert::TryInto,
13-
};
10+
use {crate::builder::BoxedDst, alloc::vec::Vec};
1411

1512
pub(crate) const METADATA_SIZE: usize = mem::size_of::<TagTypeId>() + mem::size_of::<u32>();
1613

@@ -72,22 +69,17 @@ impl Debug for CommandLineTag {
7269
}
7370

7471
impl TagTrait for CommandLineTag {
72+
const ID: TagType = TagType::Cmdline;
73+
7574
fn dst_size(base_tag: &Tag) -> usize {
7675
assert!(base_tag.size as usize >= METADATA_SIZE);
7776
base_tag.size as usize - METADATA_SIZE
7877
}
7978
}
8079

81-
#[cfg(feature = "builder")]
82-
impl StructAsBytes for CommandLineTag {
83-
fn byte_size(&self) -> usize {
84-
self.size.try_into().unwrap()
85-
}
86-
}
87-
8880
#[cfg(test)]
8981
mod tests {
90-
use crate::{CommandLineTag, Tag, TagType};
82+
use super::*;
9183

9284
const MSG: &str = "hello";
9385

@@ -123,10 +115,8 @@ mod tests {
123115
#[test]
124116
#[cfg(feature = "builder")]
125117
fn test_build_str() {
126-
use crate::builder::traits::StructAsBytes;
127-
128118
let tag = CommandLineTag::new(MSG);
129-
let bytes = tag.struct_as_bytes();
119+
let bytes = tag.as_bytes();
130120
assert_eq!(bytes, get_bytes());
131121
assert_eq!(tag.cmdline(), Ok(MSG));
132122

0 commit comments

Comments
 (0)