Skip to content

Commit 838a9a9

Browse files
committed
Prepare the ACPI tables for generation
Combine all ACPI tables into the format expected by firmware(OVMF) by using fw_cfg's table-loader commands for address patching and checksum computation. Signed-off-by: Amey Narkhede <ameynarkhede03@gmail.com>
1 parent 56a7f41 commit 838a9a9

1 file changed

Lines changed: 234 additions & 1 deletion

File tree

lib/propolis/src/hw/qemu/fwcfg.rs

Lines changed: 234 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1478,6 +1478,7 @@ pub mod formats {
14781478

14791479
pub const ACPI_TABLE_HEADER_SIZE: usize = 36;
14801480
const ACPI_TABLE_LENGTH_OFFSET: usize = 4;
1481+
pub const ACPI_TABLE_CHECKSUM_OFF: usize = 9;
14811482

14821483
#[derive(Copy, Clone, IntoBytes, Immutable)]
14831484
#[repr(C, packed)]
@@ -1551,7 +1552,7 @@ pub mod formats {
15511552

15521553
pub fn add_entry(&mut self) -> u32 {
15531554
let offset = self.data.len() as u32;
1554-
self.data.extend_from_slice(&[0u8; 8]);
1555+
self.data.extend_from_slice(&[0u8; size_of::<u64>()]);
15551556
offset
15561557
}
15571558

@@ -2004,6 +2005,238 @@ pub mod formats {
20042005
}
20052006
}
20062007

2008+
pub struct AcpiConfig {
2009+
pub num_cpus: u8,
2010+
pub local_apic_addr: u32,
2011+
pub io_apic_id: u8,
2012+
pub io_apic_addr: u32,
2013+
pub pcie_ecam_base: u64,
2014+
pub pcie_ecam_size: u64,
2015+
pub pcie_bus_start: u8,
2016+
pub pcie_bus_end: u8,
2017+
pub pcie_mmio32_base: u64,
2018+
pub pcie_mmio32_limit: u64,
2019+
pub pcie_mmio64_base: u64,
2020+
pub pcie_mmio64_limit: u64,
2021+
pub com_ports: Vec<(u16, u8)>,
2022+
}
2023+
2024+
impl Default for AcpiConfig {
2025+
fn default() -> Self {
2026+
Self {
2027+
num_cpus: 1,
2028+
local_apic_addr: 0xfee0_0000,
2029+
io_apic_id: 0,
2030+
io_apic_addr: 0xfec0_0000,
2031+
pcie_ecam_base: 0xe000_0000,
2032+
pcie_ecam_size: 0x1000_0000,
2033+
pcie_bus_start: 0,
2034+
pcie_bus_end: 255,
2035+
pcie_mmio32_base: 0xc000_0000,
2036+
pcie_mmio32_limit: 0xfbff_ffff,
2037+
pcie_mmio64_base: 0x1_0000_0000,
2038+
pcie_mmio64_limit: 0xf_ffff_ffff,
2039+
com_ports: Vec::new(),
2040+
}
2041+
}
2042+
}
2043+
2044+
pub struct AcpiTables {
2045+
pub tables: Vec<u8>,
2046+
pub rsdp: Vec<u8>,
2047+
pub loader: Vec<u8>,
2048+
}
2049+
2050+
pub fn build_acpi_tables(config: &AcpiConfig) -> AcpiTables {
2051+
use crate::firmware::acpi::{
2052+
build_dsdt_aml, ComPortConfig, DsdtConfig, PcieConfig,
2053+
};
2054+
2055+
let mut tables = Vec::new();
2056+
let mut loader = TableLoader::new();
2057+
2058+
let dsdt_config = DsdtConfig {
2059+
pcie: Some(PcieConfig {
2060+
ecam_base: config.pcie_ecam_base,
2061+
ecam_size: config.pcie_ecam_size,
2062+
bus_start: config.pcie_bus_start,
2063+
bus_end: config.pcie_bus_end,
2064+
mmio32_base: config.pcie_mmio32_base,
2065+
mmio32_limit: config.pcie_mmio32_limit,
2066+
mmio64_base: config.pcie_mmio64_base,
2067+
mmio64_limit: config.pcie_mmio64_limit,
2068+
}),
2069+
com_ports: config
2070+
.com_ports
2071+
.iter()
2072+
.map(|&(io_base, irq)| ComPortConfig { io_base, irq })
2073+
.collect(),
2074+
};
2075+
let aml = build_dsdt_aml(&dsdt_config);
2076+
let mut dsdt = Dsdt::new();
2077+
dsdt.append_aml(&aml);
2078+
let dsdt_offset = tables.len();
2079+
tables.extend_from_slice(&dsdt.finish());
2080+
2081+
let fadt = Fadt::new();
2082+
let fadt_offset = tables.len();
2083+
tables.extend_from_slice(&fadt.finish());
2084+
2085+
let mut madt = Madt::new(config.local_apic_addr);
2086+
for i in 0..config.num_cpus {
2087+
madt.add_local_apic(i, i, MADT_LAPIC_ENABLED);
2088+
}
2089+
madt.add_io_apic(config.io_apic_id, config.io_apic_addr, 0);
2090+
madt.add_int_src_override(ISA_BUS, ISA_IRQ_TIMER, GSI_TIMER, 0);
2091+
madt.add_int_src_override(
2092+
ISA_BUS,
2093+
ISA_IRQ_SCI,
2094+
GSI_SCI,
2095+
MADT_INT_LEVEL_ACTIVE_HIGH,
2096+
);
2097+
madt.add_lapic_nmi(ACPI_PROCESSOR_ALL, MADT_INT_FLAGS_DEFAULT, LINT1);
2098+
let madt_offset = tables.len();
2099+
tables.extend_from_slice(&madt.finish());
2100+
2101+
let mut mcfg = Mcfg::new();
2102+
mcfg.add_allocation(
2103+
config.pcie_ecam_base,
2104+
0,
2105+
config.pcie_bus_start,
2106+
config.pcie_bus_end,
2107+
);
2108+
let mcfg_offset = tables.len();
2109+
tables.extend_from_slice(&mcfg.finish());
2110+
2111+
let hpet = Hpet::new();
2112+
let hpet_offset = tables.len();
2113+
tables.extend_from_slice(&hpet.finish());
2114+
2115+
let mut xsdt = Xsdt::new();
2116+
let xsdt_fadt_off = xsdt.add_entry();
2117+
let xsdt_madt_off = xsdt.add_entry();
2118+
let xsdt_mcfg_off = xsdt.add_entry();
2119+
let xsdt_hpet_off = xsdt.add_entry();
2120+
let xsdt_offset = tables.len();
2121+
tables.extend_from_slice(&xsdt.finish());
2122+
2123+
let facs = Facs::new();
2124+
let facs_offset = tables.len();
2125+
tables.extend_from_slice(&facs.finish());
2126+
2127+
let rsdp_data = Rsdp::new().finish();
2128+
2129+
tables[fadt_offset + FADT_OFF_FACS32
2130+
..fadt_offset + FADT_OFF_FACS32 + size_of::<u32>()]
2131+
.copy_from_slice(&(facs_offset as u32).to_le_bytes());
2132+
2133+
tables[fadt_offset + FADT_OFF_DSDT32
2134+
..fadt_offset + FADT_OFF_DSDT32 + size_of::<u32>()]
2135+
.copy_from_slice(&(dsdt_offset as u32).to_le_bytes());
2136+
tables[fadt_offset + FADT_OFF_DSDT64
2137+
..fadt_offset + FADT_OFF_DSDT64 + size_of::<u64>()]
2138+
.copy_from_slice(&(dsdt_offset as u64).to_le_bytes());
2139+
2140+
let xsdt_entries = [
2141+
(xsdt_fadt_off, fadt_offset),
2142+
(xsdt_madt_off, madt_offset),
2143+
(xsdt_mcfg_off, mcfg_offset),
2144+
(xsdt_hpet_off, hpet_offset),
2145+
];
2146+
for (entry_off, table_offset) in xsdt_entries {
2147+
let off = xsdt_offset + entry_off as usize;
2148+
tables[off..off + size_of::<u64>()]
2149+
.copy_from_slice(&(table_offset as u64).to_le_bytes());
2150+
}
2151+
2152+
loader
2153+
.add_allocate(ACPI_TABLES_FWCFG_NAME, 64, AllocZone::High)
2154+
.unwrap();
2155+
loader.add_allocate(ACPI_RSDP_FWCFG_NAME, 16, AllocZone::FSeg).unwrap();
2156+
2157+
let table_pointers: &[(u32, u8)] = &[
2158+
(
2159+
fadt_offset as u32 + FADT_OFF_FACS32 as u32,
2160+
size_of::<u32>() as u8,
2161+
),
2162+
(
2163+
fadt_offset as u32 + FADT_OFF_DSDT32 as u32,
2164+
size_of::<u32>() as u8,
2165+
),
2166+
(
2167+
fadt_offset as u32 + FADT_OFF_DSDT64 as u32,
2168+
size_of::<u64>() as u8,
2169+
),
2170+
(xsdt_offset as u32 + xsdt_fadt_off, size_of::<u64>() as u8),
2171+
(xsdt_offset as u32 + xsdt_madt_off, size_of::<u64>() as u8),
2172+
(xsdt_offset as u32 + xsdt_mcfg_off, size_of::<u64>() as u8),
2173+
(xsdt_offset as u32 + xsdt_hpet_off, size_of::<u64>() as u8),
2174+
];
2175+
for &(offset, size) in table_pointers {
2176+
loader
2177+
.add_pointer(
2178+
ACPI_TABLES_FWCFG_NAME,
2179+
ACPI_TABLES_FWCFG_NAME,
2180+
offset,
2181+
size,
2182+
)
2183+
.unwrap();
2184+
}
2185+
2186+
loader
2187+
.add_pointer(
2188+
ACPI_RSDP_FWCFG_NAME,
2189+
ACPI_TABLES_FWCFG_NAME,
2190+
RSDP_XSDT_ADDR_OFFSET as u32,
2191+
size_of::<u64>() as u8,
2192+
)
2193+
.unwrap();
2194+
2195+
let table_offsets = [
2196+
dsdt_offset,
2197+
fadt_offset,
2198+
madt_offset,
2199+
mcfg_offset,
2200+
hpet_offset,
2201+
xsdt_offset,
2202+
facs_offset,
2203+
];
2204+
for pair in table_offsets.windows(2) {
2205+
let (start, end) = (pair[0] as u32, pair[1] as u32);
2206+
loader
2207+
.add_checksum(
2208+
ACPI_TABLES_FWCFG_NAME,
2209+
start + ACPI_TABLE_CHECKSUM_OFF as u32,
2210+
start,
2211+
end - start,
2212+
)
2213+
.unwrap();
2214+
}
2215+
2216+
let rsdp_checksums = [
2217+
(RSDP_CHECKSUM_OFFSET, RSDP_V1_SIZE),
2218+
(RSDP_EXT_CHECKSUM_OFFSET, RSDP_SIZE),
2219+
];
2220+
for (checksum_off, length) in rsdp_checksums {
2221+
loader
2222+
.add_checksum(
2223+
ACPI_RSDP_FWCFG_NAME,
2224+
checksum_off as u32,
2225+
0,
2226+
length as u32,
2227+
)
2228+
.unwrap();
2229+
}
2230+
2231+
let loader_entry = loader.finish();
2232+
let loader_bytes = match loader_entry {
2233+
super::Entry::Bytes(b) => b,
2234+
_ => unreachable!(),
2235+
};
2236+
2237+
AcpiTables { tables, rsdp: rsdp_data, loader: loader_bytes }
2238+
}
2239+
20072240
#[cfg(test)]
20082241
mod test_table_loader {
20092242
use super::*;

0 commit comments

Comments
 (0)