1use crate::{
4 AddressHeaderTag, ConsoleHeaderTag, EfiBootServiceHeaderTag, EndHeaderTag,
5 EntryAddressHeaderTag, EntryEfi32HeaderTag, EntryEfi64HeaderTag, FramebufferHeaderTag,
6 HeaderTagISA, InformationRequestHeaderTag, ModuleAlignHeaderTag, Multiboot2BasicHeader,
7 RelocatableHeaderTag,
8};
9use alloc::boxed::Box;
10use alloc::vec::Vec;
11use multiboot2_common::{DynSizedStructure, MaybeDynSized, increase_to_alignment, new_boxed};
12
13#[derive(Debug)]
15pub struct Builder {
16 arch: HeaderTagISA,
17 information_request_tag: Option<Box<InformationRequestHeaderTag>>,
18 address_tag: Option<AddressHeaderTag>,
19 entry_tag: Option<EntryAddressHeaderTag>,
20 console_tag: Option<ConsoleHeaderTag>,
21 framebuffer_tag: Option<FramebufferHeaderTag>,
22 module_align_tag: Option<ModuleAlignHeaderTag>,
23 efi_bs_tag: Option<EfiBootServiceHeaderTag>,
24 efi_32_tag: Option<EntryEfi32HeaderTag>,
25 efi_64_tag: Option<EntryEfi64HeaderTag>,
26 relocatable_tag: Option<RelocatableHeaderTag>,
27 }
29
30impl Builder {
31 #[must_use]
33 pub const fn new(arch: HeaderTagISA) -> Self {
34 Self {
35 arch,
36 information_request_tag: None,
37 address_tag: None,
38 entry_tag: None,
39 console_tag: None,
40 framebuffer_tag: None,
41 module_align_tag: None,
42 efi_bs_tag: None,
43 efi_32_tag: None,
44 efi_64_tag: None,
45 relocatable_tag: None,
46 }
47 }
48
49 #[must_use]
51 pub fn information_request_tag(
52 mut self,
53 information_request_tag: Box<InformationRequestHeaderTag>,
54 ) -> Self {
55 self.information_request_tag = Some(information_request_tag);
56 self
57 }
58
59 #[must_use]
61 pub const fn address_tag(mut self, address_tag: AddressHeaderTag) -> Self {
62 self.address_tag = Some(address_tag);
63 self
64 }
65
66 #[must_use]
68 pub const fn entry_tag(mut self, entry_tag: EntryAddressHeaderTag) -> Self {
69 self.entry_tag = Some(entry_tag);
70 self
71 }
72
73 #[must_use]
75 pub const fn console_tag(mut self, console_tag: ConsoleHeaderTag) -> Self {
76 self.console_tag = Some(console_tag);
77 self
78 }
79
80 #[must_use]
82 pub const fn framebuffer_tag(mut self, framebuffer_tag: FramebufferHeaderTag) -> Self {
83 self.framebuffer_tag = Some(framebuffer_tag);
84 self
85 }
86
87 #[must_use]
89 pub const fn module_align_tag(mut self, module_align_tag: ModuleAlignHeaderTag) -> Self {
90 self.module_align_tag = Some(module_align_tag);
91 self
92 }
93
94 #[must_use]
96 pub const fn efi_bs_tag(mut self, efi_bs_tag: EfiBootServiceHeaderTag) -> Self {
97 self.efi_bs_tag = Some(efi_bs_tag);
98 self
99 }
100
101 #[must_use]
103 pub const fn efi_32_tag(mut self, efi_32_tag: EntryEfi32HeaderTag) -> Self {
104 self.efi_32_tag = Some(efi_32_tag);
105 self
106 }
107
108 #[must_use]
110 pub const fn efi_64_tag(mut self, efi_64_tag: EntryEfi64HeaderTag) -> Self {
111 self.efi_64_tag = Some(efi_64_tag);
112 self
113 }
114
115 #[must_use]
117 pub const fn relocatable_tag(mut self, relocatable_tag: RelocatableHeaderTag) -> Self {
118 self.relocatable_tag = Some(relocatable_tag);
119 self
120 }
121
122 #[must_use]
125 pub fn build(self) -> Box<DynSizedStructure<Multiboot2BasicHeader>> {
126 fn fill_zeroes_to_alignment(vec: &mut Vec<u8>) {
127 let pad = increase_to_alignment(vec.len()) - vec.len();
128 for _ in 0..pad {
129 vec.push(0);
130 }
131 }
132
133 let header = Multiboot2BasicHeader::new(self.arch, 0);
134 let mut buffer_tags = Vec::<u8>::new();
137 if let Some(tag) = self.information_request_tag.as_ref() {
138 buffer_tags.extend_from_slice(tag.as_bytes());
139 fill_zeroes_to_alignment(&mut buffer_tags);
140 }
141 if let Some(tag) = self.address_tag.as_ref() {
142 buffer_tags.extend_from_slice(tag.as_bytes());
143 fill_zeroes_to_alignment(&mut buffer_tags);
144 }
145 if let Some(tag) = self.entry_tag.as_ref() {
146 buffer_tags.extend_from_slice(tag.as_bytes());
147 fill_zeroes_to_alignment(&mut buffer_tags);
148 }
149 if let Some(tag) = self.console_tag.as_ref() {
150 buffer_tags.extend_from_slice(tag.as_bytes());
151 fill_zeroes_to_alignment(&mut buffer_tags);
152 }
153 if let Some(tag) = self.framebuffer_tag.as_ref() {
154 buffer_tags.extend_from_slice(tag.as_bytes());
155 fill_zeroes_to_alignment(&mut buffer_tags);
156 }
157 if let Some(tag) = self.module_align_tag.as_ref() {
158 buffer_tags.extend_from_slice(tag.as_bytes());
159 fill_zeroes_to_alignment(&mut buffer_tags);
160 }
161 if let Some(tag) = self.efi_bs_tag.as_ref() {
162 buffer_tags.extend_from_slice(tag.as_bytes());
163 fill_zeroes_to_alignment(&mut buffer_tags);
164 }
165 if let Some(tag) = self.efi_32_tag.as_ref() {
166 buffer_tags.extend_from_slice(tag.as_bytes());
167 fill_zeroes_to_alignment(&mut buffer_tags);
168 }
169 if let Some(tag) = self.efi_64_tag.as_ref() {
170 buffer_tags.extend_from_slice(tag.as_bytes());
171 fill_zeroes_to_alignment(&mut buffer_tags);
172 }
173 if let Some(tag) = self.relocatable_tag.as_ref() {
174 buffer_tags.extend_from_slice(tag.as_bytes());
175 fill_zeroes_to_alignment(&mut buffer_tags);
176 }
177 let end_tag = EndHeaderTag::new();
179
180 buffer_tags.extend_from_slice(end_tag.as_bytes());
181 new_boxed(header, &[buffer_tags.as_slice()])
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188 use crate::ConsoleHeaderTagFlags::ConsoleRequired;
189 use crate::HeaderTagFlag::{Optional, Required};
190 use crate::RelocatableHeaderTagPreference::High;
191 use crate::{Header, MbiTagType};
192
193 #[test]
194 fn build_and_parse() {
195 let builder = Builder::new(HeaderTagISA::I386)
196 .information_request_tag(InformationRequestHeaderTag::new(
197 Optional,
198 &[
199 MbiTagType::Cmdline,
200 MbiTagType::BootLoaderName,
201 MbiTagType::Module,
202 MbiTagType::BasicMeminfo,
203 MbiTagType::Bootdev,
204 MbiTagType::Mmap,
205 MbiTagType::Vbe,
206 MbiTagType::Framebuffer,
207 MbiTagType::ElfSections,
208 MbiTagType::Apm,
209 MbiTagType::Efi32,
210 MbiTagType::Efi64,
211 MbiTagType::Smbios,
212 MbiTagType::AcpiV1,
213 MbiTagType::AcpiV2,
214 MbiTagType::Network,
215 MbiTagType::EfiMmap,
216 MbiTagType::EfiBs,
217 MbiTagType::Efi32Ih,
218 MbiTagType::Efi64Ih,
219 MbiTagType::LoadBaseAddr,
220 MbiTagType::Custom(0x1337),
221 ],
222 ))
223 .address_tag(AddressHeaderTag::new(
224 Required, 0x1000, 0x2000, 0x3000, 0x4000,
225 ))
226 .entry_tag(EntryAddressHeaderTag::new(Required, 0x5000))
227 .console_tag(ConsoleHeaderTag::new(Required, ConsoleRequired))
228 .framebuffer_tag(FramebufferHeaderTag::new(Optional, 720, 1024, 8))
229 .module_align_tag(ModuleAlignHeaderTag::new(Required))
230 .efi_bs_tag(EfiBootServiceHeaderTag::new(Optional))
231 .efi_32_tag(EntryEfi32HeaderTag::new(Required, 0x7000))
232 .efi_64_tag(EntryEfi64HeaderTag::new(Required, 0x8000))
233 .relocatable_tag(RelocatableHeaderTag::new(
234 Required, 0x9000, 0x10000, 4096, High,
235 ));
236
237 let structure = builder.build();
238
239 #[cfg(miri)]
240 let _all_initialized = structure
241 .as_bytes()
242 .iter()
243 .map(|&byte| byte as u64)
244 .sum::<u64>();
245
246 let header = {
247 unsafe { Header::load(structure.as_bytes().as_ptr().cast()) }.unwrap()
250 };
251
252 assert_eq!(header.verify_checksum(), Ok(()));
253 assert_eq!(
254 header.iter().last().unwrap().header().typ(),
255 crate::HeaderTagType::End
256 );
257
258 for tag in header.iter() {
259 dbg!(tag);
260 }
261
262 dbg!(header.arch());
263 dbg!(header.checksum());
264 dbg!(header.information_request_tag());
265 dbg!(header.address_tag());
266 dbg!(header.entry_address_tag());
267 dbg!(header.console_flags_tag());
268 dbg!(header.framebuffer_tag());
269 dbg!(header.module_align_tag());
270 dbg!(header.efi_boot_services_tag());
271 dbg!(header.entry_address_efi32_tag());
272 dbg!(header.entry_address_efi64_tag());
273 dbg!(header.relocatable_tag());
274 }
275}