1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use crate::{HeaderTagFlag, HeaderTagHeader};
use crate::{HeaderTagType, MbiTagTypeId};
use core::fmt;
use core::fmt::{Debug, Formatter};
use core::mem;
#[cfg(feature = "builder")]
use multiboot2_common::new_boxed;
use multiboot2_common::{MaybeDynSized, Tag};
#[cfg(feature = "builder")]
use {
    alloc::boxed::Box,
    core::{ptr, slice},
};

/// Specifies what specific tag types the bootloader should provide
/// inside the mbi.
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, ptr_meta::Pointee)]
#[repr(C, align(8))]
pub struct InformationRequestHeaderTag {
    header: HeaderTagHeader,
    requests: [MbiTagTypeId],
}

impl InformationRequestHeaderTag {
    /// Creates a new object.
    #[cfg(feature = "builder")]
    #[must_use]
    pub fn new(flags: HeaderTagFlag, requests: &[MbiTagTypeId]) -> Box<Self> {
        let header = HeaderTagHeader::new(HeaderTagType::InformationRequest, flags, 0);
        let requests = unsafe {
            let ptr = ptr::addr_of!(*requests);
            slice::from_raw_parts(ptr.cast::<u8>(), mem::size_of_val(requests))
        };
        new_boxed(header, &[requests])
    }

    /// Returns the [`HeaderTagType`].
    #[must_use]
    pub const fn typ(&self) -> HeaderTagType {
        self.header.typ()
    }

    /// Returns the [`HeaderTagFlag`]s.
    #[must_use]
    pub const fn flags(&self) -> HeaderTagFlag {
        self.header.flags()
    }

    /// Returns the size.
    #[must_use]
    pub const fn size(&self) -> u32 {
        self.header.size()
    }

    /// Returns the requests as array
    #[must_use]
    pub const fn requests(&self) -> &[MbiTagTypeId] {
        &self.requests
    }
}

impl Debug for InformationRequestHeaderTag {
    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
        f.debug_struct("InformationRequestHeaderTag")
            .field("type", &self.typ())
            .field("flags", &self.flags())
            .field("size", &self.size())
            .field("requests", &self.requests())
            .finish()
    }
}

impl MaybeDynSized for InformationRequestHeaderTag {
    type Header = HeaderTagHeader;

    const BASE_SIZE: usize = mem::size_of::<HeaderTagHeader>();

    fn dst_len(header: &Self::Header) -> Self::Metadata {
        let dst_size = header.size() as usize - Self::BASE_SIZE;
        assert_eq!(dst_size % mem::size_of::<MbiTagTypeId>(), 0);
        dst_size / mem::size_of::<MbiTagTypeId>()
    }
}

impl Tag for InformationRequestHeaderTag {
    type IDType = HeaderTagType;
    const ID: HeaderTagType = HeaderTagType::InformationRequest;
}

#[cfg(test)]
#[cfg(feature = "builder")]
mod tests {
    use super::*;
    use crate::MbiTagType;

    #[test]
    fn creation() {
        // Main objective here is to satisfy Miri.
        let _ir = InformationRequestHeaderTag::new(
            HeaderTagFlag::Optional,
            &[
                MbiTagType::Cmdline.into(),
                MbiTagType::BootLoaderName.into(),
                MbiTagType::Module.into(),
                MbiTagType::BasicMeminfo.into(),
                MbiTagType::Bootdev.into(),
                MbiTagType::Mmap.into(),
                MbiTagType::Vbe.into(),
                MbiTagType::Framebuffer.into(),
                MbiTagType::ElfSections.into(),
                MbiTagType::Apm.into(),
                MbiTagType::Efi32.into(),
                MbiTagType::Efi64.into(),
                MbiTagType::Smbios.into(),
                MbiTagType::AcpiV1.into(),
                MbiTagType::AcpiV2.into(),
                MbiTagType::Network.into(),
                MbiTagType::EfiMmap.into(),
                MbiTagType::EfiBs.into(),
                MbiTagType::Efi32Ih.into(),
                MbiTagType::Efi64Ih.into(),
                MbiTagType::LoadBaseAddr.into(),
                MbiTagType::Custom(0x1337).into(),
            ],
        );
    }
}