From 10efbfb09e45a9f41250d9075c789082d69f83fe Mon Sep 17 00:00:00 2001 From: Tom Date: Sun, 2 Jan 2022 16:27:21 -0700 Subject: [PATCH] Kernel: Scan ACPI memory ranges for the RSDP table On some systems the ACPI RSDP table may be located in ACPI reserved memory ranges rather than in the EBDA or BIOS areas. --- Kernel/Firmware/ACPI/Parser.cpp | 23 ++++++++++++++++++++++- Kernel/Memory/MemoryManager.cpp | 11 +++++++++++ Kernel/Memory/MemoryManager.h | 2 ++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/Kernel/Firmware/ACPI/Parser.cpp b/Kernel/Firmware/ACPI/Parser.cpp index 706cfa284f..6960596075 100644 --- a/Kernel/Firmware/ACPI/Parser.cpp +++ b/Kernel/Firmware/ACPI/Parser.cpp @@ -388,7 +388,28 @@ UNMAP_AFTER_INIT Optional StaticParsing::find_rsdp() auto rsdp = map_ebda().find_chunk_starting_with(signature, 16); if (rsdp.has_value()) return rsdp; - return map_bios().find_chunk_starting_with(signature, 16); + rsdp = map_bios().find_chunk_starting_with(signature, 16); + if (rsdp.has_value()) + return rsdp; + + // On some systems the RSDP may be located in ACPI NVS or reclaimable memory regions + MM.for_each_physical_memory_range([&](auto& memory_range) { + if (!(memory_range.type == Memory::PhysicalMemoryRangeType::ACPI_NVS || memory_range.type == Memory::PhysicalMemoryRangeType::ACPI_Reclaimable)) + return IterationDecision::Continue; + + Memory::MappedROM mapping; + mapping.region = MM.allocate_kernel_region(memory_range.start, Memory::page_round_up(memory_range.length).release_value_but_fixme_should_propagate_errors(), {}, Memory::Region::Access::Read).release_value(); + mapping.offset = memory_range.start.offset_in_page(); + mapping.size = memory_range.length; + mapping.paddr = memory_range.start; + + rsdp = mapping.find_chunk_starting_with(signature, 16); + if (rsdp.has_value()) + return IterationDecision::Break; + + return IterationDecision::Continue; + }); + return rsdp; } UNMAP_AFTER_INIT Optional StaticParsing::find_table(PhysicalAddress rsdp_address, StringView signature) diff --git a/Kernel/Memory/MemoryManager.cpp b/Kernel/Memory/MemoryManager.cpp index ae7950a9b2..389d91ee2c 100644 --- a/Kernel/Memory/MemoryManager.cpp +++ b/Kernel/Memory/MemoryManager.cpp @@ -174,6 +174,17 @@ UNMAP_AFTER_INIT void MemoryManager::protect_ksyms_after_init() dmesgln("Write-protected kernel symbols after init."); } +IterationDecision MemoryManager::for_each_physical_memory_range(Function callback) +{ + VERIFY(!m_physical_memory_ranges.is_empty()); + for (auto& current_range : m_physical_memory_ranges) { + IterationDecision decision = callback(current_range); + if (decision != IterationDecision::Continue) + return decision; + } + return IterationDecision::Continue; +} + UNMAP_AFTER_INIT void MemoryManager::register_reserved_ranges() { VERIFY(!m_physical_memory_ranges.is_empty()); diff --git a/Kernel/Memory/MemoryManager.h b/Kernel/Memory/MemoryManager.h index fcd70e462e..b23ec04ffb 100644 --- a/Kernel/Memory/MemoryManager.h +++ b/Kernel/Memory/MemoryManager.h @@ -237,6 +237,8 @@ public: void copy_physical_page(PhysicalPage&, u8 page_buffer[PAGE_SIZE]); + IterationDecision for_each_physical_memory_range(Function); + private: MemoryManager(); ~MemoryManager();