diff --git a/Kernel/Arch/aarch64/Firmware/ACPI/StaticParsing.cpp b/Kernel/Arch/aarch64/Firmware/ACPI/StaticParsing.cpp new file mode 100644 index 0000000000..ba0d9bc13e --- /dev/null +++ b/Kernel/Arch/aarch64/Firmware/ACPI/StaticParsing.cpp @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2023, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +namespace Kernel::ACPI::StaticParsing { + +ErrorOr> find_rsdp_in_platform_specific_memory_locations() +{ + // FIXME: Implement finding RSDP for aarch64. + return Optional {}; +} + +} diff --git a/Kernel/Arch/x86_64/Firmware/ACPI/StaticParsing.cpp b/Kernel/Arch/x86_64/Firmware/ACPI/StaticParsing.cpp new file mode 100644 index 0000000000..3ae2a4866b --- /dev/null +++ b/Kernel/Arch/x86_64/Firmware/ACPI/StaticParsing.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2023, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include + +namespace Kernel::ACPI::StaticParsing { + +// https://uefi.org/specs/ACPI/6.4/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#finding-the-rsdp-on-ia-pc-systems +ErrorOr> find_rsdp_in_platform_specific_memory_locations() +{ + constexpr auto signature = "RSD PTR "sv; + auto ebda_or_error = map_ebda(); + if (!ebda_or_error.is_error()) { + auto rsdp = ebda_or_error.value().find_chunk_starting_with(signature, 16); + if (rsdp.has_value()) + return rsdp; + } + auto bios_or_error = map_bios(); + if (!bios_or_error.is_error()) { + auto rsdp = bios_or_error.value().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 + Optional rsdp; + 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; + auto region_size_or_error = Memory::page_round_up(memory_range.length); + if (region_size_or_error.is_error()) + return IterationDecision::Continue; + auto region_or_error = MM.allocate_kernel_region(memory_range.start, region_size_or_error.value(), {}, Memory::Region::Access::Read); + if (region_or_error.is_error()) + return IterationDecision::Continue; + mapping.region = region_or_error.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; +} + +} diff --git a/Kernel/Arch/x86_64/InterruptManagement.cpp b/Kernel/Arch/x86_64/InterruptManagement.cpp index f392eff467..cd6d063038 100644 --- a/Kernel/Arch/x86_64/InterruptManagement.cpp +++ b/Kernel/Arch/x86_64/InterruptManagement.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -118,20 +119,19 @@ NonnullLockRefPtr InterruptManagement::get_responsible_irq_contro VERIFY_NOT_REACHED(); } -UNMAP_AFTER_INIT PhysicalAddress InterruptManagement::search_for_madt() +UNMAP_AFTER_INIT ErrorOr> InterruptManagement::find_madt_physical_address() { dbgln("Early access to ACPI tables for interrupt setup"); - auto rsdp = ACPI::StaticParsing::find_rsdp(); - if (!rsdp.has_value()) - return {}; - auto apic = ACPI::StaticParsing::find_table(rsdp.value(), "APIC"sv); - if (!apic.has_value()) - return {}; - return apic.value(); + auto possible_rsdp_physical_address = TRY(ACPI::StaticParsing::find_rsdp_in_platform_specific_memory_locations()); + if (!possible_rsdp_physical_address.has_value()) + return Optional {}; + auto possible_apic_physical_address = TRY(ACPI::StaticParsing::find_table(possible_rsdp_physical_address.value(), "APIC"sv)); + if (!possible_apic_physical_address.has_value()) + return Optional {}; + return possible_apic_physical_address.value(); } UNMAP_AFTER_INIT InterruptManagement::InterruptManagement() - : m_madt(search_for_madt()) { } @@ -151,13 +151,15 @@ UNMAP_AFTER_INIT void InterruptManagement::switch_to_ioapic_mode() dmesgln("Interrupts: Switch to IOAPIC mode"); InterruptDisabler disabler; - if (m_madt.is_null()) { + m_madt_physical_address = MUST(find_madt_physical_address()); + + if (!m_madt_physical_address.has_value()) { dbgln("Interrupts: ACPI MADT is not available, reverting to PIC mode"); switch_to_pic_mode(); return; } - dbgln("Interrupts: MADT @ P {}", m_madt.as_ptr()); + dbgln("Interrupts: MADT @ P {}", m_madt_physical_address.value().as_ptr()); locate_apic_data(); if (m_interrupt_controllers.size() == 1) { if (get_interrupt_controller(0).type() == IRQControllerType::i8259) { @@ -187,8 +189,8 @@ UNMAP_AFTER_INIT void InterruptManagement::switch_to_ioapic_mode() UNMAP_AFTER_INIT void InterruptManagement::locate_apic_data() { - VERIFY(!m_madt.is_null()); - auto madt = Memory::map_typed(m_madt).release_value_but_fixme_should_propagate_errors(); + VERIFY(m_madt_physical_address.has_value()); + auto madt = Memory::map_typed(m_madt_physical_address.value()).release_value_but_fixme_should_propagate_errors(); if (madt->flags & PCAT_COMPAT_FLAG) m_interrupt_controllers.append(adopt_lock_ref(*new PIC())); diff --git a/Kernel/Arch/x86_64/InterruptManagement.h b/Kernel/Arch/x86_64/InterruptManagement.h index 684e5f951e..129dc454d0 100644 --- a/Kernel/Arch/x86_64/InterruptManagement.h +++ b/Kernel/Arch/x86_64/InterruptManagement.h @@ -48,8 +48,8 @@ public: static u8 acquire_mapped_interrupt_number(u8 original_irq); static u8 acquire_irq_number(u8 mapped_interrupt_vector); - virtual void switch_to_pic_mode(); - virtual void switch_to_ioapic_mode(); + void switch_to_pic_mode(); + void switch_to_ioapic_mode(); NonnullLockRefPtr get_responsible_irq_controller(u8 interrupt_vector); NonnullLockRefPtr get_responsible_irq_controller(IRQControllerType controller_type, u8 interrupt_vector); @@ -67,12 +67,12 @@ protected: private: InterruptManagement(); - PhysicalAddress search_for_madt(); + ErrorOr> find_madt_physical_address(); void locate_apic_data(); Vector> m_interrupt_controllers; Vector m_isa_interrupt_overrides; Vector m_pci_interrupt_overrides; - PhysicalAddress m_madt; + Optional m_madt_physical_address; }; } diff --git a/Kernel/Arch/x86_64/Interrupts/APIC.cpp b/Kernel/Arch/x86_64/Interrupts/APIC.cpp index e29a30e36b..b746fd1bf2 100644 --- a/Kernel/Arch/x86_64/Interrupts/APIC.cpp +++ b/Kernel/Arch/x86_64/Interrupts/APIC.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -261,19 +262,30 @@ UNMAP_AFTER_INIT bool APIC::init_bsp() m_apic_base = region_or_error.release_value(); } - auto rsdp = ACPI::StaticParsing::find_rsdp(); - if (!rsdp.has_value()) { + auto possible_rsdp_physical_address_or_error = ACPI::StaticParsing::find_rsdp_in_platform_specific_memory_locations(); + if (possible_rsdp_physical_address_or_error.is_error()) { + dbgln("APIC: Failed to map RSDP"); + return false; + } + auto possible_rsdp_physical_address = possible_rsdp_physical_address_or_error.release_value(); + if (!possible_rsdp_physical_address.has_value()) { dbgln("APIC: RSDP not found"); return false; } - auto madt_address = ACPI::StaticParsing::find_table(rsdp.value(), "APIC"sv); - if (!madt_address.has_value()) { + + auto possible_apic_physical_address_or_error = ACPI::StaticParsing::find_table(possible_rsdp_physical_address.value(), "APIC"sv); + if (possible_apic_physical_address_or_error.is_error()) { + dbgln("APIC: Failed to map RSDT/XSDT"); + return false; + } + auto possible_apic_physical_address = possible_apic_physical_address_or_error.release_value(); + if (!possible_apic_physical_address.has_value()) { dbgln("APIC: MADT table not found"); return false; } if (kernel_command_line().is_smp_enabled()) { - auto madt_or_error = Memory::map_typed(madt_address.value()); + auto madt_or_error = Memory::map_typed(possible_apic_physical_address.value()); if (madt_or_error.is_error()) { dbgln("APIC: Failed to map MADT table"); return false; diff --git a/Kernel/CMakeLists.txt b/Kernel/CMakeLists.txt index 99cec35d13..5da5389a8d 100644 --- a/Kernel/CMakeLists.txt +++ b/Kernel/CMakeLists.txt @@ -209,6 +209,7 @@ set(KERNEL_SOURCES Firmware/BIOS.cpp Firmware/ACPI/Initialize.cpp Firmware/ACPI/Parser.cpp + Firmware/ACPI/StaticParsing.cpp Firmware/MultiProcessor/Parser.cpp Interrupts/GenericInterruptHandler.cpp Interrupts/IRQHandler.cpp @@ -370,6 +371,8 @@ if ("${SERENITY_ARCH}" STREQUAL "x86_64") Arch/x86_64/DebugOutput.cpp Arch/x86_64/Delay.cpp + Arch/x86_64/Firmware/ACPI/StaticParsing.cpp + Arch/x86_64/Hypervisor/BochsDisplayConnector.cpp Arch/x86_64/Hypervisor/VMWareBackdoor.cpp @@ -460,6 +463,8 @@ elseif("${SERENITY_ARCH}" STREQUAL "aarch64") ${SOURCES_RUNNING_WITHOUT_MMU} Arch/Processor.cpp + Arch/aarch64/Firmware/ACPI/StaticParsing.cpp + Arch/aarch64/boot.S Arch/aarch64/BootPPMParser.cpp Arch/aarch64/CPUID.cpp diff --git a/Kernel/Firmware/ACPI/Definitions.h b/Kernel/Firmware/ACPI/Definitions.h index 438a8ce6c9..08c45341b4 100644 --- a/Kernel/Firmware/ACPI/Definitions.h +++ b/Kernel/Firmware/ACPI/Definitions.h @@ -327,11 +327,4 @@ struct [[gnu::packed]] DSDT { }; } -class Parser; - -namespace StaticParsing { -Optional find_rsdp(); -Optional find_table(PhysicalAddress rsdp, StringView signature); -} - } diff --git a/Kernel/Firmware/ACPI/Initialize.cpp b/Kernel/Firmware/ACPI/Initialize.cpp index 85c0b30e38..77e06e1855 100644 --- a/Kernel/Firmware/ACPI/Initialize.cpp +++ b/Kernel/Firmware/ACPI/Initialize.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -18,11 +19,11 @@ UNMAP_AFTER_INIT void initialize() if (feature_level == AcpiFeatureLevel::Disabled) return; - auto rsdp = StaticParsing::find_rsdp(); + auto rsdp = MUST(StaticParsing::find_rsdp_in_platform_specific_memory_locations()); if (!rsdp.has_value()) return; - auto facp = StaticParsing::find_table(rsdp.value(), "FACP"sv); + auto facp = MUST(StaticParsing::find_table(rsdp.value(), "FACP"sv)); if (!facp.has_value()) return; auto facp_table_or_error = Memory::map_typed(facp.value()); diff --git a/Kernel/Firmware/ACPI/Parser.cpp b/Kernel/Firmware/ACPI/Parser.cpp index 98863f7355..d69c41e024 100644 --- a/Kernel/Firmware/ACPI/Parser.cpp +++ b/Kernel/Firmware/ACPI/Parser.cpp @@ -120,9 +120,6 @@ void Parser::enumerate_static_tables(Function search_table_in_xsdt(PhysicalAddress xsdt, StringView signature); -static Optional search_table_in_rsdt(PhysicalAddress rsdt, StringView signature); static bool validate_table(Structures::SDTHeader const&, size_t length); UNMAP_AFTER_INIT void Parser::locate_static_data() @@ -417,103 +414,4 @@ static bool validate_table(Structures::SDTHeader const& v_header, size_t length) return false; } -// https://uefi.org/specs/ACPI/6.4/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#finding-the-rsdp-on-ia-pc-systems -UNMAP_AFTER_INIT Optional StaticParsing::find_rsdp() -{ - constexpr auto signature = "RSD PTR "sv; - auto ebda_or_error = map_ebda(); - if (!ebda_or_error.is_error()) { - auto rsdp = ebda_or_error.value().find_chunk_starting_with(signature, 16); - if (rsdp.has_value()) - return rsdp; - } - auto bios_or_error = map_bios(); - if (!bios_or_error.is_error()) { - auto rsdp = bios_or_error.value().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 - Optional rsdp; - 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; - auto region_size_or_error = Memory::page_round_up(memory_range.length); - if (region_size_or_error.is_error()) - return IterationDecision::Continue; - auto region_or_error = MM.allocate_kernel_region(memory_range.start, region_size_or_error.value(), {}, Memory::Region::Access::Read); - if (region_or_error.is_error()) - return IterationDecision::Continue; - mapping.region = region_or_error.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) -{ - // FIXME: There's no validation of ACPI tables here. Use the checksum to validate the tables. - VERIFY(signature.length() == 4); - - auto rsdp = Memory::map_typed(rsdp_address).release_value_but_fixme_should_propagate_errors(); - - if (rsdp->base.revision == 0) - return search_table_in_rsdt(PhysicalAddress(rsdp->base.rsdt_ptr), signature); - - if (rsdp->base.revision >= 2) { - if (rsdp->xsdt_ptr) - return search_table_in_xsdt(PhysicalAddress(rsdp->xsdt_ptr), signature); - return search_table_in_rsdt(PhysicalAddress(rsdp->base.rsdt_ptr), signature); - } - VERIFY_NOT_REACHED(); -} - -UNMAP_AFTER_INIT static Optional search_table_in_xsdt(PhysicalAddress xsdt_address, StringView signature) -{ - // FIXME: There's no validation of ACPI tables here. Use the checksum to validate the tables. - VERIFY(signature.length() == 4); - - auto xsdt = Memory::map_typed(xsdt_address).release_value_but_fixme_should_propagate_errors(); - - for (size_t i = 0; i < ((xsdt->h.length - sizeof(Structures::SDTHeader)) / sizeof(u64)); ++i) { - if (match_table_signature(PhysicalAddress((PhysicalPtr)xsdt->table_ptrs[i]), signature)) - return PhysicalAddress((PhysicalPtr)xsdt->table_ptrs[i]); - } - return {}; -} - -static bool match_table_signature(PhysicalAddress table_header, StringView signature) -{ - // FIXME: There's no validation of ACPI tables here. Use the checksum to validate the tables. - VERIFY(signature.length() == 4); - - auto table = Memory::map_typed(table_header).release_value_but_fixme_should_propagate_errors(); - return !strncmp(table->h.sig, signature.characters_without_null_termination(), 4); -} - -UNMAP_AFTER_INIT static Optional search_table_in_rsdt(PhysicalAddress rsdt_address, StringView signature) -{ - // FIXME: There's no validation of ACPI tables here. Use the checksum to validate the tables. - VERIFY(signature.length() == 4); - - auto rsdt = Memory::map_typed(rsdt_address).release_value_but_fixme_should_propagate_errors(); - - for (u32 i = 0; i < ((rsdt->h.length - sizeof(Structures::SDTHeader)) / sizeof(u32)); i++) { - if (match_table_signature(PhysicalAddress((PhysicalPtr)rsdt->table_ptrs[i]), signature)) - return PhysicalAddress((PhysicalPtr)rsdt->table_ptrs[i]); - } - return {}; -} - } diff --git a/Kernel/Firmware/ACPI/StaticParsing.cpp b/Kernel/Firmware/ACPI/StaticParsing.cpp new file mode 100644 index 0000000000..2b967f01bd --- /dev/null +++ b/Kernel/Firmware/ACPI/StaticParsing.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2023, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include + +namespace Kernel::ACPI::StaticParsing { + +static bool match_table_signature(PhysicalAddress table_header, StringView signature) +{ + // FIXME: There's no validation of ACPI tables here. Use the checksum to validate the tables. + VERIFY(signature.length() == 4); + + auto table = Memory::map_typed(table_header).release_value_but_fixme_should_propagate_errors(); + return !strncmp(table->h.sig, signature.characters_without_null_termination(), 4); +} + +ErrorOr> search_table_in_xsdt(PhysicalAddress xsdt_address, StringView signature) +{ + // FIXME: There's no validation of ACPI tables here. Use the checksum to validate the tables. + VERIFY(signature.length() == 4); + + auto xsdt = TRY(Memory::map_typed(xsdt_address)); + + for (size_t i = 0; i < ((xsdt->h.length - sizeof(Structures::SDTHeader)) / sizeof(u64)); ++i) { + if (match_table_signature(PhysicalAddress((PhysicalPtr)xsdt->table_ptrs[i]), signature)) + return PhysicalAddress((PhysicalPtr)xsdt->table_ptrs[i]); + } + return Optional {}; +} + +ErrorOr> find_table(PhysicalAddress rsdp_address, StringView signature) +{ + // FIXME: There's no validation of ACPI tables here. Use the checksum to validate the tables. + VERIFY(signature.length() == 4); + + auto rsdp = TRY(Memory::map_typed(rsdp_address)); + + if (rsdp->base.revision == 0) + return search_table_in_rsdt(PhysicalAddress(rsdp->base.rsdt_ptr), signature); + + if (rsdp->base.revision >= 2) { + if (rsdp->xsdt_ptr) + return search_table_in_xsdt(PhysicalAddress(rsdp->xsdt_ptr), signature); + return search_table_in_rsdt(PhysicalAddress(rsdp->base.rsdt_ptr), signature); + } + VERIFY_NOT_REACHED(); +} + +ErrorOr> search_table_in_rsdt(PhysicalAddress rsdt_address, StringView signature) +{ + // FIXME: There's no validation of ACPI tables here. Use the checksum to validate the tables. + VERIFY(signature.length() == 4); + + auto rsdt = TRY(Memory::map_typed(rsdt_address)); + + for (u32 i = 0; i < ((rsdt->h.length - sizeof(Structures::SDTHeader)) / sizeof(u32)); i++) { + if (match_table_signature(PhysicalAddress((PhysicalPtr)rsdt->table_ptrs[i]), signature)) + return PhysicalAddress((PhysicalPtr)rsdt->table_ptrs[i]); + } + return Optional {}; +} + +} diff --git a/Kernel/Firmware/ACPI/StaticParsing.h b/Kernel/Firmware/ACPI/StaticParsing.h new file mode 100644 index 0000000000..fec03ff1f4 --- /dev/null +++ b/Kernel/Firmware/ACPI/StaticParsing.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2023, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include + +namespace Kernel::ACPI::StaticParsing { + +ErrorOr> find_table(PhysicalAddress rsdp, StringView signature); +ErrorOr> search_table_in_xsdt(PhysicalAddress xsdt, StringView signature); +ErrorOr> search_table_in_rsdt(PhysicalAddress rsdt, StringView signature); + +// NOTE: This function is implemented for each CPU architecture in a subdirectory +// under the Kernel/Arch directory. +ErrorOr> find_rsdp_in_platform_specific_memory_locations(); + +}