Skip to content

Commit

Permalink
coreboot: Add initial coreboot support
Browse files Browse the repository at this point in the history
This commit adds coreboot specific info parser to satisfy Info trait
requirements. The coreboot info table includes various information, but
this supports E820 like memory map parsing and ACPI RSDP address search
only. It is based on coreboot's libpayload[1].

[1] payloads/libpayload/libc/coreboot.c (e1a7a26)

Signed-off-by: Akira Moroo <[email protected]>
  • Loading branch information
retrage committed Nov 6, 2020
1 parent 230daa6 commit ed06590
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 2 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ log-serial = []
# gets you most of the code size reduction, without losing _all_ debugging.
log-panic = ["log-serial"]
integration_tests = []
coreboot = []

[dependencies]
bitflags = "1.2"
Expand Down
180 changes: 180 additions & 0 deletions src/coreboot.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (C) 2020 Akira Moroo
// Copyright (C) 2009 coresystems GmbH
// Copyright (C) 2008 Advanced Micro Devices, Inc.

use core::mem::size_of;

use crate::boot::{E820Entry, Info};

#[derive(Debug)]
#[repr(C)]
struct Header {
signature: [u8; 4],
header_bytes: u32,
header_checksum: u32,
table_bytes: u32,
table_checksum: u32,
table_entries: u32,
}

#[derive(Debug)]
#[repr(C)]
struct Record {
tag: u32,
size: u32,
}

impl Record {
pub const TAG_FORWARD: u32 = 0x11;
pub const TAG_MEMORY: u32 = 0x01;
}

#[derive(Debug)]
#[repr(C)]
struct Forward {
tag: u32,
size: u32,
forward: u64,
}

#[derive(Debug)]
#[repr(C)]
struct MemMapEntry {
addr: CBUInt64,
size: CBUInt64,
entry_type: u32,
}

#[derive(Debug)]
#[repr(C)]
struct CBUInt64 {
lo: u32,
hi: u32,
}

impl CBUInt64 {
pub fn to_u64(&self) -> u64 {
((self.hi as u64) << 32) | self.lo as u64
}
}

#[derive(Debug)]
#[repr(C)]
pub struct StartInfo {
rsdp_addr: u64,
memmap_addr: u64,
memmap_entries: usize,
}

impl Default for StartInfo {
fn default() -> Self {
let (memmap_addr, memmap_entries) = match parse_info(0x0, 0x1000) {
Some((addr, n_entries)) => (addr, n_entries),
None => match parse_info(0xf0000, 0x1000) {
Some((addr, n_entries)) => (addr, n_entries),
None => panic!("coreboot table not found"),
},
};
let ebda_addr = unsafe { *(0x40e as *const u16) };
let rsdp_addr = match find_rsdp(ebda_addr as u64, 0x400) {
Some(addr) => addr,
None => match find_rsdp(0xe0000, 0x20000) {
Some(addr) => addr,
None => panic!("RSDP table not found"),
},
};
Self {
rsdp_addr,
memmap_addr,
memmap_entries,
}
}
}

impl Info for StartInfo {
fn name(&self) -> &str {
"coreboot"
}
fn rsdp_addr(&self) -> u64 {
self.rsdp_addr
}
fn cmdline(&self) -> &[u8] {
b""
}
fn num_entries(&self) -> u8 {
if self.memmap_addr == 0 {
return 0;
}
self.memmap_entries as u8
}
fn entry(&self, idx: u8) -> E820Entry {
assert!(idx < self.num_entries());
let ptr = self.memmap_addr as *const MemMapEntry;
let entry = unsafe { &*ptr.offset(idx as isize) };
E820Entry {
addr: entry.addr.to_u64(),
size: entry.size.to_u64(),
entry_type: entry.entry_type,
}
}
}

fn find_header(start: u64, len: usize) -> Option<u64> {
const CB_SIGNATURE: u32 = 0x4f49424c;
for addr in (start..(start + len as u64)).step_by(16) {
let val = unsafe { *(addr as *const u32) };
if val == CB_SIGNATURE {
return Some(addr);
}
}
None
}

fn find_rsdp(start: u64, len: usize) -> Option<u64> {
const RSDP_SIGNATURE: u64 = 0x2052_5450_2044_5352;
for addr in (start..(start + len as u64)).step_by(16) {
let val = unsafe { *(addr as *const u64) };
if val == RSDP_SIGNATURE {
return Some(addr);
}
}
None
}

fn parse_info(start: u64, len: usize) -> Option<(u64, usize)> {
let header_addr = match find_header(start, len) {
Some(addr) => addr,
None => {
return None;
}
};
let header = unsafe { &*(header_addr as *const Header) };
let ptr = unsafe { (header_addr as *const Header).offset(1) };
let mut offset = 0;
for _ in 0..header.table_entries {
let rec_ptr = unsafe { (ptr as *const u8).offset(offset as isize) };
let record = unsafe { &(*(rec_ptr as *const Record)) };
match record.tag {
Record::TAG_FORWARD => {
let forward = unsafe { &*(rec_ptr as *const Forward) };
return parse_info(forward.forward, len);
}
Record::TAG_MEMORY => {
return Some(parse_memmap(record));
}
_ => {}
}
offset += record.size;
}
None
}

fn parse_memmap(record: &Record) -> (u64, usize) {
assert_eq!(record.tag, Record::TAG_MEMORY);
let n_entries = record.size as usize / size_of::<MemMapEntry>();
let rec_size = size_of::<Record>() as isize;
let rec_ptr = (record as *const Record) as *const u8;
let mem_ptr = unsafe { rec_ptr.offset(rec_size) as *const MemMapEntry };
(mem_ptr as u64, n_entries)
}
20 changes: 18 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ mod asm;
mod block;
mod boot;
mod bzimage;
mod coreboot;
mod efi;
mod fat;
mod gdt;
Expand Down Expand Up @@ -141,17 +142,32 @@ fn boot_from_device(device: &mut block::VirtioBlockDevice, info: &dyn boot::Info
}

#[no_mangle]
#[cfg(not(feature = "coreboot"))]
pub extern "C" fn rust64_start(rdi: &pvh::StartInfo) -> ! {
serial::PORT.borrow_mut().init();

enable_sse();
paging::setup();

main(rdi)
}

fn main(info: &dyn boot::Info) -> ! {
#[no_mangle]
#[cfg(feature = "coreboot")]
pub extern "C" fn rust64_start() -> ! {
serial::PORT.borrow_mut().init();
log!("\nBooting with {}", info.name());

enable_sse();
paging::setup();

let info = coreboot::StartInfo::default();

main(&info)
}

fn main(info: &dyn boot::Info) -> ! {
log!("\nBooting with {}", info.name());

pci::print_bus();

pci::with_devices(
Expand Down

0 comments on commit ed06590

Please sign in to comment.