pub mod bindings;
pub mod reg;
use std::mem::{offset_of, size_of};
use zerocopy::{FromBytes, IntoBytes, transmute};
#[cfg(target_arch = "x86_64")]
use crate::arch::layout::{
APIC_START, IOAPIC_START, PORT_ACPI_RESET, PORT_ACPI_SLEEP_CONTROL, PORT_ACPI_SLEEP_STATUS,
};
use crate::arch::layout::{PCIE_CONFIG_START, PORT_ACPI_TIMER};
use crate::firmware::acpi::bindings::AcpiFadtFlag;
use crate::utils::wrapping_sum;
use self::bindings::{
AcpiGenericAddress, AcpiMadtIoApic, AcpiMadtLocalX2apic, AcpiMcfgAllocation,
AcpiSubtableHeader, AcpiTableFadt, AcpiTableHeader, AcpiTableMadt, AcpiTableMcfg1,
AcpiTableRsdp, AcpiTableXsdt3, FADT_MAJOR_VERSION, FADT_MINOR_VERSION, MADT_IO_APIC,
MADT_LOCAL_X2APIC, MADT_REVISION, MCFG_REVISION, RSDP_REVISION, SIG_FADT, SIG_MADT, SIG_MCFG,
SIG_RSDP, SIG_XSDT, XSDT_REVISION,
};
use self::reg::FADT_RESET_VAL;
const OEM_ID: [u8; 6] = *b"ALIOTH";
fn default_header() -> AcpiTableHeader {
AcpiTableHeader {
checksum: 0,
oem_id: OEM_ID,
oem_table_id: *b"ALIOTHVM",
oem_revision: 1,
asl_compiler_id: *b"ALTH",
asl_compiler_revision: 1,
..Default::default()
}
}
pub fn create_rsdp(xsdt_addr: u64) -> AcpiTableRsdp {
AcpiTableRsdp {
signature: SIG_RSDP,
oem_id: OEM_ID,
revision: RSDP_REVISION,
length: size_of::<AcpiTableRsdp>() as u32,
xsdt_physical_address: transmute!(xsdt_addr),
..Default::default()
}
}
pub fn create_xsdt(entries: [u64; 3]) -> AcpiTableXsdt3 {
let total_length = size_of::<AcpiTableHeader>() + size_of::<u64>() * 3;
let entries = entries.map(|e| transmute!(e));
AcpiTableXsdt3 {
header: AcpiTableHeader {
signature: SIG_XSDT,
length: total_length as u32,
revision: XSDT_REVISION,
..default_header()
},
entries,
}
}
pub fn create_fadt(dsdt_addr: u64) -> AcpiTableFadt {
AcpiTableFadt {
header: AcpiTableHeader {
signature: SIG_FADT,
revision: FADT_MAJOR_VERSION,
length: size_of::<AcpiTableFadt>() as u32,
..default_header()
},
reset_register: AcpiGenericAddress {
space_id: 1,
bit_width: 8,
bit_offset: 0,
access_width: 1,
address: transmute!(PORT_ACPI_RESET as u64),
},
reset_value: FADT_RESET_VAL,
xpm_timer_block: AcpiGenericAddress {
space_id: 1,
bit_width: 32,
bit_offset: 0,
access_width: 3,
address: transmute!(PORT_ACPI_TIMER as u64),
},
sleep_control: AcpiGenericAddress {
space_id: 1,
bit_width: 8,
bit_offset: 0,
access_width: 1,
address: transmute!(PORT_ACPI_SLEEP_CONTROL as u64),
},
sleep_status: AcpiGenericAddress {
space_id: 1,
bit_width: 8,
bit_offset: 0,
access_width: 1,
address: transmute!(PORT_ACPI_SLEEP_STATUS as u64),
},
flags: AcpiFadtFlag::HW_REDUCED_ACPI
| AcpiFadtFlag::RESET_REG_SUP
| AcpiFadtFlag::TMR_VAL_EXT,
minor_revision: FADT_MINOR_VERSION,
hypervisor_id: *b"ALIOTH ",
xdsdt: transmute!(dsdt_addr),
..Default::default()
}
}
#[cfg(target_arch = "x86_64")]
pub fn create_madt(apic_ids: &[u32]) -> (AcpiTableMadt, AcpiMadtIoApic, Vec<AcpiMadtLocalX2apic>) {
let total_length = size_of::<AcpiTableMadt>()
+ size_of::<AcpiMadtIoApic>()
+ apic_ids.len() * size_of::<AcpiMadtLocalX2apic>();
let mut checksum = 0u8;
let mut madt = AcpiTableMadt {
header: AcpiTableHeader {
signature: SIG_MADT,
length: total_length as u32,
revision: MADT_REVISION,
..default_header()
},
address: APIC_START as u32,
flags: 0,
};
checksum = checksum.wrapping_sub(wrapping_sum(madt.as_bytes()));
let io_apic = AcpiMadtIoApic {
header: AcpiSubtableHeader {
type_: MADT_IO_APIC,
length: size_of::<AcpiMadtIoApic>() as u8,
},
id: 0,
address: IOAPIC_START as u32,
global_irq_base: 0,
..Default::default()
};
checksum = checksum.wrapping_sub(wrapping_sum(io_apic.as_bytes()));
let mut x2apics = vec![];
for (index, apic_id) in apic_ids.iter().enumerate() {
let x2apic = AcpiMadtLocalX2apic {
header: AcpiSubtableHeader {
type_: MADT_LOCAL_X2APIC,
length: size_of::<AcpiMadtLocalX2apic>() as u8,
},
local_apic_id: *apic_id,
uid: index as u32,
lapic_flags: 1,
..Default::default()
};
checksum = checksum.wrapping_sub(wrapping_sum(x2apic.as_bytes()));
x2apics.push(x2apic);
}
madt.header.checksum = checksum;
(madt, io_apic, x2apics)
}
pub fn create_mcfg() -> AcpiTableMcfg1 {
let mut mcfg = AcpiTableMcfg1 {
header: AcpiTableHeader {
signature: SIG_MCFG,
length: size_of::<AcpiTableMcfg1>() as u32,
revision: MCFG_REVISION,
..default_header()
},
reserved: [0; 8],
allocations: [AcpiMcfgAllocation {
address: transmute!(PCIE_CONFIG_START),
pci_segment: 0,
start_bus_number: 0,
end_bus_number: 0,
..Default::default()
}],
};
mcfg.header.checksum = 0u8.wrapping_sub(wrapping_sum(mcfg.as_bytes()));
mcfg
}
pub struct AcpiTable {
pub(crate) rsdp: AcpiTableRsdp,
pub(crate) tables: Vec<u8>,
pub(crate) table_pointers: Vec<usize>,
pub(crate) table_checksums: Vec<(usize, usize)>,
}
impl AcpiTable {
pub fn relocate(&mut self, table_addr: u64) {
let old_addr: u64 = transmute!(self.rsdp.xsdt_physical_address);
self.rsdp.xsdt_physical_address = transmute!(table_addr);
for pointer in self.table_pointers.iter() {
let (old_val, _) = u64::read_from_prefix(&self.tables[*pointer..]).unwrap();
let new_val = old_val.wrapping_sub(old_addr).wrapping_add(table_addr);
IntoBytes::write_to_prefix(&new_val, &mut self.tables[*pointer..]).unwrap();
}
}
pub fn update_checksums(&mut self) {
let sum = wrapping_sum(&self.rsdp.as_bytes()[0..20]);
self.rsdp.checksum = self.rsdp.checksum.wrapping_sub(sum);
let ext_sum = wrapping_sum(self.rsdp.as_bytes());
self.rsdp.extended_checksum = self.rsdp.extended_checksum.wrapping_sub(ext_sum);
for (start, len) in self.table_checksums.iter() {
let sum = wrapping_sum(&self.tables[*start..(*start + *len)]);
let checksum = &mut self.tables[start + offset_of!(AcpiTableHeader, checksum)];
*checksum = checksum.wrapping_sub(sum);
}
}
pub fn clear_checksums(&mut self) {
for (start, _) in self.table_checksums.iter() {
let checksum = &mut self.tables[start + offset_of!(AcpiTableHeader, checksum)];
*checksum = 0;
}
self.rsdp.checksum = 0;
self.rsdp.extended_checksum = 0;
}
pub fn rsdp(&self) -> &AcpiTableRsdp {
&self.rsdp
}
pub fn tables(&self) -> &[u8] {
&self.tables
}
pub fn pointers(&self) -> &[usize] {
&self.table_pointers
}
pub fn checksums(&self) -> &[(usize, usize)] {
&self.table_checksums
}
pub fn take(self) -> (AcpiTableRsdp, Vec<u8>) {
(self.rsdp, self.tables)
}
}