1use crate::apm::ApmTag;
4use crate::bootdev::BootdevTag;
5use crate::network::NetworkTag;
6use crate::{
7 BasicMemoryInfoTag, BootInformationHeader, BootLoaderNameTag, CommandLineTag,
8 EFIBootServicesNotExitedTag, EFIImageHandle32Tag, EFIImageHandle64Tag, EFIMemoryMapTag,
9 EFISdt32Tag, EFISdt64Tag, ElfSectionsTag, EndTag, FramebufferTag, ImageLoadPhysAddrTag,
10 MemoryMapTag, ModuleTag, RsdpV1Tag, RsdpV2Tag, SmbiosTag, TagHeader, TagType, VBEInfoTag,
11};
12use alloc::boxed::Box;
13use alloc::vec::Vec;
14use multiboot2_common::{DynSizedStructure, MaybeDynSized, new_boxed};
15
16#[derive(Debug)]
19pub struct Builder {
20 cmdline: Option<Box<CommandLineTag>>,
21 bootloader: Option<Box<BootLoaderNameTag>>,
22 modules: Vec<Box<ModuleTag>>,
23 meminfo: Option<BasicMemoryInfoTag>,
24 bootdev: Option<BootdevTag>,
25 mmap: Option<Box<MemoryMapTag>>,
26 vbe: Option<VBEInfoTag>,
27 framebuffer: Option<Box<FramebufferTag>>,
28 elf_sections: Option<Box<ElfSectionsTag>>,
29 apm: Option<ApmTag>,
30 efi32: Option<EFISdt32Tag>,
31 efi64: Option<EFISdt64Tag>,
32 smbios: Vec<Box<SmbiosTag>>,
33 rsdpv1: Option<RsdpV1Tag>,
34 rsdpv2: Option<RsdpV2Tag>,
35 network: Option<Box<NetworkTag>>,
36 efi_mmap: Option<Box<EFIMemoryMapTag>>,
37 efi_bs: Option<EFIBootServicesNotExitedTag>,
38 efi32_ih: Option<EFIImageHandle32Tag>,
39 efi64_ih: Option<EFIImageHandle64Tag>,
40 image_load_addr: Option<ImageLoadPhysAddrTag>,
41 custom_tags: Vec<Box<DynSizedStructure<TagHeader>>>,
42}
43
44impl Default for Builder {
45 fn default() -> Self {
46 Self::new()
47 }
48}
49
50impl Builder {
51 #[must_use]
53 pub const fn new() -> Self {
54 Self {
55 cmdline: None,
56 bootloader: None,
57 modules: vec![],
58 meminfo: None,
59 bootdev: None,
60 mmap: None,
61 vbe: None,
62 framebuffer: None,
63 elf_sections: None,
64 apm: None,
65 efi32: None,
66 efi64: None,
67 smbios: vec![],
68 rsdpv1: None,
69 rsdpv2: None,
70 efi_mmap: None,
71 network: None,
72 efi_bs: None,
73 efi32_ih: None,
74 efi64_ih: None,
75 image_load_addr: None,
76 custom_tags: vec![],
77 }
78 }
79
80 #[must_use]
82 pub fn cmdline(mut self, cmdline: Box<CommandLineTag>) -> Self {
83 self.cmdline = Some(cmdline);
84 self
85 }
86
87 #[must_use]
89 pub fn bootloader(mut self, bootloader: Box<BootLoaderNameTag>) -> Self {
90 self.bootloader = Some(bootloader);
91 self
92 }
93
94 #[must_use]
96 pub fn add_module(mut self, module: Box<ModuleTag>) -> Self {
97 self.modules.push(module);
98 self
99 }
100
101 #[must_use]
103 pub const fn meminfo(mut self, meminfo: BasicMemoryInfoTag) -> Self {
104 self.meminfo = Some(meminfo);
105 self
106 }
107
108 #[must_use]
110 pub const fn bootdev(mut self, bootdev: BootdevTag) -> Self {
111 self.bootdev = Some(bootdev);
112 self
113 }
114
115 #[must_use]
117 pub fn mmap(mut self, mmap: Box<MemoryMapTag>) -> Self {
118 self.mmap = Some(mmap);
119 self
120 }
121
122 #[must_use]
124 pub const fn vbe(mut self, vbe: VBEInfoTag) -> Self {
125 self.vbe = Some(vbe);
126 self
127 }
128
129 #[must_use]
131 pub fn framebuffer(mut self, framebuffer: Box<FramebufferTag>) -> Self {
132 self.framebuffer = Some(framebuffer);
133 self
134 }
135
136 #[must_use]
138 pub fn elf_sections(mut self, elf_sections: Box<ElfSectionsTag>) -> Self {
139 self.elf_sections = Some(elf_sections);
140 self
141 }
142
143 #[must_use]
145 pub const fn apm(mut self, apm: ApmTag) -> Self {
146 self.apm = Some(apm);
147 self
148 }
149
150 #[must_use]
152 pub const fn efi32(mut self, efi32: EFISdt32Tag) -> Self {
153 self.efi32 = Some(efi32);
154 self
155 }
156
157 #[must_use]
159 pub const fn efi64(mut self, efi64: EFISdt64Tag) -> Self {
160 self.efi64 = Some(efi64);
161 self
162 }
163
164 #[must_use]
166 pub fn add_smbios(mut self, smbios: Box<SmbiosTag>) -> Self {
167 self.smbios.push(smbios);
168 self
169 }
170
171 #[must_use]
173 pub const fn rsdpv1(mut self, rsdpv1: RsdpV1Tag) -> Self {
174 self.rsdpv1 = Some(rsdpv1);
175 self
176 }
177
178 #[must_use]
180 pub const fn rsdpv2(mut self, rsdpv2: RsdpV2Tag) -> Self {
181 self.rsdpv2 = Some(rsdpv2);
182 self
183 }
184
185 #[must_use]
187 pub fn efi_mmap(mut self, efi_mmap: Box<EFIMemoryMapTag>) -> Self {
188 self.efi_mmap = Some(efi_mmap);
189 self
190 }
191
192 #[must_use]
194 pub fn network(mut self, network: Box<NetworkTag>) -> Self {
195 self.network = Some(network);
196 self
197 }
198
199 #[must_use]
201 pub const fn efi_bs(mut self, efi_bs: EFIBootServicesNotExitedTag) -> Self {
202 self.efi_bs = Some(efi_bs);
203 self
204 }
205
206 #[must_use]
208 pub const fn efi32_ih(mut self, efi32_ih: EFIImageHandle32Tag) -> Self {
209 self.efi32_ih = Some(efi32_ih);
210 self
211 }
212
213 #[must_use]
215 pub const fn efi64_ih(mut self, efi64_ih: EFIImageHandle64Tag) -> Self {
216 self.efi64_ih = Some(efi64_ih);
217 self
218 }
219
220 #[must_use]
222 pub const fn image_load_addr(mut self, image_load_addr: ImageLoadPhysAddrTag) -> Self {
223 self.image_load_addr = Some(image_load_addr);
224 self
225 }
226
227 #[must_use]
229 pub fn add_custom_tag(mut self, custom_tag: Box<DynSizedStructure<TagHeader>>) -> Self {
230 if let TagType::Custom(_c) = custom_tag.header().typ.into() {
231 self.custom_tags.push(custom_tag);
232 } else {
233 panic!("Only for custom types!");
234 }
235 self
236 }
237
238 #[must_use]
241 pub fn build(self) -> Box<DynSizedStructure<BootInformationHeader>> {
242 let header = BootInformationHeader::new(0);
243 let mut byte_refs = Vec::new();
244 if let Some(tag) = self.cmdline.as_ref() {
245 byte_refs.push(tag.as_bytes().as_ref());
246 }
247 if let Some(tag) = self.bootloader.as_ref() {
248 byte_refs.push(tag.as_bytes().as_ref());
249 }
250 for i in &self.modules {
251 byte_refs.push(i.as_bytes().as_ref());
252 }
253 if let Some(tag) = self.meminfo.as_ref() {
254 byte_refs.push(tag.as_bytes().as_ref());
255 }
256 if let Some(tag) = self.bootdev.as_ref() {
257 byte_refs.push(tag.as_bytes().as_ref());
258 }
259 if let Some(tag) = self.mmap.as_ref() {
260 byte_refs.push(tag.as_bytes().as_ref());
261 }
262 if let Some(tag) = self.vbe.as_ref() {
263 byte_refs.push(tag.as_bytes().as_ref());
264 }
265 if let Some(tag) = self.framebuffer.as_ref() {
266 byte_refs.push(tag.as_bytes().as_ref());
267 }
268 if let Some(tag) = self.elf_sections.as_ref() {
269 byte_refs.push(tag.as_bytes().as_ref());
270 }
271 if let Some(tag) = self.apm.as_ref() {
272 byte_refs.push(tag.as_bytes().as_ref());
273 }
274 if let Some(tag) = self.efi32.as_ref() {
275 byte_refs.push(tag.as_bytes().as_ref());
276 }
277 if let Some(tag) = self.efi64.as_ref() {
278 byte_refs.push(tag.as_bytes().as_ref());
279 }
280 for i in &self.smbios {
281 byte_refs.push(i.as_bytes().as_ref());
282 }
283 if let Some(tag) = self.rsdpv1.as_ref() {
284 byte_refs.push(tag.as_bytes().as_ref());
285 }
286 if let Some(tag) = self.rsdpv2.as_ref() {
287 byte_refs.push(tag.as_bytes().as_ref());
288 }
289 if let Some(tag) = self.efi_mmap.as_ref() {
290 byte_refs.push(tag.as_bytes().as_ref());
291 }
292 if let Some(tag) = self.efi_bs.as_ref() {
293 byte_refs.push(tag.as_bytes().as_ref());
294 }
295 if let Some(tag) = self.efi32_ih.as_ref() {
296 byte_refs.push(tag.as_bytes().as_ref());
297 }
298 if let Some(tag) = self.efi64_ih.as_ref() {
299 byte_refs.push(tag.as_bytes().as_ref());
300 }
301 if let Some(tag) = self.image_load_addr.as_ref() {
302 byte_refs.push(tag.as_bytes().as_ref());
303 }
304 for i in &self.custom_tags {
305 byte_refs.push(i.as_bytes().as_ref());
306 }
307 let end_tag = EndTag::default();
308 byte_refs.push(end_tag.as_bytes().as_ref());
309 new_boxed(header, byte_refs.as_slice())
310 }
311}
312
313#[cfg(test)]
314mod tests {
315 use super::*;
316 use crate::{
317 BootInformation, FramebufferType, MemoryArea, MemoryAreaType, VBEControlInfo, VBEModeInfo,
318 };
319 use uefi_raw::table::boot::MemoryDescriptor;
320
321 #[test]
322 fn build_and_parse() {
323 let builder = Builder::new()
324 .cmdline(CommandLineTag::new("this is a command line"))
325 .bootloader(BootLoaderNameTag::new("this is the bootloader"))
326 .add_module(ModuleTag::new(0x1000, 0x2000, "module 1"))
327 .add_module(ModuleTag::new(0x3000, 0x4000, "module 2"))
328 .meminfo(BasicMemoryInfoTag::new(0x4000, 0x5000))
329 .bootdev(BootdevTag::new(0x00, 0x00, 0x00))
330 .mmap(MemoryMapTag::new(&[MemoryArea::new(
331 0x1000000,
332 0x1000,
333 MemoryAreaType::Available,
334 )]))
335 .vbe(VBEInfoTag::new(
336 42,
337 2,
338 4,
339 9,
340 VBEControlInfo::default(),
341 VBEModeInfo::default(),
342 ))
343 .framebuffer(FramebufferTag::new(
345 0x1000,
346 1,
347 756,
348 1024,
349 8,
350 FramebufferType::Text,
351 ))
352 .elf_sections(ElfSectionsTag::new(0, 32, 0, &[]))
353 .apm(ApmTag::new(0, 0, 0, 0, 0, 0, 0, 0, 0))
354 .efi32(EFISdt32Tag::new(0x1000))
355 .efi64(EFISdt64Tag::new(0x1000))
356 .add_smbios(SmbiosTag::new(0, 0, &[1, 2, 3]))
357 .add_smbios(SmbiosTag::new(1, 1, &[4, 5, 6]))
358 .rsdpv1(RsdpV1Tag::new(0, *b"abcdef", 5, 6))
359 .rsdpv2(RsdpV2Tag::new(0, *b"abcdef", 5, 6, 5, 4, 7))
360 .efi_mmap(EFIMemoryMapTag::new_from_descs(&[
361 MemoryDescriptor::default(),
362 MemoryDescriptor::default(),
363 ]))
364 .network(NetworkTag::new(&[0; 1500]))
365 .efi_bs(EFIBootServicesNotExitedTag::new())
366 .efi32_ih(EFIImageHandle32Tag::new(0x1000))
367 .efi64_ih(EFIImageHandle64Tag::new(0x1000))
368 .image_load_addr(ImageLoadPhysAddrTag::new(0x1000))
369 .add_custom_tag(new_boxed::<DynSizedStructure<TagHeader>>(
370 TagHeader::new(TagType::Custom(0x1337), 0),
371 &[],
372 ));
373
374 let structure = builder.build();
375
376 let info = unsafe { BootInformation::load(structure.as_bytes().as_ptr().cast()) }.unwrap();
377 for tag in info.tags() {
378 dbg!(tag.header(), tag.payload().len());
380 }
381 eprintln!("{info:#x?}")
382 }
383}