1use crate::{
4 AddressHeaderTag, ConsoleHeaderTag, EfiBootServiceHeaderTag, EntryAddressHeaderTag,
5 EntryEfi32HeaderTag, EntryEfi64HeaderTag, FramebufferHeaderTag, HeaderTagISA,
6 InformationRequestHeaderTag, ModuleAlignHeaderTag, Multiboot2BasicHeader, RelocatableHeaderTag,
7};
8use alloc::boxed::Box;
9use alloc::vec::Vec;
10use multiboot2_common::{DynSizedStructure, MaybeDynSized, new_boxed};
11
12#[derive(Debug)]
14pub struct Builder {
15 arch: HeaderTagISA,
16 information_request_tag: Option<Box<InformationRequestHeaderTag>>,
17 address_tag: Option<AddressHeaderTag>,
18 entry_tag: Option<EntryAddressHeaderTag>,
19 console_tag: Option<ConsoleHeaderTag>,
20 framebuffer_tag: Option<FramebufferHeaderTag>,
21 module_align_tag: Option<ModuleAlignHeaderTag>,
22 efi_bs_tag: Option<EfiBootServiceHeaderTag>,
23 efi_32_tag: Option<EntryEfi32HeaderTag>,
24 efi_64_tag: Option<EntryEfi64HeaderTag>,
25 relocatable_tag: Option<RelocatableHeaderTag>,
26 }
28
29impl Builder {
30 #[must_use]
32 pub const fn new(arch: HeaderTagISA) -> Self {
33 Self {
34 arch,
35 information_request_tag: None,
36 address_tag: None,
37 entry_tag: None,
38 console_tag: None,
39 framebuffer_tag: None,
40 module_align_tag: None,
41 efi_bs_tag: None,
42 efi_32_tag: None,
43 efi_64_tag: None,
44 relocatable_tag: None,
45 }
46 }
47
48 #[must_use]
50 pub fn information_request_tag(
51 mut self,
52 information_request_tag: Box<InformationRequestHeaderTag>,
53 ) -> Self {
54 self.information_request_tag = Some(information_request_tag);
55 self
56 }
57
58 #[must_use]
60 pub const fn address_tag(mut self, address_tag: AddressHeaderTag) -> Self {
61 self.address_tag = Some(address_tag);
62 self
63 }
64
65 #[must_use]
67 pub const fn entry_tag(mut self, entry_tag: EntryAddressHeaderTag) -> Self {
68 self.entry_tag = Some(entry_tag);
69 self
70 }
71
72 #[must_use]
74 pub const fn console_tag(mut self, console_tag: ConsoleHeaderTag) -> Self {
75 self.console_tag = Some(console_tag);
76 self
77 }
78
79 #[must_use]
81 pub const fn framebuffer_tag(mut self, framebuffer_tag: FramebufferHeaderTag) -> Self {
82 self.framebuffer_tag = Some(framebuffer_tag);
83 self
84 }
85
86 #[must_use]
88 pub const fn module_align_tag(mut self, module_align_tag: ModuleAlignHeaderTag) -> Self {
89 self.module_align_tag = Some(module_align_tag);
90 self
91 }
92
93 #[must_use]
95 pub const fn efi_bs_tag(mut self, efi_bs_tag: EfiBootServiceHeaderTag) -> Self {
96 self.efi_bs_tag = Some(efi_bs_tag);
97 self
98 }
99
100 #[must_use]
102 pub const fn efi_32_tag(mut self, efi_32_tag: EntryEfi32HeaderTag) -> Self {
103 self.efi_32_tag = Some(efi_32_tag);
104 self
105 }
106
107 #[must_use]
109 pub const fn efi_64_tag(mut self, efi_64_tag: EntryEfi64HeaderTag) -> Self {
110 self.efi_64_tag = Some(efi_64_tag);
111 self
112 }
113
114 #[must_use]
116 pub const fn relocatable_tag(mut self, relocatable_tag: RelocatableHeaderTag) -> Self {
117 self.relocatable_tag = Some(relocatable_tag);
118 self
119 }
120
121 #[must_use]
124 pub fn build(self) -> Box<DynSizedStructure<Multiboot2BasicHeader>> {
125 let header = Multiboot2BasicHeader::new(self.arch, 0);
126 let mut byte_refs = Vec::new();
127 if let Some(tag) = self.information_request_tag.as_ref() {
128 byte_refs.push(tag.as_bytes().as_ref());
129 }
130 if let Some(tag) = self.address_tag.as_ref() {
131 byte_refs.push(tag.as_bytes().as_ref());
132 }
133 if let Some(tag) = self.entry_tag.as_ref() {
134 byte_refs.push(tag.as_bytes().as_ref());
135 }
136 if let Some(tag) = self.console_tag.as_ref() {
137 byte_refs.push(tag.as_bytes().as_ref());
138 }
139 if let Some(tag) = self.framebuffer_tag.as_ref() {
140 byte_refs.push(tag.as_bytes().as_ref());
141 }
142 if let Some(tag) = self.module_align_tag.as_ref() {
143 byte_refs.push(tag.as_bytes().as_ref());
144 }
145 if let Some(tag) = self.efi_bs_tag.as_ref() {
146 byte_refs.push(tag.as_bytes().as_ref());
147 }
148 if let Some(tag) = self.efi_32_tag.as_ref() {
149 byte_refs.push(tag.as_bytes().as_ref());
150 }
151 if let Some(tag) = self.efi_64_tag.as_ref() {
152 byte_refs.push(tag.as_bytes().as_ref());
153 }
154 if let Some(tag) = self.relocatable_tag.as_ref() {
155 byte_refs.push(tag.as_bytes().as_ref());
156 }
157 new_boxed(header, byte_refs.as_slice())
159 }
160}
161
162#[cfg(test)]
163mod tests {
164 use super::*;
165 use crate::ConsoleHeaderTagFlags::ConsoleRequired;
166 use crate::HeaderTagFlag::{Optional, Required};
167 use crate::RelocatableHeaderTagPreference::High;
168 use crate::{MbiTagType, Multiboot2Header};
169
170 #[test]
171 fn build_and_parse() {
172 let builder = Builder::new(HeaderTagISA::I386)
173 .information_request_tag(InformationRequestHeaderTag::new(
174 Optional,
175 &[
176 MbiTagType::Cmdline.into(),
177 MbiTagType::BootLoaderName.into(),
178 MbiTagType::Module.into(),
179 MbiTagType::BasicMeminfo.into(),
180 MbiTagType::Bootdev.into(),
181 MbiTagType::Mmap.into(),
182 MbiTagType::Vbe.into(),
183 MbiTagType::Framebuffer.into(),
184 MbiTagType::ElfSections.into(),
185 MbiTagType::Apm.into(),
186 MbiTagType::Efi32.into(),
187 MbiTagType::Efi64.into(),
188 MbiTagType::Smbios.into(),
189 MbiTagType::AcpiV1.into(),
190 MbiTagType::AcpiV2.into(),
191 MbiTagType::Network.into(),
192 MbiTagType::EfiMmap.into(),
193 MbiTagType::EfiBs.into(),
194 MbiTagType::Efi32Ih.into(),
195 MbiTagType::Efi64Ih.into(),
196 MbiTagType::LoadBaseAddr.into(),
197 MbiTagType::Custom(0x1337).into(),
198 ],
199 ))
200 .address_tag(AddressHeaderTag::new(
201 Required, 0x1000, 0x2000, 0x3000, 0x4000,
202 ))
203 .entry_tag(EntryAddressHeaderTag::new(Required, 0x5000))
204 .console_tag(ConsoleHeaderTag::new(Required, ConsoleRequired))
205 .framebuffer_tag(FramebufferHeaderTag::new(Optional, 720, 1024, 8))
206 .module_align_tag(ModuleAlignHeaderTag::new(Required))
207 .efi_bs_tag(EfiBootServiceHeaderTag::new(Optional))
208 .efi_32_tag(EntryEfi32HeaderTag::new(Required, 0x7000))
209 .efi_64_tag(EntryEfi64HeaderTag::new(Required, 0x8000))
210 .relocatable_tag(RelocatableHeaderTag::new(
211 Required, 0x9000, 0x10000, 4096, High,
212 ));
213
214 let structure = builder.build();
215 let header =
216 unsafe { Multiboot2Header::load(structure.as_bytes().as_ref().as_ptr().cast()) }
217 .unwrap();
218
219 assert!(header.verify_checksum());
220
221 for tag in header.iter() {
222 dbg!(tag);
223 }
224
225 dbg!(header.arch());
226 dbg!(header.checksum());
227 dbg!(header.information_request_tag());
228 dbg!(header.address_tag());
229 dbg!(header.entry_address_tag());
230 dbg!(header.console_flags_tag());
231 dbg!(header.framebuffer_tag());
232 dbg!(header.module_align_tag());
233 dbg!(header.efi_boot_services_tag());
234 dbg!(header.entry_address_efi32_tag());
235 dbg!(header.entry_address_efi64_tag());
236 dbg!(header.relocatable_tag());
237 }
238}