From 5a86c41d0746c1bde485f589285ef700440bc0d8 Mon Sep 17 00:00:00 2001 From: Artemis Tosini Date: Sat, 3 Aug 2024 23:01:20 +0000 Subject: [PATCH] Start designing Serialize trait --- src/abi.rs | 212 ++++++++++++++++++++++++++++++++++++---------------- src/main.rs | 2 +- 2 files changed, 148 insertions(+), 66 deletions(-) diff --git a/src/abi.rs b/src/abi.rs index d1904fd..93dd3a4 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -1,5 +1,21 @@ +extern crate alloc; +use alloc::string::String; +use alloc::vec::Vec; use uefi::proto::console::gop::{GraphicsOutput, PixelFormat}; +/// Serialize object into a buffer for FreeBSD +pub trait Serialize { + /// Output buffer must be aligned to this size + fn alignment() -> usize; + + /// Calculate output size of object, from base address to final byte written + fn size(&self) -> usize; + + /// Serliaze data into a buffer. Buffer must be aligned at alignment. + fn serialize(&self, out: &mut [u8]); +} + +#[derive(Debug, Copy, Clone)] #[repr(C)] pub struct EFIFramebufferParams { pub addr: u64, @@ -45,76 +61,142 @@ impl EFIFramebufferParams { } } -/// Single TLV in the metadata buffer. -/// In the FreeBSD kernel would be placed in `preload_metadata` -pub enum PreloadDirectoryElem<'a> { - /// Module name (MOD_NAME) - Name(&'a str), - /// Module type (MOD_TYPE) - Type(&'a str), - /// Module parameters (MOD_ARGS) - Args(&'a str), +impl Serialize for EFIFramebufferParams { + fn alignment() -> usize { + 4 + } + + fn size(&self) -> usize { + core::mem::size_of::() + } + + fn serialize(&self, out: &mut [u8]) { + // we're already repr(C) so just copy + out.copy_from_slice(unsafe { + core::slice::from_raw_parts( + self as *const Self as *const u8, + core::mem::size_of_val(self), + ) + }) + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[repr(u32)] +/// Tag in the module info TLV +pub enum ModuleInfoType { + /// Module name (MODINFO_NAME) + Name = 0x1, + /// Module type (MODINFO_TYPE) + Type = 0x2, // TODO: figure out how to make this pointer safer - /// Module address (MOD_ADDR) - LoadAddress(*const u8), - /// Module size (MOD_SIZE) + /// Module address (MODINFO_ADDR) + LoadAddress = 0x3, + /// Module size (MODINFO_SIZE) + Size = 0x4, + /// Module parameters (MODINFO_ARGS) + Args = 0x6, + + /// a.out header (MODINFOMD_AOUTEXEC) + AoutExecHeader = 0x8001, + /// ELF header (MODINFOMD_ELFHDR) + ElfHeader = 0x8002, + /// Start virtual address of symtab/strtab (MODINFOMD_SSYM) + StartSymbols = 0x8003, + /// End virtual address of symtab/strtab (MODINFOMD_SSYM) + EndSymbols = 0x8004, + /// Base virtual address of `PT_DYNAMIC` segment (MODINFOMD_DYNAMIC) + Dynamic = 0x8005, + /// Section header table (MODINFOMD_SHDR) + SectionHeader = 0x8009, + /// Base virtual address of constructors (MODINFOMD_CTORS_ADDR) + CtorsAddress = 0x800a, + /// Size of constructors (MODINFOMD_CTORS_SIZE) + CtorsSize = 0x800b, + /// Pointer to firmware object, on EFI this means Runtime SystemTable (MODINFOMD_FW_HANDLE) + FirmwareHandle = 0x800c, + /// Crypto key buffer, used for geli (MODINFOMD_KEYBUF) + KeyBuffer = 0x800d, + /// Console font (MODINFOMD_FONT) + Font = 0x800e, + + #[cfg(target_arch = "x86_64")] + /// Base virtual address of device tree (MODINFOMD_DTBP) + DeviceTreePointer = 0x9003, + + #[cfg(target_arch = "x86_64")] + /// EFI memory map (MODINFOMD_EFI_MAP) + EFIMemoryMap = 0x9004, + + #[cfg(target_arch = "x86_64")] + /// EFI framebuffer metadata (MODINFOMD_EFI_FB) + EFIFrameBuffer = 0x9005, +} + +/// Value in the module info TLV +#[derive(Debug, Clone)] +pub enum ModuleInfoValue { + StaticString(&'static str), + String(String), + // TODO: figure out how to make this pointer safer + Pointer(*const u8), Size(usize), - /// Type-speicfic metadata (MOD_METADATA) - Metadata(FileMetadataType, &'a [u8]), - End, + Buffer(Vec), } -impl<'a> PreloadDirectoryElem<'a> { - fn copy_str(data: &str, output: &mut [u8]) -> Option { - output[..data.len()].copy_from_slice(data.as_bytes()); - output[data.len()] = 0; - data.len().checked_add(1)?.try_into().ok() - } - - pub fn copy_to_output<'b>(&'a self, output: &'b mut [u8]) -> Option<&'b mut [u8]> { - let usize_size = core::mem::size_of::(); - - let (tag, length) = match self { - Self::Name(name) => (1u32, Self::copy_str(name, &mut output[8..])?), - Self::Type(typ) => (2u32, Self::copy_str(typ, &mut output[8..])?), - Self::Args(args) => (6u32, Self::copy_str(args, &mut output[8..])?), - Self::LoadAddress(addr) => { - output[8..(8 + usize_size)].copy_from_slice(&(*addr as usize).to_ne_bytes()); - (3u32, usize_size as u32) - } - Self::Size(size) => { - output[8..(8 + usize_size)].copy_from_slice(&size.to_ne_bytes()); - (4u32, usize_size as u32) - } - Self::Metadata(typ, metadata) => { - output[8..(8 + metadata.len())].copy_from_slice(metadata); - (0x8000 | (*typ as u32), metadata.len() as u32) - } - Self::End => (0u32, 0u32), - }; - - output[..4].copy_from_slice(&tag.to_ne_bytes()); - output[4..8].copy_from_slice(&length.to_ne_bytes()); - - let aligned_length = ((length as usize + usize_size - 1) / usize_size) * usize_size; - - Some(&mut output[(aligned_length + 8)..]) +impl ModuleInfoValue { + fn serialize_str(s: &str, out: &mut [u8]) { + out[..s.len()].copy_from_slice(s.as_bytes()); + out[s.len()] = 0; } } -#[derive(Debug, Copy, Clone)] -#[repr(u16)] -pub enum FileMetadataType { - AoutExecHeader = 1, - ElfHeader = 2, - StartSymbols = 3, - EndSymbols = 4, - Dynamic = 5, - MB2Header = 6, - SectionHeader = 9, - CtorsAddress = 10, - CtorsSize = 11, - FirmwareHandle = 12, - KeyBuffer = 13, - Font = 14, +impl Serialize for ModuleInfoValue { + fn alignment() -> usize { + 4 + } + + fn size(&self) -> usize { + match self { + ModuleInfoValue::StaticString(s) => s.len() + 1, + ModuleInfoValue::String(s) => s.len() + 1, + ModuleInfoValue::Pointer(obj) => core::mem::size_of_val(obj), + ModuleInfoValue::Size(obj) => core::mem::size_of_val(obj), + ModuleInfoValue::Buffer(buf) => buf.len(), + } + } + + fn serialize(&self, out: &mut [u8]) { + match self { + ModuleInfoValue::StaticString(s) => Self::serialize_str(s, out), + ModuleInfoValue::String(s) => Self::serialize_str(s, out), + ModuleInfoValue::Pointer(p) => out.copy_from_slice(&usize::to_ne_bytes(*p as usize)), + ModuleInfoValue::Size(p) => out.copy_from_slice(&usize::to_ne_bytes(*p)), + ModuleInfoValue::Buffer(buf) => out.copy_from_slice(buf), + } + } +} + +/// Key and value in the module info TLV +/// TODO: figure out how to make this properly typesafe +#[derive(Debug, Clone)] +pub struct ModuleInfoItem { + tag: ModuleInfoType, + value: ModuleInfoValue, +} + +impl Serialize for ModuleInfoItem { + fn alignment() -> usize { + core::mem::size_of::() + } + + fn size(&self) -> usize { + 8 + self.value.size() + } + + fn serialize(&self, out: &mut [u8]) { + out[..4].copy_from_slice(&u32::to_ne_bytes(self.tag as u32)); + out[4..8].copy_from_slice(&u32::to_ne_bytes(self.value.size().try_into().unwrap())); + self.value.serialize(&mut out[8..]); + } } diff --git a/src/main.rs b/src/main.rs index b4dc398..2b5c616 100644 --- a/src/main.rs +++ b/src/main.rs @@ -32,7 +32,7 @@ fn main(image_handle: Handle, mut system_table: SystemTable) -> Status { staging_buf[..kernel.len()].copy_from_slice(&kernel); let header = - elf::ElfBytes::::minimal_parse(&staging_buf).expect("Failed to parse kernel"); + elf::ElfBytes::::minimal_parse(staging_buf).expect("Failed to parse kernel"); info!("Kernel is {:?}", header.ehdr.class);