Skip to content

Commit

Permalink
Load SMBIOS tables from fwcfg
Browse files Browse the repository at this point in the history
  • Loading branch information
ardbiesheuvel committed Nov 4, 2023
1 parent 6bc2bb1 commit b72adde
Show file tree
Hide file tree
Showing 4 changed files with 158 additions and 113 deletions.
52 changes: 52 additions & 0 deletions src/fwcfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,58 @@ impl FwCfg {
pub fn load_firmware_tables<'a>(&self, efi: &'a EfiContext) -> Result<*const u8, &'static str> {
FwCfgTableLoader::new(self, efi).load_firmware_tables()
}

pub fn load_smbios_tables<'a>(&self, efi: &'a EfiContext) -> Result<*const u8, &'static str> {
let v: Vec<_> = self
.files()
.filter_map(|f| {
from_utf8(&f.filename).map_or(None, |s| match s.trim_end_matches("\0") {
"etc/smbios/smbios-anchor" => Some((0, f)),
"etc/smbios/smbios-tables" => Some((1, f)),
_ => None,
})
})
.collect::<BTreeMap<_, _>>()
.into_values()
.collect();
if v.len() < 2 {
return Err("No SMBIOS tables available");
}

if v[0].size() < 24 {
return Err("Unexpected anchor type");
}

let b = efi
.allocate_pages(
memmap::size_to_pages(v[0].size() + v[1].size()),
MemoryType::EfiACPIReclaimMemory,
Placement::Anywhere,
)
.ok_or("Failed to allocate blob memory")?;

let (a, t) = b.split_at_mut(v[0].size());
let a = self.load_file_mut(a, 0, v[0].size(), v[0].select())?;
let t = self.load_file_mut(t, 0, v[1].size(), v[1].select())?;

// SAFETY: a[] is page aligned and at least 24 bytes in size so writing
// 8 bytes at offset #16 is safe.
unsafe {
// Point the address field at offset #16 in the anchor to the table blob
let p = a.as_mut_ptr().offset(16) as *mut *const u8;
*p = t.as_ptr();
}

let size = a[6] as usize;
let mut checksum = 0u8;

for c in &a[..size] {
checksum = checksum.wrapping_sub(*c);
}
a[5] = checksum;

Ok(a.as_ptr() as *const u8)
}
}

struct FwCfgTableLoader<'a> {
Expand Down
31 changes: 20 additions & 11 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,26 +37,32 @@ extern crate aarch64_intrinsics;
extern crate aarch64_paging;
use aarch64_paging::paging::Attributes;

use efiloader::memmap::MemoryMap;
use efiloader::memorytype::MemoryType::*;
use efiloader::*;
use efiloader::memmap::*;
use efiloader::memorytype::*;
use efiloader::DumbConsole;
use efiloader::{guid, Guid};
use efiloader::memorytype::MemoryType::*;

pub const DTB_GUID: Guid = guid!(
const DTB_GUID: Guid = guid!(
0xb1b621d5,
0xf19c,
0x41a5,
[0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0]
);

pub const RSDP_GUID: Guid = guid!(
const RSDP_GUID: Guid = guid!(
0x8868e871,
0xe4f1,
0x11d3,
[0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81]
);

const SMBIOS3_GUID: Guid = guid!(
0xf2fd1544,
0x9794,
0x4a2c,
[0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94]
);

#[global_allocator]
pub static ALLOCATOR: LockedHeap = LockedHeap::empty();

Expand Down Expand Up @@ -232,7 +238,7 @@ extern "C" fn efilite_main(base: *mut u8, used: isize, avail: usize) {
}

let con = con.map(|c| c as &(dyn DumbConsole + Send + Sync));
let rng = rng::Random::new();
let rng = Some(rng::Random::new());
let efi = efiloader::init(con, memmap, mapper, rng).expect("Failed to init EFI runtime");

// Register our PSCI based ResetSystem implementation
Expand All @@ -242,8 +248,7 @@ extern "C" fn efilite_main(base: *mut u8, used: isize, avail: usize) {
let tbl = fwcfg.load_firmware_tables(efi);
if let Ok(rsdp) = tbl {
info!("Booting in ACPI mode\n");
efi.install_configtable(&RSDP_GUID, rsdp as *const ())
.expect("Failed to install config table\n");
efi.install_configtable(&RSDP_GUID, rsdp as *const ());

// ACPI does not describe the RTC as a device, so we need to expose
// it via the GetTime EFI runtime service
Expand All @@ -254,8 +259,12 @@ extern "C" fn efilite_main(base: *mut u8, used: isize, avail: usize) {
} else {
debug!("ACPI tables unavailable: {}\n", tbl.err().unwrap());
info!("Booting in DT mode\n");
efi.install_configtable(&DTB_GUID, dtb.start as *const ())
.expect("Failed to install config table\n");
efi.install_configtable(&DTB_GUID, dtb.start as *const ());
}

if let Ok(anchor) = fwcfg.load_smbios_tables(efi) {
info!("Installing SMBIOS tables\n");
efi.install_configtable(&SMBIOS3_GUID, anchor as *const ());
}

fwcfg.get_initrd_loader().map(|i| efi.set_initrd_loader(i));
Expand Down
30 changes: 16 additions & 14 deletions src/mapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,28 @@
use aarch64_paging::{paging::*, *};
use efiloader::memorytype::*;

use alloc::boxed::Box;
use alloc::vec::Vec;
use core::ops::Range;
use spinning_top::Spinlock;

const ASID: usize = 1;
const PAGING_ROOT_LEVEL: usize = 1; // must match the page tables in flash

pub(crate) struct MemoryMapper {
idmap: idmap::IdMap,
idmap: Spinlock<idmap::IdMap>,
reserved: Vec<Range<usize>>,
}

impl MemoryMapper {
pub(crate) fn new() -> Box<MemoryMapper> {
Box::new(MemoryMapper {
idmap: idmap::IdMap::new(ASID, PAGING_ROOT_LEVEL),
pub(crate) fn new() -> MemoryMapper {
MemoryMapper {
idmap: Spinlock::new(idmap::IdMap::new(ASID, PAGING_ROOT_LEVEL)),
reserved: Vec::new(),
})
}
}

pub(crate) fn activate(&mut self) {
unsafe { self.idmap.activate() }
unsafe { self.idmap.lock().activate() }
}

fn match_efi_attributes(attributes: u64) -> Attributes {
Expand All @@ -49,9 +49,10 @@ impl MemoryMapper {
ret
}

pub(crate) fn map_range(&mut self, r: &Range<usize>, flags: Attributes) {
pub(crate) fn map_range(&self, r: &Range<usize>, flags: Attributes) {
let mr = MemoryRegion::new(r.start, r.end);
self.idmap
.lock()
.map_range(&mr, flags)
.unwrap_or_else(|e| log::error!("Failed to map range {e}\n"));
log::info!("[{mr}] {flags:?}\n");
Expand All @@ -73,7 +74,7 @@ impl MemoryMapper {
}

impl efiloader::MemoryMapper for MemoryMapper {
fn remap_range(&mut self, range: &Range<usize>, set: u64, clr: u64) -> Result<(), &str> {
fn remap_range(&self, range: &Range<usize>, set: u64, clr: u64) -> Result<(), &str> {
let r = MemoryRegion::new(range.start, range.end);
let set = Self::match_efi_attributes(set);
let clr = Self::match_efi_attributes(clr);
Expand All @@ -84,22 +85,23 @@ impl efiloader::MemoryMapper for MemoryMapper {

let c = |_: &MemoryRegion, d: &mut Descriptor, _: usize| Ok(d.modify_flags(set, clr));

self.idmap
let mut idmap = self.idmap.lock();
idmap
.modify_range(&r, &c)
.or_else(|e| match e {
MapError::BreakBeforeMakeViolation(_) => {
// SAFETY: this code and the current stack are covered by the initial
// mapping in NOR flash so deactivating this mapping is safe
unsafe {
self.idmap.deactivate();
idmap.deactivate();
}

let e = self.idmap.modify_range(&r, &c);
let e = idmap.modify_range(&r, &c);

// SAFETY: we are reactivating the ID mapping we deactivated just now
// and we double checked that the reserved regions were left untouched
unsafe {
self.idmap.activate();
idmap.activate();
}
e
}
Expand Down Expand Up @@ -133,7 +135,7 @@ impl efiloader::MemoryMapper for MemoryMapper {
}
};

self.idmap.walk_range(&r, &mut c).ok()?;
self.idmap.lock().walk_range(&r, &mut c).ok()?;
Some(Self::get_attr_from_flags(any.bits()))
}
}
Loading

0 comments on commit b72adde

Please sign in to comment.