use super::aml_compiler::AmlBuilder;
use util::byte_code::ByteCode;
use util::checksum::generate_checksum;
pub const TABLE_CHECKSUM_OFFSET: u32 = 9;
pub const INTERRUPT_PPIS_COUNT: u32 = 16;
pub const INTERRUPT_SGIS_COUNT: u32 = 16;
pub const ACPI_GTDT_ARCH_TIMER_VIRT_IRQ: u32 = 11;
pub const ACPI_GTDT_ARCH_TIMER_S_EL1_IRQ: u32 = 13;
pub const ACPI_GTDT_ARCH_TIMER_NS_EL1_IRQ: u32 = 14;
pub const ACPI_GTDT_ARCH_TIMER_NS_EL2_IRQ: u32 = 10;
pub const ACPI_GTDT_INTERRUPT_MODE_LEVEL: u32 = 0;
pub const ACPI_GTDT_CAP_ALWAYS_ON: u32 = 4;
pub const ACPI_IORT_NODE_ITS_GROUP: u8 = 0x00;
pub const ACPI_IORT_NODE_PCI_ROOT_COMPLEX: u8 = 0x02;
pub const ROOT_COMPLEX_ENTRY_SIZE: u16 = 36;
pub const ID_MAPPING_ENTRY_SIZE: u16 = 20;
pub const ACPI_MADT_GENERIC_CPU_INTERFACE: u8 = 11;
pub const ACPI_MADT_GENERIC_DISTRIBUTOR: u8 = 12;
pub const ACPI_MADT_GENERIC_REDISTRIBUTOR: u8 = 14;
pub const ACPI_MADT_GENERIC_TRANSLATOR: u8 = 15;
#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct AcpiGenericAddress {
space_id: u8,
bit_width: u8,
bit_offset: u8,
access_size: u8,
address: u64,
}
impl AcpiGenericAddress {
pub fn new_io_address<T: Into<u64>>(addr: T) -> AcpiGenericAddress {
AcpiGenericAddress {
space_id: 1,
bit_width: 8 * std::mem::size_of::<T>() as u8,
bit_offset: 0,
access_size: std::mem::size_of::<T>() as u8,
address: addr.into(),
}
}
}
impl ByteCode for AcpiGenericAddress {}
impl AmlBuilder for AcpiGenericAddress {
fn aml_bytes(&self) -> Vec<u8> {
self.as_bytes().to_vec()
}
}
#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct AcpiTableHeader {
signature: [u8; 4],
length: u32,
revision: u8,
checksum: u8,
oem_id: [u8; 6],
oem_table_id: [u8; 8],
oem_revision: u32,
asl_compiler_id: [u8; 4],
asl_compiler_revision: u32,
}
impl ByteCode for AcpiTableHeader {}
impl AmlBuilder for AcpiTableHeader {
fn aml_bytes(&self) -> Vec<u8> {
self.as_bytes().to_vec()
}
}
pub struct AcpiTable {
entries: Vec<u8>,
}
impl AcpiTable {
pub fn new(
signature: [u8; 4],
revision: u8,
oem_id: [u8; 6],
oem_table_id: [u8; 8],
oem_revision: u32,
) -> AcpiTable {
AcpiTable {
entries: AcpiTableHeader {
signature,
length: 0,
revision,
checksum: 0,
oem_id,
oem_table_id,
oem_revision,
asl_compiler_id: [0_u8; 4],
asl_compiler_revision: 0_u32,
}
.aml_bytes(),
}
}
pub fn table_len(&self) -> usize {
self.entries.len()
}
pub fn set_table_len(&mut self, new_size: usize) {
if new_size < self.entries.len() {
panic!("New size is smaller than old-size, truncation is not supported.");
}
self.entries
.extend(vec![0_u8; new_size - self.entries.len()].as_slice());
self.entries[4..=7].copy_from_slice((new_size as u32).as_bytes());
}
pub fn set_field<T: ByteCode>(&mut self, byte_index: usize, new_value: T) {
let value_len = std::mem::size_of::<T>();
if byte_index >= self.entries.len() || byte_index + value_len > self.entries.len() {
panic!("Set field in table failed: overflow occurs.");
}
self.entries[byte_index..(byte_index + value_len)].copy_from_slice(new_value.as_bytes());
}
pub fn append_child(&mut self, bytes: &[u8]) {
self.entries.extend(bytes);
let table_len = self.entries.len() as u32;
self.entries[4..=7].copy_from_slice(table_len.as_bytes());
}
pub fn update_checksum(&mut self) {
self.entries[TABLE_CHECKSUM_OFFSET as usize] = 0;
let checksum = generate_checksum(&self.entries);
self.entries[TABLE_CHECKSUM_OFFSET as usize] = checksum;
}
}
impl AmlBuilder for AcpiTable {
fn aml_bytes(&self) -> Vec<u8> {
self.entries.clone()
}
}
#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct ProcessorHierarchyNode {
r#type: u8,
length: u8,
reserved: u16,
flags: u32,
parent: u32,
acpi_processor_id: u32,
num_private_resources: u32,
}
impl ByteCode for ProcessorHierarchyNode {}
impl AmlBuilder for ProcessorHierarchyNode {
fn aml_bytes(&self) -> Vec<u8> {
self.as_bytes().to_vec()
}
}
impl ProcessorHierarchyNode {
pub fn new(
flags: u32,
parent: u32,
acpi_processor_id: u32,
num_private_resources: u32,
) -> Self {
Self {
r#type: 0,
length: 20 + num_private_resources as u8 * 4,
reserved: 0,
flags,
parent,
acpi_processor_id,
num_private_resources,
}
}
}
pub fn processor_append_priv_res(pptt: &mut AcpiTable, priv_resources: Vec<u32>) {
let start = pptt.table_len();
pptt.set_table_len(start + priv_resources.len() * 4);
for (i, priv_res) in priv_resources.iter().enumerate() {
pptt.set_field(start + i * 4, *priv_res);
}
}
pub enum CacheType {
L1D,
L1I,
L2,
L3,
}
struct CacheNode {
size: u32,
sets: u32,
associativity: u8,
attributes: u8,
line_size: u16,
}
const CACHE_NODES: [CacheNode; CacheType::L3 as usize + 1] = [
CacheNode {
size: 65536,
sets: 256,
associativity: 4,
attributes: 2,
line_size: 64,
},
CacheNode {
size: 65536,
sets: 256,
associativity: 4,
attributes: 4,
line_size: 64,
},
CacheNode {
size: 524288,
sets: 1024,
associativity: 8,
attributes: 10,
line_size: 64,
},
CacheNode {
size: 33554432,
sets: 2048,
associativity: 15,
attributes: 10,
line_size: 128,
},
];
#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct CacheHierarchyNode {
r#type: u8,
length: u8,
reserved: u16,
flags: u32,
next_level: u32,
size: u32,
number_sets: u32,
associativity: u8,
attributes: u8,
line_size: u16,
}
impl ByteCode for CacheHierarchyNode {}
impl AmlBuilder for CacheHierarchyNode {
fn aml_bytes(&self) -> Vec<u8> {
self.as_bytes().to_vec()
}
}
impl CacheHierarchyNode {
pub fn new(next_level: u32, cache_type: CacheType) -> Self {
let cache_node = &CACHE_NODES[cache_type as usize];
Self {
r#type: 1,
length: 24,
reserved: 0,
flags: 127,
next_level,
size: cache_node.size,
number_sets: cache_node.sets,
associativity: cache_node.associativity,
attributes: cache_node.attributes,
line_size: cache_node.line_size,
}
}
}
#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct AcpiRsdp {
signature: [u8; 8],
checksum: u8,
oem_id: [u8; 6],
revision: u8,
rsdt_tlb_addr: u32,
length: u32,
xsdt_tlb_addr: u64,
extended_checksum: u8,
reserved: [u8; 3],
}
impl AcpiRsdp {
pub fn new(oem_id: [u8; 6]) -> AcpiRsdp {
AcpiRsdp {
signature: *b"RSD PTR ",
checksum: 0,
oem_id,
revision: 2,
rsdt_tlb_addr: 0_u32,
length: std::mem::size_of::<AcpiRsdp>() as u32,
xsdt_tlb_addr: 0_u64,
extended_checksum: 0,
reserved: [0_u8; 3],
}
}
pub fn set_xsdt_addr(&mut self, addr: u64) {
self.xsdt_tlb_addr = addr;
}
pub fn update_checksum(&mut self) {
self.checksum = 0;
self.extended_checksum = 0;
self.checksum = generate_checksum(&self.as_bytes()[..20]);
self.extended_checksum = generate_checksum(self.as_bytes());
}
}
impl ByteCode for AcpiRsdp {}
impl AmlBuilder for AcpiRsdp {
fn aml_bytes(&self) -> Vec<u8> {
self.as_bytes().to_vec()
}
}
#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct AcpiSratProcessorAffinity {
pub type_id: u8,
pub length: u8,
pub proximity_lo: u8,
pub local_apic_id: u8,
pub flags: u32,
pub local_sapic_eid: u8,
pub proximity_hi: [u8; 3],
pub clock_domain: u32,
}
impl ByteCode for AcpiSratProcessorAffinity {}
impl AmlBuilder for AcpiSratProcessorAffinity {
fn aml_bytes(&self) -> Vec<u8> {
Vec::from(self.as_bytes())
}
}
#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct AcpiSratGiccAffinity {
pub type_id: u8,
pub length: u8,
pub proximity_domain: u32,
pub process_uid: u32,
pub flags: u32,
pub clock_domain: u32,
}
impl ByteCode for AcpiSratGiccAffinity {}
impl AmlBuilder for AcpiSratGiccAffinity {
fn aml_bytes(&self) -> Vec<u8> {
Vec::from(self.as_bytes())
}
}
#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct AcpiSratMemoryAffinity {
pub type_id: u8,
pub length: u8,
pub proximity_domain: u32,
pub reserved1: u16,
pub base_addr: u64,
pub range_length: u64,
pub reserved2: u32,
pub flags: u32,
pub reserved3: u64,
}
impl ByteCode for AcpiSratMemoryAffinity {}
impl AmlBuilder for AcpiSratMemoryAffinity {
fn aml_bytes(&self) -> Vec<u8> {
Vec::from(self.as_bytes())
}
}
#[cfg(target_arch = "x86_64")]
pub mod madt_subtable {
use super::*;
pub const IOAPIC_BASE_ADDR: u32 = 0xfec0_0000;
pub const LAPIC_BASE_ADDR: u32 = 0xfee0_0000;
#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct AcpiLocalApic {
pub type_id: u8,
pub length: u8,
pub processor_uid: u8,
pub apic_id: u8,
pub flags: u32,
}
impl ByteCode for AcpiLocalApic {}
impl AmlBuilder for AcpiLocalApic {
fn aml_bytes(&self) -> Vec<u8> {
Vec::from(self.as_bytes())
}
}
#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct AcpiIoApic {
pub type_id: u8,
pub length: u8,
pub io_apic_id: u8,
pub reserved: u8,
pub io_apic_addr: u32,
pub gsi_base: u32,
}
impl ByteCode for AcpiIoApic {}
impl AmlBuilder for AcpiIoApic {
fn aml_bytes(&self) -> Vec<u8> {
Vec::from(self.as_bytes())
}
}
}
#[cfg(target_arch = "aarch64")]
pub mod madt_subtable {
use super::*;
pub const ARCH_GIC_MAINT_IRQ: u32 = 9;
#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct AcpiGicCpu {
pub type_id: u8,
pub length: u8,
reserved_1: u16,
pub cpu_interface_num: u32,
pub processor_uid: u32,
pub flags: u32,
pub parking_version: u32,
pub perf_interrupt: u32,
pub parked_addr: u64,
pub base_addr: u64,
pub gicv_addr: u64,
pub gich_addr: u64,
pub vgic_interrupt: u32,
pub gicr_addr: u64,
pub mpidr: u64,
reserved_2: u32,
}
impl ByteCode for AcpiGicCpu {}
impl AmlBuilder for AcpiGicCpu {
fn aml_bytes(&self) -> Vec<u8> {
Vec::from(self.as_bytes())
}
}
#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct AcpiGicDistributor {
pub type_id: u8,
pub length: u8,
reserved_1: u16,
pub gic_id: u32,
pub base_addr: u64,
pub sys_vector_base: u32,
pub gic_version: u8,
reserved_2: [u8; 3],
}
impl ByteCode for AcpiGicDistributor {}
impl AmlBuilder for AcpiGicDistributor {
fn aml_bytes(&self) -> Vec<u8> {
Vec::from(self.as_bytes())
}
}
#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct AcpiGicRedistributor {
pub type_id: u8,
pub length: u8,
reserved_1: u16,
pub base_addr: u64,
pub range_length: u32,
}
impl ByteCode for AcpiGicRedistributor {}
impl AmlBuilder for AcpiGicRedistributor {
fn aml_bytes(&self) -> Vec<u8> {
Vec::from(self.as_bytes())
}
}
#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct AcpiGicIts {
pub type_id: u8,
pub length: u8,
reserved_1: u16,
pub its_id: u32,
pub base_addr: u64,
reserved_2: u32,
}
impl ByteCode for AcpiGicIts {}
impl AmlBuilder for AcpiGicIts {
fn aml_bytes(&self) -> Vec<u8> {
Vec::from(self.as_bytes())
}
}
}