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();