From 4c235e52ce0964145489009dc60732138d0a069b Mon Sep 17 00:00:00 2001 From: Sarah Date: Wed, 22 Nov 2023 23:46:54 +0100 Subject: [PATCH] (feat) add functionality to set the Multiple APIC Descriptor Table (MADT) and parse the Fixed ACPI Description Table (FADT) (parsing in itself is successful but it still breaks because of a deallocate) --- src/arch/x86_64/kernel/acpi.rs | 99 +++++++++++++++++++++++++++++++++- src/arch/x86_64/kernel/mod.rs | 6 ++- 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/src/arch/x86_64/kernel/acpi.rs b/src/arch/x86_64/kernel/acpi.rs index a78cbd9ae1..78761702aa 100644 --- a/src/arch/x86_64/kernel/acpi.rs +++ b/src/arch/x86_64/kernel/acpi.rs @@ -50,6 +50,7 @@ static SLP_TYPA: OnceCell = OnceCell::new(); /// The "Root System Description Pointer" structure providing pointers to all other ACPI tables. #[repr(C, packed)] +#[derive(Debug)] struct AcpiRsdp { signature: [u8; 8], checksum: u8, @@ -87,6 +88,9 @@ impl AcpiSdtHeader { fn signature(&self) -> &str { str::from_utf8(&self.signature).unwrap() } + pub fn header_start_address(&self) -> usize { + self as *const _ as usize + } } /// A convenience structure to work with an ACPI table. @@ -309,6 +313,7 @@ fn detect_rsdp(start_address: PhysAddr, end_address: PhysAddr) -> Result<&'stati /// Detects ACPI support of the computer system. /// Returns a reference to the ACPI RSDP within the Ok() if successful or an empty Err() on failure. fn detect_acpi() -> Result<&'static AcpiRsdp, ()> { + // For UEFI Systems, the tables are already mapped so we only need to return a proper reference to the table if crate::arch::kernel::is_uefi() { let rsdp = crate::arch::kernel::get_rsdp_addr(); trace!("rsdp detected successfully at {rsdp:#x?}"); @@ -421,7 +426,17 @@ fn parse_fadt(fadt: AcpiTable<'_>) { } else { PhysAddr(fadt_table.dsdt.into()) }; - let dsdt = AcpiTable::map(dsdt_address); + let dsdt = if !crate::arch::kernel::is_uefi() { + AcpiTable::map(dsdt_address) + } else { + // For UEFI Systems, the tables are already mapped so we only need to return a proper reference to the table + let table = unsafe { (dsdt_address.0 as *const AcpiSdtHeader).as_ref().unwrap() }; + AcpiTable { + header: table, + allocated_virtual_address: VirtAddr(dsdt_address.0), + allocated_length: table.length as usize, + } + }; // Check it. assert!( @@ -532,3 +547,85 @@ pub fn init() { } } } + +pub fn init_uefi() { + // Detect the RSDP and get a pointer to either the XSDT (64-bit) or RSDT (32-bit), whichever is available. + // Both are called RSDT in the following. + let rsdp = detect_acpi().expect("Hermit requires an ACPI-compliant system"); + let rsdt_physical_address = if rsdp.revision >= 2 { + PhysAddr(rsdp.xsdt_physical_address) + } else { + PhysAddr(rsdp.rsdt_physical_address.into()) + }; + + //Load RSDT + let rsdt = &unsafe { *(rsdt_physical_address.0 as *const AcpiSdtHeader) }; + trace!("RSDT: {rsdt:#x?}"); + + // The RSDT contains pointers to all available ACPI tables. + // Iterate through them. + let mut current_address = rsdt_physical_address.0 as usize + mem::size_of::(); + trace!("RSDT start address at {current_address:#x}"); + let nr_entries = + (rsdt.length as usize - mem::size_of::()) / mem::size_of::(); + let end_addr = current_address + nr_entries * mem::size_of::(); + while current_address < end_addr { + trace!("current_address: {current_address:#x}"); + + // Depending on the RSDP revision, either an XSDT or an RSDT has been chosen above. + // The XSDT contains 64-bit pointers whereas the RSDT has 32-bit pointers. + let table_physical_address = if rsdp.revision >= 2 { + let address = PhysAddr(unsafe { ptr::read_unaligned(current_address as *const u64) }); + current_address += mem::size_of::(); + address + } else { + let address = + PhysAddr((unsafe { ptr::read_unaligned(current_address as *const u32) }).into()); + current_address += mem::size_of::(); + address + }; + + trace!("table_physical_address: {table_physical_address:#x}"); + + let table = unsafe { + (table_physical_address.0 as *const AcpiSdtHeader) + .as_ref() + .unwrap() + }; + + trace!("table: {table:#x?}"); + + let signature = table.signature(); + + debug!("Found ACPI table: {signature:#?}"); + + if signature == "APIC" { + // This is a "Multiple APIC Descriptor Table" (MADT) aka "APIC Table" + // Check and save the entire APIC table for the get_apic_table() call + assert!( + verify_checksum(table.header_start_address(), table.length as usize).is_ok(), + "MADT at {table_physical_address:#x} has invalid checksum" + ); + let madt: AcpiTable<'static> = AcpiTable { + header: table, + allocated_virtual_address: VirtAddr(table_physical_address.0), + allocated_length: table.length as usize, + }; + MADT.set(madt).unwrap(); + trace!("setting MADT successful"); + } else if signature == "FACP" { + // This is the "Fixed ACPI Description Table" (FADT) aka "Fixed ACPI Control Pointer" (FACP) + // Check and parse this table for the poweroff() call + assert!( + verify_checksum(table.header_start_address(), table.length as usize).is_ok(), + "FADT at {table_physical_address:#x} has invalid checksum" + ); + let fadt: AcpiTable<'static> = AcpiTable { + header: table, + allocated_virtual_address: VirtAddr(table_physical_address.0), + allocated_length: table.length as usize, + }; + parse_fadt(fadt); + } + } +} diff --git a/src/arch/x86_64/kernel/mod.rs b/src/arch/x86_64/kernel/mod.rs index 189340a3dd..2a0f3d0f2a 100644 --- a/src/arch/x86_64/kernel/mod.rs +++ b/src/arch/x86_64/kernel/mod.rs @@ -198,7 +198,11 @@ pub fn boot_processor_init() { } if !env::is_uhyve() { #[cfg(feature = "acpi")] - acpi::init(); + if is_uefi() { + acpi::init_uefi(); + } else { + acpi::init(); + } } apic::init();