Skip to content

Commit b24f54d

Browse files
committed
multiboot2: expose get_tag publicly to allow custom tags
1 parent d2aabc8 commit b24f54d

File tree

3 files changed

+68
-20
lines changed

3 files changed

+68
-20
lines changed

multiboot2/src/lib.rs

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,17 @@ pub use memory_map::{
5555
};
5656
pub use module::{ModuleIter, ModuleTag};
5757
pub use rsdp::{RsdpV1Tag, RsdpV2Tag};
58-
pub use tag_type::TagType;
59-
use tag_type::{Tag, TagIter};
58+
pub use tag_type::Tag;
6059
pub use vbe_info::{
6160
VBECapabilities, VBEControlInfo, VBEDirectColorAttributes, VBEField, VBEInfoTag,
6261
VBEMemoryModel, VBEModeAttributes, VBEModeInfo, VBEWindowAttributes,
6362
};
63+
pub use {
64+
tag_type::SpecifiedOrCustomTagType, tag_type::SpecifiedOrCustomTagTypeSerialized,
65+
tag_type::TagType,
66+
};
67+
68+
use tag_type::TagIter;
6469

6570
#[macro_use]
6671
extern crate bitflags;
@@ -308,8 +313,41 @@ impl BootInformation {
308313
unsafe { &*self.inner }
309314
}
310315

311-
fn get_tag(&self, typ: TagType) -> Option<&Tag> {
312-
self.tags().find(|tag| tag.typ == typ)
316+
/// Public getter to find any tag type you are looking for.
317+
///
318+
/// # Specified or Custom Tags
319+
/// The Multiboot2 specification specifies a list of tags, see [`TagType`]. However, it doesn't
320+
/// forbid to use custom tags. Because of this, there exists the [`SpecifiedOrCustomTagType`]
321+
/// abstraction. **It is recommended** to use this getter only for custom tags. For specified
322+
/// tags, use getters, such as [`Self::efi_64_ih`].
323+
///
324+
/// ## Use Custom Tags
325+
/// The following example shows how you may use this interface to parse custom tags from
326+
/// the MBI.
327+
///
328+
/// ```ignore
329+
/// use multiboot2::SpecifiedOrCustomTagTypeSerialized;
330+
/// #[repr(C, align(8))]
331+
/// struct CustomTag {
332+
/// // new type from the lib: has repr(u32)
333+
/// tag: SpecifiedOrCustomTagTypeSerialized,
334+
/// size: u32,
335+
/// // begin of inline string
336+
/// name: u8,
337+
/// }
338+
///
339+
/// let tag = bi
340+
/// // this function is now public!
341+
/// .get_tag(0x1337.into())
342+
/// .unwrap()
343+
/// // type definition from end user. must be Sized!
344+
/// .cast_tag::<CustomTag>();
345+
/// let name = &tag.name as *const u8 as *const c_char;
346+
/// let str = unsafe { CStr::from_ptr(name).to_str().unwrap() };
347+
/// assert_eq!(str, "name");
348+
/// ```
349+
pub fn get_tag(&self, typ: SpecifiedOrCustomTagType) -> Option<&Tag> {
350+
self.tags().find(|tag: &&Tag| tag.typ == typ)
313351
}
314352

315353
fn tags(&self) -> TagIter {
@@ -319,16 +357,16 @@ impl BootInformation {
319357

320358
impl BootInformationInner {
321359
fn has_valid_end_tag(&self) -> bool {
322-
const END_TAG: Tag = Tag {
323-
typ: TagType::End,
360+
let end_tag_prototype: Tag = Tag {
361+
typ: TagType::End.into(),
324362
size: 8,
325363
};
326364

327365
let self_ptr = self as *const _;
328-
let end_tag_addr = self_ptr as usize + (self.total_size - END_TAG.size) as usize;
366+
let end_tag_addr = self_ptr as usize + (self.total_size - end_tag_prototype.size) as usize;
329367
let end_tag = unsafe { &*(end_tag_addr as *const Tag) };
330368

331-
end_tag.typ == END_TAG.typ && end_tag.size == END_TAG.size
369+
end_tag.typ == end_tag_prototype.typ && end_tag.size == end_tag_prototype.size
332370
}
333371
}
334372

@@ -437,6 +475,7 @@ impl Reader {
437475
#[cfg(test)]
438476
mod tests {
439477
use super::*;
478+
use std::ffi::{c_char, CStr};
440479

441480
#[test]
442481
fn no_tags() {

multiboot2/src/module.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ impl<'a> Iterator for ModuleIter<'a> {
7575

7676
fn next(&mut self) -> Option<&'a ModuleTag> {
7777
self.iter
78-
.find(|x| x.typ == TagType::Module)
78+
.find(|tag| tag.typ == TagType::Module)
7979
.map(|tag| unsafe { &*(tag as *const Tag as *const ModuleTag) })
8080
}
8181
}

multiboot2/src/tag_type.rs

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -345,15 +345,16 @@ impl TagType {
345345
pub const MAX_INDEX: u32 = 21;
346346
}
347347

348-
/// All tags that could passed via the Multiboot2 information structure to a payload/program/kernel.
349-
/// Better not confuse this with the Multiboot2 header tags. They are something different.
348+
/// Common base structure for all tags that can be passed via the Multiboot2 information structure
349+
/// (MBI) to a Multiboot2 payload/program/kernel.
350+
///
351+
/// Do not confuse them with the Multiboot2 header tags. They are something different.
350352
#[derive(Clone, Copy)]
351353
#[repr(C)]
352354
pub struct Tag {
353-
// u32 value
354-
pub typ: TagType,
355+
pub typ: SpecifiedOrCustomTagTypeSerialized, // u32
355356
pub size: u32,
356-
// tag specific fields
357+
// additional, tag specific fields
357358
}
358359

359360
impl Tag {
@@ -365,11 +366,18 @@ impl Tag {
365366

366367
impl Debug for Tag {
367368
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
368-
f.debug_struct("Tag")
369-
.field("typ", &self.typ)
370-
.field("typ (numeric)", &(self.typ as u32))
371-
.field("size", &(self.size))
372-
.finish()
369+
let tag_type = SpecifiedOrCustomTagType::from(self.typ);
370+
371+
let mut debug = f.debug_struct("Tag");
372+
debug.field("typ", &tag_type);
373+
374+
if matches!(tag_type, SpecifiedOrCustomTagType::Specified(_)) {
375+
debug.field("typ (numeric)", &(u32::from(self.typ)));
376+
}
377+
378+
debug.field("size", &(self.size));
379+
380+
debug.finish()
373381
}
374382
}
375383

@@ -394,7 +402,8 @@ impl<'a> Iterator for TagIter<'a> {
394402
fn next(&mut self) -> Option<&'a Tag> {
395403
match unsafe { &*self.current } {
396404
&Tag {
397-
typ: TagType::End,
405+
// END-Tag
406+
typ: SpecifiedOrCustomTagTypeSerialized(0),
398407
size: 8,
399408
} => None, // end tag
400409
tag => {

0 commit comments

Comments
 (0)