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