pub const HEADER_MAGIC: u32 = 0xe85250d6; #[repr(C, packed)] #[derive(Clone, Copy, PartialEq, Eq)] pub struct Header { magic: u32, arch: HeaderArchitecture, length: u32, checksum: i32, // optional flags typ: u16, flags: u16, size: u32, } impl Header { pub const fn new() -> Self { let length = size_of::() as _; let arch = HeaderArchitecture::ProtectedI386; Header { magic: HEADER_MAGIC, arch, length, checksum: -(HEADER_MAGIC as i32 + length as i32 + arch as u32 as i32), typ: 0, flags: 0, size: 0, } } } impl Default for Header { fn default() -> Self { Self::new() } } #[repr(u32)] #[derive(Clone, Copy, PartialEq, Eq)] pub enum HeaderArchitecture { ProtectedI386 = 0, MIPS32 = 4, } pub mod bif { //! # Boot Information Format //! //! use core::ptr; pub trait TagType { const ID: u32 = 4; } pub mod types { macro tagset($taggedvis:vis $taggedname:ident { $( $typname:ident ($typn:expr) { $($typprop:ident : $typpropty:ty),* $(,)? } ),* $(,)? }) { $( #[repr(C)] #[derive(Debug)] pub struct $typname { $(pub $typprop: $typpropty),* } impl super::TagType for $typname { const ID: u32 = $typn; } )* #[derive(Debug)] $taggedvis enum $taggedname<'a> { $( $typname(&'a $typname) ),* } } tagset! { pub TagTagged { Terminate(0) {}, BootCommandLine(1) { string: [u8], }, BootLoaderName(2) { string: [u8], }, BasicMemoryInformation(4) { mem_lower: u32, mem_upper: u32, }, BIOSBootDevice(5) { biosdev: u32, partition: u32, sub_partition: u32, }, ImageLoadBasePhyAddr(21) { load_base_addr: u32, }, }} } pub use types::TagTagged; #[repr(C)] pub struct TagHead { typ: u32, size: u32, __end: (), } impl TagHead { pub fn typ(&self) -> u32 { self.typ } pub fn size(&self) -> u32 { self.size } pub fn aligned8_size(&self) -> u32 { (self.size + 7) & !7 } /// Gets the reference of the next laying in memory tag, considering this one's size. /// /// # Safety /// /// Assumes there's a contiguous one in memory. pub unsafe fn next(&self) -> &Self { unsafe { &*ptr::from_ref(self).byte_add(self.aligned8_size() as usize) } } pub fn tag<'a>(&self) -> Option> { let typ = self.typ; let size = self.size; let contents_addr = ptr::addr_of!(self.__end).cast::<()>(); macro typ_match(match $var:ident { $($name:ident)* } fat { $($fatname:ident)* }) { match $var { $( types::$name::ID => Some(TagTagged::$name(unsafe { &*core::ptr::from_raw_parts::( contents_addr, (), ) })) ),*, $( types::$fatname::ID => Some(TagTagged::$fatname(unsafe { &*core::ptr::from_raw_parts::( contents_addr, size as usize - core::mem::size_of::(), ) })) ),*, _ => None, } } typ_match!(match typ { BasicMemoryInformation BIOSBootDevice Terminate ImageLoadBasePhyAddr } fat { BootCommandLine BootLoaderName }) } } // --- /// Represents the fixed part of the BIF #[repr(C, align(8))] pub struct FixedPart { pub total_size: u32, _reserved: u32, __end: (), } /// Iterator for the tags of a [`FixedPart`] pub struct TagsIter<'a> { rem_size: u32, next_ref: &'a TagHead, } impl<'a> TagsIter<'a> { pub fn new(fixed: &FixedPart) -> Self { let rem_size = fixed.total_size - core::mem::size_of::() as u32; let next_ptr = unsafe { &*core::ptr::addr_of!(fixed.__end).cast() }; Self { rem_size, next_ref: next_ptr, } } } impl<'a> Iterator for TagsIter<'a> { type Item = &'a TagHead; fn next(&mut self) -> Option<&'a TagHead> { if self.rem_size > 0 { let this_ref = self.next_ref; self.rem_size -= this_ref.aligned8_size(); // SAFETY: if there were no tags left we'd reach rem_size and not use this referece // any further self.next_ref = unsafe { this_ref.next() }; Some(this_ref) } else { None } } } }