builder.rs 8.4 KB

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