summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArd Biesheuvel <ardb@kernel.org>2023-10-09 23:44:56 +0200
committerArd Biesheuvel <ardb@kernel.org>2023-10-10 01:07:28 +0200
commit7a1be111dd09f596bd146e06dcd3c31fa080da5b (patch)
treee4b63a9312a35c5b19d370a2bc23d4f02db8324d
parente88d20e7c94aeb7444c4571995c491368ddea77c (diff)
downloadefilite-7a1be111dd09f596bd146e06dcd3c31fa080da5b.tar.gz
WIP ACPI stuff
-rw-r--r--src/efi/bootservices.rs8
-rw-r--r--src/efi/memmap.rs15
-rw-r--r--src/efi/mod.rs42
-rw-r--r--src/fwcfg.rs436
-rw-r--r--src/main.rs20
5 files changed, 449 insertions, 72 deletions
diff --git a/src/efi/bootservices.rs b/src/efi/bootservices.rs
index b321afb..40ae88b 100644
--- a/src/efi/bootservices.rs
+++ b/src/efi/bootservices.rs
@@ -3,10 +3,10 @@
// Author: Ard Biesheuvel <ardb@google.com>
use crate::efi::devicepath::DevicePath;
+use crate::efi::efi_rtsdata_pool;
use crate::efi::memmap;
use crate::efi::memmap::Placement;
use crate::efi::ProtocolPtr;
-use crate::efi::efi_rtsdata_pool;
use crate::efi::{memorytype::*, status::*, tableheader::*};
use crate::efi::{Bool, Char16, Event, EventNotify, Guid, Handle, PhysicalAddress, Tpl};
use crate::efi::{ProtocolDb, PROTOCOL_DB, TPL_APPLICATION, UEFI_REVISION};
@@ -16,8 +16,8 @@ use crate::efi::devicepath;
use crate::efi::devicepath::EFI_DEVICE_PATH_PROTOCOL_GUID;
use crate::efi::loadedimage::exit_image;
use crate::efi::LoadedImage;
-use crate::efi::EFI_LOADED_IMAGE_PROTOCOL_GUID;
use crate::efi::EFI;
+use crate::efi::EFI_LOADED_IMAGE_PROTOCOL_GUID;
use core::sync::atomic::{AtomicUsize, Ordering};
use core::{ptr, slice};
@@ -524,7 +524,9 @@ extern "C" fn locate_device_path(
}
extern "C" fn install_configuration_table(guid: *const Guid, table: *const ()) -> Status {
- EFI.get().unwrap().install_configtable(unsafe { &*guid }, table);
+ EFI.get()
+ .unwrap()
+ .install_configtable(unsafe { &*guid }, table);
Status::EFI_SUCCESS
}
diff --git a/src/efi/memmap.rs b/src/efi/memmap.rs
index cc2c902..7583252 100644
--- a/src/efi/memmap.rs
+++ b/src/efi/memmap.rs
@@ -209,20 +209,23 @@ fn convert_region(
}
pub fn allocate_region(region: &[u8], _type: MemoryType) -> Result<(), ()> {
- let base = region.as_ptr() as PhysicalAddress;
- let size = region.len() as usize;
convert_region(
&mut MEMMAP.lock(),
- base,
- size,
+ region.as_ptr() as PhysicalAddress,
+ region.len() as usize,
Some(EfiConventionalMemory),
_type,
)
}
pub fn free_pages(base: u64, pages: usize) -> Result<(), ()> {
- let size = pages << EFI_PAGE_SHIFT;
- convert_region(&mut MEMMAP.lock(), base, size, None, EfiConventionalMemory)
+ convert_region(
+ &mut MEMMAP.lock(),
+ base,
+ pages << EFI_PAGE_SHIFT,
+ None,
+ EfiConventionalMemory,
+ )
}
pub enum Placement {
diff --git a/src/efi/mod.rs b/src/efi/mod.rs
index 800dd86..44e72ce 100644
--- a/src/efi/mod.rs
+++ b/src/efi/mod.rs
@@ -2,10 +2,10 @@
// Copyright 2022-2023 Google LLC
// Author: Ard Biesheuvel <ardb@google.com>
+use crate::efi::bootservices::BootServices;
use crate::efi::configtable::ConfigurationTable;
use crate::efi::loadedimage::EFI_LOADED_IMAGE_PROTOCOL_GUID;
use crate::efi::memmap::*;
-use crate::efi::bootservices::BootServices;
use crate::efi::runtimeservices::RuntimeServices;
use crate::efi::MemoryType::*;
use crate::efi::{loadedimage::*, memorytype::*, systemtable::*};
@@ -207,17 +207,17 @@ pub fn efi_rtsdata_pool() -> &'static LockedHeap {
&EFI.get().unwrap().rtsdata
}
-fn alloc_table<T>(h: &LockedHeap, tmpl: T) -> Result<Box<T>, ()> {
- let layout = Layout::from_size_align(mem::size_of::<T>(), 8).map_err(|_| ())?;
- let rtp = h.lock().allocate_first_fit(layout).map_err(|_| ())?;
- let mut rt: Box<mem::MaybeUninit<T>> = unsafe { Box::from_raw(rtp.as_ptr() as *mut _) };
- rt.write(tmpl);
-
- unsafe { Ok(mem::transmute::<Box<mem::MaybeUninit<T>>, Box<T>>(rt)) }
-}
-
pub fn init() -> Result<&'static EfiContext, ()> {
let ctx = EFI.get_or_try_init(|| {
+ fn alloc_table<T>(h: &LockedHeap, tmpl: T) -> Result<Box<T>, ()> {
+ let layout = Layout::from_size_align(mem::size_of::<T>(), 8).map_err(|_| ())?;
+ let rtp = h.lock().allocate_first_fit(layout).map_err(|_| ())?;
+ let mut rt: Box<mem::MaybeUninit<T>> = unsafe { Box::from_raw(rtp.as_ptr() as *mut _) };
+ rt.write(tmpl);
+
+ unsafe { Ok(mem::transmute::<Box<mem::MaybeUninit<T>>, Box<T>>(rt)) }
+ }
+
let rtspool = memmap::allocate_pages(
16,
MemoryType::EfiRuntimeServicesData,
@@ -240,21 +240,21 @@ pub fn init() -> Result<&'static EfiContext, ()> {
ctx.unwrap().install_configtable(
&EFI_RT_PROPERTIES_TABLE_GUID,
&RT_PROPERTIES_TABLE as *const _ as *const (),
- );
-// efi.install_configtable(
-// &EFI_MEMORY_ATTRIBUTES_TABLE_GUID,
-// MemoryAttributesTable::new() as *const _ as *const (),
-// );
- ctx
+ );
+ ctx.unwrap().install_configtable(
+ &EFI_MEMORY_ATTRIBUTES_TABLE_GUID,
+ MemoryAttributesTable::new() as *const _ as *const (),
+ );
+ ctx
}
-pub fn install_protocol<T>(handle: Handle, guid: &'static Guid, protocol: &T) {
+pub fn install_protocol<T>(handle: Handle, guid: &Guid, protocol: &T) {
PROTOCOL_DB
.lock()
.insert((handle, *guid), ProtocolPtr::from(protocol));
}
-pub fn uninstall_protocol<T>(handle: Handle, guid: &'static Guid, _protocol: &T) {
+pub fn uninstall_protocol<T>(handle: Handle, guid: &Guid, _protocol: &T) {
PROTOCOL_DB.lock().remove(&(handle, *guid));
}
@@ -267,7 +267,7 @@ impl EfiContext {
};
db.insert(*guid, entry);
- let array: Vec<ConfigurationTable> = db.values().cloned().collect();
+ let array: Vec<_> = db.values().cloned().collect();
SystemTable::update_config_table_array(array.as_slice());
}
@@ -276,7 +276,7 @@ impl EfiContext {
pe_image: &'a Parser,
cmdline: &'a Vec<u16>,
randomized: bool,
- ) -> LoadedImageData<'a> {
+ ) -> LoadedImageData<'a> {
LoadedImageData::new(
pe_image.get_image(),
cmdline.as_slice(),
@@ -284,6 +284,6 @@ impl EfiContext {
EfiLoaderData,
pe_image.get_entrypoint(),
randomized,
- )
+ )
}
}
diff --git a/src/fwcfg.rs b/src/fwcfg.rs
index 7d1668e..ab77785 100644
--- a/src/fwcfg.rs
+++ b/src/fwcfg.rs
@@ -2,11 +2,14 @@
// Copyright 2022-2023 Google LLC
// Author: Ard Biesheuvel <ardb@google.com>
-use crate::efi;
+use crate::{efi, MemoryType, Placement};
use core::{
- mem::MaybeUninit,
+ fmt,
+ marker::PhantomData,
+ mem::{size_of, MaybeUninit},
pin::pin,
slice,
+ str::from_utf8,
sync::atomic::{fence, Ordering},
};
use mmio::{Allow, Deny, VolBox};
@@ -31,9 +34,12 @@ const CFG_KERNEL_DATA: u16 = 0x11;
const CFG_INITRD_SIZE: u16 = 0x0b;
const CFG_INITRD_DATA: u16 = 0x12;
+const CFG_FILE_DIR: u16 = 0x19;
+
const CFG_DMACTL_DONE: u32 = 0;
const CFG_DMACTL_ERROR: u32 = 1;
const CFG_DMACTL_READ: u32 = 2;
+const CFG_DMACTL_SKIP: u32 = 4;
#[repr(C)]
struct DmaTransfer {
@@ -42,34 +48,84 @@ struct DmaTransfer {
address: u64,
}
-impl FwCfg {
- pub fn from_fdt_node(node: fdt::node::FdtNode) -> Option<FwCfg> {
- let addr = node.reg()?.nth(0)?.starting_address;
+#[derive(Copy, Clone)]
+#[repr(C)]
+struct FwCfgFile {
+ _size: u32,
+ _select: u16,
+ reserved: u16,
+ filename: [u8; 56],
+}
+
+impl FwCfgFile {
+ pub fn size(&self) -> usize {
+ u32::to_be(self._size) as usize
+ }
+
+ pub fn select(&self) -> u16 {
+ u16::to_be(self._select)
+ }
+}
+
+#[derive(Copy, Clone)]
+struct FwCfgFileIterator<'a, T> {
+ count: u32,
+ next: u32,
+ select: u16,
+ offset: u32,
+ fwcfg: &'a FwCfg,
+ phantom: PhantomData<T>,
+}
+
+impl<T: Copy> Iterator for FwCfgFileIterator<'_, T> {
+ type Item = T;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if self.next == self.count {
+ return None;
+ }
+
+ let itemsz = size_of::<Self::Item>() as u32;
+ let offset = self.offset + self.next * itemsz;
+ let out = pin!(MaybeUninit::<T>::uninit());
+ let mut mmio = self.fwcfg.0.lock();
+
+ mmio.selector.write(u16::to_be(self.select));
+ fence(Ordering::Release);
+
+ mmio.dma_transfer(0, offset as u32).ok()?;
+ mmio.dma_transfer(&*out as *const _ as u64, itemsz as u32)
+ .ok()?;
+ self.next += 1;
+
+ unsafe { Some(out.assume_init()) }
+ }
+}
+
+impl FwCfgMmio {
+ fn new(addr: *const u8) -> FwCfgMmio {
unsafe {
- Some(FwCfg(Spinlock::new(FwCfgMmio {
+ FwCfgMmio {
data: VolBox::<u64, Allow, Deny>::new(addr as *mut u64),
selector: VolBox::<u16, Deny, Allow>::new(addr.offset(8) as *mut u16),
dmacontrol: VolBox::<u64, Deny, Allow>::new(addr.offset(16) as *mut u64),
- })))
+ }
}
}
- fn dma_transfer(
- &self,
- loadbuffer: &mut [MaybeUninit<u8>],
- size: usize,
- config_item: u16,
- ) -> Result<(), ()> {
+ fn dma_transfer(&mut self, addr: u64, size: u32) -> Result<(), ()> {
+ let control = match addr {
+ 0 => CFG_DMACTL_SKIP,
+ _ => CFG_DMACTL_READ,
+ };
+
let xfer = pin!(DmaTransfer {
- control: u32::to_be(CFG_DMACTL_READ),
- length: u32::to_be(size as u32),
- address: u64::to_be(loadbuffer.as_ptr() as u64),
+ control: u32::to_be(control),
+ length: u32::to_be(size),
+ address: u64::to_be(addr),
});
- let mut mmio = self.0.lock();
- mmio.selector.write(u16::to_be(config_item));
- fence(Ordering::Release);
- mmio.dmacontrol.write(u64::to_be(&*xfer as *const _ as u64));
+ self.dmacontrol.write(u64::to_be(&*xfer as *const _ as u64));
let control =
unsafe { VolBox::<u32, Allow, Deny>::new(&xfer.control as *const _ as *mut u32) };
@@ -81,6 +137,141 @@ impl FwCfg {
}
}
}
+}
+
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct FwCfgLoaderAllocate {
+ pub filename: [u8; 56],
+ pub alignment: u32,
+ pub zone: u8,
+}
+
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct FwCfgLoaderAddPointer {
+ pub pointer: [u8; 56],
+ pub pointee: [u8; 56],
+ pub offset: u32,
+ pub size: u8,
+}
+
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct FwCfgLoaderAddChecksum {
+ pub filename: [u8; 56],
+ pub result_offset: u32,
+ pub start: u32,
+ pub size: u32,
+}
+
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct FwCfgLoaderWritePointer {
+ pub pointer: [u8; 56],
+ pub pointee: [u8; 56],
+ pub pointer_offset: u32,
+ pub pointee_offset: u32,
+ pub size: u8,
+}
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub union FwCfgLoaderUnion {
+ pub allocate: FwCfgLoaderAllocate,
+ pub add_pointer: FwCfgLoaderAddPointer,
+ pub add_checksum: FwCfgLoaderAddChecksum,
+ pub write_pointer: FwCfgLoaderWritePointer,
+}
+
+#[derive(Copy, Clone, Debug)]
+#[repr(u32)]
+#[allow(dead_code)]
+pub enum FwCfgLoaderCmdType {
+ FwCfgLoaderCmdUnused,
+ FwCfgLoaderCmdAllocate,
+ FwCfgLoaderCmdAddPointer,
+ FwCfgLoaderCmdAddChecksum,
+ FwCfgLoaderCmdWritePointer,
+}
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct FwCfgLoaderEntry {
+ pub _type: FwCfgLoaderCmdType,
+ pub u: FwCfgLoaderUnion,
+}
+
+impl fmt::Debug for FwCfgLoaderEntry {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut out = f.debug_struct("FwCfgLoaderEntry");
+
+ match self._type {
+ FwCfgLoaderCmdType::FwCfgLoaderCmdAllocate => unsafe {
+ out.field("u", &self.u.allocate);
+ },
+ FwCfgLoaderCmdType::FwCfgLoaderCmdAddPointer => unsafe {
+ out.field("u", &self.u.add_pointer);
+ },
+ FwCfgLoaderCmdType::FwCfgLoaderCmdAddChecksum => unsafe {
+ out.field("u", &self.u.add_checksum);
+ },
+ FwCfgLoaderCmdType::FwCfgLoaderCmdWritePointer => unsafe {
+ out.field("u", &self.u.write_pointer);
+ },
+ _ => (),
+ };
+ out.finish()
+ }
+}
+
+impl FwCfg {
+ fn new(addr: *const u8) -> FwCfg {
+ FwCfg(Spinlock::new(FwCfgMmio::new(addr)))
+ }
+
+ fn files(&self) -> FwCfgFileIterator<FwCfgFile> {
+ let size = u32::to_be(self.get_file_size(CFG_FILE_DIR) as u32);
+ FwCfgFileIterator {
+ count: size,
+ next: 0,
+ select: CFG_FILE_DIR,
+ offset: size_of::<u32>() as u32,
+ fwcfg: self,
+ phantom: PhantomData,
+ }
+ }
+
+ fn loader(&self) -> Option<FwCfgFileIterator<FwCfgLoaderEntry>> {
+ let f = self.files().find(|f| {
+ from_utf8(&f.filename).map_or(false, |s| s.trim_end_matches("\0") == "etc/table-loader")
+ })?;
+ Some(FwCfgFileIterator {
+ count: (f.size() / size_of::<FwCfgLoaderEntry>()) as u32,
+ next: 0,
+ select: f.select(),
+ offset: 0,
+ fwcfg: self,
+ phantom: PhantomData,
+ })
+ }
+
+ pub fn from_fdt_node(node: fdt::node::FdtNode) -> Option<FwCfg> {
+ let addr = node.reg()?.nth(0)?.starting_address;
+ Some(Self::new(addr))
+ }
+
+ fn dma_read(
+ &self,
+ loadbuffer: &mut [MaybeUninit<u8>],
+ size: usize,
+ config_item: u16,
+ ) -> Result<(), ()> {
+ let mut mmio = self.0.lock();
+ mmio.selector.write(u16::to_be(config_item));
+ fence(Ordering::Release);
+ mmio.dma_transfer(loadbuffer.as_ptr() as u64, size as u32)
+ }
pub fn get_file_size(&self, size_cfg: u16) -> usize {
let mut mmio = self.0.lock();
@@ -92,15 +283,11 @@ impl FwCfg {
pub fn load_file<'a>(
&self,
loadbuffer: &'a mut [MaybeUninit<u8>],
- size_cfg: u16,
+ size: usize,
data_cfg: u16,
) -> Result<&'a [u8], ()> {
- let size = self.get_file_size(size_cfg);
- if size == 0 {
- return Err(());
- }
let size = size.min(loadbuffer.len());
- self.dma_transfer(loadbuffer, size, data_cfg)?;
+ self.dma_read(loadbuffer, size, data_cfg)?;
if size < loadbuffer.len() {
loadbuffer.split_at_mut(size).1.fill(MaybeUninit::zeroed());
}
@@ -112,37 +299,210 @@ impl FwCfg {
}
}
- pub fn get_kernel_loader(&self) -> FwCfgFileLoader {
- FwCfgFileLoader {
- size_cfg: CFG_KERNEL_SIZE,
- data_cfg: CFG_KERNEL_DATA,
- fwcfg: self,
+ pub fn load_file_mut<'a>(
+ &self,
+ loadbuffer: &'a mut [MaybeUninit<u8>],
+ size: usize,
+ data_cfg: u16,
+ ) -> Result<&'a mut [u8], ()> {
+ let size = size.min(loadbuffer.len());
+ self.dma_read(loadbuffer, size, data_cfg)?;
+ if size < loadbuffer.len() {
+ loadbuffer.split_at_mut(size).1.fill(MaybeUninit::zeroed());
+ }
+ unsafe {
+ Ok(slice::from_raw_parts_mut(
+ loadbuffer.as_ptr() as *mut _,
+ loadbuffer.len(),
+ ))
}
}
- pub fn get_initrd_loader(&self) -> FwCfgFileLoader {
- FwCfgFileLoader {
- size_cfg: CFG_INITRD_SIZE,
- data_cfg: CFG_INITRD_DATA,
+ fn get_loader(&self, size_cfg: u16, data_cfg: u16) -> Option<FwCfgFileLoader> {
+ let size = self.get_file_size(size_cfg);
+ if size == 0 {
+ return None;
+ }
+ Some(FwCfgFileLoader {
+ size: size,
+ data_cfg: data_cfg,
fwcfg: self,
+ })
+ }
+
+ pub fn get_kernel_loader(&self) -> Option<FwCfgFileLoader> {
+ self.get_loader(CFG_KERNEL_SIZE, CFG_KERNEL_DATA)
+ }
+
+ pub fn get_initrd_loader(&self) -> Option<FwCfgFileLoader> {
+ self.get_loader(CFG_INITRD_SIZE, CFG_INITRD_DATA)
+ }
+
+ pub fn load_firmware_tables(&self) -> Result<*const u8, ()> {
+ FwCfgTableLoader::new(self).load_firmware_tables()
+ }
+}
+
+use alloc::collections::BTreeMap;
+
+struct FwCfgTableLoader<'a> {
+ loaded_tables: BTreeMap<[u8; 56], &'a mut [u8]>,
+ fwcfg: &'a FwCfg,
+}
+
+impl<'a> FwCfgTableLoader<'a> {
+ pub fn new(fwcfg: &'a FwCfg) -> Self {
+ FwCfgTableLoader {
+ loaded_tables: BTreeMap::new(),
+ fwcfg: fwcfg,
+ }
+ }
+
+ fn allocate(&mut self, allocate: &FwCfgLoaderAllocate) -> Result<(), ()> {
+ let f = self
+ .fwcfg
+ .files()
+ .find(|f| f.filename == allocate.filename)
+ .ok_or(())?;
+ let b = efi::memmap::allocate_pages(
+ efi::memmap::size_to_pages(f.size()),
+ MemoryType::EfiACPIReclaimMemory,
+ Placement::Anywhere,
+ )
+ .ok_or(())?;
+ let b = self.fwcfg.load_file_mut(b, f.size(), f.select())?;
+ self.loaded_tables.insert(f.filename, b);
+ Ok(())
+ }
+
+ fn add_pointer(&mut self, add_pointer: &FwCfgLoaderAddPointer) -> Result<(), ()> {
+ let tables = &mut self.loaded_tables;
+ let addend = tables.get(&add_pointer.pointee).ok_or(())?.as_ptr() as u64;
+ let pointer = tables.get_mut(&add_pointer.pointer).ok_or(())?;
+ let offset = add_pointer.offset as usize;
+
+ match add_pointer.size {
+ 1 => add_value_at_offset(addend as u8, offset, pointer),
+ 2 => add_value_at_offset(addend as u16, offset, pointer),
+ 4 => add_value_at_offset(addend as u32, offset, pointer),
+ 8 => add_value_at_offset(addend as u64, offset, pointer),
+ _ => (),
}
+ Ok(())
+ }
+
+ fn add_checksum(&mut self, add_checksum: &FwCfgLoaderAddChecksum) -> Result<(), ()> {
+ let tables = &mut self.loaded_tables;
+ let start = add_checksum.start as usize;
+ let end = start + add_checksum.size as usize;
+ let offset = add_checksum.result_offset as usize;
+ let table = tables.get_mut(&add_checksum.filename).ok_or(())?;
+ let mut checksum = 0u8;
+ table[start..end]
+ .iter()
+ .for_each(|&c| checksum = checksum.wrapping_sub(c));
+ add_value_at_offset(checksum, offset, table);
+ Ok(())
}
+
+ pub fn load_firmware_tables(&mut self) -> Result<*const u8, ()> {
+ for entry in self.fwcfg.loader().ok_or(())? {
+ match entry._type {
+ FwCfgLoaderCmdType::FwCfgLoaderCmdAllocate => unsafe {
+ self.allocate(&entry.u.allocate)
+ },
+ FwCfgLoaderCmdType::FwCfgLoaderCmdAddPointer => unsafe {
+ self.add_pointer(&entry.u.add_pointer)
+ },
+ FwCfgLoaderCmdType::FwCfgLoaderCmdAddChecksum => unsafe {
+ self.add_checksum(&entry.u.add_checksum)
+ },
+ //FwCfgLoaderCmdType::FwCfgLoaderCmdWritePointer => unsafe {
+ //},
+ _ => Err(()),
+ }?;
+ }
+ let rsdp = self
+ .loaded_tables
+ .iter()
+ .find(|(&k, &ref _v)| {
+ from_utf8(&k).map_or(false, |s| s.trim_end_matches("\0") == "etc/acpi/rsdp")
+ })
+ .ok_or(())?
+ .1;
+ Ok(rsdp.as_ptr())
+ }
+}
+
+trait LeBytes<T, const N: usize> {
+ fn from_le_bytes(val: &[u8; N]) -> T;
+ fn to_le_bytes(val: T) -> [u8; N];
+}
+
+impl LeBytes<u8, 1> for u8 {
+ fn from_le_bytes(val: &[u8; 1]) -> u8 {
+ val[0]
+ }
+
+ fn to_le_bytes(val: u8) -> [u8; 1] {
+ [val]
+ }
+}
+
+impl LeBytes<u16, 2> for u16 {
+ fn from_le_bytes(val: &[u8; 2]) -> u16 {
+ u16::from_le_bytes(*val)
+ }
+
+ fn to_le_bytes(val: u16) -> [u8; 2] {
+ u16::to_le_bytes(val)
+ }
+}
+
+impl LeBytes<u32, 4> for u32 {
+ fn from_le_bytes(val: &[u8; 4]) -> u32 {
+ u32::from_le_bytes(*val)
+ }
+
+ fn to_le_bytes(val: u32) -> [u8; 4] {
+ u32::to_le_bytes(val)
+ }
+}
+
+impl LeBytes<u64, 8> for u64 {
+ fn from_le_bytes(val: &[u8; 8]) -> u64 {
+ u64::from_le_bytes(*val)
+ }
+
+ fn to_le_bytes(val: u64) -> [u8; 8] {
+ u64::to_le_bytes(val)
+ }
+}
+
+fn add_value_at_offset<T: LeBytes<T, N> + core::ops::Add<Output = T>, const N: usize>(
+ addend: T,
+ offset: usize,
+ buf: &mut &mut [u8],
+) {
+ let end = offset + N;
+ let val: T = T::from_le_bytes(buf[offset..end].try_into().unwrap()) + addend;
+ buf[offset..end].copy_from_slice(&T::to_le_bytes(val));
}
pub struct FwCfgFileLoader<'a> {
- size_cfg: u16,
+ size: usize,
data_cfg: u16,
fwcfg: &'a FwCfg,
}
impl efi::FileLoader for FwCfgFileLoader<'_> {
fn get_size(&self) -> usize {
- self.fwcfg.get_file_size(self.size_cfg)
+ self.size
}
fn load_file<'a>(&self, loadbuffer: &'a mut [MaybeUninit<u8>]) -> Result<&'a [u8], &str> {
self.fwcfg
- .load_file(loadbuffer, self.size_cfg, self.data_cfg)
+ .load_file(loadbuffer, self.size, self.data_cfg)
.or(Err("Failed to load file from fwcfg"))
}
}
diff --git a/src/main.rs b/src/main.rs
index 333206c..a30911c 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -57,6 +57,13 @@ pub const DTB_GUID: Guid = guid!(
[0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0]
);
+pub const RSDP_GUID: Guid = guid!(
+ 0x8868e871,
+ 0xe4f1,
+ 0x11d3,
+ [0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81]
+);
+
#[global_allocator]
pub static ALLOCATOR: LockedHeap = LockedHeap::empty();
@@ -133,8 +140,6 @@ extern "C" fn efilite_main(base: *mut u8, mapped: usize, used: isize, avail: usi
let efi = efi::init().expect("Failed to init EFI runtime");
- efi.install_configtable(&DTB_GUID, dtb.as_ptr() as *const ());
-
let compat = ["qemu,fw-cfg-mmio"];
let fwcfg_node = fdt
.find_compatible(&compat)
@@ -144,6 +149,13 @@ extern "C" fn efilite_main(base: *mut u8, mapped: usize, used: isize, avail: usi
let fwcfg = fwcfg::FwCfg::from_fdt_node(fwcfg_node).expect("Failed to open fwcfg device");
+ if let Ok(rsdp) = fwcfg.load_firmware_tables() {
+ info!("Installing ACPI tables from fwcfg\n");
+ efi.install_configtable(&RSDP_GUID, rsdp as *const ());
+ } else {
+ efi.install_configtable(&DTB_GUID, dtb.as_ptr() as *const ());
+ }
+
let (placement, randomized) = if let Some(seed) = rng::get_random::<u32>() {
(Placement::Random(seed, 0x20000), true)
} else {
@@ -151,7 +163,7 @@ extern "C" fn efilite_main(base: *mut u8, mapped: usize, used: isize, avail: usi
};
let pe_image = {
- let ldr = fwcfg.get_kernel_loader();
+ let ldr = fwcfg.get_kernel_loader().unwrap();
let buf = efi::memmap::allocate_pages(
efi::memmap::size_to_pages(ldr.get_size()),
MemoryType::EfiLoaderData,
@@ -195,7 +207,7 @@ extern "C" fn efilite_main(base: *mut u8, mapped: usize, used: isize, avail: usi
idmap.map_range(code, ro_flags.non_global());
idmap.activate();
- let initrdloader = fwcfg.get_initrd_loader();
+ let initrdloader = fwcfg.get_initrd_loader().unwrap();
let _initrd = efi::initrdloadfile2::new(&initrdloader);
let _rng = efi::rng::new();
let _memattr = efi::memattr::new(&mut idmap);