From b3f59acf7edbf9ebd7f9f6969e2c50820e173a9d Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Thu, 4 Feb 2021 19:47:17 -0800 Subject: [PATCH] [kernel] Make sure to virtualize ACPI table pointers Probably due to old UEFI page tables going away, some systems failed to load ACPI tables at their physical location. Make sure to translate them to kernel offset-mapped addresses. --- src/kernel/acpi_tables.h | 2 +- src/kernel/device_manager.cpp | 40 +++++++++++++++++++++++------------ src/kernel/device_manager.h | 13 +++++------- 3 files changed, 33 insertions(+), 22 deletions(-) diff --git a/src/kernel/acpi_tables.h b/src/kernel/acpi_tables.h index 100e9b3..806315f 100644 --- a/src/kernel/acpi_tables.h +++ b/src/kernel/acpi_tables.h @@ -23,7 +23,7 @@ struct acpi_table_header } __attribute__ ((packed)); #define TABLE_HEADER(signature) \ - static const uint32_t type_id = kutil::byteswap(signature); \ + static constexpr uint32_t type_id = kutil::byteswap(signature); \ acpi_table_header header; diff --git a/src/kernel/device_manager.cpp b/src/kernel/device_manager.cpp index 7a3887a..19e4939 100644 --- a/src/kernel/device_manager.cpp +++ b/src/kernel/device_manager.cpp @@ -38,7 +38,7 @@ struct acpi2_rsdp uint32_t rsdt_address; uint32_t length; - uint64_t xsdt_address; + acpi_table_header *xsdt_address; uint8_t checksum20; uint8_t reserved[3]; } __attribute__ ((packed)); @@ -73,13 +73,20 @@ device_manager::device_manager() : m_irqs[2] = ignore_endpoint; } +template static const T * +check_get_table(const acpi_table_header *header) +{ + kassert(header && header->validate(T::type_id), "Invalid ACPI table."); + return reinterpret_cast(header); +} + void device_manager::parse_acpi(const void *root_table) { kassert(root_table != 0, "ACPI root table pointer is null."); - const acpi1_rsdp *acpi1 = - reinterpret_cast(root_table); + const acpi1_rsdp *acpi1 = memory::to_virtual( + reinterpret_cast(root_table)); for (int i = 0; i < sizeof(acpi1->signature); ++i) kassert(acpi1->signature[i] == expected_signature[i], @@ -96,7 +103,7 @@ device_manager::parse_acpi(const void *root_table) sum = kutil::checksum(acpi2, sizeof(acpi2_rsdp), sizeof(acpi1_rsdp)); kassert(sum == 0, "ACPI 2.0 RSDP checksum mismatch."); - load_xsdt(reinterpret_cast(acpi2->xsdt_address)); + load_xsdt(memory::to_virtual(acpi2->xsdt_address)); } ioapic * @@ -112,9 +119,9 @@ put_sig(char *into, uint32_t type) } void -device_manager::load_xsdt(const acpi_xsdt *xsdt) +device_manager::load_xsdt(const acpi_table_header *header) { - kassert(xsdt && acpi_validate(xsdt), "Invalid ACPI XSDT."); + const auto *xsdt = check_get_table(header); char sig[5] = {0,0,0,0,0}; log::info(logs::device, "ACPI 2.0+ tables loading"); @@ -124,7 +131,8 @@ device_manager::load_xsdt(const acpi_xsdt *xsdt) size_t num_tables = acpi_table_entries(xsdt, sizeof(void*)); for (size_t i = 0; i < num_tables; ++i) { - const acpi_table_header *header = xsdt->headers[i]; + const acpi_table_header *header = + memory::to_virtual(xsdt->headers[i]); put_sig(sig, header->type); log::debug(logs::device, " Found table %s", sig); @@ -133,15 +141,15 @@ device_manager::load_xsdt(const acpi_xsdt *xsdt) switch (header->type) { case acpi_apic::type_id: - load_apic(reinterpret_cast(header)); + load_apic(header); break; case acpi_mcfg::type_id: - load_mcfg(reinterpret_cast(header)); + load_mcfg(header); break; case acpi_hpet::type_id: - load_hpet(reinterpret_cast(header)); + load_hpet(header); break; default: @@ -151,8 +159,10 @@ device_manager::load_xsdt(const acpi_xsdt *xsdt) } void -device_manager::load_apic(const acpi_apic *apic) +device_manager::load_apic(const acpi_table_header *header) { + const auto *apic = check_get_table(header); + uintptr_t local = apic->local_address; m_lapic = new lapic(local, isr::isrSpurious); @@ -249,8 +259,10 @@ device_manager::load_apic(const acpi_apic *apic) } void -device_manager::load_mcfg(const acpi_mcfg *mcfg) +device_manager::load_mcfg(const acpi_table_header *header) { + const auto *mcfg = check_get_table(header); + size_t count = acpi_table_entries(mcfg, sizeof(acpi_mcfg_entry)); m_pci.set_size(count); m_devices.set_capacity(16); @@ -271,8 +283,10 @@ device_manager::load_mcfg(const acpi_mcfg *mcfg) } void -device_manager::load_hpet(const acpi_hpet *hpet) +device_manager::load_hpet(const acpi_table_header *header) { + const auto *hpet = check_get_table(header); + log::debug(logs::device, " Found HPET device #%3d: base %016lx pmin %d attr %02x", hpet->index, hpet->base_address.address, hpet->periodic_min, hpet->attributes); diff --git a/src/kernel/device_manager.h b/src/kernel/device_manager.h index f5b412f..d18c670 100644 --- a/src/kernel/device_manager.h +++ b/src/kernel/device_manager.h @@ -6,10 +6,7 @@ #include "hpet.h" #include "pci.h" -struct acpi_xsdt; -struct acpi_apic; -struct acpi_mcfg; -struct acpi_hpet; +struct acpi_table_header; class block_device; class endpoint; @@ -100,19 +97,19 @@ public: private: /// Parse the ACPI XSDT and load relevant sub-tables. /// \arg xsdt Pointer to the XSDT from the firmware - void load_xsdt(const acpi_xsdt *xsdt); + void load_xsdt(const acpi_table_header *xsdt); /// Parse the ACPI MADT and initialize APICs from it. /// \arg apic Pointer to the MADT from the XSDT - void load_apic(const acpi_apic *apic); + void load_apic(const acpi_table_header *apic); /// Parse the ACPI MCFG and initialize PCIe from it. /// \arg mcfg Pointer to the MCFG from the XSDT - void load_mcfg(const acpi_mcfg *mcfg); + void load_mcfg(const acpi_table_header *mcfg); /// Parse the ACPI HPET and initialize an HPET from it. /// \arg hpet Pointer to the HPET from the XSDT - void load_hpet(const acpi_hpet *hpet); + void load_hpet(const acpi_table_header *hpet); /// Probe the PCIe busses and add found devices to our /// device list. The device list is destroyed and rebuilt.