From 6431678503611a4774a60f0cf03b0b3f202d6083 Mon Sep 17 00:00:00 2001 From: volca Date: Wed, 7 Aug 2024 17:29:40 +0800 Subject: [PATCH 01/12] [fix]: set to rustshyper version --- acpi/src/lib.rs | 1 + rust-toolchain | 3 +++ 2 files changed, 4 insertions(+) create mode 100644 rust-toolchain diff --git a/acpi/src/lib.rs b/acpi/src/lib.rs index 1bc1f78..d7f78a1 100644 --- a/acpi/src/lib.rs +++ b/acpi/src/lib.rs @@ -58,6 +58,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)] diff --git a/rust-toolchain b/rust-toolchain new file mode 100644 index 0000000..87111cb --- /dev/null +++ b/rust-toolchain @@ -0,0 +1,3 @@ +[toolchain] +channel = "nightly-2023-11-09" +components = ["rust-src", "llvm-tools-preview"] From e39a8cd1dcc33a06229ebf73727d416ba8a7f813 Mon Sep 17 00:00:00 2001 From: volca Date: Wed, 28 Aug 2024 12:53:19 +0800 Subject: [PATCH 02/12] rsdp: add method to get from uefi system table --- acpi/Cargo.toml | 1 + acpi/src/lib.rs | 6 ++++++ acpi/src/rsdp.rs | 38 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/acpi/Cargo.toml b/acpi/Cargo.toml index 5c26f54..aa68001 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/lib.rs b/acpi/src/lib.rs index d7f78a1..490fd32 100644 --- a/acpi/src/lib.rs +++ b/acpi/src/lib.rs @@ -184,6 +184,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. diff --git a/acpi/src/rsdp.rs b/acpi/src/rsdp.rs index 3c33e9c..e68e096 100644 --- a/acpi/src/rsdp.rs +++ b/acpi/src/rsdp.rs @@ -1,3 +1,5 @@ +use uefi::table::{cfg::ACPI2_GUID, SystemTable}; + use crate::{AcpiError, AcpiHandler, AcpiResult, PhysicalMapping}; use core::{mem, ops::Range, slice, str}; @@ -97,6 +99,42 @@ 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, + { + let system_table = unsafe { + SystemTable::::from_ptr(system_table as *mut c_void).unwrap() + }; + + let config_table = system_table.config_table(); + let rsdp = config_table.iter().find_map(|entry| { + if entry.guid == ACPI2_GUID { + let rsdp_mapping = unsafe { handler.map_physical_region::(entry.address, mem::size_of::()) }; + match rsdp_mapping.validate() { + Ok(()) => Some(rsdp_mapping), + Err(AcpiError::RsdpIncorrectSignature) => None, + Err(err) => { + log::warn!("Invalid RSDP found at {:#x}: {:?}", address, err); + None + } + } + } else { + None + } + }); + rsdp.ok_or(AcpiError::NoValidRsdp) + } + /// Checks that: /// 1) The signature is correct /// 2) The checksum is correct From 152120a8e75562baac79653bbd85331158b14143 Mon Sep 17 00:00:00 2001 From: volca Date: Mon, 2 Sep 2024 16:26:07 +0800 Subject: [PATCH 03/12] fix the method to get from uefi system table --- acpi/src/rsdp.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/acpi/src/rsdp.rs b/acpi/src/rsdp.rs index e68e096..da98ebb 100644 --- a/acpi/src/rsdp.rs +++ b/acpi/src/rsdp.rs @@ -1,7 +1,7 @@ -use uefi::table::{cfg::ACPI2_GUID, SystemTable}; +use uefi::table::{cfg::ACPI2_GUID, Boot, SystemTable}; use crate::{AcpiError, AcpiHandler, AcpiResult, PhysicalMapping}; -use core::{mem, ops::Range, slice, str}; +use core::{mem, ops::Range, slice, str, ffi::c_void}; /// The size in bytes of the ACPI 1.0 RSDP. const RSDP_V1_LENGTH: usize = 20; @@ -119,12 +119,12 @@ impl Rsdp { let config_table = system_table.config_table(); let rsdp = config_table.iter().find_map(|entry| { if entry.guid == ACPI2_GUID { - let rsdp_mapping = unsafe { handler.map_physical_region::(entry.address, mem::size_of::()) }; + 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}: {:?}", address, err); + log::warn!("Invalid RSDP found at {:#x}: {:?}", system_table.as_ptr() as usize, err); None } } From e5db3fcebfea49555645bbf564ba9a8473f9cdf4 Mon Sep 17 00:00:00 2001 From: volca Date: Mon, 2 Sep 2024 16:27:48 +0800 Subject: [PATCH 04/12] acpi: add support for SRAT table --- acpi/src/lib.rs | 1 + acpi/src/srat.rs | 179 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 acpi/src/srat.rs diff --git a/acpi/src/lib.rs b/acpi/src/lib.rs index 490fd32..1517a93 100644 --- a/acpi/src/lib.rs +++ b/acpi/src/lib.rs @@ -77,6 +77,7 @@ pub mod mcfg; pub mod rsdp; pub mod sdt; pub mod spcr; +pub mod srat; #[cfg(feature = "allocator_api")] mod managed_slice; diff --git a/acpi/src/srat.rs b/acpi/src/srat.rs new file mode 100644 index 0000000..404343f --- /dev/null +++ b/acpi/src/srat.rs @@ -0,0 +1,179 @@ +use core::marker::PhantomData; + +use crate::{ + sdt::{SdtHeader, Signature}, + AcpiTable, +}; + +pub enum SratError { + +} + +#[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 { + 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 { + pub struct_type: u8, + pub length: u8, +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct LocalApicAffinity { + pub struct_header: StructHeader, + pub proximity_domain_lo: u8, + pub apic_id: u8, + 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 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, + pub flags: u32, + pub _reserved3: [u8; 8], +} + +#[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, + pub flags: u32, + pub clock_domain: u32, + pub _reserved2: u32, +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct GiccAffinity { + pub struct_header: StructHeader, + pub proximity_domain: u32, + pub acpi_processor_uid: u32, + pub flags: u32, + pub clock_domain: 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, + pub device_handle_type: u8, + pub proximity_domain: u32, + pub device_handle: [u8; 16], + pub flags: u32, + pub _reserved2: u32, +} \ No newline at end of file From 221de6f336a6e93e6023314e247026ce6b982a4e Mon Sep 17 00:00:00 2001 From: volca Date: Mon, 2 Sep 2024 16:29:18 +0800 Subject: [PATCH 05/12] madt: add the support for Gic and Arm64 processor --- acpi/src/madt.rs | 179 ++++++++++++++++++++++++++++++--- acpi/src/platform/interrupt.rs | 84 ++++++++++++++++ acpi/src/platform/mod.rs | 53 +--------- acpi/src/platform/processor.rs | 91 +++++++++++++++++ 4 files changed, 340 insertions(+), 67 deletions(-) create mode 100644 acpi/src/platform/processor.rs diff --git a/acpi/src/madt.rs b/acpi/src/madt.rs index f89ba17..5f9f74d 100644 --- a/acpi/src/madt.rs +++ b/acpi/src/madt.rs @@ -1,6 +1,5 @@ use crate::{ - sdt::{ExtendedField, SdtHeader, Signature}, - AcpiTable, + sdt::{ExtendedField, SdtHeader, Signature}, AcpiTable }; use bit_field::BitField; use core::{marker::PhantomData, mem}; @@ -9,7 +8,7 @@ use core::{marker::PhantomData, mem}; use crate::{ platform::{ interrupt::{InterruptModel, Polarity, TriggerMode}, - ProcessorInfo, + processor::ProcessorInfo, }, AcpiResult, }; @@ -48,6 +47,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 { #[cfg(feature = "allocator_api")] pub fn parse_interrupt_model_in<'a, A>( @@ -84,7 +94,7 @@ impl Madt { MadtEntry::GicMsiFrame(_) | MadtEntry::GicRedistributor(_) | MadtEntry::GicInterruptTranslationService(_) => { - unimplemented!(); + return self.parse_gic_model_in(allocator); } MadtEntry::MultiprocessorWakeup(_) => () @@ -113,8 +123,10 @@ impl Madt { NmiProcessor, NmiSource, }, - Processor, - ProcessorState, + processor::{ + X86Processor, + ProcessorState, + }, }, AcpiError, }; @@ -145,14 +157,14 @@ impl Madt { 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; + 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 { @@ -161,7 +173,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) { @@ -170,7 +182,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, @@ -181,12 +193,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) { @@ -195,7 +208,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, @@ -206,7 +219,8 @@ impl Madt { application_processors[processor_count] = processor; processor_count += 1; } else { - boot_processor = Some(processor); + application_processors[0] = processor; + found_bsp = true; } } @@ -297,10 +311,143 @@ 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, + Gicd, + Gicc, + GicMsiFrame, + Gicr, + GicIts, + }, + processor::Arm64Processor, + }, + AcpiError, + }; + + // 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) => { + // TODO the ProcessorInfo struct is not implemented for aaarch64 yet. + // TODO need to implement the ProcessorInfo. + 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 as u32, + mpidr: entry.mpidr, + gicc_base_address: entry.gic_registers_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)))) + } + pub fn entries(&self) -> MadtEntryIter { MadtEntryIter { pointer: unsafe { (self as *const Madt as *const u8).add(mem::size_of::()) }, diff --git a/acpi/src/platform/interrupt.rs b/acpi/src/platform/interrupt.rs index 75d2eff..638cd16 100644 --- a/acpi/src/platform/interrupt.rs +++ b/acpi/src/platform/interrupt.rs @@ -116,6 +116,88 @@ 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 +212,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 c8f2221..38b6406 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; 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..92487e9 --- /dev/null +++ b/acpi/src/platform/processor.rs @@ -0,0 +1,91 @@ +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, +} + +#[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) + } +} \ No newline at end of file From 02af66dc7f670878c2bbffaff4bc62150779167c Mon Sep 17 00:00:00 2001 From: volca Date: Tue, 8 Oct 2024 17:47:59 +0800 Subject: [PATCH 06/12] acpi: add support for MPAM table but have some questions --- acpi/src/lib.rs | 1 + acpi/src/madt.rs | 4 +- acpi/src/mpam.rs | 209 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 211 insertions(+), 3 deletions(-) create mode 100644 acpi/src/mpam.rs diff --git a/acpi/src/lib.rs b/acpi/src/lib.rs index 1517a93..96f982e 100644 --- a/acpi/src/lib.rs +++ b/acpi/src/lib.rs @@ -78,6 +78,7 @@ pub mod rsdp; pub mod sdt; pub mod spcr; pub mod srat; +pub mod mpam; #[cfg(feature = "allocator_api")] mod managed_slice; diff --git a/acpi/src/madt.rs b/acpi/src/madt.rs index 5f9f74d..10fac30 100644 --- a/acpi/src/madt.rs +++ b/acpi/src/madt.rs @@ -375,8 +375,6 @@ impl Madt { for entry in self.entries() { match entry { MadtEntry::Gicc(entry) => { - // TODO the ProcessorInfo struct is not implemented for aaarch64 yet. - // TODO need to implement the ProcessorInfo. gicc[gicc_count] = Gicc { cpu_interface_number: entry.cpu_interface_number, acpi_processor_uid: entry.processor_uid, @@ -394,7 +392,7 @@ impl Madt { spe_overflow_interrupt: entry.spe_overflow_interrupt, }; processors[processor_count] = Arm64Processor { - processor_uid: entry.processor_uid as u32, + processor_uid: entry.processor_uid, mpidr: entry.mpidr, gicc_base_address: entry.gic_registers_address, }; diff --git a/acpi/src/mpam.rs b/acpi/src/mpam.rs new file mode 100644 index 0000000..ad3bd83 --- /dev/null +++ b/acpi/src/mpam.rs @@ -0,0 +1,209 @@ +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)?; + let mut i = 100; + for node in self.nodes() { + write!(f, "\n{:#x?}", node)?; + i -= 1; + if i == 0 { + break; + } + } + 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, +} \ No newline at end of file From 77f84e4c6d2c6bf79333f4bb95bb6332550ef29e Mon Sep 17 00:00:00 2001 From: volca Date: Fri, 11 Oct 2024 13:52:11 +0800 Subject: [PATCH 07/12] acpi: add simple support for IORT table, need to improve. This commit adds support for the IORT (IO Remapping Table) ACPI table. The IORT table contains a number of IORT Nodes, each representing a component such as an SMMU, an ITS Group, a root complex, or a component described in the namespace. The IORT table is implemented as a valid ACPI table and provides a display format for debugging purposes. It also includes iterators for accessing the nodes and ID mappings. --- acpi/src/iort.rs | 236 +++++++++++++++++++++++++++++++++ acpi/src/lib.rs | 1 + acpi/src/platform/processor.rs | 3 +- acpi/src/srat.rs | 53 +++++--- 4 files changed, 273 insertions(+), 20 deletions(-) create mode 100644 acpi/src/iort.rs diff --git a/acpi/src/iort.rs b/acpi/src/iort.rs new file mode 100644 index 0000000..4df4dca --- /dev/null +++ b/acpi/src/iort.rs @@ -0,0 +1,236 @@ +///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; +use crate::{ + sdt::{SdtHeader, Signature}, + AcpiTable, +}; + +pub enum IortError { + +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct Iort { + header: SdtHeader, + 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{:#x?}", node)? + } + Ok(()) + } +} + +impl Iort { + pub fn nodes(&self) -> IortNodeIter { + let pointer = unsafe { (self as *const Iort).add(1) as *const u8 }; + let remaining_length = self.header.length as u32 - size_of::() as u32; + + IortNodeIter { + pointer, + remaining_length, + _phantom: PhantomData + } + } +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct IortNodeHeader { + node_type: u8, + length: u16, + revision: u8, + 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 +} + +#[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 IortNode { + pub fn id_mapping_array(&self) -> Option<&[IortIdMapping]> { + let id_mapping_num = unsafe {*(self as *const IortNode as *const IortNodeHeader).id_mapping_num}; + let id_mapping_array_offset = unsafe {*(self as *const IortNode as *const IortNodeHeader).id_mapping_array_offset}; + + if id_mapping_num == 0 { + return None; + } else { + unsafe { + let ptr = (self as *const IortNode as *const u8).add(id_mapping_array_offset as usize); + Some(core::slice::from_raw_parts(ptr as *const IortIdMapping, id_mapping_num as usize)) + } + } + } +} + +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) }; + self.remaining_length -= node_length as u32; + + Some(node) + } +} + + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct ItsNode { + header: IortNodeHeader, + its_number: u32, + // This is followed by the ITS Identifer Array of length 4 * its_number +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct NamedComponentNode { + header: IortNodeHeader, + node_flags: u32, + mem_access_properties: u64, + 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. +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct RootComplexNode { + header: IortNodeHeader, + mem_access_properties: u64, + ats_attribute: u32, + pci_segment_number: u32, + mem_address_size_limit: u8, + pasid_capabilities: u16, + reserved: u8, + flags: u32, +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct SmmuV12Node { + header: IortNodeHeader, + base_address: u64, + span: u64, + model: u32, + flags: u32, + global_interrupt_array_offset: u32, + context_interrupt_array_num: u32, + context_interrupt_array_offset: u32, + pmu_interrupt_array_num: u32, + pmu_interrupt_array_offset: u32, + // 后面是几个中断数组 +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct SmmuV3Node { + header: IortNodeHeader, + base_address: u64, + flags: u32, + reserved: u32, + vatos_address: u64, + model: u32, + event: u32, + pri: u32, + gerr: u32, + sync: u32, + proximity_domain: u32, + device_id_mapping_index: u32, +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct PmcgNode { + header: IortNodeHeader, + pg0_base_address: u64, + overflow_interrupt: u32, + node_reference: u32, + pg1_base_address: u64, +} + +#[derive(Debug, Clone, Copy)] +#[repr(C, packed)] +pub struct MemoryRangeNode { + header: IortNodeHeader, + flags: u32, + mem_range_discriptor_array_num: u32, + mem_range_discriptor_array_offset: u32, + // After the base address of the node is offset, there are multiple MemoryRangeDescriptor +} + +#[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 { + input_base: u32, + id_count: u32, + output_base: u32, + output_reference: u32, + flags: u32, +} \ No newline at end of file diff --git a/acpi/src/lib.rs b/acpi/src/lib.rs index 96f982e..baf09bd 100644 --- a/acpi/src/lib.rs +++ b/acpi/src/lib.rs @@ -79,6 +79,7 @@ pub mod sdt; pub mod spcr; pub mod srat; pub mod mpam; +pub mod iort; #[cfg(feature = "allocator_api")] mod managed_slice; diff --git a/acpi/src/platform/processor.rs b/acpi/src/platform/processor.rs index 92487e9..c1af5ff 100644 --- a/acpi/src/platform/processor.rs +++ b/acpi/src/platform/processor.rs @@ -28,7 +28,8 @@ pub struct Arm64Processor { 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. + /// 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, } diff --git a/acpi/src/srat.rs b/acpi/src/srat.rs index 404343f..a15e428 100644 --- a/acpi/src/srat.rs +++ b/acpi/src/srat.rs @@ -42,6 +42,22 @@ impl fmt::Display for Srat { } 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. + 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, + } + }) + } + 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; @@ -57,7 +73,6 @@ impl Srat { #[derive(Debug)] pub struct AffinityStructIter<'a> { pointer: *const u8, - remaining_length: u32, _phantom: PhantomData<&'a ()> } @@ -108,18 +123,6 @@ pub struct StructHeader { pub length: u8, } -#[derive(Debug, Clone, Copy)] -#[repr(C, packed)] -pub struct LocalApicAffinity { - pub struct_header: StructHeader, - pub proximity_domain_lo: u8, - pub apic_id: u8, - 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 MemoryAffinity { @@ -137,24 +140,36 @@ pub struct MemoryAffinity { #[derive(Debug, Clone, Copy)] #[repr(C, packed)] -pub struct LocalX2ApicAffinity { +pub struct GiccAffinity { pub struct_header: StructHeader, - pub _reserved: u16, pub proximity_domain: u32, - pub x2apic_id: u32, + pub acpi_processor_uid: u32, pub flags: u32, pub clock_domain: u32, - pub _reserved2: u32, } #[derive(Debug, Clone, Copy)] #[repr(C, packed)] -pub struct GiccAffinity { +pub struct LocalApicAffinity { pub struct_header: StructHeader, + pub proximity_domain_lo: u8, + pub apic_id: u8, + 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 acpi_processor_uid: u32, + pub x2apic_id: u32, pub flags: u32, pub clock_domain: u32, + pub _reserved2: u32, } #[derive(Debug, Clone, Copy)] From beba5290b4d245724d64bd327344a173da4974c3 Mon Sep 17 00:00:00 2001 From: volca Date: Fri, 11 Oct 2024 15:32:00 +0800 Subject: [PATCH 08/12] iort: fix some bugs --- acpi/src/iort.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/acpi/src/iort.rs b/acpi/src/iort.rs index 4df4dca..6f351d5 100644 --- a/acpi/src/iort.rs +++ b/acpi/src/iort.rs @@ -45,7 +45,7 @@ impl fmt::Display for Iort { impl Iort { pub fn nodes(&self) -> IortNodeIter { let pointer = unsafe { (self as *const Iort).add(1) as *const u8 }; - let remaining_length = self.header.length as u32 - size_of::() as u32; + let remaining_length = self.header.length as u32 - core::mem::size_of::() as u32; IortNodeIter { pointer, @@ -79,10 +79,11 @@ pub enum IortNode<'a> { MemoryRange(&'a MemoryRangeNode), } -impl IortNode { +impl IortNode<'_> { pub fn id_mapping_array(&self) -> Option<&[IortIdMapping]> { - let id_mapping_num = unsafe {*(self as *const IortNode as *const IortNodeHeader).id_mapping_num}; - let id_mapping_array_offset = unsafe {*(self as *const IortNode as *const IortNodeHeader).id_mapping_array_offset}; + let node_header = unsafe{ *(self as *const IortNode as *const IortNodeHeader) }; + let id_mapping_num = node_header.id_mapping_num; + let id_mapping_array_offset = node_header.id_mapping_array_offset; if id_mapping_num == 0 { return None; @@ -123,7 +124,7 @@ impl<'a> Iterator for IortNodeIter<'a> { _ => return None, }; - self.pointer = unsafe { self.pointer.add(node_length) }; + self.pointer = unsafe { self.pointer.add(node_length as usize) }; self.remaining_length -= node_length as u32; Some(node) From 912e9cb7fcb771eaf1a09c5bd3171d83a3939c8e Mon Sep 17 00:00:00 2001 From: volca Date: Mon, 14 Oct 2024 23:38:26 +0800 Subject: [PATCH 09/12] beauty: beautify code style --- acpi/src/iort.rs | 29 +++++++------------ acpi/src/lib.rs | 4 +-- acpi/src/madt.rs | 53 ++++++++++++++-------------------- acpi/src/mpam.rs | 35 +++++++++------------- acpi/src/platform/interrupt.rs | 8 +---- acpi/src/platform/processor.rs | 6 ++-- acpi/src/rsdp.rs | 9 +++--- acpi/src/srat.rs | 36 ++++++++++------------- aml/src/value.rs | 2 +- 9 files changed, 72 insertions(+), 110 deletions(-) diff --git a/acpi/src/iort.rs b/acpi/src/iort.rs index 6f351d5..d2eda3d 100644 --- a/acpi/src/iort.rs +++ b/acpi/src/iort.rs @@ -1,15 +1,13 @@ -///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; 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 { - -} +pub enum IortError {} #[derive(Debug, Clone, Copy)] #[repr(C, packed)] @@ -47,11 +45,7 @@ impl Iort { let pointer = unsafe { (self as *const Iort).add(1) as *const u8 }; let remaining_length = self.header.length as u32 - core::mem::size_of::() as u32; - IortNodeIter { - pointer, - remaining_length, - _phantom: PhantomData - } + IortNodeIter { pointer, remaining_length, _phantom: PhantomData } } } @@ -81,10 +75,10 @@ pub enum IortNode<'a> { impl IortNode<'_> { pub fn id_mapping_array(&self) -> Option<&[IortIdMapping]> { - let node_header = unsafe{ *(self as *const IortNode as *const IortNodeHeader) }; + let node_header = unsafe { *(self as *const IortNode as *const IortNodeHeader) }; let id_mapping_num = node_header.id_mapping_num; let id_mapping_array_offset = node_header.id_mapping_array_offset; - + if id_mapping_num == 0 { return None; } else { @@ -99,7 +93,7 @@ impl IortNode<'_> { pub struct IortNodeIter<'a> { pointer: *const u8, remaining_length: u32, - _phantom: PhantomData<&'a ()> + _phantom: PhantomData<&'a ()>, } impl<'a> Iterator for IortNodeIter<'a> { @@ -131,7 +125,6 @@ impl<'a> Iterator for IortNodeIter<'a> { } } - #[derive(Debug, Clone, Copy)] #[repr(C, packed)] pub struct ItsNode { @@ -147,7 +140,7 @@ pub struct NamedComponentNode { node_flags: u32, mem_access_properties: u64, device_mem_address_size_limit: u8, - // This is followed by a ASCII Null terminated string + // 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. } @@ -234,4 +227,4 @@ pub struct IortIdMapping { output_base: u32, output_reference: u32, flags: u32, -} \ No newline at end of file +} diff --git a/acpi/src/lib.rs b/acpi/src/lib.rs index baf09bd..e63d51c 100644 --- a/acpi/src/lib.rs +++ b/acpi/src/lib.rs @@ -72,14 +72,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; -pub mod mpam; -pub mod iort; #[cfg(feature = "allocator_api")] mod managed_slice; diff --git a/acpi/src/madt.rs b/acpi/src/madt.rs index 10fac30..328d61e 100644 --- a/acpi/src/madt.rs +++ b/acpi/src/madt.rs @@ -1,5 +1,6 @@ use crate::{ - sdt::{ExtendedField, SdtHeader, Signature}, AcpiTable + sdt::{ExtendedField, SdtHeader, Signature}, + AcpiTable, }; use bit_field::BitField; use core::{marker::PhantomData, mem}; @@ -123,10 +124,7 @@ impl Madt { NmiProcessor, NmiSource, }, - processor::{ - X86Processor, - ProcessorState, - }, + processor::{ProcessorState, X86Processor}, }, AcpiError, }; @@ -156,8 +154,7 @@ 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, allocator)?; // Subtract one for the BSP + 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; @@ -324,14 +321,7 @@ impl Madt { { use crate::{ platform::{ - interrupt::{ - Gic, - Gicd, - Gicc, - GicMsiFrame, - Gicr, - GicIts, - }, + interrupt::{Gic, GicIts, GicMsiFrame, Gicc, Gicd, Gicr}, processor::Arm64Processor, }, AcpiError, @@ -348,7 +338,10 @@ impl Madt { for entry in self.entries() { match entry { - MadtEntry::Gicc(_) => {gicc_count += 1; processor_count += 1;}, + 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, @@ -359,10 +352,13 @@ impl Madt { 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 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 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; @@ -425,25 +421,20 @@ impl Madt { gicr_count += 1; } MadtEntry::GicInterruptTranslationService(entry) => { - gic_its[gic_its_count] = GicIts { - id: entry.id, - physical_base_address: entry.physical_base_address, - }; + 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)))) + Ok(( + InterruptModel::Gic(Gic::new(gicc, gicd, gic_msi_frame, gicr, gic_its)), + Some(ProcessorInfo::new_arm64(processors)), + )) } pub fn entries(&self) -> MadtEntryIter { diff --git a/acpi/src/mpam.rs b/acpi/src/mpam.rs index ad3bd83..bbbb92b 100644 --- a/acpi/src/mpam.rs +++ b/acpi/src/mpam.rs @@ -43,20 +43,12 @@ impl Mpam { 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 - } + 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 - }; + return if node.if_type == 0x00 { Some((node.base_address, node.mmio_size)) } else { None }; }) } } @@ -64,7 +56,7 @@ impl Mpam { pub struct MscNodeIter<'a> { pointer: *const u8, remaining_length: u32, - _phantom: PhantomData<&'a ()> + _phantom: PhantomData<&'a ()>, } impl Iterator for MscNodeIter<'_> { @@ -77,7 +69,7 @@ impl Iterator for MscNodeIter<'_> { 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; @@ -95,12 +87,12 @@ pub struct MscNode { 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, @@ -135,7 +127,7 @@ impl MscNode { pointer: ptr, remaining_length, remaining_nodes: self.resource_node_num, - _phantom: PhantomData + _phantom: PhantomData, } } } @@ -144,7 +136,7 @@ pub struct ResourceNodeIter<'a> { pointer: *const u8, remaining_length: u32, remaining_nodes: u32, - _phantom: PhantomData<&'a ()> + _phantom: PhantomData<&'a ()>, } impl Iterator for ResourceNodeIter<'_> { @@ -156,8 +148,9 @@ impl Iterator for ResourceNodeIter<'_> { } let node = unsafe { &*(self.pointer as *const ResourceNode) }; - let node_length = size_of::() + (node.func_dep_num as usize) * size_of::(); - + 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; @@ -194,9 +187,7 @@ impl ResourceNode { 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) - } + unsafe { core::slice::from_raw_parts(ptr, self.func_dep_num as usize) } } } @@ -206,4 +197,4 @@ pub struct FunctionDependency { // Function dependency structure pub producer: u32, pub reserved: u32, -} \ No newline at end of file +} diff --git a/acpi/src/platform/interrupt.rs b/acpi/src/platform/interrupt.rs index 638cd16..4607ae8 100644 --- a/acpi/src/platform/interrupt.rs +++ b/acpi/src/platform/interrupt.rs @@ -188,13 +188,7 @@ where gicr: ManagedSlice<'a, Gicr, A>, gic_its: ManagedSlice<'a, GicIts, A>, ) -> Self { - Self { - gicc, - gicd, - gic_msi_frame, - gicr, - gic_its, - } + Self { gicc, gicd, gic_msi_frame, gicr, gic_its } } } diff --git a/acpi/src/platform/processor.rs b/acpi/src/platform/processor.rs index c1af5ff..db69ebd 100644 --- a/acpi/src/platform/processor.rs +++ b/acpi/src/platform/processor.rs @@ -3,7 +3,7 @@ use core::alloc::Allocator; /// Processor trait pub trait Processor { - /// The OS associates this GICC Structure with a processor device object in the namespace + /// 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; } @@ -23,7 +23,7 @@ impl Processor for X86Processor { /// 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 + /// 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. @@ -89,4 +89,4 @@ where pub fn new_arm64(processors: ManagedSlice<'a, Arm64Processor, A>) -> Self { ProcessorInfo::Arm64Processors(processors) } -} \ No newline at end of file +} diff --git a/acpi/src/rsdp.rs b/acpi/src/rsdp.rs index da98ebb..e99e948 100644 --- a/acpi/src/rsdp.rs +++ b/acpi/src/rsdp.rs @@ -1,7 +1,7 @@ use uefi::table::{cfg::ACPI2_GUID, Boot, SystemTable}; use crate::{AcpiError, AcpiHandler, AcpiResult, PhysicalMapping}; -use core::{mem, ops::Range, slice, str, ffi::c_void}; +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; @@ -112,14 +112,13 @@ impl Rsdp { where H: AcpiHandler, { - let system_table = unsafe { - SystemTable::::from_ptr(system_table as *mut c_void).unwrap() - }; + let system_table = unsafe { SystemTable::::from_ptr(system_table as *mut c_void).unwrap() }; let config_table = system_table.config_table(); let rsdp = config_table.iter().find_map(|entry| { if entry.guid == ACPI2_GUID { - let rsdp_mapping = unsafe { handler.map_physical_region::(entry.address as usize, mem::size_of::()) }; + 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, diff --git a/acpi/src/srat.rs b/acpi/src/srat.rs index a15e428..2cae97e 100644 --- a/acpi/src/srat.rs +++ b/acpi/src/srat.rs @@ -5,9 +5,7 @@ use crate::{ AcpiTable, }; -pub enum SratError { - -} +pub enum SratError {} #[derive(Debug, Clone, Copy)] #[repr(C, packed)] @@ -16,8 +14,8 @@ pub struct Srat { _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, + // 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. } @@ -47,14 +45,12 @@ impl 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. 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, - } + 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, }) } @@ -62,11 +58,7 @@ impl Srat { 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, - } + AffinityStructIter { pointer, remaining_length, _phantom: PhantomData } } } @@ -74,7 +66,7 @@ impl Srat { pub struct AffinityStructIter<'a> { pointer: *const u8, remaining_length: u32, - _phantom: PhantomData<&'a ()> + _phantom: PhantomData<&'a ()>, } #[derive(Debug)] @@ -105,7 +97,9 @@ impl<'a> Iterator for AffinityStructIter<'a> { 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) }), + 5 => AffinityStruct::GenericInitiatorAffinity(unsafe { + &*(self.pointer as *const GenericInitiatorAffinity) + }), _ => return None, }; @@ -191,4 +185,4 @@ pub struct GenericInitiatorAffinity { pub device_handle: [u8; 16], pub flags: u32, pub _reserved2: u32, -} \ No newline at end of file +} 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 }), } } From ad1b570b6947a10d3f3f9dc055993001352ef80b Mon Sep 17 00:00:00 2001 From: volca Date: Sun, 27 Oct 2024 21:44:28 +0800 Subject: [PATCH 10/12] fix: fix IORT node pointer calculation and add SMMU V3 base address iterator --- acpi/src/iort.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/acpi/src/iort.rs b/acpi/src/iort.rs index d2eda3d..22d47de 100644 --- a/acpi/src/iort.rs +++ b/acpi/src/iort.rs @@ -42,11 +42,19 @@ impl fmt::Display for Iort { impl Iort { pub fn nodes(&self) -> IortNodeIter { - let pointer = unsafe { (self as *const Iort).add(1) as *const u8 }; - let remaining_length = self.header.length as u32 - core::mem::size_of::() as u32; + 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 as u32 - node_offset as u32; IortNodeIter { pointer, remaining_length, _phantom: PhantomData } } + + 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)] From 136af5261f35efdc856c10ec6b96ae446421d488 Mon Sep 17 00:00:00 2001 From: volca Date: Fri, 15 Nov 2024 21:51:13 +0800 Subject: [PATCH 11/12] Add methods for adding SSDT --- acpi/src/handler.rs | 14 ++++++++++++++ acpi/src/iort.rs | 2 +- acpi/src/lib.rs | 37 +++++++++++++++++++++++++++++++++++++ acpi/src/rsdp.rs | 22 ++++++++++++++++++++-- rust-toolchain | 3 --- 5 files changed, 72 insertions(+), 6 deletions(-) delete mode 100644 rust-toolchain diff --git a/acpi/src/handler.rs b/acpi/src/handler.rs index 72adc0d..63f458a 100644 --- a/acpi/src/handler.rs +++ b/acpi/src/handler.rs @@ -76,6 +76,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 index 22d47de..df34722 100644 --- a/acpi/src/iort.rs +++ b/acpi/src/iort.rs @@ -43,7 +43,7 @@ impl fmt::Display for Iort { 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 pointer = unsafe { (self as *const Iort as *const u8).add(node_offset) }; let remaining_length = self.header.length as u32 - node_offset as u32; IortNodeIter { pointer, remaining_length, _phantom: PhantomData } diff --git a/acpi/src/lib.rs b/acpi/src/lib.rs index 0406d14..374d9d4 100644 --- a/acpi/src/lib.rs +++ b/acpi/src/lib.rs @@ -367,6 +367,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`](crate::platform::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/rsdp.rs b/acpi/src/rsdp.rs index e99e948..0fcdea7 100644 --- a/acpi/src/rsdp.rs +++ b/acpi/src/rsdp.rs @@ -1,4 +1,8 @@ -use uefi::table::{cfg::ACPI2_GUID, Boot, SystemTable}; +use uefi::table::{ + cfg::{ACPI2_GUID, ACPI_GUID}, + Boot, + SystemTable, +}; use crate::{AcpiError, AcpiHandler, AcpiResult, PhysicalMapping}; use core::{ffi::c_void, mem, ops::Range, slice, str}; @@ -112,9 +116,11 @@ impl Rsdp { 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 { let rsdp_mapping = @@ -127,10 +133,22 @@ impl Rsdp { None } } + } else if 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) } diff --git a/rust-toolchain b/rust-toolchain deleted file mode 100644 index 87111cb..0000000 --- a/rust-toolchain +++ /dev/null @@ -1,3 +0,0 @@ -[toolchain] -channel = "nightly-2023-11-09" -components = ["rust-src", "llvm-tools-preview"] From 1c31f8fe7eefe87c4a77baca751d2ac4a7097988 Mon Sep 17 00:00:00 2001 From: volca Date: Mon, 25 Nov 2024 21:29:27 +0800 Subject: [PATCH 12/12] Improve changes to iort, srat, and other tables --- acpi/src/iort.rs | 326 ++++++++++++++++++++++++++------- acpi/src/madt.rs | 33 ++-- acpi/src/mpam.rs | 5 - acpi/src/platform/processor.rs | 2 + acpi/src/rsdp.rs | 16 +- acpi/src/srat.rs | 27 ++- 6 files changed, 300 insertions(+), 109 deletions(-) diff --git a/acpi/src/iort.rs b/acpi/src/iort.rs index df34722..20f83f6 100644 --- a/acpi/src/iort.rs +++ b/acpi/src/iort.rs @@ -7,13 +7,18 @@ use crate::{ /// an ITS Group, a root complex, or a component that is described in the namespace. use core::marker::PhantomData; -pub enum IortError {} +pub enum IortError { + InvalidNodeType, + InvalidLength, + RevisionNotSupported, + OffsetOutOfRange, +} #[derive(Debug, Clone, Copy)] #[repr(C, packed)] pub struct Iort { header: SdtHeader, - node_number: u32, + pub node_number: u32, node_array_offset: u32, reserved: u32, // After offset_to_node_array, there are node_number IORT Nodes @@ -34,7 +39,7 @@ 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{:#x?}", node)? + write!(f, "\n{}", node)?; } Ok(()) } @@ -44,11 +49,42 @@ 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 as u32 - node_offset as u32; + 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), @@ -60,16 +96,44 @@ impl Iort { #[derive(Debug, Clone, Copy)] #[repr(C, packed)] pub struct IortNodeHeader { - node_type: u8, - length: u16, - revision: u8, - identifier: u32, + 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), @@ -81,19 +145,45 @@ pub enum IortNode<'a> { 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) -> Option<&[IortIdMapping]> { - let node_header = unsafe { *(self as *const IortNode as *const IortNodeHeader) }; + 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; - if id_mapping_num == 0 { - return None; - } else { - unsafe { - let ptr = (self as *const IortNode as *const u8).add(id_mapping_array_offset as usize); - Some(core::slice::from_raw_parts(ptr as *const IortIdMapping, id_mapping_num as usize)) - } + 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, } } } @@ -108,7 +198,7 @@ impl<'a> Iterator for IortNodeIter<'a> { type Item = IortNode<'a>; fn next(&mut self) -> Option { - if self.remaining_length <= 0 { + if self.remaining_length == 0 { return None; } @@ -127,7 +217,7 @@ impl<'a> Iterator for IortNodeIter<'a> { }; self.pointer = unsafe { self.pointer.add(node_length as usize) }; - self.remaining_length -= node_length as u32; + self.remaining_length -= node_length; Some(node) } @@ -136,89 +226,183 @@ impl<'a> Iterator for IortNodeIter<'a> { #[derive(Debug, Clone, Copy)] #[repr(C, packed)] pub struct ItsNode { - header: IortNodeHeader, - its_number: u32, + 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 { - header: IortNodeHeader, - node_flags: u32, - mem_access_properties: u64, - device_mem_address_size_limit: u8, + 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 { - header: IortNodeHeader, - mem_access_properties: u64, - ats_attribute: u32, - pci_segment_number: u32, - mem_address_size_limit: u8, - pasid_capabilities: u16, - reserved: u8, - flags: u32, + 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 { - header: IortNodeHeader, - base_address: u64, - span: u64, - model: u32, - flags: u32, - global_interrupt_array_offset: u32, - context_interrupt_array_num: u32, - context_interrupt_array_offset: u32, - pmu_interrupt_array_num: u32, - pmu_interrupt_array_offset: u32, - // 后面是几个中断数组 + 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 { - header: IortNodeHeader, - base_address: u64, - flags: u32, - reserved: u32, - vatos_address: u64, - model: u32, - event: u32, - pri: u32, - gerr: u32, - sync: u32, - proximity_domain: u32, - device_id_mapping_index: u32, + 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 { - header: IortNodeHeader, - pg0_base_address: u64, - overflow_interrupt: u32, - node_reference: u32, - pg1_base_address: u64, + 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 { - header: IortNodeHeader, - flags: u32, - mem_range_discriptor_array_num: u32, - mem_range_discriptor_array_offset: u32, + 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 { @@ -230,9 +414,11 @@ pub struct MemoryRangeDescriptor { #[derive(Debug, Clone, Copy)] #[repr(C, packed)] pub struct IortIdMapping { - input_base: u32, - id_count: u32, - output_base: u32, - output_reference: u32, - flags: u32, + 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/madt.rs b/acpi/src/madt.rs index 6dd70b0..b60fab2 100644 --- a/acpi/src/madt.rs +++ b/acpi/src/madt.rs @@ -124,20 +124,17 @@ impl Madt { where A: core::alloc::Allocator + Clone, { - use crate::{ - platform::{ - interrupt::{ - Apic, - InterruptSourceOverride, - IoApic, - LocalInterruptLine, - NmiLine, - NmiProcessor, - NmiSource, - }, - processor::{ProcessorState, X86Processor}, + use crate::platform::{ + interrupt::{ + Apic, + InterruptSourceOverride, + IoApic, + LocalInterruptLine, + NmiLine, + NmiProcessor, + NmiSource, }, - AcpiError, + processor::{ProcessorState, X86Processor}, }; let mut local_apic_address = self.local_apic_address as u64; @@ -332,12 +329,9 @@ impl Madt { where A: core::alloc::Allocator + Clone, { - use crate::{ - platform::{ - interrupt::{Gic, GicIts, GicMsiFrame, Gicc, Gicd, Gicr}, - processor::Arm64Processor, - }, - AcpiError, + use crate::platform::{ + interrupt::{Gic, GicIts, GicMsiFrame, Gicc, Gicd, Gicr}, + processor::Arm64Processor, }; // need to count the number of each type of entry @@ -404,6 +398,7 @@ impl Madt { 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; diff --git a/acpi/src/mpam.rs b/acpi/src/mpam.rs index bbbb92b..5dab5da 100644 --- a/acpi/src/mpam.rs +++ b/acpi/src/mpam.rs @@ -25,13 +25,8 @@ use core::fmt; impl fmt::Display for Mpam { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "MAPM: {:#x?}", self.header)?; - let mut i = 100; for node in self.nodes() { write!(f, "\n{:#x?}", node)?; - i -= 1; - if i == 0 { - break; - } } Ok(()) } diff --git a/acpi/src/platform/processor.rs b/acpi/src/platform/processor.rs index db69ebd..5785262 100644 --- a/acpi/src/platform/processor.rs +++ b/acpi/src/platform/processor.rs @@ -32,6 +32,8 @@ pub struct Arm64Processor { /// 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)] diff --git a/acpi/src/rsdp.rs b/acpi/src/rsdp.rs index 0fcdea7..27a84db 100644 --- a/acpi/src/rsdp.rs +++ b/acpi/src/rsdp.rs @@ -110,7 +110,7 @@ impl Rsdp { /// 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`. + /// - 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 @@ -122,20 +122,10 @@ impl Rsdp { // 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 { - 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 if entry.guid == ACPI_GUID { + 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, diff --git a/acpi/src/srat.rs b/acpi/src/srat.rs index 2cae97e..3f02ede 100644 --- a/acpi/src/srat.rs +++ b/acpi/src/srat.rs @@ -5,8 +5,6 @@ use crate::{ AcpiTable, }; -pub enum SratError {} - #[derive(Debug, Clone, Copy)] #[repr(C, packed)] pub struct Srat { @@ -44,6 +42,9 @@ impl 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(( @@ -54,6 +55,9 @@ impl Srat { }) } + /// 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; @@ -113,6 +117,13 @@ impl<'a> Iterator for AffinityStructIter<'a> { #[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, } @@ -128,6 +139,10 @@ pub struct MemoryAffinity { 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], } @@ -138,6 +153,8 @@ 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, } @@ -148,6 +165,8 @@ 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], @@ -161,6 +180,8 @@ pub struct LocalX2ApicAffinity { 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, @@ -180,6 +201,8 @@ pub struct GicItsAffinity { 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],