Start designing Serialize trait

This commit is contained in:
Artemis Tosini 2024-08-03 23:01:20 +00:00
parent 974cfd8ad9
commit 5a86c41d07
Signed by: artemist
GPG key ID: EE5227935FE3FF18
2 changed files with 148 additions and 66 deletions

View file

@ -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::<Self>()
}
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<u8>),
}
impl<'a> PreloadDirectoryElem<'a> {
fn copy_str(data: &str, output: &mut [u8]) -> Option<u32> {
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::<usize>();
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::<usize>()
}
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..]);
}
}

View file

@ -32,7 +32,7 @@ fn main(image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
staging_buf[..kernel.len()].copy_from_slice(&kernel);
let header =
elf::ElfBytes::<NativeEndian>::minimal_parse(&staging_buf).expect("Failed to parse kernel");
elf::ElfBytes::<NativeEndian>::minimal_parse(staging_buf).expect("Failed to parse kernel");
info!("Kernel is {:?}", header.ehdr.class);