diff --git a/Cargo.lock b/Cargo.lock index 9ad89fb..9da7bcd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,6 +24,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" name = "freeloader" version = "0.1.0" dependencies = [ + "bitflags", "goblin", "log", "uefi", diff --git a/Cargo.toml b/Cargo.toml index 4f2a442..4310155 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,3 +8,4 @@ uefi = { version = "0.29.0", default-features = false, features = [ "alloc", "gl log = { version = "0.4.22", default-features = false } goblin = { version = "0.8.2", default-features = false, features = [ "elf64", "elf32", "endian_fd" ] } x86_64 = { version = "0.15.1", default-features = false } +bitflags = "2.6.0" diff --git a/src/abi.rs b/src/abi.rs index 7ab9d2e..061665e 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -1,6 +1,9 @@ extern crate alloc; use alloc::vec::Vec; use alloc::{collections::BTreeMap, string::String}; +use bitflags::bitflags; +use uefi::prelude::BootServices; +use uefi::table::boot::MemoryType; use uefi::{ proto::console::gop::{GraphicsOutput, PixelFormat}, table::boot::PAGE_SIZE, @@ -112,6 +115,110 @@ impl Serialize for EFIFramebufferParams { } } +#[repr(C)] +#[derive(Debug, Copy, Clone)] +struct EFIMemoryMapHeader { + memory_size: usize, + descriptor_size: usize, + descriptor_version: u32, +} + +#[derive(Debug, Clone)] +pub struct EFIMemoryMapParams { + header: EFIMemoryMapHeader, + map: Vec, +} + +impl EFIMemoryMapParams { + pub fn from_boot_services(bs: &BootServices) -> Self { + let map = bs + .memory_map(MemoryType::LOADER_DATA) + .expect("Failed to get EFI memory map"); + + let (raw, meta) = map.as_raw(); + + let header = EFIMemoryMapHeader { + memory_size: meta.map_size, + descriptor_size: meta.desc_size, + descriptor_version: meta.desc_version, + }; + + Self { + header, + map: raw.to_vec(), + } + } +} + +impl Serialize for EFIMemoryMapParams { + fn alignment() -> usize { + 4 + } + + fn size(&self) -> usize { + core::mem::size_of::() + self.map.len() + } + + fn serialize_raw(&self, out: &mut [u8]) { + let header_size = core::mem::size_of_val(&self.header); + let header_bytes = unsafe { + core::slice::from_raw_parts( + &self.header as *const EFIMemoryMapHeader as *const u8, + header_size, + ) + }; + + out[..header_size].copy_from_slice(header_bytes); + out[header_size..].copy_from_slice(&self.map); + } +} + +bitflags! { + #[derive(Debug, Copy, Clone, PartialEq, Eq)] + pub struct Howto: u32 { + /// Don't set flags, system should figure it out + const AUTOBOOT = 0; + /// Prompt for root filesystem + const ASKNAME = 1 << 0; + /// Enter single user mode + const SINGLE = 1 << 1; + /// Use default rootdev from kernel buidl time + const DFLTROOT = 1 << 5; + /// Enable kernel debugger + const KDB = 1 << 6; + /// Make console more verbose + const VERBOSE = 1 << 11; + /// Set serial port as primary console + const SERIAL = 1 << 12; + /// Boot from CD rootfs + const CDROM = 1 << 13; + /// Use gdb for kernel debugger + const GDB = 1 << 15; + /// Disable console output + const MUTE = 1 << 16; + /// Wait for input after every console line + const PAUSE = 1 << 20; + ///Make console quieter + const QUIET = 1 << 21; + /// Set console to both serial and display + const DUAL = 1 << 29; + } +} + +impl Serialize for Howto { + fn alignment() -> usize { + core::mem::size_of::() + } + + fn size(&self) -> usize { + core::mem::size_of::() + } + + fn serialize_raw(&self, out: &mut [u8]) { + out.copy_from_slice(&u32::to_ne_bytes(self.bits())) + } +} + #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[repr(u32)] #[allow(dead_code)] @@ -176,10 +283,12 @@ pub enum ModuleInfoType { pub enum ModuleInfoValue { StaticString(&'static str), String(String), - // TODO: figure out how to make this pointer safer Pointer(*const u8), Size(usize), Buffer(Vec), + Howto(Howto), + EFIFrameBuffer(EFIFramebufferParams), + EFIMemoryMap(EFIMemoryMapParams), } impl ModuleInfoValue { @@ -201,6 +310,9 @@ impl Serialize for ModuleInfoValue { ModuleInfoValue::Pointer(obj) => core::mem::size_of_val(obj), ModuleInfoValue::Size(obj) => core::mem::size_of_val(obj), ModuleInfoValue::Buffer(buf) => buf.len(), + ModuleInfoValue::Howto(obj) => obj.size(), + ModuleInfoValue::EFIFrameBuffer(obj) => obj.size(), + ModuleInfoValue::EFIMemoryMap(obj) => obj.size(), } } @@ -211,6 +323,9 @@ impl Serialize for ModuleInfoValue { 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), + ModuleInfoValue::Howto(obj) => obj.serialize_raw(out), + ModuleInfoValue::EFIFrameBuffer(obj) => obj.serialize_raw(out), + ModuleInfoValue::EFIMemoryMap(obj) => obj.serialize_raw(out), } } } @@ -218,11 +333,16 @@ impl Serialize for ModuleInfoValue { impl core::fmt::Debug for ModuleInfoValue { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { - Self::StaticString(arg0) => f.debug_tuple("StaticString").field(arg0).finish(), - Self::String(arg0) => f.debug_tuple("String").field(arg0).finish(), - Self::Pointer(arg0) => f.debug_tuple("Pointer").field(arg0).finish(), - Self::Size(arg0) => f.debug_tuple("Size").field(arg0).finish(), - Self::Buffer(arg0) => write!(f, "Buffer(len={})", arg0.len()), + ModuleInfoValue::StaticString(arg0) => { + f.debug_tuple("StaticString").field(arg0).finish() + } + ModuleInfoValue::String(arg0) => f.debug_tuple("String").field(arg0).finish(), + ModuleInfoValue::Pointer(arg0) => f.debug_tuple("Pointer").field(arg0).finish(), + ModuleInfoValue::Size(arg0) => f.debug_tuple("Size").field(arg0).finish(), + ModuleInfoValue::Buffer(arg0) => write!(f, "Buffer(len={})", arg0.len()), + ModuleInfoValue::Howto(arg0) => f.debug_tuple("Howto").field(arg0).finish(), + ModuleInfoValue::EFIFrameBuffer(_) => write!(f, "EFIFrameBuffer(elided)"), + ModuleInfoValue::EFIMemoryMap(_) => write!(f, "EFIMemoryMap(elided)"), } } }