Serenity Operating System
at hosted 455 lines 19 kB view raw
1/* 2 * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il> 3 * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright notice, this 10 * list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include <AK/StringView.h> 29#include <Kernel/ACPI/Parser.h> 30#include <Kernel/PCI/Access.h> 31#include <Kernel/VM/MemoryManager.h> 32#include <Kernel/VM/TypedMapping.h> 33#include <LibBareMetal/IO.h> 34#include <LibBareMetal/StdLib.h> 35 36namespace Kernel { 37namespace ACPI { 38 39static Parser* s_acpi_parser; 40 41Parser* Parser::the() 42{ 43 return s_acpi_parser; 44} 45 46void Parser::set_the(Parser& parser) 47{ 48 ASSERT(!s_acpi_parser); 49 s_acpi_parser = &parser; 50} 51 52static bool match_table_signature(PhysicalAddress table_header, const StringView& signature); 53static PhysicalAddress search_table_in_xsdt(PhysicalAddress xsdt, const StringView& signature); 54static PhysicalAddress search_table_in_rsdt(PhysicalAddress rsdt, const StringView& signature); 55static bool validate_table(const Structures::SDTHeader&, size_t length); 56 57void Parser::locate_static_data() 58{ 59 locate_main_system_description_table(); 60 initialize_main_system_description_table(); 61 init_fadt(); 62 init_facs(); 63} 64 65PhysicalAddress Parser::find_table(const StringView& signature) 66{ 67#ifdef ACPI_DEBUG 68 dbg() << "ACPI: Calling Find Table method!"; 69#endif 70 for (auto p_sdt : m_sdt_pointers) { 71 auto sdt = map_typed<Structures::SDTHeader>(p_sdt); 72#ifdef ACPI_DEBUG 73 dbg() << "ACPI: Examining Table @ P " << p_sdt; 74#endif 75 if (!strncmp(sdt->sig, signature.characters_without_null_termination(), 4)) { 76#ifdef ACPI_DEBUG 77 dbg() << "ACPI: Found Table @ P " << p_sdt; 78#endif 79 return p_sdt; 80 } 81 } 82 return {}; 83} 84 85void Parser::init_facs() 86{ 87 m_facs = find_table("FACS"); 88} 89 90void Parser::init_fadt() 91{ 92 klog() << "ACPI: Initializing Fixed ACPI data"; 93 klog() << "ACPI: Searching for the Fixed ACPI Data Table"; 94 95 m_fadt = find_table("FACP"); 96 ASSERT(!m_fadt.is_null()); 97 98 auto sdt = map_typed<Structures::FADT>(m_fadt); 99 100#ifdef ACPI_DEBUG 101 dbg() << "ACPI: FADT @ V " << sdt << ", P " << (void*)m_fadt.as_ptr(); 102#endif 103 klog() << "ACPI: Fixed ACPI data, Revision " << sdt->h.revision << ", Length " << sdt->h.length << " bytes"; 104 klog() << "ACPI: DSDT " << PhysicalAddress(sdt->dsdt_ptr); 105 m_x86_specific_flags.cmos_rtc_not_present = (sdt->ia_pc_boot_arch_flags & (u8)FADTFlags::IA_PC_Flags::CMOS_RTC_Not_Present); 106 m_x86_specific_flags.keyboard_8042 = (sdt->ia_pc_boot_arch_flags & (u8)FADTFlags::IA_PC_Flags::PS2_8042); 107 m_x86_specific_flags.legacy_devices = (sdt->ia_pc_boot_arch_flags & (u8)FADTFlags::IA_PC_Flags::Legacy_Devices); 108 m_x86_specific_flags.msi_not_supported = (sdt->ia_pc_boot_arch_flags & (u8)FADTFlags::IA_PC_Flags::MSI_Not_Supported); 109 m_x86_specific_flags.vga_not_present = (sdt->ia_pc_boot_arch_flags & (u8)FADTFlags::IA_PC_Flags::VGA_Not_Present); 110 111 m_hardware_flags.cpu_software_sleep = (sdt->flags & (u32)FADTFlags::FeatureFlags::CPU_SW_SLP); 112 m_hardware_flags.docking_capability = (sdt->flags & (u32)FADTFlags::FeatureFlags::DCK_CAP); 113 m_hardware_flags.fix_rtc = (sdt->flags & (u32)FADTFlags::FeatureFlags::FIX_RTC); 114 m_hardware_flags.force_apic_cluster_model = (sdt->flags & (u32)FADTFlags::FeatureFlags::FORCE_APIC_CLUSTER_MODEL); 115 m_hardware_flags.force_apic_physical_destination_mode = (sdt->flags & (u32)FADTFlags::FeatureFlags::FORCE_APIC_PHYSICAL_DESTINATION_MODE); 116 m_hardware_flags.hardware_reduced_acpi = (sdt->flags & (u32)FADTFlags::FeatureFlags::HW_REDUCED_ACPI); 117 m_hardware_flags.headless = (sdt->flags & (u32)FADTFlags::FeatureFlags::HEADLESS); 118 m_hardware_flags.low_power_s0_idle_capable = (sdt->flags & (u32)FADTFlags::FeatureFlags::LOW_POWER_S0_IDLE_CAPABLE); 119 m_hardware_flags.multiprocessor_c2 = (sdt->flags & (u32)FADTFlags::FeatureFlags::P_LVL2_UP); 120 m_hardware_flags.pci_express_wake = (sdt->flags & (u32)FADTFlags::FeatureFlags::PCI_EXP_WAK); 121 m_hardware_flags.power_button = (sdt->flags & (u32)FADTFlags::FeatureFlags::PWR_BUTTON); 122 m_hardware_flags.processor_c1 = (sdt->flags & (u32)FADTFlags::FeatureFlags::PROC_C1); 123 m_hardware_flags.remote_power_on_capable = (sdt->flags & (u32)FADTFlags::FeatureFlags::REMOTE_POWER_ON_CAPABLE); 124 m_hardware_flags.reset_register_supported = (sdt->flags & (u32)FADTFlags::FeatureFlags::RESET_REG_SUPPORTED); 125 m_hardware_flags.rtc_s4 = (sdt->flags & (u32)FADTFlags::FeatureFlags::RTC_s4); 126 m_hardware_flags.s4_rtc_status_valid = (sdt->flags & (u32)FADTFlags::FeatureFlags::S4_RTC_STS_VALID); 127 m_hardware_flags.sealed_case = (sdt->flags & (u32)FADTFlags::FeatureFlags::SEALED_CASE); 128 m_hardware_flags.sleep_button = (sdt->flags & (u32)FADTFlags::FeatureFlags::SLP_BUTTON); 129 m_hardware_flags.timer_value_extension = (sdt->flags & (u32)FADTFlags::FeatureFlags::TMR_VAL_EXT); 130 m_hardware_flags.use_platform_clock = (sdt->flags & (u32)FADTFlags::FeatureFlags::USE_PLATFORM_CLOCK); 131 m_hardware_flags.wbinvd = (sdt->flags & (u32)FADTFlags::FeatureFlags::WBINVD); 132 m_hardware_flags.wbinvd_flush = (sdt->flags & (u32)FADTFlags::FeatureFlags::WBINVD_FLUSH); 133} 134 135bool Parser::can_reboot() 136{ 137 auto fadt = map_typed<Structures::FADT>(m_fadt); 138 if (fadt->h.revision < 2) 139 return false; 140 return m_hardware_flags.reset_register_supported; 141} 142 143void Parser::access_generic_address(const Structures::GenericAddressStructure& structure, u32 value) 144{ 145 switch ((GenericAddressStructure::AddressSpace)structure.address_space) { 146 case GenericAddressStructure::AddressSpace::SystemIO: { 147 IOAddress address(structure.address); 148 dbg() << "ACPI: Sending value 0x" << String::format("%x", value) << " to " << address; 149 switch (structure.access_size) { 150 case (u8)GenericAddressStructure::AccessSize::QWord: { 151 dbg() << "Trying to send QWord to IO port"; 152 ASSERT_NOT_REACHED(); 153 break; 154 } 155 case (u8)GenericAddressStructure::AccessSize::Undefined: { 156 dbg() << "ACPI Warning: Unknown access size " << structure.access_size; 157 ASSERT(structure.bit_width != (u8)GenericAddressStructure::BitWidth::QWord); 158 ASSERT(structure.bit_width != (u8)GenericAddressStructure::BitWidth::Undefined); 159 dbg() << "ACPI: Bit Width - " << structure.bit_width << " bits"; 160 address.out(value, structure.bit_width); 161 break; 162 } 163 default: 164 address.out(value, (8 << (structure.access_size - 1))); 165 break; 166 } 167 return; 168 } 169 case GenericAddressStructure::AddressSpace::SystemMemory: { 170 dbg() << "ACPI: Sending value 0x" << String::format("%x", value) << " to " << PhysicalAddress(structure.address); 171 switch ((GenericAddressStructure::AccessSize)structure.access_size) { 172 case GenericAddressStructure::AccessSize::Byte: 173 *map_typed<u8>(PhysicalAddress(structure.address)) = value; 174 break; 175 case GenericAddressStructure::AccessSize::Word: 176 *map_typed<u16>(PhysicalAddress(structure.address)) = value; 177 break; 178 case GenericAddressStructure::AccessSize::DWord: 179 *map_typed<u32>(PhysicalAddress(structure.address)) = value; 180 break; 181 case GenericAddressStructure::AccessSize::QWord: { 182 *map_typed<u64>(PhysicalAddress(structure.address)) = value; 183 break; 184 } 185 default: 186 ASSERT_NOT_REACHED(); 187 } 188 return; 189 } 190 case GenericAddressStructure::AddressSpace::PCIConfigurationSpace: { 191 // According to the ACPI specification 6.2, page 168, PCI addresses must be confined to devices on Segment group 0, bus 0. 192 auto pci_address = PCI::Address(0, 0, ((structure.address >> 24) & 0xFF), ((structure.address >> 16) & 0xFF)); 193 dbg() << "ACPI: Sending value 0x" << String::format("%x", value) << " to " << pci_address; 194 u32 offset_in_pci_address = structure.address & 0xFFFF; 195 if (structure.access_size == (u8)GenericAddressStructure::AccessSize::QWord) { 196 dbg() << "Trying to send QWord to PCI configuration space"; 197 ASSERT_NOT_REACHED(); 198 } 199 ASSERT(structure.access_size != (u8)GenericAddressStructure::AccessSize::Undefined); 200 PCI::raw_access(pci_address, offset_in_pci_address, (1 << (structure.access_size - 1)), value); 201 return; 202 } 203 default: 204 ASSERT_NOT_REACHED(); 205 } 206 ASSERT_NOT_REACHED(); 207} 208 209bool Parser::validate_reset_register() 210{ 211 // According to the ACPI spec 6.2, page 152, The reset register can only be located in I/O bus, PCI bus or memory-mapped. 212 auto fadt = map_typed<Structures::FADT>(m_fadt); 213 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); 214} 215 216void Parser::try_acpi_reboot() 217{ 218 InterruptDisabler disabler; 219 if (!can_reboot()) { 220 klog() << "ACPI: Reboot, Not supported!"; 221 return; 222 } 223#ifdef ACPI_DEBUG 224 dbg() << "ACPI: Rebooting, Probing FADT (" << m_fadt << ")"; 225#endif 226 227 auto fadt = map_typed<Structures::FADT>(m_fadt); 228 ASSERT(validate_reset_register()); 229 access_generic_address(fadt->reset_reg, fadt->reset_value); 230 hang(); 231} 232 233void Parser::try_acpi_shutdown() 234{ 235 klog() << "ACPI: Shutdown is not supported with the current configuration, Abort!"; 236} 237 238size_t Parser::get_table_size(PhysicalAddress table_header) 239{ 240 InterruptDisabler disabler; 241#ifdef ACPI_DEBUG 242 dbg() << "ACPI: Checking SDT Length"; 243#endif 244 return map_typed<Structures::SDTHeader>(table_header)->length; 245} 246 247u8 Parser::get_table_revision(PhysicalAddress table_header) 248{ 249 InterruptDisabler disabler; 250#ifdef ACPI_DEBUG 251 dbg() << "ACPI: Checking SDT Revision"; 252#endif 253 return map_typed<Structures::SDTHeader>(table_header)->revision; 254} 255 256void Parser::initialize_main_system_description_table() 257{ 258#ifdef ACPI_DEBUG 259 dbg() << "ACPI: Checking Main SDT Length to choose the correct mapping size"; 260#endif 261 ASSERT(!m_main_system_description_table.is_null()); 262 auto length = get_table_size(m_main_system_description_table); 263 auto revision = get_table_revision(m_main_system_description_table); 264 265 auto sdt = map_typed<Structures::SDTHeader>(m_main_system_description_table, length); 266 267 klog() << "ACPI: Main Description Table valid? " << validate_table(*sdt, length); 268 269 if (m_xsdt_supported) { 270 auto& xsdt = (const Structures::XSDT&)*sdt; 271 klog() << "ACPI: Using XSDT, Enumerating tables @ " << m_main_system_description_table; 272 klog() << "ACPI: XSDT Revision " << revision << ", Total length - " << length; 273#ifdef ACPI_DEBUG 274 dbg() << "ACPI: XSDT pointer @ V " << xsdt; 275#endif 276 for (u32 i = 0; i < ((length - sizeof(Structures::SDTHeader)) / sizeof(u64)); i++) { 277#ifdef ACPI_DEBUG 278 dbg() << "ACPI: Found new table [" << i << "], @ V 0x" << String::format("%x", &xsdt.table_ptrs[i]) << " - P 0x" << String::format("%x", xsdt.table_ptrs[i]); 279#endif 280 m_sdt_pointers.append(PhysicalAddress(xsdt.table_ptrs[i])); 281 } 282 } else { 283 auto& rsdt = (const Structures::RSDT&)*sdt; 284 klog() << "ACPI: Using RSDT, Enumerating tables @ " << m_main_system_description_table; 285 klog() << "ACPI: RSDT Revision " << revision << ", Total length - " << length; 286#ifdef ACPI_DEBUG 287 dbg() << "ACPI: RSDT pointer @ V " << rsdt; 288#endif 289 for (u32 i = 0; i < ((length - sizeof(Structures::SDTHeader)) / sizeof(u32)); i++) { 290#ifdef ACPI_DEBUG 291 dbg() << "ACPI: Found new table [" << i << "], @ V 0x" << String::format("%x", &rsdt.table_ptrs[i]) << " - P 0x" << String::format("%x", rsdt.table_ptrs[i]); 292#endif 293 m_sdt_pointers.append(PhysicalAddress(rsdt.table_ptrs[i])); 294 } 295 } 296} 297 298void Parser::locate_main_system_description_table() 299{ 300 auto rsdp = map_typed<Structures::RSDPDescriptor20>(m_rsdp); 301 if (rsdp->base.revision == 0) { 302 m_xsdt_supported = false; 303 } else if (rsdp->base.revision >= 2) { 304 if (rsdp->xsdt_ptr != (u64) nullptr) { 305 m_xsdt_supported = true; 306 } else { 307 m_xsdt_supported = false; 308 } 309 } 310 if (!m_xsdt_supported) { 311 m_main_system_description_table = PhysicalAddress(rsdp->base.rsdt_ptr); 312 } else { 313 m_main_system_description_table = PhysicalAddress(rsdp->xsdt_ptr); 314 } 315} 316 317Parser::Parser(PhysicalAddress rsdp) 318 : m_rsdp(rsdp) 319{ 320 klog() << "ACPI: Using RSDP @ " << rsdp; 321 locate_static_data(); 322} 323 324static PhysicalAddress find_rsdp_in_ebda(u16 ebda_segment) 325{ 326 auto rsdp_region = MM.allocate_kernel_region(PhysicalAddress(page_base_of((u32)(ebda_segment << 4))), PAGE_ROUND_UP(1024), "ACPI Static Parser RSDP Finding #1", Region::Access::Read, false, true); 327 char* p_rsdp_str = (char*)(PhysicalAddress(ebda_segment << 4).as_ptr()); 328 for (char* rsdp_str = (char*)rsdp_region->vaddr().offset(offset_in_page((u32)(ebda_segment << 4))).as_ptr(); rsdp_str < (char*)(rsdp_region->vaddr().offset(offset_in_page((u32)(ebda_segment << 4))).get() + 1024); rsdp_str += 16) { 329#ifdef ACPI_DEBUG 330 dbg() << "ACPI: Looking for RSDP in EBDA @ V " << (void*)rsdp_str << ", P " << (void*)p_rsdp_str; 331#endif 332 if (!strncmp("RSD PTR ", rsdp_str, strlen("RSD PTR "))) 333 return PhysicalAddress((FlatPtr)p_rsdp_str); 334 p_rsdp_str += 16; 335 } 336 return {}; 337} 338 339static PhysicalAddress find_rsdp_in_bios_area() 340{ 341 auto rsdp_region = MM.allocate_kernel_region(PhysicalAddress(0xE0000), PAGE_ROUND_UP(0xFFFFF - 0xE0000), "ACPI Static Parser RSDP Finding #2", Region::Access::Read, false, true); 342 char* p_rsdp_str = (char*)(PhysicalAddress(0xE0000).as_ptr()); 343 for (char* rsdp_str = (char*)rsdp_region->vaddr().offset(offset_in_page((u32)(0xE0000))).as_ptr(); rsdp_str < (char*)(rsdp_region->vaddr().offset(offset_in_page((u32)(0xE0000))).get() + (0xFFFFF - 0xE0000)); rsdp_str += 16) { 344#ifdef ACPI_DEBUG 345 dbg() << "ACPI: Looking for RSDP in BIOS ROM area @ V " << (void*)rsdp_str << ", P " << (void*)p_rsdp_str; 346#endif 347 if (!strncmp("RSD PTR ", rsdp_str, strlen("RSD PTR "))) 348 return PhysicalAddress((FlatPtr)p_rsdp_str); 349 p_rsdp_str += 16; 350 } 351 return {}; 352} 353 354static bool validate_table(const Structures::SDTHeader& v_header, size_t length) 355{ 356 u8 checksum = 0; 357 auto* sdt = (const u8*)&v_header; 358 for (size_t i = 0; i < length; i++) 359 checksum += sdt[i]; 360 if (checksum == 0) 361 return true; 362 return false; 363} 364 365PhysicalAddress StaticParsing::find_rsdp() 366{ 367 auto ebda_seg_ptr = map_typed<u16>(PhysicalAddress(0x40e)); 368 klog() << "ACPI: Probing EBDA, Segment 0x" << String::format("%x", *ebda_seg_ptr); 369 auto rsdp = find_rsdp_in_ebda(*ebda_seg_ptr); 370 if (!rsdp.is_null()) 371 return rsdp; 372 return find_rsdp_in_bios_area(); 373} 374 375PhysicalAddress StaticParsing::find_table(PhysicalAddress rsdp_address, const StringView& signature) 376{ 377 // FIXME: There's no validation of ACPI tables here. Use the checksum to validate the tables. 378 // FIXME: Don't blindly use PAGE_SIZE here, but probe the actual length. 379 ASSERT(signature.length() == 4); 380 381 auto rsdp = map_typed<Structures::RSDPDescriptor20>(rsdp_address); 382 383 if (rsdp->base.revision == 0) 384 return search_table_in_rsdt(PhysicalAddress(rsdp->base.rsdt_ptr), signature); 385 386 if (rsdp->base.revision >= 2) { 387 if (rsdp->xsdt_ptr) 388 return search_table_in_xsdt(PhysicalAddress(rsdp->xsdt_ptr), signature); 389 return search_table_in_rsdt(PhysicalAddress(rsdp->base.rsdt_ptr), signature); 390 } 391 ASSERT_NOT_REACHED(); 392} 393 394static PhysicalAddress search_table_in_xsdt(PhysicalAddress xsdt_address, const StringView& signature) 395{ 396 // FIXME: There's no validation of ACPI tables here. Use the checksum to validate the tables. 397 // FIXME: Don't blindly use PAGE_SIZE here, but probe the actual length. 398 ASSERT(signature.length() == 4); 399 400 auto xsdt = map_typed<Structures::XSDT>(xsdt_address); 401 402 for (size_t i = 0; i < ((xsdt->h.length - sizeof(Structures::SDTHeader)) / sizeof(u64)); ++i) { 403 if (match_table_signature(PhysicalAddress((FlatPtr)xsdt->table_ptrs[i]), signature)) 404 return PhysicalAddress((FlatPtr)xsdt->table_ptrs[i]); 405 } 406 return {}; 407} 408 409static bool match_table_signature(PhysicalAddress table_header, const StringView& signature) 410{ 411 // FIXME: There's no validation of ACPI tables here. Use the checksum to validate the tables. 412 // FIXME: Don't blindly use PAGE_SIZE here, but probe the actual length. 413 ASSERT(signature.length() == 4); 414 415 auto table = map_typed<Structures::RSDT>(table_header); 416 return !strncmp(table->h.sig, signature.characters_without_null_termination(), 4); 417} 418 419static PhysicalAddress search_table_in_rsdt(PhysicalAddress rsdt_address, const StringView& signature) 420{ 421 // FIXME: There's no validation of ACPI tables here. Use the checksum to validate the tables. 422 // FIXME: Don't blindly use PAGE_SIZE here, but probe the actual length. 423 ASSERT(signature.length() == 4); 424 425 auto rsdt = map_typed<Structures::RSDT>(rsdt_address); 426 427 for (u32 i = 0; i < ((rsdt->h.length - sizeof(Structures::SDTHeader)) / sizeof(u32)); i++) { 428 if (match_table_signature(PhysicalAddress((FlatPtr)rsdt->table_ptrs[i]), signature)) 429 return PhysicalAddress((FlatPtr)rsdt->table_ptrs[i]); 430 } 431 return {}; 432} 433 434void Parser::enable_aml_interpretation() 435{ 436 ASSERT_NOT_REACHED(); 437} 438 439void Parser::enable_aml_interpretation(File&) 440{ 441 ASSERT_NOT_REACHED(); 442} 443 444void Parser::enable_aml_interpretation(u8*, u32) 445{ 446 ASSERT_NOT_REACHED(); 447} 448 449void Parser::disable_aml_interpretation() 450{ 451 ASSERT_NOT_REACHED(); 452} 453 454} 455}