#pragma once #include "acpi/acpi.h" #include "memory/pointer.h" #include "util/number.h" namespace acpi { struct fadt_flags_t { uint32_t wbinvd : 1; uint32_t wbinvd_flush : 1; uint32_t processor_c1 : 1; uint32_t p_level2_up : 1; uint32_t power_button : 1; uint32_t sleep_button : 1; uint32_t fixed_rtc : 1; uint32_t rtc_s4 : 1; uint32_t timer_value_extended : 1; uint32_t reserved : 23; }; static_assert(sizeof(fadt_flags_t) == 4); // Prefix of the FADT through the flags field; real tables continue past this, // so no field after flags may be added without also handling table revisions. struct fadt_t { sdt_header_t header; uint32_t firmware_control; uint32_t dsdt_address; uint8_t reserved; uint8_t preferred_pm_profile; uint16_t sci_interrupt; uint32_t smi_command_port; uint8_t acpi_enable; uint8_t acpi_disable; uint8_t s4bios_request; uint8_t pstate_control; uint32_t pm1a_event_block; uint32_t pm1b_event_block; uint32_t pm1a_control_block; uint32_t pm1b_control_block; uint32_t pm2_control_block; uint32_t pm_timer_block; uint32_t gpe0_block; uint32_t gpe1_block; uint8_t pm1_event_length; uint8_t pm1_control_length; uint8_t pm2_control_length; uint8_t pm_timer_length; uint8_t gpe0_block_length; uint8_t gpe1_block_length; uint8_t gpe1_base; uint8_t cstate_control; uint16_t p_level2_latency; uint16_t p_level3_latency; uint16_t flush_size; uint16_t flush_stride; uint8_t duty_offset; uint8_t duty_width; uint8_t day_alarm; uint8_t month_alarm; uint8_t century; uint16_t iapc_boot_architecture; uint8_t reserved2; fadt_flags_t flags; } __attribute__((packed)); static_assert(sizeof(fadt_t) == 116); constexpr uint64_t pm_timer_frequency_hz = 3'579'545; struct pm_timer_duration_t { uint64_t pm_ticks; }; constexpr pm_timer_duration_t pm_timer_milliseconds(uint64_t count) { return pm_timer_duration_t{count * pm_timer_frequency_hz / 1'000}; } struct Fadt { explicit Fadt(paddr_t fadt_physical) : table(fadt_physical.access()) {} explicit Fadt(const fadt_t* fadt_table) : table(fadt_table) {} bool has_pm_timer() const { return table->pm_timer_block != 0 && table->pm_timer_length == 4; } uint16_t pm_timer_port() const { return static_cast(table->pm_timer_block); } bool pm_timer_is_32bit() const { return table->flags.timer_value_extended != 0; } private: const fadt_t* table; }; } // namespace acpi