Skip to main content

multiboot2_header/
information_request.rs

1use crate::{HeaderTagFlag, HeaderTagHeader, HeaderTagType};
2use crate::{MbiTagType, MbiTagTypeRaw};
3use core::fmt;
4use core::fmt::{Debug, Formatter};
5#[cfg(feature = "builder")]
6use multiboot2_common::new_boxed;
7use multiboot2_common::{MaybeDynSized, Tag};
8#[cfg(feature = "builder")]
9use {alloc::boxed::Box, alloc::vec::Vec};
10
11/// Specifies which tag types the bootloader should provide
12/// inside the mbi.
13#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, ptr_meta::Pointee)]
14#[repr(C, align(8))]
15pub struct InformationRequestHeaderTag {
16    header: HeaderTagHeader,
17    requests: [MbiTagTypeRaw],
18}
19
20impl InformationRequestHeaderTag {
21    /// Creates a new object.
22    #[cfg(feature = "builder")]
23    #[must_use]
24    pub fn new(flags: HeaderTagFlag, requests: &[MbiTagType]) -> Box<Self> {
25        let header = HeaderTagHeader::new(HeaderTagType::InformationRequest, flags, 0);
26        let requests = requests
27            .iter()
28            .flat_map(|request| request.val().to_ne_bytes())
29            .collect::<Vec<_>>();
30        new_boxed(header, &[requests.as_slice()])
31    }
32
33    /// Returns the [`HeaderTagType`].
34    #[must_use]
35    pub const fn typ(&self) -> HeaderTagType {
36        self.header.typ()
37    }
38
39    /// Returns the [`HeaderTagFlag`]s.
40    #[must_use]
41    pub const fn flags(&self) -> HeaderTagFlag {
42        self.header.flags()
43    }
44
45    /// Returns the size.
46    #[must_use]
47    pub const fn size(&self) -> u32 {
48        self.header.size()
49    }
50
51    /// Returns an iterator over the requested tag types.
52    pub fn requests(&self) -> impl Iterator<Item = MbiTagType> + '_ {
53        self.requests.iter().map(|&raw| MbiTagType::from(raw))
54    }
55}
56
57/// Debug-formats the requests of an [`InformationRequestHeaderTag`] as a list
58/// of [`MbiTagType`].
59struct RequestsDebug<'a>(&'a InformationRequestHeaderTag);
60
61impl Debug for RequestsDebug<'_> {
62    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
63        f.debug_list().entries(self.0.requests()).finish()
64    }
65}
66
67impl Debug for InformationRequestHeaderTag {
68    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
69        f.debug_struct("InformationRequestHeaderTag")
70            .field("type", &self.typ())
71            .field("flags", &self.flags())
72            .field("size", &self.size())
73            .field("requests", &RequestsDebug(self))
74            .finish()
75    }
76}
77
78// SAFETY: The tag is repr(C) with the header as first field, any bit
79// pattern is valid, and `BASE_SIZE`/`dst_len` match the ABI.
80unsafe impl MaybeDynSized for InformationRequestHeaderTag {
81    type Header = HeaderTagHeader;
82
83    const BASE_SIZE: usize = size_of::<HeaderTagHeader>();
84
85    fn dst_len(header: &Self::Header) -> Self::Metadata {
86        assert!(header.size() as usize >= Self::BASE_SIZE);
87        let dst_size = header.size() as usize - Self::BASE_SIZE;
88        assert_eq!(dst_size % size_of::<MbiTagTypeRaw>(), 0);
89        dst_size / size_of::<MbiTagTypeRaw>()
90    }
91}
92
93impl Tag for InformationRequestHeaderTag {
94    type IDType = HeaderTagType;
95    const ID: HeaderTagType = HeaderTagType::InformationRequest;
96}
97
98#[cfg(test)]
99#[cfg(feature = "builder")]
100mod tests {
101    use super::*;
102
103    #[test]
104    #[should_panic]
105    fn dst_len_rejects_undersized_header() {
106        let header = HeaderTagHeader::new(
107            HeaderTagType::InformationRequest,
108            HeaderTagFlag::Optional,
109            4,
110        );
111        let _ = <InformationRequestHeaderTag as MaybeDynSized>::dst_len(&header);
112    }
113
114    #[test]
115    fn creation() {
116        let requests = [
117            MbiTagType::Cmdline,
118            MbiTagType::BootLoaderName,
119            MbiTagType::Module,
120            MbiTagType::BasicMeminfo,
121            MbiTagType::Bootdev,
122            MbiTagType::Mmap,
123            MbiTagType::Vbe,
124            MbiTagType::Framebuffer,
125            MbiTagType::ElfSections,
126            MbiTagType::Apm,
127            MbiTagType::Efi32,
128            MbiTagType::Efi64,
129            MbiTagType::Smbios,
130            MbiTagType::AcpiV1,
131            MbiTagType::AcpiV2,
132            MbiTagType::Network,
133            MbiTagType::EfiMmap,
134            MbiTagType::EfiBs,
135            MbiTagType::Efi32Ih,
136            MbiTagType::Efi64Ih,
137            MbiTagType::LoadBaseAddr,
138            MbiTagType::Custom(0x1337),
139        ];
140        // Statement also is a good test for Miri.
141        let ir = InformationRequestHeaderTag::new(HeaderTagFlag::Optional, &requests);
142        assert!(ir.requests().eq(requests.iter().copied()));
143    }
144}