diff --git a/acpi/Cargo.toml b/acpi/Cargo.toml index 73da5a3..7ba1975 100644 --- a/acpi/Cargo.toml +++ b/acpi/Cargo.toml @@ -13,6 +13,7 @@ edition = "2021" bit_field = "0.10.2" bitflags = "2.5.0" log = "0.4.20" +uefi = "0.31.0" [features] default = ["allocator_api", "alloc"] diff --git a/acpi/src/handler.rs b/acpi/src/handler.rs index 46a6532..491eec4 100644 --- a/acpi/src/handler.rs +++ b/acpi/src/handler.rs @@ -84,6 +84,20 @@ where pub fn handler(&self) -> &H { &self.handler } + + pub fn write(&mut self, offset: usize, value: V) { + unsafe { + let ptr = (self.virtual_start.as_ptr() as *mut u8).add(offset) as *mut V; + ptr.write(value); + } + } + + pub fn read(&self, offset: usize) -> V { + unsafe { + let ptr = (self.virtual_start.as_ptr() as *mut u8).add(offset) as *mut V; + ptr.read() + } + } } unsafe impl Send for PhysicalMapping {} diff --git a/acpi/src/iort.rs b/acpi/src/iort.rs new file mode 100644 index 0000000..20f83f6 --- /dev/null +++ b/acpi/src/iort.rs @@ -0,0 +1,424 @@ +use crate::{ + sdt::{SdtHeader, Signature}, + AcpiTable, +}; +///Apart from the basic header, the table contains a number of IORT Nodes. +/// Each node represents a component, which can be an SMMU, +/// an ITS Group, a root complex, or a component that is described in the namespace. +use core::marker::PhantomData; + +pub enum IortError { + InvalidNodeType, + InvalidLength, + RevisionNotSupported, + OffsetOutOfRange, +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct Iort { + header: SdtHeader, + pub node_number: u32, + node_array_offset: u32, + reserved: u32, + // After offset_to_node_array, there are node_number IORT Nodes +} + +/// ### Safety: This is safe to implement. +/// The IORT table is safe to implement because it is a valid ACPI table. +unsafe impl AcpiTable for Iort { + const SIGNATURE: Signature = Signature::IORT; + + fn header(&self) -> &SdtHeader { + &self.header + } +} + +use core::fmt; +impl fmt::Display for Iort { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "IORT: {:?}", self.header)?; + for node in self.nodes() { + write!(f, "\n{}", node)?; + } + Ok(()) + } +} + +impl Iort { + pub fn nodes(&self) -> IortNodeIter { + let node_offset = self.node_array_offset as usize; + let pointer = unsafe { (self as *const Iort as *const u8).add(node_offset) }; + let remaining_length = self.header.length - node_offset as u32; + + IortNodeIter { pointer, remaining_length, _phantom: PhantomData } + } + + /// Returns the IORT node at the given offset. + /// Used to find the node pointed to by the output_reference field in the id_mapping + /// If the type field is invalid, return None. + pub fn get_node(&self, offset: usize) -> Option { + let node = unsafe { *((self as *const Iort as *const u8).add(offset) as *const IortNodeHeader) }; + match node.node_type { + 0 => Some(IortNode::Its(unsafe { + &*((self as *const Iort as *const u8).add(offset) as *const ItsNode) + })), + 1 => Some(IortNode::NamedComponent(unsafe { + &*((self as *const Iort as *const u8).add(offset) as *const NamedComponentNode) + })), + 2 => Some(IortNode::RootComplex(unsafe { + &*((self as *const Iort as *const u8).add(offset) as *const RootComplexNode) + })), + 3 => Some(IortNode::SmmuV12(unsafe { + &*((self as *const Iort as *const u8).add(offset) as *const SmmuV12Node) + })), + 4 => Some(IortNode::SmmuV3(unsafe { + &*((self as *const Iort as *const u8).add(offset) as *const SmmuV3Node) + })), + 5 => Some(IortNode::Pmcg(unsafe { + &*((self as *const Iort as *const u8).add(offset) as *const PmcgNode) + })), + 6 => Some(IortNode::MemoryRange(unsafe { + &*((self as *const Iort as *const u8).add(offset) as *const MemoryRangeNode) + })), + _ => None, + } + } + + pub fn smmuv3_bases(&self) -> impl Iterator + '_ { + self.nodes().filter_map(|node| match node { + IortNode::SmmuV3(smmu_v3) => Some(smmu_v3.base_address), + _ => None, + }) + } +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct IortNodeHeader { + pub node_type: u8, + pub length: u16, + pub revision: u8, + pub identifier: u32, + pub id_mapping_num: u32, + pub id_mapping_array_offset: u32, + // Between this and id_mapping_array, there are data fields that are specific to each node type + // After offset_to_id_mapping_array, there are id_mapping_num ID Mappings +} + +impl IortNodeHeader { + pub fn validate(&self) -> Result<(), IortError> { + if self.node_type > 6 { + return Err(IortError::InvalidNodeType); + } + if self.length < core::mem::size_of::() as u16 { + return Err(IortError::InvalidLength); + } + if self.id_mapping_array_offset < self.length as u32 { + return Err(IortError::OffsetOutOfRange); + } + let revision_valid = match self.node_type { + 0 => self.revision == 1, + 1 => self.revision == 4, + 2 => self.revision == 4, + 3 => self.revision == 3, + 4 => self.revision == 5, + 5 => self.revision == 2, + 6 => self.revision == 3, + _ => false, + }; + if !revision_valid { + return Err(IortError::RevisionNotSupported); + } + Ok(()) + } +} + +#[derive(Debug)] +pub enum IortNode<'a> { + Its(&'a ItsNode), + NamedComponent(&'a NamedComponentNode), + RootComplex(&'a RootComplexNode), + SmmuV12(&'a SmmuV12Node), + SmmuV3(&'a SmmuV3Node), + Pmcg(&'a PmcgNode), + MemoryRange(&'a MemoryRangeNode), +} + +impl fmt::Display for IortNode<'_> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let _ = match self { + IortNode::Its(node) => write!(f, "{}", node), + IortNode::NamedComponent(node) => write!(f, "{}", node), + IortNode::RootComplex(node) => write!(f, "{}", node), + IortNode::SmmuV12(node) => write!(f, "{}", node), + IortNode::SmmuV3(node) => write!(f, "{}", node), + IortNode::Pmcg(node) => write!(f, "{}", node), + IortNode::MemoryRange(node) => write!(f, "{}", node), + }; + for id in self.id_mapping_array() { + write!(f, "\n{:#x?}", id)? + } + Ok(()) + } +} + +impl IortNode<'_> { + pub fn id_mapping_array(&self) -> &[IortIdMapping] { + let node_header = self.header(); + let id_mapping_num = node_header.id_mapping_num; + let id_mapping_array_offset = node_header.id_mapping_array_offset; + + unsafe { + let ptr = (node_header as *const IortNodeHeader as *const u8).add(id_mapping_array_offset as usize); + core::slice::from_raw_parts(ptr as *const IortIdMapping, id_mapping_num as usize) + } + } + + pub fn header(&self) -> &IortNodeHeader { + match self { + IortNode::Its(node) => &node.header, + IortNode::NamedComponent(node) => &node.header, + IortNode::RootComplex(node) => &node.header, + IortNode::SmmuV12(node) => &node.header, + IortNode::SmmuV3(node) => &node.header, + IortNode::Pmcg(node) => &node.header, + IortNode::MemoryRange(node) => &node.header, + } + } +} + +pub struct IortNodeIter<'a> { + pointer: *const u8, + remaining_length: u32, + _phantom: PhantomData<&'a ()>, +} + +impl<'a> Iterator for IortNodeIter<'a> { + type Item = IortNode<'a>; + + fn next(&mut self) -> Option { + if self.remaining_length == 0 { + return None; + } + + let node = unsafe { &*(self.pointer as *const IortNodeHeader) }; + let node_length = node.length as u32; + + let node = match node.node_type { + 0 => IortNode::Its(unsafe { &*(self.pointer as *const ItsNode) }), + 1 => IortNode::NamedComponent(unsafe { &*(self.pointer as *const NamedComponentNode) }), + 2 => IortNode::RootComplex(unsafe { &*(self.pointer as *const RootComplexNode) }), + 3 => IortNode::SmmuV12(unsafe { &*(self.pointer as *const SmmuV12Node) }), + 4 => IortNode::SmmuV3(unsafe { &*(self.pointer as *const SmmuV3Node) }), + 5 => IortNode::Pmcg(unsafe { &*(self.pointer as *const PmcgNode) }), + 6 => IortNode::MemoryRange(unsafe { &*(self.pointer as *const MemoryRangeNode) }), + _ => return None, + }; + + self.pointer = unsafe { self.pointer.add(node_length as usize) }; + self.remaining_length -= node_length; + + Some(node) + } +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct ItsNode { + pub header: IortNodeHeader, + pub its_number: u32, + // This is followed by the ITS Identifer Array of length 4 * its_number +} + +impl fmt::Display for ItsNode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:#x?}", self)?; + write!(f, "\n\tIdentifiers:")?; + for id in self.its_identifiers() { + write!(f, " {} ", id)? + } + Ok(()) + } +} + +impl ItsNode { + pub fn its_identifiers(&self) -> &[u32] { + let its_number = self.its_number; + let its_identifiers_offset = core::mem::size_of::() as u32; + + unsafe { + let ptr = (self as *const ItsNode as *const u8).add(its_identifiers_offset as usize); + core::slice::from_raw_parts(ptr as *const u32, its_number as usize) + } + } +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct NamedComponentNode { + pub header: IortNodeHeader, + pub node_flags: u32, + pub mem_access_properties: u64, + pub device_mem_address_size_limit: u8, + // This is followed by a ASCII Null terminated string + // with the full path to the entry in the namespace for this object + // and a padding to 32-bit word-aligned. +} + +impl fmt::Display for NamedComponentNode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:#x?}", self)?; + write!(f, "\n\tName: {}", self.name()) + } +} + +impl NamedComponentNode { + pub fn name(&self) -> &str { + let name_offset = core::mem::size_of::() as u32; + let name_ptr = unsafe { (self as *const NamedComponentNode as *const u8).add(name_offset as usize) }; + + let mut length = 0; + while unsafe { *name_ptr.add(length as usize) } != 0 { + length += 1; + } + + unsafe { core::str::from_utf8_unchecked(core::slice::from_raw_parts(name_ptr, length as usize)) } + } +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct RootComplexNode { + pub header: IortNodeHeader, + pub mem_access_properties: u64, + pub ats_attribute: u32, + pub pci_segment_number: u32, + pub mem_address_size_limit: u8, + pub pasid_capabilities: u16, + pub reserved: u8, + pub flags: u32, +} + +impl fmt::Display for RootComplexNode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:#x?}", self) + } +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct SmmuV12Node { + pub header: IortNodeHeader, + pub base_address: u64, + pub span: u64, + pub model: u32, + pub flags: u32, + pub global_interrupt_array_offset: u32, + pub context_interrupt_array_num: u32, + pub context_interrupt_array_offset: u32, + pub pmu_interrupt_array_num: u32, + pub pmu_interrupt_array_offset: u32, + // Followed by several interrupt arrays +} + +impl fmt::Display for SmmuV12Node { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:#x?}", self) + } +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct SmmuV3Node { + pub header: IortNodeHeader, + pub base_address: u64, + pub flags: u32, + pub reserved: u32, + pub vatos_address: u64, + pub model: u32, + pub event: u32, + pub pri: u32, + pub gerr: u32, + pub sync: u32, + pub proximity_domain: u32, + pub device_id_mapping_index: u32, +} + +impl fmt::Display for SmmuV3Node { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:#x?}", self) + } +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct PmcgNode { + pub header: IortNodeHeader, + pub pg0_base_address: u64, + pub overflow_interrupt: u32, + pub node_reference: u32, + pub pg1_base_address: u64, +} + +impl fmt::Display for PmcgNode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:#x?}", self) + } +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct MemoryRangeNode { + pub header: IortNodeHeader, + pub flags: u32, + pub mem_range_discriptor_array_num: u32, + pub mem_range_discriptor_array_offset: u32, + // After the base address of the node is offset, there are multiple MemoryRangeDescriptor +} + +impl fmt::Display for MemoryRangeNode { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:#x?}", self)?; + for descriptor in self.memory_range_descriptors() { + write!(f, "\n\t{:#x?}", descriptor)? + } + Ok(()) + } +} + +impl MemoryRangeNode { + pub fn memory_range_descriptors(&self) -> &[MemoryRangeDescriptor] { + let mem_range_discriptor_array_num = self.mem_range_discriptor_array_num; + let mem_range_discriptor_array_offset = self.mem_range_discriptor_array_offset; + + unsafe { + let ptr = + (self as *const MemoryRangeNode as *const u8).add(mem_range_discriptor_array_offset as usize); + core::slice::from_raw_parts( + ptr as *const MemoryRangeDescriptor, + mem_range_discriptor_array_num as usize, + ) + } + } +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct MemoryRangeDescriptor { + physical_range_offset: u64, + physical_range_length: u64, + reserved: u32, +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct IortIdMapping { + pub input_base: u32, + pub id_count: u32, + pub output_base: u32, + /// A reference to the output IORT Node. This field contains the + /// address offset of the IORT Node relative to the start of the IORT. + pub output_reference: u32, + pub flags: u32, +} diff --git a/acpi/src/lib.rs b/acpi/src/lib.rs index 0b254df..54ee83a 100644 --- a/acpi/src/lib.rs +++ b/acpi/src/lib.rs @@ -55,6 +55,7 @@ #![no_std] #![deny(unsafe_op_in_unsafe_fn)] #![cfg_attr(feature = "allocator_api", feature(allocator_api))] +#![feature(ptr_from_ref)] #[cfg_attr(test, macro_use)] #[cfg(test)] @@ -68,11 +69,14 @@ pub mod bgrt; pub mod fadt; pub mod handler; pub mod hpet; +pub mod iort; pub mod madt; pub mod mcfg; +pub mod mpam; pub mod rsdp; pub mod sdt; pub mod spcr; +pub mod srat; #[cfg(feature = "allocator_api")] mod managed_slice; @@ -223,6 +227,12 @@ where unsafe { Self::from_validated_rsdp(handler, rsdp_mapping) } } + pub unsafe fn search_for_rsdp_uefi(handler: H, system_table: usize) -> AcpiResult { + let rsdp_mapping = unsafe { Rsdp::search_for_on_uefi(handler.clone(), system_table)? }; + // Safety: RSDP has been validated from `Rsdp::search_for_on_uefi` + unsafe { Self::from_validated_rsdp(handler, rsdp_mapping) } + } + /// Create an `AcpiTables` if you have a `PhysicalMapping` of the RSDP that you know is correct. This is called /// from `from_rsdp` after validation, but can also be used if you've searched for the RSDP manually on a BIOS /// system. @@ -364,6 +374,43 @@ where SsdtIterator { tables_phys_ptrs: self.tables_phys_ptrs(), handler: self.handler.clone() } } + /// Add a new SSDT to the list of tables. + /// Sould edit the XSDT or RSDT to include the new table. + /// Safety: The address must be valid for reading as an SSDT. And must match the revision of the tables. + /// The address must be 8-byte aligned and the 8-byte after xsdt must be not used. + pub unsafe fn add_ssdt(&mut self, address: usize) -> AcpiResult<()> { + #[repr(transparent)] + struct Xsdt { + header: SdtHeader, + } + + unsafe impl AcpiTable for Xsdt { + const SIGNATURE: Signature = Signature::XSDT; + + fn header(&self) -> &SdtHeader { + &self.header + } + } + + let mut xsdt = + unsafe { read_table::(self.handler.clone(), self.mapping.physical_start()).unwrap() }; + + xsdt.write::(xsdt.header.length as usize, address as u64); + + xsdt.write::(4, xsdt.header.length + 8); // length of the table + xsdt.write::(9, 0); // checksum + let mut sum = 0u8; + for i in 0..xsdt.header.length as usize { + sum = sum.wrapping_add(xsdt.read::(i)); + } + xsdt.write::(9, (!sum).wrapping_add(1)); // checksum + + let address = xsdt.physical_start(); + let handler = xsdt.handler().clone(); + self.mapping = read_root_table!(XSDT, address, handler); + Ok(()) + } + /// Convenience method for contructing a [`PlatformInfo`]. This is one of the first things you should usually do /// with an `AcpiTables`, and allows to collect helpful information about the platform from the ACPI tables. /// diff --git a/acpi/src/madt.rs b/acpi/src/madt.rs index 8424e89..b60fab2 100644 --- a/acpi/src/madt.rs +++ b/acpi/src/madt.rs @@ -10,7 +10,7 @@ use core::{marker::PhantomData, mem}; use crate::{ platform::{ interrupt::{InterruptModel, Polarity, TriggerMode}, - ProcessorInfo, + processor::ProcessorInfo, }, AcpiResult, }; @@ -50,6 +50,17 @@ unsafe impl AcpiTable for Madt { } } +use core::fmt; +impl fmt::Display for Madt { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "MADT: {:#x?}", self.header)?; + for entry in self.entries() { + write!(f, "\n{:#x?}", entry)? + } + Ok(()) + } +} + impl Madt { pub fn get_mpwk_mailbox_addr(&self) -> Result { for entry in self.entries() { @@ -95,7 +106,7 @@ impl Madt { MadtEntry::GicMsiFrame(_) | MadtEntry::GicRedistributor(_) | MadtEntry::GicInterruptTranslationService(_) => { - unimplemented!(); + return self.parse_gic_model_in(allocator); } MadtEntry::MultiprocessorWakeup(_) => () @@ -123,8 +134,7 @@ impl Madt { NmiProcessor, NmiSource, }, - Processor, - ProcessorState, + processor::{ProcessorState, X86Processor}, }; let mut local_apic_address = self.local_apic_address as u64; @@ -152,15 +162,14 @@ impl Madt { let mut interrupt_source_overrides = crate::ManagedSlice::new_in(iso_count, allocator.clone())?; let mut nmi_sources = crate::ManagedSlice::new_in(nmi_source_count, allocator.clone())?; let mut local_apic_nmi_lines = crate::ManagedSlice::new_in(local_nmi_line_count, allocator.clone())?; - let mut application_processors = - crate::ManagedSlice::new_in(processor_count.saturating_sub(1), allocator)?; // Subtract one for the BSP - let mut boot_processor = None; + let mut application_processors = crate::ManagedSlice::new_in(processor_count, allocator)?; // Subtract one for the BSP + let mut found_bsp = false; io_apic_count = 0; iso_count = 0; nmi_source_count = 0; local_nmi_line_count = 0; - processor_count = 0; + processor_count = 1; for entry in self.entries() { match entry { @@ -169,7 +178,7 @@ impl Madt { * The first processor is the BSP. Subsequent ones are APs. If we haven't found * the BSP yet, this must be it. */ - let is_ap = boot_processor.is_some(); + let is_ap = found_bsp; let is_disabled = !{ entry.flags }.get_bit(0); let state = match (is_ap, is_disabled) { @@ -178,7 +187,7 @@ impl Madt { (false, false) => ProcessorState::Running, }; - let processor = Processor { + let processor = X86Processor { processor_uid: entry.processor_id as u32, local_apic_id: entry.apic_id as u32, state, @@ -189,12 +198,13 @@ impl Madt { application_processors[processor_count] = processor; processor_count += 1; } else { - boot_processor = Some(processor); + application_processors[0] = processor; + found_bsp = true; } } MadtEntry::LocalX2Apic(entry) => { - let is_ap = boot_processor.is_some(); + let is_ap = found_bsp; let is_disabled = !{ entry.flags }.get_bit(0); let state = match (is_ap, is_disabled) { @@ -203,7 +213,7 @@ impl Madt { (false, false) => ProcessorState::Running, }; - let processor = Processor { + let processor = X86Processor { processor_uid: entry.processor_uid, local_apic_id: entry.x2apic_id, state, @@ -214,7 +224,8 @@ impl Madt { application_processors[processor_count] = processor; processor_count += 1; } else { - boot_processor = Some(processor); + application_processors[0] = processor; + found_bsp = true; } } @@ -307,7 +318,130 @@ impl Madt { nmi_sources, self.supports_8259(), )), - Some(ProcessorInfo::new(boot_processor.unwrap(), application_processors)), + Some(ProcessorInfo::new_x86(application_processors)), + )) + } + + fn parse_gic_model_in<'a, A>( + &self, + allocator: A, + ) -> AcpiResult<(InterruptModel<'a, A>, Option>)> + where + A: core::alloc::Allocator + Clone, + { + use crate::platform::{ + interrupt::{Gic, GicIts, GicMsiFrame, Gicc, Gicd, Gicr}, + processor::Arm64Processor, + }; + + // need to count the number of each type of entry + + let mut gicc_count = 0; + let mut gicd_count = 0; + let mut gic_msi_frame_count = 0; + let mut gicr_count = 0; + let mut gic_its_count = 0; + let mut processor_count = 0; + + for entry in self.entries() { + match entry { + MadtEntry::Gicc(_) => { + gicc_count += 1; + processor_count += 1; + } + MadtEntry::Gicd(_) => gicd_count += 1, + MadtEntry::GicMsiFrame(_) => gic_msi_frame_count += 1, + MadtEntry::GicRedistributor(_) => gicr_count += 1, + MadtEntry::GicInterruptTranslationService(_) => gic_its_count += 1, + _ => (), + } + } + + let mut gicc: crate::ManagedSlice = crate::ManagedSlice::new_in(gicc_count, allocator.clone())?; + let mut gicd: crate::ManagedSlice = crate::ManagedSlice::new_in(gicd_count, allocator.clone())?; + let mut gic_msi_frame: crate::ManagedSlice = + crate::ManagedSlice::new_in(gic_msi_frame_count, allocator.clone())?; + let mut gicr: crate::ManagedSlice = crate::ManagedSlice::new_in(gicr_count, allocator.clone())?; + let mut gic_its: crate::ManagedSlice = + crate::ManagedSlice::new_in(gic_its_count, allocator.clone())?; + let mut processors: crate::ManagedSlice = + crate::ManagedSlice::new_in(processor_count, allocator.clone())?; + // let mut boot_processor = None; + + gicc_count = 0; + gicd_count = 0; + gic_msi_frame_count = 0; + gicr_count = 0; + gic_its_count = 0; + processor_count = 0; + + for entry in self.entries() { + match entry { + MadtEntry::Gicc(entry) => { + gicc[gicc_count] = Gicc { + cpu_interface_number: entry.cpu_interface_number, + acpi_processor_uid: entry.processor_uid, + flags: entry.flags, + parking_version: entry.parking_protocol_version, + performance_interrupt_gsiv: entry.performance_interrupt_gsiv, + parked_address: entry.parked_address, + physical_base_address: entry.gic_registers_address, + gicv: entry.gic_virtual_registers_address, + gich: entry.gic_hypervisor_registers_address, + vgic_maintenance_interrupt: entry.vgic_maintenance_interrupt, + gicr_base_address: entry.gicr_base_address, + mpidr: entry.mpidr, + processor_power_efficiency_class: entry.processor_power_efficiency_class, + spe_overflow_interrupt: entry.spe_overflow_interrupt, + }; + processors[processor_count] = Arm64Processor { + processor_uid: entry.processor_uid, + mpidr: entry.mpidr, + gicc_base_address: entry.gic_registers_address, + gicr_base_address: entry.gicr_base_address, + }; + gicc_count += 1; + processor_count += 1; + } + MadtEntry::Gicd(entry) => { + gicd[gicd_count] = Gicd { + id: entry.gic_id, + physical_base_address: entry.physical_base_address, + gic_version: entry.gic_version, + }; + gicd_count += 1; + } + MadtEntry::GicMsiFrame(entry) => { + gic_msi_frame[gic_msi_frame_count] = GicMsiFrame { + id: entry.frame_id, + physical_base_address: entry.physical_base_address, + spi_count_base_select: { entry.flags }.get_bit(0), + spi_count: entry.spi_count, + spi_base: entry.spi_base, + }; + gic_msi_frame_count += 1; + } + MadtEntry::GicRedistributor(entry) => { + gicr[gicr_count] = Gicr { + base_address: entry.discovery_range_base_address, + length: entry.discovery_range_length, + }; + gicr_count += 1; + } + MadtEntry::GicInterruptTranslationService(entry) => { + gic_its[gic_its_count] = + GicIts { id: entry.id, physical_base_address: entry.physical_base_address }; + gic_its_count += 1; + } + _ => { + return Err(AcpiError::InvalidMadt(MadtError::UnexpectedEntry)); + } + } + } + + Ok(( + InterruptModel::Gic(Gic::new(gicc, gicd, gic_msi_frame, gicr, gic_its)), + Some(ProcessorInfo::new_arm64(processors)), )) } diff --git a/acpi/src/mpam.rs b/acpi/src/mpam.rs new file mode 100644 index 0000000..5dab5da --- /dev/null +++ b/acpi/src/mpam.rs @@ -0,0 +1,195 @@ +use core::{marker::PhantomData, mem::size_of}; + +use crate::{ + sdt::{SdtHeader, Signature}, + AcpiTable, +}; + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct Mpam { + header: SdtHeader, + // An array of MPAM node structures that describes MSCs in the system. +} + +/// ### Safety: This is safe to implement. +unsafe impl AcpiTable for Mpam { + const SIGNATURE: Signature = Signature::MPAM; + + fn header(&self) -> &SdtHeader { + &self.header + } +} + +use core::fmt; +impl fmt::Display for Mpam { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "MAPM: {:#x?}", self.header)?; + for node in self.nodes() { + write!(f, "\n{:#x?}", node)?; + } + Ok(()) + } +} + +impl Mpam { + /// Returns an iterator over the MPAM node structures. + pub fn nodes(&self) -> MscNodeIter { + let pointer = unsafe { (self as *const Mpam).add(1) as *const u8 }; + let remaining_length = self.header.length as u32 - size_of::() as u32; + + MscNodeIter { pointer, remaining_length, _phantom: PhantomData } + } + + pub fn mmio_ranges(&self) -> impl Iterator + '_ { + self.nodes().filter_map(|node| { + return if node.if_type == 0x00 { Some((node.base_address, node.mmio_size)) } else { None }; + }) + } +} + +pub struct MscNodeIter<'a> { + pointer: *const u8, + remaining_length: u32, + _phantom: PhantomData<&'a ()>, +} + +impl Iterator for MscNodeIter<'_> { + type Item = MscNode; + + fn next(&mut self) -> Option { + if self.remaining_length <= 0 { + return None; + } + + let node = unsafe { &*(self.pointer as *const MscNode) }; + let node_length = node.length as u32; + + self.pointer = unsafe { self.pointer.add(node_length as usize) }; + self.remaining_length -= node_length; + + Some(*node) + } +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct MscNode { + // MPAM node structure + pub length: u16, + pub if_type: u8, + pub reserved: u8, + pub id: u32, + pub base_address: u64, + pub mmio_size: u32, + + pub overflow_interrupt: u32, + pub overflow_interrupt_flags: u32, + pub reserved2: u32, + pub overflow_interrupt_affinity: u32, + + pub error_interrupt: u32, + pub error_interrupt_flags: u32, + pub reserved3: u32, + pub error_interrupt_affinity: u32, + + pub max_nrdy_usec: u32, + pub hw_id: u64, + pub instance_id: u32, + pub resource_node_num: u32, + // Resource node list + // after the resource node list, there is resource specific data, if the length after the resource node list is not 0 +} + +impl fmt::Display for MscNode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:#x?}", self)?; + for node in self.resource_nodes() { + write!(f, "\n\t{}", node)? + } + Ok(()) + } +} + +impl MscNode { + pub fn resource_nodes(&self) -> ResourceNodeIter { + let ptr = unsafe { + let ptr = self as *const MscNode; + ptr.add(1) as *const u8 + }; + let remaining_length = self.length as u32 - size_of::() as u32; + ResourceNodeIter { + pointer: ptr, + remaining_length, + remaining_nodes: self.resource_node_num, + _phantom: PhantomData, + } + } +} + +pub struct ResourceNodeIter<'a> { + pointer: *const u8, + remaining_length: u32, + remaining_nodes: u32, + _phantom: PhantomData<&'a ()>, +} + +impl Iterator for ResourceNodeIter<'_> { + type Item = ResourceNode; + + fn next(&mut self) -> Option { + if self.remaining_length <= 0 || self.remaining_nodes <= 0 { + return None; + } + + let node = unsafe { &*(self.pointer as *const ResourceNode) }; + let node_length = + size_of::() + (node.func_dep_num as usize) * size_of::(); + + self.pointer = unsafe { self.pointer.add(node_length) }; + self.remaining_length -= node_length as u32; + self.remaining_nodes -= 1; + + Some(*node) + } +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct ResourceNode { + // Resource node structure + pub id: u32, + pub ris_id: u32, + pub reserved: u16, + pub locator_type: u8, + pub locator: (u64, u32), + pub func_dep_num: u32, + // Function dependency list [FunctionDependency] +} + +impl fmt::Display for ResourceNode { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:#x?}", self)?; + for dep in self.function_dependencies() { + write!(f, "\n\t{:#x?}", dep)? + } + Ok(()) + } +} + +impl ResourceNode { + pub fn function_dependencies(&self) -> &[FunctionDependency] { + let ptr = self as *const ResourceNode; + let ptr = unsafe { ptr.add(1) }; + let ptr = ptr as *const FunctionDependency; + unsafe { core::slice::from_raw_parts(ptr, self.func_dep_num as usize) } + } +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct FunctionDependency { + // Function dependency structure + pub producer: u32, + pub reserved: u32, +} diff --git a/acpi/src/platform/interrupt.rs b/acpi/src/platform/interrupt.rs index 75d2eff..4607ae8 100644 --- a/acpi/src/platform/interrupt.rs +++ b/acpi/src/platform/interrupt.rs @@ -116,6 +116,82 @@ where } } +#[derive(Debug)] +pub struct Gicc { + pub cpu_interface_number: u32, + pub acpi_processor_uid: u32, + pub flags: u32, + + pub parking_version: u32, + pub performance_interrupt_gsiv: u32, + pub parked_address: u64, + + pub physical_base_address: u64, + pub gicv: u64, + pub gich: u64, + pub vgic_maintenance_interrupt: u32, + pub gicr_base_address: u64, + + pub mpidr: u64, + pub processor_power_efficiency_class: u8, + pub spe_overflow_interrupt: u16, +} + +#[derive(Debug)] +pub struct Gicd { + pub id: u32, + pub physical_base_address: u64, + pub gic_version: u8, +} + +#[derive(Debug)] +pub struct GicMsiFrame { + pub id: u32, + pub physical_base_address: u64, + pub spi_count_base_select: bool, + pub spi_count: u16, + pub spi_base: u16, +} + +#[derive(Debug)] +pub struct Gicr { + pub base_address: u64, + pub length: u32, +} + +#[derive(Debug)] +pub struct GicIts { + pub id: u32, + pub physical_base_address: u64, +} + +#[derive(Debug)] +pub struct Gic<'a, A> +where + A: Allocator, +{ + pub gicc: ManagedSlice<'a, Gicc, A>, + pub gicd: ManagedSlice<'a, Gicd, A>, + pub gic_msi_frame: ManagedSlice<'a, GicMsiFrame, A>, + pub gicr: ManagedSlice<'a, Gicr, A>, + pub gic_its: ManagedSlice<'a, GicIts, A>, +} + +impl<'a, A> Gic<'a, A> +where + A: Allocator, +{ + pub(crate) fn new( + gicc: ManagedSlice<'a, Gicc, A>, + gicd: ManagedSlice<'a, Gicd, A>, + gic_msi_frame: ManagedSlice<'a, GicMsiFrame, A>, + gicr: ManagedSlice<'a, Gicr, A>, + gic_its: ManagedSlice<'a, GicIts, A>, + ) -> Self { + Self { gicc, gicd, gic_msi_frame, gicr, gic_its } + } +} + #[derive(Debug)] #[non_exhaustive] pub enum InterruptModel<'a, A> @@ -130,4 +206,6 @@ where /// XAPIC, or X2APIC). These are likely to be found on x86 and x86_64 systems and are made up of a Local APIC /// for each core and one or more I/O APICs to handle external interrupts. Apic(Apic<'a, A>), + + Gic(Gic<'a, A>), } diff --git a/acpi/src/platform/mod.rs b/acpi/src/platform/mod.rs index c3b29cf..ce53557 100644 --- a/acpi/src/platform/mod.rs +++ b/acpi/src/platform/mod.rs @@ -1,4 +1,5 @@ pub mod interrupt; +pub mod processor; use crate::{ address::GenericAddress, @@ -8,61 +9,11 @@ use crate::{ AcpiHandler, AcpiResult, AcpiTables, - ManagedSlice, PowerProfile, }; use core::{alloc::Allocator, mem, ptr}; use interrupt::InterruptModel; - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum ProcessorState { - /// A processor in this state is unusable, and you must not attempt to bring it up. - Disabled, - - /// A processor waiting for a SIPI (Startup Inter-processor Interrupt) is currently not active, - /// but may be brought up. - WaitingForSipi, - - /// A Running processor is currently brought up and running code. - Running, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub struct Processor { - /// Corresponds to the `_UID` object of the processor's `Device`, or the `ProcessorId` field of the `Processor` - /// object, in AML. - pub processor_uid: u32, - /// The ID of the local APIC of the processor. Will be less than `256` if the APIC is being used, but can be - /// greater than this if the X2APIC is being used. - pub local_apic_id: u32, - - /// The state of this processor. Check that the processor is not `Disabled` before attempting to bring it up! - pub state: ProcessorState, - - /// Whether this processor is the Bootstrap Processor (BSP), or an Application Processor (AP). - /// When the bootloader is entered, the BSP is the only processor running code. To run code on - /// more than one processor, you need to "bring up" the APs. - pub is_ap: bool, -} - -#[derive(Debug)] -pub struct ProcessorInfo<'a, A> -where - A: Allocator, -{ - pub boot_processor: Processor, - /// Application processors should be brought up in the order they're defined in this list. - pub application_processors: ManagedSlice<'a, Processor, A>, -} - -impl<'a, A> ProcessorInfo<'a, A> -where - A: Allocator, -{ - pub(crate) fn new(boot_processor: Processor, application_processors: ManagedSlice<'a, Processor, A>) -> Self { - Self { boot_processor, application_processors } - } -} +use processor::ProcessorInfo; /// Information about the ACPI Power Management Timer (ACPI PM Timer). #[derive(Debug)] diff --git a/acpi/src/platform/processor.rs b/acpi/src/platform/processor.rs new file mode 100644 index 0000000..5785262 --- /dev/null +++ b/acpi/src/platform/processor.rs @@ -0,0 +1,94 @@ +use crate::ManagedSlice; +use core::alloc::Allocator; + +/// Processor trait +pub trait Processor { + /// The OS associates this GICC Structure with a processor device object in the namespace + /// when the _UID child object of the processor device evaluates to a numeric value that matches the numeric value in this field. + fn processor_uid(&self) -> u32; +} + +impl Processor for Arm64Processor { + fn processor_uid(&self) -> u32 { + self.processor_uid + } +} + +impl Processor for X86Processor { + fn processor_uid(&self) -> u32 { + self.processor_uid + } +} + +/// Arm64 processor +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Arm64Processor { + /// The OS associates this GICC Structure with a processor device object in the namespace + /// when the _UID child object of the processor device evaluates to a numeric value that matches the numeric value in this field. + pub processor_uid: u32, + /// This fields follows the MPIDR formatting of ARM architecture. + pub mpidr: u64, + /// On GICv1/v2 systems and GICv3/4 systems in GICv2 compatibility mode, + /// this field holds the 64-bit physical address at which the processor can access this GIC CPU Interface. + /// If provided here, the “Local Interrupt Controller Address” field in the MADT must be ignored by the OSPM. + pub gicc_base_address: u64, + /// On GICv3/4 systems, this field holds the 64-bit physical address at which the processor can access this GIC Redistributor. + pub gicr_base_address: u64, +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum ProcessorState { + /// A processor in this state is unusable, and you must not attempt to bring it up. + Disabled, + + /// A processor waiting for a SIPI (Startup Inter-processor Interrupt) is currently not active, + /// but may be brought up. + WaitingForSipi, + + /// A Running processor is currently brought up and running code. + Running, +} + +/// x86_64 processor +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct X86Processor { + /// Corresponds to the `_UID` object of the processor's `Device`, or the `ProcessorId` field of the `Processor` + /// object, in AML. + pub processor_uid: u32, + /// The ID of the local APIC of the processor. Will be less than `256` if the APIC is being used, but can be + /// greater than this if the X2APIC is being used. + pub local_apic_id: u32, + + /// The state of this processor. Check that the processor is not `Disabled` before attempting to bring it up! + pub state: ProcessorState, + + /// Whether this processor is the Bootstrap Processor (BSP), or an Application Processor (AP). + /// When the bootloader is entered, the BSP is the only processor running code. To run code on + /// more than one processor, you need to "bring up" the APs. + pub is_ap: bool, +} + +#[derive(Debug)] +pub enum ProcessorInfo<'a, A> +where + A: Allocator, +{ + /// in x86_64, the BSP is the first processor. + /// Application processors should be brought up in the order they're defined in this list. + X86Processors(ManagedSlice<'a, X86Processor, A>), + + Arm64Processors(ManagedSlice<'a, Arm64Processor, A>), +} + +impl<'a, A> ProcessorInfo<'a, A> +where + A: Allocator, +{ + pub fn new_x86(processors: ManagedSlice<'a, X86Processor, A>) -> Self { + ProcessorInfo::X86Processors(processors) + } + + pub fn new_arm64(processors: ManagedSlice<'a, Arm64Processor, A>) -> Self { + ProcessorInfo::Arm64Processors(processors) + } +} diff --git a/acpi/src/rsdp.rs b/acpi/src/rsdp.rs index 3c33e9c..27a84db 100644 --- a/acpi/src/rsdp.rs +++ b/acpi/src/rsdp.rs @@ -1,5 +1,11 @@ +use uefi::table::{ + cfg::{ACPI2_GUID, ACPI_GUID}, + Boot, + SystemTable, +}; + use crate::{AcpiError, AcpiHandler, AcpiResult, PhysicalMapping}; -use core::{mem, ops::Range, slice, str}; +use core::{ffi::c_void, mem, ops::Range, slice, str}; /// The size in bytes of the ACPI 1.0 RSDP. const RSDP_V1_LENGTH: usize = 20; @@ -97,6 +103,45 @@ impl Rsdp { } } + /// This searches for a RSDP on UEFI systems. + /// ### Safety + /// This function reads the EFI configuration table, which is a list of GUIDs and their associated data. The + /// configuration table is provided by the firmware, and so should be safe to read. However, the data associated + /// with the GUIDs may not be safe to read, and so this function should be used with caution. + /// The GUIDs used to find the RSDP are: + /// - ACPI v1.0 structures use `eb9d2d30-2d88-11d3-9a16-0090273fc14d`. + /// - ACPI v2.0 or later structures use `8868e871-e4f1-11d3-bc22-0080c73c8881`. + /// You should search the entire table for the v2.0 GUID before searching for the v1.0 one. + pub unsafe fn search_for_on_uefi(handler: H, system_table: usize) -> AcpiResult> + where + H: AcpiHandler, + { + // SAFETY: `system_table` is a valid pointer to a `SystemTable`. + let system_table = unsafe { SystemTable::::from_ptr(system_table as *mut c_void).unwrap() }; + let config_table = system_table.config_table(); + + // Search the configuration table for the RSDP, using GUIDs to identify the correct entry + let rsdp = config_table.iter().find_map(|entry| { + if entry.guid == ACPI2_GUID || entry.guid == ACPI_GUID { + let rsdp_mapping = + unsafe { handler.map_physical_region::(entry.address as usize, mem::size_of::()) }; + + match rsdp_mapping.validate() { + Ok(()) => Some(rsdp_mapping), + Err(AcpiError::RsdpIncorrectSignature) => None, + Err(err) => { + log::warn!("Invalid RSDP found at {:#x}: {:?}", system_table.as_ptr() as usize, err); + None + } + } + } else { + None + } + }); + // Return the first valid RSDP found, or an error if none were found + rsdp.ok_or(AcpiError::NoValidRsdp) + } + /// Checks that: /// 1) The signature is correct /// 2) The checksum is correct diff --git a/acpi/src/srat.rs b/acpi/src/srat.rs new file mode 100644 index 0000000..3f02ede --- /dev/null +++ b/acpi/src/srat.rs @@ -0,0 +1,211 @@ +use core::marker::PhantomData; + +use crate::{ + sdt::{SdtHeader, Signature}, + AcpiTable, +}; + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct Srat { + header: SdtHeader, + _reserved: u32, + _reserved2: u64, + // Followed by `n` structs with Static Resource Allocation Structure + // A list of static resource allocation structures for the platform. + // See Processor Local APIC/SAPIC Affinity Structure, Memory Affinity Structure, + // Processor Local x2APIC Affinity Structure, and GICC Affinity Structure. +} + +/// ### Safety: Implementation properly represents a valid SRAT. +unsafe impl AcpiTable for Srat { + const SIGNATURE: Signature = Signature::SRAT; + + fn header(&self) -> &SdtHeader { + &self.header + } +} + +use core::fmt; +impl fmt::Display for Srat { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "SRAT: {:?}", self.header)?; + for entry in self.entries() { + write!(f, "\n{:#x?}", entry)? + } + Ok(()) + } +} + +impl Srat { + /// Returns an iterator over the memory ranges specified in the System Resource Affinity Table (SRAT). + /// + /// The iterator yields tuples of `(base_address, length)`, where `base_address` is the starting address of a memory range + /// and `length` is the size of the memory range. + /// + /// However, the mem ranges here are not actually the range of System RAM, + /// and the final available memory segment needs to be obtained through the Memory Map of UEFI Boot Services. + pub fn memory_ranges(&self) -> impl Iterator + '_ { + self.entries().filter_map(|entry| match entry { + AffinityStruct::MemoryAffinity(memory_affinity) => Some(( + memory_affinity.base_address_lo as u64 | ((memory_affinity.base_address_hi as u64) << 32), + memory_affinity.length_lo as u64 | ((memory_affinity.length_hi as u64) << 32), + )), + _ => None, + }) + } + + /// Returns an iterator over the affinity structures in the System Resource Affinity Table (SRAT). + /// including Local APIC/SAPIC Affinity Structure, Memory Affinity Structure, Processor Local x2APIC Affinity Structure, + /// GICC Affinity Structure, GIC ITS Affinity Structure, and Generic Initiator Affinity Structure. + pub fn entries(&self) -> AffinityStructIter { + let pointer = unsafe { (self as *const Srat).add(1) as *const u8 }; + let remaining_length = self.header.length as u32 - core::mem::size_of::() as u32; + + AffinityStructIter { pointer, remaining_length, _phantom: PhantomData } + } +} + +#[derive(Debug)] +pub struct AffinityStructIter<'a> { + pointer: *const u8, + remaining_length: u32, + _phantom: PhantomData<&'a ()>, +} + +#[derive(Debug)] +pub enum AffinityStruct<'a> { + LocalApicAffinity(&'a LocalApicAffinity), + MemoryAffinity(&'a MemoryAffinity), + LocalX2ApicAffinity(&'a LocalX2ApicAffinity), + GiccAffinity(&'a GiccAffinity), + GicItsAffinity(&'a GicItsAffinity), + GenericInitiatorAffinity(&'a GenericInitiatorAffinity), +} + +impl<'a> Iterator for AffinityStructIter<'a> { + type Item = AffinityStruct<'a>; + + fn next(&mut self) -> Option { + if self.remaining_length <= 0 { + return None; + } + + let struct_header = unsafe { &*(self.pointer as *const StructHeader) }; + let struct_length = struct_header.length as u32; + let struct_type = struct_header.struct_type; + + let affinity_struct = match struct_type { + 0 => AffinityStruct::LocalApicAffinity(unsafe { &*(self.pointer as *const LocalApicAffinity) }), + 1 => AffinityStruct::MemoryAffinity(unsafe { &*(self.pointer as *const MemoryAffinity) }), + 2 => AffinityStruct::LocalX2ApicAffinity(unsafe { &*(self.pointer as *const LocalX2ApicAffinity) }), + 3 => AffinityStruct::GiccAffinity(unsafe { &*(self.pointer as *const GiccAffinity) }), + 4 => AffinityStruct::GicItsAffinity(unsafe { &*(self.pointer as *const GicItsAffinity) }), + 5 => AffinityStruct::GenericInitiatorAffinity(unsafe { + &*(self.pointer as *const GenericInitiatorAffinity) + }), + _ => return None, + }; + + self.pointer = unsafe { self.pointer.add(struct_length as usize) }; + self.remaining_length -= struct_length; + + Some(affinity_struct) + } +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct StructHeader { + /// Type of the structure + /// 0: Processor Local APIC/SAPIC Affinity Structure + /// 1: Memory Affinity Structure + /// 2: Processor Local x2APIC Affinity Structure + /// 3: GICC Affinity Structure + /// 4: GIC ITS Affinity Structure + /// 5: Generic Initiator Affinity Structure + pub struct_type: u8, + pub length: u8, +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct MemoryAffinity { + pub struct_header: StructHeader, + pub proximity_domain: u32, + pub _reserved: u16, + pub base_address_lo: u32, + pub base_address_hi: u32, + pub length_lo: u32, + pub length_hi: u32, + pub _reserved2: u32, + /// bit_offset: field + /// 0: Enabled + /// 1: Hot-pluggable + /// 2: Non-volatile + pub flags: u32, + pub _reserved3: [u8; 8], +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct GiccAffinity { + pub struct_header: StructHeader, + pub proximity_domain: u32, + pub acpi_processor_uid: u32, + /// bit_offset: field + /// 0: Enabled + pub flags: u32, + pub clock_domain: u32, +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct LocalApicAffinity { + pub struct_header: StructHeader, + pub proximity_domain_lo: u8, + pub apic_id: u8, + /// bit_offset: field + /// 0: Enabled + pub flags: u32, + pub local_sapic_eid: u8, + pub proximity_domain_hi: [u8; 3], + pub clock_domain: u32, +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct LocalX2ApicAffinity { + pub struct_header: StructHeader, + pub _reserved: u16, + pub proximity_domain: u32, + pub x2apic_id: u32, + /// bit_offset: field + /// 0: Enabled + pub flags: u32, + pub clock_domain: u32, + pub _reserved2: u32, +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct GicItsAffinity { + pub struct_header: StructHeader, + pub proximity_domain: u32, + pub _reserved: u16, + pub its_id: u32, +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct GenericInitiatorAffinity { + pub struct_header: StructHeader, + pub _reserved: u8, + /// 0: ACPI Device Handle + /// 1: PCI Device Handle + pub device_handle_type: u8, + pub proximity_domain: u32, + pub device_handle: [u8; 16], + pub flags: u32, + pub _reserved2: u32, +} diff --git a/aml/src/value.rs b/aml/src/value.rs index 363f580..3ded5e6 100644 --- a/aml/src/value.rs +++ b/aml/src/value.rs @@ -264,7 +264,7 @@ impl AmlValue { match self { AmlValue::Boolean(value) => Ok(*value), AmlValue::Integer(value) => Ok(*value != 0), - AmlValue::Field{ .. } => Ok(self.as_integer(context)? != 0), + AmlValue::Field { .. } => Ok(self.as_integer(context)? != 0), _ => Err(AmlError::IncompatibleValueConversion { current: self.type_of(), target: AmlType::Integer }), } }