mirror of
https://github.com/SerenityOS/serenity.git
synced 2026-11-07 04:29:30 -10:00
529 lines
13 KiB
C++
529 lines
13 KiB
C++
/*
|
|
* Copyright (c) 2020, Liav A. <[email protected]>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/EnumBits.h>
|
|
#include <AK/Format.h>
|
|
#include <AK/StdLibExtras.h>
|
|
#include <AK/Traits.h>
|
|
#include <AK/Types.h>
|
|
|
|
namespace ACPI {
|
|
|
|
namespace FADTFlags {
|
|
|
|
// https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html#fixed-acpi-description-table-fixed-feature-flags
|
|
enum class FeatureFlags : u32 {
|
|
WBINVD = 1 << 0,
|
|
WBINVD_FLUSH = 1 << 1,
|
|
PROC_C1 = 1 << 2,
|
|
P_LVL2_UP = 1 << 3,
|
|
PWR_BUTTON = 1 << 4,
|
|
SLP_BUTTON = 1 << 5,
|
|
FIX_RTC = 1 << 6,
|
|
RTC_s4 = 1 << 7,
|
|
TMR_VAL_EXT = 1 << 8,
|
|
DCK_CAP = 1 << 9,
|
|
RESET_REG_SUPPORTED = 1 << 10,
|
|
SEALED_CASE = 1 << 11,
|
|
HEADLESS = 1 << 12,
|
|
CPU_SW_SLP = 1 << 13,
|
|
PCI_EXP_WAK = 1 << 14,
|
|
USE_PLATFORM_CLOCK = 1 << 15,
|
|
S4_RTC_STS_VALID = 1 << 16,
|
|
REMOTE_POWER_ON_CAPABLE = 1 << 17,
|
|
FORCE_APIC_CLUSTER_MODEL = 1 << 18,
|
|
FORCE_APIC_PHYSICAL_DESTINATION_MODE = 1 << 19,
|
|
HW_REDUCED_ACPI = 1 << 20,
|
|
LOW_POWER_S0_IDLE_CAPABLE = 1 << 21
|
|
};
|
|
|
|
AK_ENUM_BITWISE_OPERATORS(FeatureFlags);
|
|
|
|
// https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html#fixed-acpi-description-table-boot-ia-pc-boot-architecture-flags
|
|
enum class IA_PC_Flags : u16 {
|
|
Legacy_Devices = 1 << 0,
|
|
PS2_8042 = 1 << 1,
|
|
VGA_Not_Present = 1 << 2,
|
|
MSI_Not_Supported = 1 << 3,
|
|
PCIe_ASPM_Controls = 1 << 4,
|
|
CMOS_RTC_Not_Present = 1 << 5
|
|
};
|
|
|
|
AK_ENUM_BITWISE_OPERATORS(IA_PC_Flags);
|
|
|
|
struct [[gnu::packed]] HardwareFeatures {
|
|
bool wbinvd : 1;
|
|
bool wbinvd_flush : 1;
|
|
bool processor_c1 : 1;
|
|
bool multiprocessor_c2 : 1;
|
|
bool power_button : 1;
|
|
bool sleep_button : 1;
|
|
bool fix_rtc : 1;
|
|
bool rtc_s4 : 1;
|
|
bool timer_value_extension : 1;
|
|
bool docking_capability : 1;
|
|
bool reset_register_supported : 1;
|
|
bool sealed_case : 1;
|
|
bool headless : 1;
|
|
bool cpu_software_sleep : 1;
|
|
bool pci_express_wake : 1;
|
|
bool use_platform_clock : 1;
|
|
bool s4_rtc_status_valid : 1;
|
|
bool remote_power_on_capable : 1;
|
|
bool force_apic_cluster_model : 1;
|
|
bool force_apic_physical_destination_mode : 1;
|
|
bool hardware_reduced_acpi : 1;
|
|
bool low_power_s0_idle_capable : 1;
|
|
};
|
|
struct [[gnu::packed]] x86_Specific_Flags {
|
|
bool legacy_devices : 1;
|
|
bool keyboard_8042 : 1;
|
|
bool vga_not_present : 1;
|
|
bool msi_not_supported : 1;
|
|
bool cmos_rtc_not_present : 1;
|
|
};
|
|
};
|
|
|
|
// https://uefi.org/specs/ACPI/6.6/05_ACPI_Software_Programming_Model.html#generic-address-structure
|
|
namespace GenericAddressStructure {
|
|
|
|
enum class AddressSpace : u8 {
|
|
SystemMemory = 0x00,
|
|
SystemIO = 0x01,
|
|
PCIConfigurationSpace = 0x02,
|
|
EmbeddedController = 0x03,
|
|
SMBus = 0x04,
|
|
SystemCMOS = 0x05,
|
|
PCIBarTarget = 0x06,
|
|
IPMI = 0x07,
|
|
GPIO = 0x08,
|
|
GenericSerialBus = 0x09,
|
|
PlatformCommunicationsChannel = 0x0A,
|
|
PlatformRuntimeMechanism = 0x0B,
|
|
FunctionalFixedHardware = 0x7F,
|
|
OEMDefined = 0x80,
|
|
};
|
|
|
|
enum class AccessSize : u8 {
|
|
Undefined = 0,
|
|
Byte = 1,
|
|
Word = 2,
|
|
DWord = 3,
|
|
QWord = 4
|
|
};
|
|
|
|
enum class BitWidth : u8 {
|
|
Undefined = 0,
|
|
Byte = 8,
|
|
Word = 16,
|
|
DWord = 32,
|
|
QWord = 64
|
|
};
|
|
}
|
|
|
|
namespace Structures {
|
|
|
|
// https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html#root-system-description-pointer-rsdp-structure
|
|
struct [[gnu::packed]] RSDPDescriptor {
|
|
char sig[8];
|
|
u8 checksum;
|
|
char oem_id[6];
|
|
u8 revision;
|
|
u32 rsdt_ptr;
|
|
};
|
|
|
|
struct [[gnu::packed]] RSDPDescriptor20 {
|
|
RSDPDescriptor base;
|
|
u32 length;
|
|
u64 xsdt_ptr;
|
|
u8 ext_checksum;
|
|
u8 reserved[3];
|
|
};
|
|
|
|
// https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html#system-description-table-header
|
|
struct [[gnu::packed]] SDTHeader {
|
|
char sig[4];
|
|
u32 length;
|
|
u8 revision;
|
|
u8 checksum;
|
|
char oem_id[6];
|
|
char oem_table_id[8];
|
|
u32 oem_revision;
|
|
u32 creator_id;
|
|
u32 creator_revision;
|
|
};
|
|
|
|
// https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html#root-system-description-table-rsdt
|
|
struct [[gnu::packed]] RSDT {
|
|
SDTHeader h;
|
|
u32 table_ptrs[];
|
|
};
|
|
|
|
// https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html#extended-system-description-table-xsdt
|
|
struct [[gnu::packed]] XSDT {
|
|
SDTHeader h;
|
|
u64 table_ptrs[];
|
|
};
|
|
|
|
// https://uefi.org/specs/ACPI/6.6/05_ACPI_Software_Programming_Model.html#generic-address-structure
|
|
struct [[gnu::packed]] GenericAddressStructure {
|
|
::ACPI::GenericAddressStructure::AddressSpace address_space;
|
|
::ACPI::GenericAddressStructure::BitWidth bit_width;
|
|
u8 bit_offset;
|
|
::ACPI::GenericAddressStructure::AccessSize access_size;
|
|
u64 address;
|
|
|
|
[[nodiscard]] bool is_null() const
|
|
{
|
|
return to_underlying(address_space) == 0 && to_underlying(bit_width) == 0 && bit_offset == 0 && to_underlying(access_size) == 0 && address == 0;
|
|
}
|
|
};
|
|
|
|
struct [[gnu::packed]] HPET {
|
|
SDTHeader h;
|
|
u8 hardware_revision_id;
|
|
u8 attributes;
|
|
u16 pci_vendor_id;
|
|
GenericAddressStructure event_timer_block;
|
|
u8 hpet_number;
|
|
u16 mininum_clock_tick;
|
|
u8 page_protection;
|
|
};
|
|
|
|
// https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html#fixed-acpi-description-table-fadt
|
|
struct [[gnu::packed]] FADT {
|
|
SDTHeader h;
|
|
u32 firmware_ctrl;
|
|
u32 dsdt_ptr;
|
|
u8 reserved;
|
|
u8 preferred_pm_profile;
|
|
u16 sci_int;
|
|
u32 smi_cmd;
|
|
u8 acpi_enable_value;
|
|
u8 acpi_disable_value;
|
|
u8 s4bios_req;
|
|
u8 pstate_cnt;
|
|
u32 PM1a_EVT_BLK;
|
|
u32 PM1b_EVT_BLK;
|
|
u32 PM1a_CNT_BLK;
|
|
u32 PM1b_CNT_BLK;
|
|
u32 PM2_CNT_BLK;
|
|
u32 PM_TMR_BLK;
|
|
u32 GPE0_BLK;
|
|
u32 GPE1_BLK;
|
|
u8 PM1_EVT_LEN;
|
|
u8 PM1_CNT_LEN;
|
|
u8 PM2_CNT_LEN;
|
|
u8 PM_TMR_LEN;
|
|
u8 GPE0_BLK_LEN;
|
|
u8 GPE1_BLK_LEN;
|
|
u8 GPE1_BASE;
|
|
u8 cst_cnt;
|
|
u16 P_LVL2_LAT;
|
|
u16 P_LVL3_LAT;
|
|
u16 flush_size;
|
|
u16 flush_stride;
|
|
u8 duty_offset;
|
|
u8 duty_width;
|
|
u8 day_alrm;
|
|
u8 mon_alrm;
|
|
u8 century;
|
|
FADTFlags::IA_PC_Flags ia_pc_boot_arch_flags;
|
|
u8 reserved2;
|
|
FADTFlags::FeatureFlags flags;
|
|
GenericAddressStructure reset_reg;
|
|
u8 reset_value;
|
|
u16 arm_boot_arch;
|
|
u8 fadt_minor_version;
|
|
u64 x_firmware_ctrl;
|
|
u64 x_dsdt;
|
|
GenericAddressStructure x_pm1a_evt_blk;
|
|
GenericAddressStructure x_pm1b_evt_blk;
|
|
GenericAddressStructure x_pm1a_cnt_blk;
|
|
GenericAddressStructure x_pm1b_cnt_blk;
|
|
GenericAddressStructure x_pm2_cnt_blk;
|
|
GenericAddressStructure x_pm_tmr_blk;
|
|
GenericAddressStructure x_gpe0_blk;
|
|
GenericAddressStructure x_gpe1_blk;
|
|
GenericAddressStructure sleep_control;
|
|
GenericAddressStructure sleep_status;
|
|
u64 hypervisor_vendor_identity;
|
|
};
|
|
|
|
// https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html#interrupt-controller-structure-types
|
|
enum class MADTEntryType : u8 {
|
|
LocalAPIC = 0x0,
|
|
IOAPIC = 0x1,
|
|
InterruptSourceOverride = 0x2,
|
|
NMI_Source = 0x3,
|
|
LocalAPIC_NMI = 0x4,
|
|
LocalAPIC_Address_Override = 0x5,
|
|
IO_SAPIC = 0x6,
|
|
Local_SAPIC = 0x7,
|
|
Platform_interrupt_Sources = 0x8,
|
|
Local_x2APIC = 0x9,
|
|
Local_x2APIC_NMI = 0xA,
|
|
GIC_CPU = 0xB,
|
|
GIC_Distributor = 0xC,
|
|
GIC_MSI = 0xD,
|
|
GIC_Redistrbutor = 0xE,
|
|
GIC_Interrupt_Translation = 0xF
|
|
};
|
|
|
|
struct [[gnu::packed]] MADTEntryHeader {
|
|
MADTEntryType type;
|
|
u8 length;
|
|
};
|
|
|
|
namespace MADTEntries {
|
|
|
|
// https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html#i-o-apic-structure
|
|
struct [[gnu::packed]] IOAPIC {
|
|
MADTEntryHeader h;
|
|
u8 ioapic_id;
|
|
u8 reserved;
|
|
u32 ioapic_address;
|
|
u32 gsi_base;
|
|
};
|
|
|
|
// https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html#processor-local-apic-structure
|
|
struct [[gnu::packed]] ProcessorLocalAPIC {
|
|
MADTEntryHeader h;
|
|
u8 acpi_processor_id;
|
|
u8 apic_id;
|
|
u32 flags;
|
|
};
|
|
|
|
// https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html#processor-local-x2apic-structure
|
|
struct [[gnu::packed]] ProcessorLocalX2APIC {
|
|
MADTEntryHeader h;
|
|
u16 reserved;
|
|
u32 apic_id;
|
|
u32 flags;
|
|
u32 acpi_processor_id;
|
|
};
|
|
|
|
// https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html#interrupt-source-override-structure
|
|
struct [[gnu::packed]] InterruptSourceOverride {
|
|
MADTEntryHeader h;
|
|
u8 bus;
|
|
u8 source;
|
|
u32 global_system_interrupt;
|
|
u16 flags;
|
|
};
|
|
}
|
|
|
|
// https://uefi.org/specs/ACPI/6.5/05_ACPI_Software_Programming_Model.html#multiple-apic-description-table-madt-format
|
|
struct [[gnu::packed]] MADT {
|
|
SDTHeader h;
|
|
u32 lapic_address;
|
|
u32 flags;
|
|
MADTEntryHeader entries[];
|
|
};
|
|
|
|
struct [[gnu::packed]] AMLTable {
|
|
SDTHeader h;
|
|
char aml_code[];
|
|
};
|
|
|
|
struct [[gnu::packed]] PCI_MMIO_Descriptor {
|
|
u64 base_addr;
|
|
u16 seg_group_number;
|
|
u8 start_pci_bus;
|
|
u8 end_pci_bus;
|
|
u32 reserved;
|
|
};
|
|
|
|
struct [[gnu::packed]] MCFG {
|
|
SDTHeader header;
|
|
u64 reserved;
|
|
PCI_MMIO_Descriptor descriptors[];
|
|
};
|
|
|
|
struct [[gnu::packed]] DSDT {
|
|
SDTHeader h;
|
|
unsigned char definition_block[];
|
|
};
|
|
|
|
// https://uefi.org/specs/ACPI/6.6/04_ACPI_Hardware_Specification.html#pm1-control-registers-fixed-hardware-feature-control-bits
|
|
struct [[gnu::packed]] PM1ControlRegister {
|
|
bool SCI_EN : 1;
|
|
bool BM_RLD : 1;
|
|
bool GBL_RS : 1;
|
|
u16 : 7;
|
|
u16 SLP_TYPx : 3;
|
|
bool SLP_EN : 1;
|
|
u16 : 2;
|
|
};
|
|
static_assert(AssertSize<PM1ControlRegister, 2>());
|
|
|
|
// https://uefi.org/specs/ACPI/6.6/04_ACPI_Hardware_Specification.html#sleep-control-register
|
|
struct [[gnu::packed]] SleepControlRegister {
|
|
u8 : 2;
|
|
u8 SLP_TYPx : 3;
|
|
bool SLP_EN : 1;
|
|
u8 : 1;
|
|
};
|
|
static_assert(AssertSize<SleepControlRegister, 1>());
|
|
|
|
}
|
|
|
|
namespace AML {
|
|
|
|
// https://uefi.org/specs/ACPI/6.6/20_AML_Specification.html#aml-byte-stream-byte-values
|
|
constexpr u8 EXT_OP_PREFIX = 0x5B;
|
|
constexpr u8 DUAL_NAME_PREFIX = 0x2E;
|
|
constexpr u8 MULTI_NAME_PREFIX = 0x2F;
|
|
|
|
// https://uefi.org/specs/ACPI/6.6/20_AML_Specification.html#aml-byte-stream-byte-values
|
|
enum class Opcode : u16 {
|
|
ZeroOp = 0x0000,
|
|
OneOp = 0x0001,
|
|
OnesOp = 0x00FF,
|
|
|
|
BytePrefix = 0x000A,
|
|
WordPrefix = 0x000B,
|
|
DWordPrefix = 0x000C,
|
|
QWordPrefix = 0x000E,
|
|
StringPrefix = 0x000D,
|
|
|
|
RevisionOp = 0x5B30,
|
|
DebugOp = 0x5B31,
|
|
|
|
AliasOp = 0x0006,
|
|
NameOp = 0x0008,
|
|
ScopeOp = 0x0010,
|
|
BufferOp = 0x0011,
|
|
PackageOp = 0x0012,
|
|
VarPackageOp = 0x0013,
|
|
MethodOp = 0x0014,
|
|
ExternalOp = 0x0015,
|
|
MutexOp = 0x5B01,
|
|
EventOp = 0x5B02,
|
|
TimerOp = 0x5B33,
|
|
OpRegionOp = 0x5B80,
|
|
FieldOp = 0x5B81,
|
|
DeviceOp = 0x5B82,
|
|
// NOTE: This opcode is missing in the latest spec but is still being used.
|
|
ProcessorOp = 0x5B83,
|
|
PowerResOp = 0x5B84,
|
|
ThermalZoneOp = 0x5B85,
|
|
IndexFieldOp = 0x5B86,
|
|
BankFieldOp = 0x5B87,
|
|
DataRegionOp = 0x5B88,
|
|
|
|
CondRefOfOp = 0x5B12,
|
|
CreateFieldOp = 0x5B13,
|
|
LoadTableOp = 0x5B1F,
|
|
LoadOp = 0x5B20,
|
|
StallOp = 0x5B21,
|
|
SleepOp = 0x5B22,
|
|
AcquireOp = 0x5B23,
|
|
SignalOp = 0x5B24,
|
|
WaitOp = 0x5B25,
|
|
ResetOp = 0x5B26,
|
|
ReleaseOp = 0x5B27,
|
|
FromBCDOp = 0x5B28,
|
|
ToBCDOp = 0x5B29,
|
|
FatalOp = 0x5B32,
|
|
StoreOp = 0x70,
|
|
RefOfOp = 0x71,
|
|
|
|
AddOp = 0x72,
|
|
ConcatOp = 0x73,
|
|
SubtractOp = 0x74,
|
|
IncrementOp = 0x75,
|
|
DecrementOp = 0x76,
|
|
MultiplyOp = 0x77,
|
|
DivideOp = 0x78,
|
|
ShiftLeftOp = 0x79,
|
|
ShiftRightOp = 0x7A,
|
|
AndOp = 0x7B,
|
|
NandOp = 0x7C,
|
|
OrOp = 0x7D,
|
|
NorOp = 0x7E,
|
|
XorOp = 0x7F,
|
|
|
|
NotOp = 0x80,
|
|
FindSetLeftBitOp = 0x81,
|
|
FindSetRightBitOp = 0x82,
|
|
|
|
DerefOfOp = 0x83,
|
|
ConcatResOp = 0x84,
|
|
ModOp = 0x85,
|
|
NotifyOp = 0x86,
|
|
SizeOfOp = 0x87,
|
|
IndexOp = 0x88,
|
|
MatchOp = 0x89,
|
|
ObjectTypeOp = 0x8E,
|
|
|
|
LAndOp = 0x90,
|
|
LOrOp = 0x91,
|
|
LNotOp = 0x92,
|
|
LEqualOp = 0x93,
|
|
LGreaterOp = 0x94,
|
|
LLessOp = 0x95,
|
|
|
|
ToBufferOp = 0x96,
|
|
ToDecimalStringOp = 0x97,
|
|
ToHexStringOp = 0x98,
|
|
ToIntegerOp = 0x99,
|
|
ToStringOp = 0x9C,
|
|
|
|
CreateBitFieldOp = 0x8D,
|
|
CreateByteFieldOp = 0x8C,
|
|
CreateWordFieldOp = 0x8B,
|
|
CreateDWordFieldOp = 0x8A,
|
|
CreateQWordFieldOp = 0x8F,
|
|
|
|
CopyObjectOp = 0x9D,
|
|
MidOp = 0x9E,
|
|
ContinueOp = 0x9F,
|
|
IfOp = 0xA0,
|
|
ElseOp = 0xA1,
|
|
WhileOp = 0xA2,
|
|
NoopOp = 0xA3,
|
|
ReturnOp = 0xA4,
|
|
BreakOp = 0xA5,
|
|
BreakPointOp = 0xCC,
|
|
|
|
Local0Op = 0x60,
|
|
Local1Op = 0x61,
|
|
Local2Op = 0x62,
|
|
Local3Op = 0x63,
|
|
Local4Op = 0x64,
|
|
Local5Op = 0x65,
|
|
Local6Op = 0x66,
|
|
Local7Op = 0x67,
|
|
Arg0Op = 0x68,
|
|
Arg1Op = 0x69,
|
|
Arg2Op = 0x6A,
|
|
Arg3Op = 0x6B,
|
|
Arg4Op = 0x6C,
|
|
Arg5Op = 0x6D,
|
|
Arg6Op = 0x6E,
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
template<>
|
|
class AK::Traits<::ACPI::Structures::SDTHeader> : public DefaultTraits<::ACPI::Structures::SDTHeader> {
|
|
public:
|
|
static constexpr bool is_trivially_serializable() { return true; }
|
|
};
|
|
|
|
template<>
|
|
struct AK::Formatter<::ACPI::AML::Opcode> : AK::Formatter<FormatString> {
|
|
ErrorOr<void> format(FormatBuilder& builder, ::ACPI::AML::Opcode opcode)
|
|
{
|
|
return AK::Formatter<FormatString>::format(builder, "{:04X}"sv, static_cast<u16>(opcode));
|
|
}
|
|
};
|