use crate::apm::ApmTag;
use crate::bootdev::BootdevTag;
use crate::network::NetworkTag;
use crate::{
BasicMemoryInfoTag, BootInformationHeader, BootLoaderNameTag, CommandLineTag,
EFIBootServicesNotExitedTag, EFIImageHandle32Tag, EFIImageHandle64Tag, EFIMemoryMapTag,
EFISdt32Tag, EFISdt64Tag, ElfSectionsTag, EndTag, FramebufferTag, ImageLoadPhysAddrTag,
MemoryMapTag, ModuleTag, RsdpV1Tag, RsdpV2Tag, SmbiosTag, TagHeader, TagType, VBEInfoTag,
};
use alloc::boxed::Box;
use alloc::vec::Vec;
use multiboot2_common::{DynSizedStructure, MaybeDynSized, new_boxed};
#[derive(Debug)]
pub struct Builder {
cmdline: Option<Box<CommandLineTag>>,
bootloader: Option<Box<BootLoaderNameTag>>,
modules: Vec<Box<ModuleTag>>,
meminfo: Option<BasicMemoryInfoTag>,
bootdev: Option<BootdevTag>,
mmap: Option<Box<MemoryMapTag>>,
vbe: Option<VBEInfoTag>,
framebuffer: Option<Box<FramebufferTag>>,
elf_sections: Option<Box<ElfSectionsTag>>,
apm: Option<ApmTag>,
efi32: Option<EFISdt32Tag>,
efi64: Option<EFISdt64Tag>,
smbios: Vec<Box<SmbiosTag>>,
rsdpv1: Option<RsdpV1Tag>,
rsdpv2: Option<RsdpV2Tag>,
network: Option<Box<NetworkTag>>,
efi_mmap: Option<Box<EFIMemoryMapTag>>,
efi_bs: Option<EFIBootServicesNotExitedTag>,
efi32_ih: Option<EFIImageHandle32Tag>,
efi64_ih: Option<EFIImageHandle64Tag>,
image_load_addr: Option<ImageLoadPhysAddrTag>,
custom_tags: Vec<Box<DynSizedStructure<TagHeader>>>,
}
impl Default for Builder {
fn default() -> Self {
Self::new()
}
}
impl Builder {
#[must_use]
pub const fn new() -> Self {
Self {
cmdline: None,
bootloader: None,
modules: vec![],
meminfo: None,
bootdev: None,
mmap: None,
vbe: None,
framebuffer: None,
elf_sections: None,
apm: None,
efi32: None,
efi64: None,
smbios: vec![],
rsdpv1: None,
rsdpv2: None,
efi_mmap: None,
network: None,
efi_bs: None,
efi32_ih: None,
efi64_ih: None,
image_load_addr: None,
custom_tags: vec![],
}
}
#[must_use]
pub fn cmdline(mut self, cmdline: Box<CommandLineTag>) -> Self {
self.cmdline = Some(cmdline);
self
}
#[must_use]
pub fn bootloader(mut self, bootloader: Box<BootLoaderNameTag>) -> Self {
self.bootloader = Some(bootloader);
self
}
#[must_use]
pub fn add_module(mut self, module: Box<ModuleTag>) -> Self {
self.modules.push(module);
self
}
#[must_use]
pub const fn meminfo(mut self, meminfo: BasicMemoryInfoTag) -> Self {
self.meminfo = Some(meminfo);
self
}
#[must_use]
pub const fn bootdev(mut self, bootdev: BootdevTag) -> Self {
self.bootdev = Some(bootdev);
self
}
#[must_use]
pub fn mmap(mut self, mmap: Box<MemoryMapTag>) -> Self {
self.mmap = Some(mmap);
self
}
#[must_use]
pub const fn vbe(mut self, vbe: VBEInfoTag) -> Self {
self.vbe = Some(vbe);
self
}
#[must_use]
pub fn framebuffer(mut self, framebuffer: Box<FramebufferTag>) -> Self {
self.framebuffer = Some(framebuffer);
self
}
#[must_use]
pub fn elf_sections(mut self, elf_sections: Box<ElfSectionsTag>) -> Self {
self.elf_sections = Some(elf_sections);
self
}
#[must_use]
pub const fn apm(mut self, apm: ApmTag) -> Self {
self.apm = Some(apm);
self
}
#[must_use]
pub const fn efi32(mut self, efi32: EFISdt32Tag) -> Self {
self.efi32 = Some(efi32);
self
}
#[must_use]
pub const fn efi64(mut self, efi64: EFISdt64Tag) -> Self {
self.efi64 = Some(efi64);
self
}
#[must_use]
pub fn add_smbios(mut self, smbios: Box<SmbiosTag>) -> Self {
self.smbios.push(smbios);
self
}
#[must_use]
pub const fn rsdpv1(mut self, rsdpv1: RsdpV1Tag) -> Self {
self.rsdpv1 = Some(rsdpv1);
self
}
#[must_use]
pub const fn rsdpv2(mut self, rsdpv2: RsdpV2Tag) -> Self {
self.rsdpv2 = Some(rsdpv2);
self
}
#[must_use]
pub fn efi_mmap(mut self, efi_mmap: Box<EFIMemoryMapTag>) -> Self {
self.efi_mmap = Some(efi_mmap);
self
}
#[must_use]
pub fn network(mut self, network: Box<NetworkTag>) -> Self {
self.network = Some(network);
self
}
#[must_use]
pub const fn efi_bs(mut self, efi_bs: EFIBootServicesNotExitedTag) -> Self {
self.efi_bs = Some(efi_bs);
self
}
#[must_use]
pub const fn efi32_ih(mut self, efi32_ih: EFIImageHandle32Tag) -> Self {
self.efi32_ih = Some(efi32_ih);
self
}
#[must_use]
pub const fn efi64_ih(mut self, efi64_ih: EFIImageHandle64Tag) -> Self {
self.efi64_ih = Some(efi64_ih);
self
}
#[must_use]
pub const fn image_load_addr(mut self, image_load_addr: ImageLoadPhysAddrTag) -> Self {
self.image_load_addr = Some(image_load_addr);
self
}
#[must_use]
pub fn add_custom_tag(mut self, custom_tag: Box<DynSizedStructure<TagHeader>>) -> Self {
if let TagType::Custom(_c) = custom_tag.header().typ.into() {
self.custom_tags.push(custom_tag);
} else {
panic!("Only for custom types!");
}
self
}
#[must_use]
pub fn build(self) -> Box<DynSizedStructure<BootInformationHeader>> {
let header = BootInformationHeader::new(0);
let mut byte_refs = Vec::new();
if let Some(tag) = self.cmdline.as_ref() {
byte_refs.push(tag.as_bytes().as_ref());
}
if let Some(tag) = self.bootloader.as_ref() {
byte_refs.push(tag.as_bytes().as_ref());
}
for i in &self.modules {
byte_refs.push(i.as_bytes().as_ref());
}
if let Some(tag) = self.meminfo.as_ref() {
byte_refs.push(tag.as_bytes().as_ref());
}
if let Some(tag) = self.bootdev.as_ref() {
byte_refs.push(tag.as_bytes().as_ref());
}
if let Some(tag) = self.mmap.as_ref() {
byte_refs.push(tag.as_bytes().as_ref());
}
if let Some(tag) = self.vbe.as_ref() {
byte_refs.push(tag.as_bytes().as_ref());
}
if let Some(tag) = self.framebuffer.as_ref() {
byte_refs.push(tag.as_bytes().as_ref());
}
if let Some(tag) = self.elf_sections.as_ref() {
byte_refs.push(tag.as_bytes().as_ref());
}
if let Some(tag) = self.apm.as_ref() {
byte_refs.push(tag.as_bytes().as_ref());
}
if let Some(tag) = self.efi32.as_ref() {
byte_refs.push(tag.as_bytes().as_ref());
}
if let Some(tag) = self.efi64.as_ref() {
byte_refs.push(tag.as_bytes().as_ref());
}
for i in &self.smbios {
byte_refs.push(i.as_bytes().as_ref());
}
if let Some(tag) = self.rsdpv1.as_ref() {
byte_refs.push(tag.as_bytes().as_ref());
}
if let Some(tag) = self.rsdpv2.as_ref() {
byte_refs.push(tag.as_bytes().as_ref());
}
if let Some(tag) = self.efi_mmap.as_ref() {
byte_refs.push(tag.as_bytes().as_ref());
}
if let Some(tag) = self.efi_bs.as_ref() {
byte_refs.push(tag.as_bytes().as_ref());
}
if let Some(tag) = self.efi32_ih.as_ref() {
byte_refs.push(tag.as_bytes().as_ref());
}
if let Some(tag) = self.efi64_ih.as_ref() {
byte_refs.push(tag.as_bytes().as_ref());
}
if let Some(tag) = self.image_load_addr.as_ref() {
byte_refs.push(tag.as_bytes().as_ref());
}
for i in &self.custom_tags {
byte_refs.push(i.as_bytes().as_ref());
}
let end_tag = EndTag::default();
byte_refs.push(end_tag.as_bytes().as_ref());
new_boxed(header, byte_refs.as_slice())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
BootInformation, FramebufferType, MemoryArea, MemoryAreaType, VBEControlInfo, VBEModeInfo,
};
use uefi_raw::table::boot::MemoryDescriptor;
#[test]
fn build_and_parse() {
let builder = Builder::new()
.cmdline(CommandLineTag::new("this is a command line"))
.bootloader(BootLoaderNameTag::new("this is the bootloader"))
.add_module(ModuleTag::new(0x1000, 0x2000, "module 1"))
.add_module(ModuleTag::new(0x3000, 0x4000, "module 2"))
.meminfo(BasicMemoryInfoTag::new(0x4000, 0x5000))
.bootdev(BootdevTag::new(0x00, 0x00, 0x00))
.mmap(MemoryMapTag::new(&[MemoryArea::new(
0x1000000,
0x1000,
MemoryAreaType::Available,
)]))
.vbe(VBEInfoTag::new(
42,
2,
4,
9,
VBEControlInfo::default(),
VBEModeInfo::default(),
))
.framebuffer(FramebufferTag::new(
0x1000,
1,
756,
1024,
8,
FramebufferType::Text,
))
.elf_sections(ElfSectionsTag::new(0, 32, 0, &[]))
.apm(ApmTag::new(0, 0, 0, 0, 0, 0, 0, 0, 0))
.efi32(EFISdt32Tag::new(0x1000))
.efi64(EFISdt64Tag::new(0x1000))
.add_smbios(SmbiosTag::new(0, 0, &[1, 2, 3]))
.add_smbios(SmbiosTag::new(1, 1, &[4, 5, 6]))
.rsdpv1(RsdpV1Tag::new(0, *b"abcdef", 5, 6))
.rsdpv2(RsdpV2Tag::new(0, *b"abcdef", 5, 6, 5, 4, 7))
.efi_mmap(EFIMemoryMapTag::new_from_descs(&[
MemoryDescriptor::default(),
MemoryDescriptor::default(),
]))
.network(NetworkTag::new(&[0; 1500]))
.efi_bs(EFIBootServicesNotExitedTag::new())
.efi32_ih(EFIImageHandle32Tag::new(0x1000))
.efi64_ih(EFIImageHandle64Tag::new(0x1000))
.image_load_addr(ImageLoadPhysAddrTag::new(0x1000))
.add_custom_tag(new_boxed::<DynSizedStructure<TagHeader>>(
TagHeader::new(TagType::Custom(0x1337), 0),
&[],
));
let structure = builder.build();
let info = unsafe { BootInformation::load(structure.as_bytes().as_ptr().cast()) }.unwrap();
for tag in info.tags() {
dbg!(tag.header(), tag.payload().len());
}
eprintln!("{info:#x?}")
}
}