Files
oxideos/members/oxide/src/multiboot2.rs
javalsai e6b231488d feat: misc
Nicer kernel, now can fetch multiboot2 boot info
2026-02-21 22:12:23 +01:00

214 lines
5.5 KiB
Rust

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::<Self>() 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
//!
//! <https://www.gnu.org/software/grub/manual/multiboot2/multiboot.html>
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<TagTagged<'a>> {
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::<types::$name>(
contents_addr,
(),
)
}))
),*,
$(
types::$fatname::ID => Some(TagTagged::$fatname(unsafe {
&*core::ptr::from_raw_parts::<types::$fatname>(
contents_addr,
size as usize - core::mem::size_of::<Self>(),
)
}))
),*,
_ => 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::<FixedPart>() 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
}
}
}
}