Serenity Operating System
at master 519 lines 24 kB view raw
1/* 2 * Copyright (c) 2020-2021, Liav A. <liavalb@hotmail.co.il> 3 * Copyright (c) 2020-2021, Andreas Kling <kling@serenityos.org> 4 * Copyright (c) 2022, the SerenityOS developers. 5 * 6 * SPDX-License-Identifier: BSD-2-Clause 7 */ 8 9#include <AK/Format.h> 10#include <AK/Platform.h> 11#include <AK/StringView.h> 12#include <AK/Try.h> 13#include <Kernel/InterruptDisabler.h> 14#if ARCH(X86_64) 15# include <Kernel/Arch/x86_64/IO.h> 16#endif 17#include <Kernel/Bus/PCI/API.h> 18#include <Kernel/Debug.h> 19#include <Kernel/Firmware/ACPI/Parser.h> 20#include <Kernel/Firmware/BIOS.h> 21#include <Kernel/Memory/TypedMapping.h> 22#include <Kernel/Sections.h> 23#include <Kernel/StdLib.h> 24 25namespace Kernel::ACPI { 26 27static Parser* s_acpi_parser; 28 29Parser* Parser::the() 30{ 31 return s_acpi_parser; 32} 33 34void Parser::must_initialize(PhysicalAddress rsdp, PhysicalAddress fadt, u8 irq_number) 35{ 36 VERIFY(!s_acpi_parser); 37 s_acpi_parser = new (nothrow) Parser(rsdp, fadt, irq_number); 38 VERIFY(s_acpi_parser); 39} 40 41UNMAP_AFTER_INIT NonnullLockRefPtr<ACPISysFSComponent> ACPISysFSComponent::create(StringView name, PhysicalAddress paddr, size_t table_size) 42{ 43 // FIXME: Handle allocation failure gracefully 44 auto table_name = KString::must_create(name); 45 return adopt_lock_ref(*new (nothrow) ACPISysFSComponent(move(table_name), paddr, table_size)); 46} 47 48ErrorOr<size_t> ACPISysFSComponent::read_bytes(off_t offset, size_t count, UserOrKernelBuffer& buffer, OpenFileDescription*) const 49{ 50 auto blob = TRY(try_to_generate_buffer()); 51 52 if ((size_t)offset >= blob->size()) 53 return 0; 54 55 ssize_t nread = min(static_cast<off_t>(blob->size() - offset), static_cast<off_t>(count)); 56 TRY(buffer.write(blob->data() + offset, nread)); 57 return nread; 58} 59 60ErrorOr<NonnullOwnPtr<KBuffer>> ACPISysFSComponent::try_to_generate_buffer() const 61{ 62 auto acpi_blob = TRY(Memory::map_typed<u8>((m_paddr), m_length)); 63 return KBuffer::try_create_with_bytes("ACPISysFSComponent: Blob"sv, Span<u8> { acpi_blob.ptr(), m_length }); 64} 65 66UNMAP_AFTER_INIT ACPISysFSComponent::ACPISysFSComponent(NonnullOwnPtr<KString> table_name, PhysicalAddress paddr, size_t table_size) 67 : SysFSComponent() 68 , m_paddr(paddr) 69 , m_length(table_size) 70 , m_table_name(move(table_name)) 71{ 72} 73 74UNMAP_AFTER_INIT void ACPISysFSDirectory::find_tables_and_register_them_as_components() 75{ 76 size_t ssdt_count = 0; 77 MUST(m_child_components.with([&](auto& list) -> ErrorOr<void> { 78 ACPI::Parser::the()->enumerate_static_tables([&](StringView signature, PhysicalAddress p_table, size_t length) { 79 if (signature == "SSDT") { 80 auto component_name = KString::formatted("{:4s}{}", signature.characters_without_null_termination(), ssdt_count).release_value_but_fixme_should_propagate_errors(); 81 list.append(ACPISysFSComponent::create(component_name->view(), p_table, length)); 82 ssdt_count++; 83 return; 84 } 85 list.append(ACPISysFSComponent::create(signature, p_table, length)); 86 }); 87 return {}; 88 })); 89 90 MUST(m_child_components.with([&](auto& list) -> ErrorOr<void> { 91 auto rsdp = Memory::map_typed<Structures::RSDPDescriptor20>(ACPI::Parser::the()->rsdp()).release_value_but_fixme_should_propagate_errors(); 92 list.append(ACPISysFSComponent::create("RSDP"sv, ACPI::Parser::the()->rsdp(), rsdp->base.revision == 0 ? sizeof(Structures::RSDPDescriptor) : rsdp->length)); 93 auto main_system_description_table = Memory::map_typed<Structures::SDTHeader>(ACPI::Parser::the()->main_system_description_table()).release_value_but_fixme_should_propagate_errors(); 94 if (ACPI::Parser::the()->is_xsdt_supported()) { 95 list.append(ACPISysFSComponent::create("XSDT"sv, ACPI::Parser::the()->main_system_description_table(), main_system_description_table->length)); 96 } else { 97 list.append(ACPISysFSComponent::create("RSDT"sv, ACPI::Parser::the()->main_system_description_table(), main_system_description_table->length)); 98 } 99 return {}; 100 })); 101} 102 103UNMAP_AFTER_INIT NonnullLockRefPtr<ACPISysFSDirectory> ACPISysFSDirectory::must_create(FirmwareSysFSDirectory& firmware_directory) 104{ 105 auto acpi_directory = MUST(adopt_nonnull_lock_ref_or_enomem(new (nothrow) ACPISysFSDirectory(firmware_directory))); 106 acpi_directory->find_tables_and_register_them_as_components(); 107 return acpi_directory; 108} 109 110UNMAP_AFTER_INIT ACPISysFSDirectory::ACPISysFSDirectory(FirmwareSysFSDirectory& firmware_directory) 111 : SysFSDirectory(firmware_directory) 112{ 113} 114 115void Parser::enumerate_static_tables(Function<void(StringView, PhysicalAddress, size_t)> callback) 116{ 117 for (auto& p_table : m_sdt_pointers) { 118 auto table = Memory::map_typed<Structures::SDTHeader>(p_table).release_value_but_fixme_should_propagate_errors(); 119 callback({ table->sig, 4 }, p_table, table->length); 120 } 121} 122 123static bool match_table_signature(PhysicalAddress table_header, StringView signature); 124static Optional<PhysicalAddress> search_table_in_xsdt(PhysicalAddress xsdt, StringView signature); 125static Optional<PhysicalAddress> search_table_in_rsdt(PhysicalAddress rsdt, StringView signature); 126static bool validate_table(Structures::SDTHeader const&, size_t length); 127 128UNMAP_AFTER_INIT void Parser::locate_static_data() 129{ 130 locate_main_system_description_table(); 131 initialize_main_system_description_table(); 132 process_fadt_data(); 133 process_dsdt(); 134} 135 136UNMAP_AFTER_INIT Optional<PhysicalAddress> Parser::find_table(StringView signature) 137{ 138 dbgln_if(ACPI_DEBUG, "ACPI: Calling Find Table method!"); 139 for (auto p_sdt : m_sdt_pointers) { 140 auto sdt_or_error = Memory::map_typed<Structures::SDTHeader>(p_sdt); 141 if (sdt_or_error.is_error()) { 142 dbgln_if(ACPI_DEBUG, "ACPI: Failed mapping Table @ {}", p_sdt); 143 continue; 144 } 145 dbgln_if(ACPI_DEBUG, "ACPI: Examining Table @ {}", p_sdt); 146 if (!strncmp(sdt_or_error.value()->sig, signature.characters_without_null_termination(), 4)) { 147 dbgln_if(ACPI_DEBUG, "ACPI: Found Table @ {}", p_sdt); 148 return p_sdt; 149 } 150 } 151 return {}; 152} 153 154bool Parser::handle_irq(RegisterState const&) 155{ 156 TODO(); 157} 158 159UNMAP_AFTER_INIT void Parser::enable_aml_parsing() 160{ 161 // FIXME: When enabled, do other things to "parse AML". 162 m_can_process_bytecode = true; 163} 164 165UNMAP_AFTER_INIT void Parser::process_fadt_data() 166{ 167 dmesgln("ACPI: Initializing Fixed ACPI data"); 168 169 VERIFY(!m_fadt.is_null()); 170 dbgln_if(ACPI_DEBUG, "ACPI: FADT @ {}", m_fadt); 171 172 auto sdt = Memory::map_typed<Structures::FADT>(m_fadt).release_value_but_fixme_should_propagate_errors(); 173 dmesgln("ACPI: Fixed ACPI data, Revision {}, length: {} bytes", (size_t)sdt->h.revision, (size_t)sdt->h.length); 174 m_x86_specific_flags.cmos_rtc_not_present = (sdt->ia_pc_boot_arch_flags & (u8)FADTFlags::IA_PC_Flags::CMOS_RTC_Not_Present); 175 176 // FIXME: QEMU doesn't report that we have an i8042 controller in these flags, even if it should (when FADT revision is 3), 177 // Later on, we need to make sure that we enumerate the ACPI namespace (AML encoded), instead of just using this value. 178 m_x86_specific_flags.keyboard_8042 = (sdt->h.revision <= 3) || (sdt->ia_pc_boot_arch_flags & (u8)FADTFlags::IA_PC_Flags::PS2_8042); 179 180 m_x86_specific_flags.legacy_devices = (sdt->ia_pc_boot_arch_flags & (u8)FADTFlags::IA_PC_Flags::Legacy_Devices); 181 m_x86_specific_flags.msi_not_supported = (sdt->ia_pc_boot_arch_flags & (u8)FADTFlags::IA_PC_Flags::MSI_Not_Supported); 182 m_x86_specific_flags.vga_not_present = (sdt->ia_pc_boot_arch_flags & (u8)FADTFlags::IA_PC_Flags::VGA_Not_Present); 183 184 m_hardware_flags.cpu_software_sleep = (sdt->flags & (u32)FADTFlags::FeatureFlags::CPU_SW_SLP); 185 m_hardware_flags.docking_capability = (sdt->flags & (u32)FADTFlags::FeatureFlags::DCK_CAP); 186 m_hardware_flags.fix_rtc = (sdt->flags & (u32)FADTFlags::FeatureFlags::FIX_RTC); 187 m_hardware_flags.force_apic_cluster_model = (sdt->flags & (u32)FADTFlags::FeatureFlags::FORCE_APIC_CLUSTER_MODEL); 188 m_hardware_flags.force_apic_physical_destination_mode = (sdt->flags & (u32)FADTFlags::FeatureFlags::FORCE_APIC_PHYSICAL_DESTINATION_MODE); 189 m_hardware_flags.hardware_reduced_acpi = (sdt->flags & (u32)FADTFlags::FeatureFlags::HW_REDUCED_ACPI); 190 m_hardware_flags.headless = (sdt->flags & (u32)FADTFlags::FeatureFlags::HEADLESS); 191 m_hardware_flags.low_power_s0_idle_capable = (sdt->flags & (u32)FADTFlags::FeatureFlags::LOW_POWER_S0_IDLE_CAPABLE); 192 m_hardware_flags.multiprocessor_c2 = (sdt->flags & (u32)FADTFlags::FeatureFlags::P_LVL2_UP); 193 m_hardware_flags.pci_express_wake = (sdt->flags & (u32)FADTFlags::FeatureFlags::PCI_EXP_WAK); 194 m_hardware_flags.power_button = (sdt->flags & (u32)FADTFlags::FeatureFlags::PWR_BUTTON); 195 m_hardware_flags.processor_c1 = (sdt->flags & (u32)FADTFlags::FeatureFlags::PROC_C1); 196 m_hardware_flags.remote_power_on_capable = (sdt->flags & (u32)FADTFlags::FeatureFlags::REMOTE_POWER_ON_CAPABLE); 197 m_hardware_flags.reset_register_supported = (sdt->flags & (u32)FADTFlags::FeatureFlags::RESET_REG_SUPPORTED); 198 m_hardware_flags.rtc_s4 = (sdt->flags & (u32)FADTFlags::FeatureFlags::RTC_s4); 199 m_hardware_flags.s4_rtc_status_valid = (sdt->flags & (u32)FADTFlags::FeatureFlags::S4_RTC_STS_VALID); 200 m_hardware_flags.sealed_case = (sdt->flags & (u32)FADTFlags::FeatureFlags::SEALED_CASE); 201 m_hardware_flags.sleep_button = (sdt->flags & (u32)FADTFlags::FeatureFlags::SLP_BUTTON); 202 m_hardware_flags.timer_value_extension = (sdt->flags & (u32)FADTFlags::FeatureFlags::TMR_VAL_EXT); 203 m_hardware_flags.use_platform_clock = (sdt->flags & (u32)FADTFlags::FeatureFlags::USE_PLATFORM_CLOCK); 204 m_hardware_flags.wbinvd = (sdt->flags & (u32)FADTFlags::FeatureFlags::WBINVD); 205 m_hardware_flags.wbinvd_flush = (sdt->flags & (u32)FADTFlags::FeatureFlags::WBINVD_FLUSH); 206} 207 208UNMAP_AFTER_INIT void Parser::process_dsdt() 209{ 210 auto sdt = Memory::map_typed<Structures::FADT>(m_fadt).release_value_but_fixme_should_propagate_errors(); 211 212 // Add DSDT-pointer to expose the full table in /sys/firmware/acpi/ 213 m_sdt_pointers.append(PhysicalAddress(sdt->dsdt_ptr)); 214 215 auto dsdt_or_error = Memory::map_typed<Structures::DSDT>(PhysicalAddress(sdt->dsdt_ptr)); 216 if (dsdt_or_error.is_error()) { 217 dmesgln("ACPI: DSDT is unmappable"); 218 return; 219 } 220 dmesgln("ACPI: Using DSDT @ {} with {} bytes", PhysicalAddress(sdt->dsdt_ptr), dsdt_or_error.value()->h.length); 221} 222 223bool Parser::can_reboot() 224{ 225 auto fadt_or_error = Memory::map_typed<Structures::FADT>(m_fadt); 226 if (fadt_or_error.is_error()) 227 return false; 228 if (fadt_or_error.value()->h.revision < 2) 229 return false; 230 return m_hardware_flags.reset_register_supported; 231} 232 233void Parser::access_generic_address(Structures::GenericAddressStructure const& structure, u32 value) 234{ 235 switch ((GenericAddressStructure::AddressSpace)structure.address_space) { 236 case GenericAddressStructure::AddressSpace::SystemIO: { 237#if ARCH(X86_64) 238 IOAddress address(structure.address); 239 dbgln("ACPI: Sending value {:x} to {}", value, address); 240 switch (structure.access_size) { 241 case (u8)GenericAddressStructure::AccessSize::QWord: { 242 dbgln("Trying to send QWord to IO port"); 243 VERIFY_NOT_REACHED(); 244 break; 245 } 246 case (u8)GenericAddressStructure::AccessSize::Undefined: { 247 dbgln("ACPI Warning: Unknown access size {}", structure.access_size); 248 VERIFY(structure.bit_width != (u8)GenericAddressStructure::BitWidth::QWord); 249 VERIFY(structure.bit_width != (u8)GenericAddressStructure::BitWidth::Undefined); 250 dbgln("ACPI: Bit Width - {} bits", structure.bit_width); 251 address.out(value, structure.bit_width); 252 break; 253 } 254 default: 255 address.out(value, (8 << (structure.access_size - 1))); 256 break; 257 } 258#endif 259 return; 260 } 261 case GenericAddressStructure::AddressSpace::SystemMemory: { 262 dbgln("ACPI: Sending value {:x} to {}", value, PhysicalAddress(structure.address)); 263 switch ((GenericAddressStructure::AccessSize)structure.access_size) { 264 case GenericAddressStructure::AccessSize::Byte: 265 *Memory::map_typed<u8>(PhysicalAddress(structure.address)).release_value_but_fixme_should_propagate_errors() = value; 266 break; 267 case GenericAddressStructure::AccessSize::Word: 268 *Memory::map_typed<u16>(PhysicalAddress(structure.address)).release_value_but_fixme_should_propagate_errors() = value; 269 break; 270 case GenericAddressStructure::AccessSize::DWord: 271 *Memory::map_typed<u32>(PhysicalAddress(structure.address)).release_value_but_fixme_should_propagate_errors() = value; 272 break; 273 case GenericAddressStructure::AccessSize::QWord: { 274 *Memory::map_typed<u64>(PhysicalAddress(structure.address)).release_value_but_fixme_should_propagate_errors() = value; 275 break; 276 } 277 default: 278 VERIFY_NOT_REACHED(); 279 } 280 return; 281 } 282 case GenericAddressStructure::AddressSpace::PCIConfigurationSpace: { 283 // According to https://uefi.org/specs/ACPI/6.4/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#address-space-format, 284 // PCI addresses must be confined to devices on Segment group 0, bus 0. 285 auto pci_address = PCI::Address(0, 0, ((structure.address >> 24) & 0xFF), ((structure.address >> 16) & 0xFF)); 286 dbgln("ACPI: Sending value {:x} to {}", value, pci_address); 287 u32 offset_in_pci_address = structure.address & 0xFFFF; 288 if (structure.access_size == (u8)GenericAddressStructure::AccessSize::QWord) { 289 dbgln("Trying to send QWord to PCI configuration space"); 290 VERIFY_NOT_REACHED(); 291 } 292 VERIFY(structure.access_size != (u8)GenericAddressStructure::AccessSize::Undefined); 293 auto& pci_device_identifier = PCI::get_device_identifier(pci_address); 294 PCI::raw_access(pci_device_identifier, offset_in_pci_address, (1 << (structure.access_size - 1)), value); 295 return; 296 } 297 default: 298 VERIFY_NOT_REACHED(); 299 } 300 VERIFY_NOT_REACHED(); 301} 302 303bool Parser::validate_reset_register(Memory::TypedMapping<Structures::FADT> const& fadt) 304{ 305 // According to https://uefi.org/specs/ACPI/6.4/04_ACPI_Hardware_Specification/ACPI_Hardware_Specification.html#reset-register, 306 // the reset register can only be located in I/O bus, PCI bus or memory-mapped. 307 return (fadt->reset_reg.address_space == (u8)GenericAddressStructure::AddressSpace::PCIConfigurationSpace || fadt->reset_reg.address_space == (u8)GenericAddressStructure::AddressSpace::SystemMemory || fadt->reset_reg.address_space == (u8)GenericAddressStructure::AddressSpace::SystemIO); 308} 309 310void Parser::try_acpi_reboot() 311{ 312 InterruptDisabler disabler; 313 if (!can_reboot()) { 314 dmesgln("ACPI: Reboot not supported!"); 315 return; 316 } 317 dbgln_if(ACPI_DEBUG, "ACPI: Rebooting, probing FADT ({})", m_fadt); 318 319 auto fadt_or_error = Memory::map_typed<Structures::FADT>(m_fadt); 320 if (fadt_or_error.is_error()) { 321 dmesgln("ACPI: Failed probing FADT {}", fadt_or_error.error()); 322 return; 323 } 324 auto fadt = fadt_or_error.release_value(); 325 VERIFY(validate_reset_register(fadt)); 326 access_generic_address(fadt->reset_reg, fadt->reset_value); 327 Processor::halt(); 328} 329 330void Parser::try_acpi_shutdown() 331{ 332 dmesgln("ACPI: Shutdown is not supported with the current configuration, aborting!"); 333} 334 335size_t Parser::get_table_size(PhysicalAddress table_header) 336{ 337 InterruptDisabler disabler; 338 dbgln_if(ACPI_DEBUG, "ACPI: Checking SDT Length"); 339 return Memory::map_typed<Structures::SDTHeader>(table_header).release_value_but_fixme_should_propagate_errors()->length; 340} 341 342u8 Parser::get_table_revision(PhysicalAddress table_header) 343{ 344 InterruptDisabler disabler; 345 dbgln_if(ACPI_DEBUG, "ACPI: Checking SDT Revision"); 346 return Memory::map_typed<Structures::SDTHeader>(table_header).release_value_but_fixme_should_propagate_errors()->revision; 347} 348 349UNMAP_AFTER_INIT void Parser::initialize_main_system_description_table() 350{ 351 dbgln_if(ACPI_DEBUG, "ACPI: Checking Main SDT Length to choose the correct mapping size"); 352 VERIFY(!m_main_system_description_table.is_null()); 353 auto length = get_table_size(m_main_system_description_table); 354 auto revision = get_table_revision(m_main_system_description_table); 355 356 auto sdt = Memory::map_typed<Structures::SDTHeader>(m_main_system_description_table, length).release_value_but_fixme_should_propagate_errors(); 357 358 dmesgln("ACPI: Main Description Table valid? {}", validate_table(*sdt, length)); 359 360 if (m_xsdt_supported) { 361 auto& xsdt = (Structures::XSDT const&)*sdt; 362 dmesgln("ACPI: Using XSDT, enumerating tables @ {}", m_main_system_description_table); 363 dmesgln("ACPI: XSDT revision {}, total length: {}", revision, length); 364 dbgln_if(ACPI_DEBUG, "ACPI: XSDT pointer @ {}", VirtualAddress { &xsdt }); 365 for (u32 i = 0; i < ((length - sizeof(Structures::SDTHeader)) / sizeof(u64)); i++) { 366 dbgln_if(ACPI_DEBUG, "ACPI: Found new table [{0}], @ V{1:p} - P{1:p}", i, &xsdt.table_ptrs[i]); 367 m_sdt_pointers.append(PhysicalAddress(xsdt.table_ptrs[i])); 368 } 369 } else { 370 auto& rsdt = (Structures::RSDT const&)*sdt; 371 dmesgln("ACPI: Using RSDT, enumerating tables @ {}", m_main_system_description_table); 372 dmesgln("ACPI: RSDT revision {}, total length: {}", revision, length); 373 dbgln_if(ACPI_DEBUG, "ACPI: RSDT pointer @ V{}", &rsdt); 374 for (u32 i = 0; i < ((length - sizeof(Structures::SDTHeader)) / sizeof(u32)); i++) { 375 dbgln_if(ACPI_DEBUG, "ACPI: Found new table [{0}], @ V{1:p} - P{1:p}", i, &rsdt.table_ptrs[i]); 376 m_sdt_pointers.append(PhysicalAddress(rsdt.table_ptrs[i])); 377 } 378 } 379} 380 381UNMAP_AFTER_INIT void Parser::locate_main_system_description_table() 382{ 383 auto rsdp = Memory::map_typed<Structures::RSDPDescriptor20>(m_rsdp).release_value_but_fixme_should_propagate_errors(); 384 if (rsdp->base.revision == 0) { 385 m_xsdt_supported = false; 386 } else if (rsdp->base.revision >= 2) { 387 if (rsdp->xsdt_ptr != (u64) nullptr) { 388 m_xsdt_supported = true; 389 } else { 390 m_xsdt_supported = false; 391 } 392 } 393 if (!m_xsdt_supported) { 394 m_main_system_description_table = PhysicalAddress(rsdp->base.rsdt_ptr); 395 } else { 396 m_main_system_description_table = PhysicalAddress(rsdp->xsdt_ptr); 397 } 398} 399 400UNMAP_AFTER_INIT Parser::Parser(PhysicalAddress rsdp, PhysicalAddress fadt, u8 irq_number) 401 : IRQHandler(irq_number) 402 , m_rsdp(rsdp) 403 , m_fadt(fadt) 404{ 405 dmesgln("ACPI: Using RSDP @ {}", rsdp); 406 locate_static_data(); 407} 408 409static bool validate_table(Structures::SDTHeader const& v_header, size_t length) 410{ 411 u8 checksum = 0; 412 auto* sdt = (u8 const*)&v_header; 413 for (size_t i = 0; i < length; i++) 414 checksum += sdt[i]; 415 if (checksum == 0) 416 return true; 417 return false; 418} 419 420// https://uefi.org/specs/ACPI/6.4/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#finding-the-rsdp-on-ia-pc-systems 421UNMAP_AFTER_INIT Optional<PhysicalAddress> StaticParsing::find_rsdp() 422{ 423 constexpr auto signature = "RSD PTR "sv; 424 auto ebda_or_error = map_ebda(); 425 if (!ebda_or_error.is_error()) { 426 auto rsdp = ebda_or_error.value().find_chunk_starting_with(signature, 16); 427 if (rsdp.has_value()) 428 return rsdp; 429 } 430 auto bios_or_error = map_bios(); 431 if (!bios_or_error.is_error()) { 432 auto rsdp = bios_or_error.value().find_chunk_starting_with(signature, 16); 433 if (rsdp.has_value()) 434 return rsdp; 435 } 436 437 // On some systems the RSDP may be located in ACPI NVS or reclaimable memory regions 438 Optional<PhysicalAddress> rsdp; 439 MM.for_each_physical_memory_range([&](auto& memory_range) { 440 if (!(memory_range.type == Memory::PhysicalMemoryRangeType::ACPI_NVS || memory_range.type == Memory::PhysicalMemoryRangeType::ACPI_Reclaimable)) 441 return IterationDecision::Continue; 442 443 Memory::MappedROM mapping; 444 auto region_size_or_error = Memory::page_round_up(memory_range.length); 445 if (region_size_or_error.is_error()) 446 return IterationDecision::Continue; 447 auto region_or_error = MM.allocate_kernel_region(memory_range.start, region_size_or_error.value(), {}, Memory::Region::Access::Read); 448 if (region_or_error.is_error()) 449 return IterationDecision::Continue; 450 mapping.region = region_or_error.release_value(); 451 mapping.offset = memory_range.start.offset_in_page(); 452 mapping.size = memory_range.length; 453 mapping.paddr = memory_range.start; 454 455 rsdp = mapping.find_chunk_starting_with(signature, 16); 456 if (rsdp.has_value()) 457 return IterationDecision::Break; 458 459 return IterationDecision::Continue; 460 }); 461 return rsdp; 462} 463 464UNMAP_AFTER_INIT Optional<PhysicalAddress> StaticParsing::find_table(PhysicalAddress rsdp_address, StringView signature) 465{ 466 // FIXME: There's no validation of ACPI tables here. Use the checksum to validate the tables. 467 VERIFY(signature.length() == 4); 468 469 auto rsdp = Memory::map_typed<Structures::RSDPDescriptor20>(rsdp_address).release_value_but_fixme_should_propagate_errors(); 470 471 if (rsdp->base.revision == 0) 472 return search_table_in_rsdt(PhysicalAddress(rsdp->base.rsdt_ptr), signature); 473 474 if (rsdp->base.revision >= 2) { 475 if (rsdp->xsdt_ptr) 476 return search_table_in_xsdt(PhysicalAddress(rsdp->xsdt_ptr), signature); 477 return search_table_in_rsdt(PhysicalAddress(rsdp->base.rsdt_ptr), signature); 478 } 479 VERIFY_NOT_REACHED(); 480} 481 482UNMAP_AFTER_INIT static Optional<PhysicalAddress> search_table_in_xsdt(PhysicalAddress xsdt_address, StringView signature) 483{ 484 // FIXME: There's no validation of ACPI tables here. Use the checksum to validate the tables. 485 VERIFY(signature.length() == 4); 486 487 auto xsdt = Memory::map_typed<Structures::XSDT>(xsdt_address).release_value_but_fixme_should_propagate_errors(); 488 489 for (size_t i = 0; i < ((xsdt->h.length - sizeof(Structures::SDTHeader)) / sizeof(u64)); ++i) { 490 if (match_table_signature(PhysicalAddress((PhysicalPtr)xsdt->table_ptrs[i]), signature)) 491 return PhysicalAddress((PhysicalPtr)xsdt->table_ptrs[i]); 492 } 493 return {}; 494} 495 496static bool match_table_signature(PhysicalAddress table_header, StringView signature) 497{ 498 // FIXME: There's no validation of ACPI tables here. Use the checksum to validate the tables. 499 VERIFY(signature.length() == 4); 500 501 auto table = Memory::map_typed<Structures::RSDT>(table_header).release_value_but_fixme_should_propagate_errors(); 502 return !strncmp(table->h.sig, signature.characters_without_null_termination(), 4); 503} 504 505UNMAP_AFTER_INIT static Optional<PhysicalAddress> search_table_in_rsdt(PhysicalAddress rsdt_address, StringView signature) 506{ 507 // FIXME: There's no validation of ACPI tables here. Use the checksum to validate the tables. 508 VERIFY(signature.length() == 4); 509 510 auto rsdt = Memory::map_typed<Structures::RSDT>(rsdt_address).release_value_but_fixme_should_propagate_errors(); 511 512 for (u32 i = 0; i < ((rsdt->h.length - sizeof(Structures::SDTHeader)) / sizeof(u32)); i++) { 513 if (match_table_signature(PhysicalAddress((PhysicalPtr)rsdt->table_ptrs[i]), signature)) 514 return PhysicalAddress((PhysicalPtr)rsdt->table_ptrs[i]); 515 } 516 return {}; 517} 518 519}