Skip to content

Commit 4a3843f

Browse files
committed
coreboot: Add initial coreboot support
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]>
1 parent e16524d commit 4a3843f

File tree

3 files changed

+188
-2
lines changed

3 files changed

+188
-2
lines changed

Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ log-serial = []
2222
# gets you most of the code size reduction, without losing _all_ debugging.
2323
log-panic = ["log-serial"]
2424
integration_tests = []
25+
coreboot = []
2526

2627
[dependencies]
2728
bitflags = "1.2"

src/coreboot.rs

+169
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
// Copyright (C) 2020 Akira Moroo
3+
// Copyright (C) 2009 coresystems GmbH
4+
// Copyright (C) 2008 Advanced Micro Devices, Inc.
5+
6+
use core::mem::size_of;
7+
8+
use crate::boot::{E820Entry, Info};
9+
10+
#[derive(Debug)]
11+
#[repr(C)]
12+
struct Header {
13+
signature: [u8; 4],
14+
header_bytes: u32,
15+
header_checksum: u32,
16+
table_bytes: u32,
17+
table_checksum: u32,
18+
table_entries: u32,
19+
}
20+
21+
#[derive(Debug)]
22+
#[repr(C)]
23+
struct Record {
24+
tag: u32,
25+
size: u32,
26+
}
27+
28+
impl Record {
29+
pub const TAG_FORWARD: u32 = 0x11;
30+
pub const TAG_MEMORY: u32 = 0x01;
31+
}
32+
33+
#[derive(Debug)]
34+
#[repr(C)]
35+
struct Forward {
36+
tag: u32,
37+
size: u32,
38+
forward: u64,
39+
}
40+
41+
#[derive(Debug)]
42+
#[repr(C)]
43+
struct MemMapEntry {
44+
addr: u64,
45+
size: u64,
46+
entry_type: u32,
47+
}
48+
49+
#[derive(Debug)]
50+
#[repr(C)]
51+
pub struct StartInfo {
52+
rsdp_addr: u64,
53+
memmap_addr: u64,
54+
memmap_entries: usize,
55+
}
56+
57+
impl Default for StartInfo {
58+
fn default() -> Self {
59+
let (memmap_addr, memmap_entries) = match parse_info(0x0, 0x1000) {
60+
Some((addr, n_entries)) => (addr, n_entries),
61+
None => match parse_info(0xf0000, 0x1000) {
62+
Some((addr, n_entries)) => (addr, n_entries),
63+
None => panic!("coreboot table not found"),
64+
},
65+
};
66+
let ebda_addr = unsafe { *(0x40e as *const u16) };
67+
let rsdp_addr = match find_rsdp(ebda_addr as u64, 0x400) {
68+
Some(addr) => addr,
69+
None => match find_rsdp(0xe0000, 0x20000) {
70+
Some(addr) => addr,
71+
None => panic!("RSDP table not found"),
72+
},
73+
};
74+
Self {
75+
rsdp_addr,
76+
memmap_addr,
77+
memmap_entries,
78+
}
79+
}
80+
}
81+
82+
impl Info for StartInfo {
83+
fn name(&self) -> &str {
84+
"coreboot"
85+
}
86+
fn rsdp_addr(&self) -> u64 {
87+
self.rsdp_addr
88+
}
89+
fn cmdline(&self) -> &[u8] {
90+
b""
91+
}
92+
fn num_entries(&self) -> u8 {
93+
if self.memmap_addr == 0 {
94+
return 0;
95+
}
96+
self.memmap_entries as u8
97+
}
98+
fn entry(&self, idx: u8) -> E820Entry {
99+
assert!(idx < self.num_entries());
100+
let ptr = self.memmap_addr as *const MemMapEntry;
101+
let entry = unsafe { &*ptr.offset(idx as isize) };
102+
let addr = (entry.addr & ((1 << 32) - 1) << 32) | (entry.addr >> 32);
103+
let size = (entry.size & ((1 << 32) - 1) << 32) | (entry.size >> 32);
104+
E820Entry {
105+
addr,
106+
size,
107+
entry_type: entry.entry_type,
108+
}
109+
}
110+
}
111+
112+
fn find_header(start: u64, len: usize) -> Option<u64> {
113+
const CB_SIGNATURE: u32 = 0x4f49424c;
114+
for addr in (start..(start + len as u64)).step_by(16) {
115+
let val = unsafe { *(addr as *const u32) };
116+
if val == CB_SIGNATURE {
117+
return Some(addr);
118+
}
119+
}
120+
None
121+
}
122+
123+
fn find_rsdp(start: u64, len: usize) -> Option<u64> {
124+
const RSDP_SIGNATURE: u64 = 0x2052_5450_2044_5352;
125+
for addr in (start..(start + len as u64)).step_by(16) {
126+
let val = unsafe { *(addr as *const u64) };
127+
if val == RSDP_SIGNATURE {
128+
return Some(addr);
129+
}
130+
}
131+
None
132+
}
133+
134+
fn parse_info(start: u64, len: usize) -> Option<(u64, usize)> {
135+
let header_addr = match find_header(start, len) {
136+
Some(addr) => addr,
137+
None => {
138+
return None;
139+
}
140+
};
141+
let header = unsafe { &*(header_addr as *const Header) };
142+
let ptr = unsafe { (header_addr as *const Header).offset(1) };
143+
let mut offset = 0;
144+
for _ in 0..header.table_entries {
145+
let rec_ptr = unsafe { (ptr as *const u8).offset(offset as isize) };
146+
let record = unsafe { &(*(rec_ptr as *const Record)) };
147+
match record.tag {
148+
Record::TAG_FORWARD => {
149+
let forward = unsafe { &*(rec_ptr as *const Forward) };
150+
return parse_info(forward.forward, len);
151+
}
152+
Record::TAG_MEMORY => {
153+
return Some(parse_memmap(record));
154+
}
155+
_ => {}
156+
}
157+
offset += record.size;
158+
}
159+
None
160+
}
161+
162+
fn parse_memmap(record: &Record) -> (u64, usize) {
163+
assert_eq!(record.tag, Record::TAG_MEMORY);
164+
let n_entries = record.size as usize / size_of::<MemMapEntry>();
165+
let rec_size = size_of::<Record>() as isize;
166+
let rec_ptr = (record as *const Record) as *const u8;
167+
let mem_ptr = unsafe { rec_ptr.offset(rec_size) as *const MemMapEntry };
168+
(mem_ptr as u64, n_entries)
169+
}

src/main.rs

+18-2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ mod asm;
3636
mod block;
3737
mod boot;
3838
mod bzimage;
39+
mod coreboot;
3940
mod efi;
4041
mod fat;
4142
mod gdt;
@@ -141,17 +142,32 @@ fn boot_from_device(device: &mut block::VirtioBlockDevice, info: &dyn boot::Info
141142
}
142143

143144
#[no_mangle]
145+
#[cfg(not(feature = "coreboot"))]
144146
pub extern "C" fn rust64_start(rdi: &pvh::StartInfo) -> ! {
147+
serial::PORT.borrow_mut().init();
148+
149+
enable_sse();
150+
paging::setup();
151+
145152
main(rdi)
146153
}
147154

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

152160
enable_sse();
153161
paging::setup();
154162

163+
let info = coreboot::StartInfo::default();
164+
165+
main(&info)
166+
}
167+
168+
fn main(info: &dyn boot::Info) -> ! {
169+
log!("\nBooting with {}", info.name());
170+
155171
pci::print_bus();
156172

157173
pci::with_devices(

0 commit comments

Comments
 (0)