feat: add fadt based lapic timer calibration

This commit is contained in:
Katharina 2026-07-03 22:35:16 +02:00
parent 54d48e7d91
commit 61dfda6a70
7 changed files with 257 additions and 28 deletions

View file

@ -60,6 +60,7 @@ struct rsdp_t {
static_assert(sizeof(rsdp_t) == 36);
struct madt_t;
struct fadt_t;
struct Rsdp {
explicit Rsdp(paddr_t rsdp_physical) : physical(rsdp_physical) {}
@ -90,6 +91,7 @@ private:
switch (static_cast<signature>(header->signature)) {
ACPI_DISPATCH(madt, madt_t)
ACPI_DISPATCH(fadt, fadt_t)
default:
break;
}

View file

@ -0,0 +1,17 @@
#pragma once
#include "acpi/acpi.h"
#include "acpi/fadt.h"
#include "acpi/madt.h"
#include "util/optional.h"
namespace acpi {
struct discovery_result_t {
optional<Rsdp> rsdp;
optional<Madt> madt;
// TODO(wiring): capture the FADT in setupAcpi and store it here
optional<Fadt> fadt;
};
} // namespace acpi

View file

@ -0,0 +1,98 @@
#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<fadt_t>()) {}
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<uint16_t>(table->pm_timer_block);
}
bool pm_timer_is_32bit() const {
return table->flags.timer_value_extended != 0;
}
private:
const fadt_t* table;
};
} // namespace acpi

View file

@ -1,6 +1,6 @@
#pragma once
#include "acpi/madt.h"
#include "acpi/discovery.h"
namespace apic {
@ -12,6 +12,11 @@ struct timestamp_t {
uint64_t timer_count;
};
struct seconds_nanoseconds_t {
uint64_t seconds;
uint64_t nanoseconds;
};
constexpr duration_t operator+(duration_t left, duration_t right) {
return duration_t{left.timer_count + right.timer_count};
}
@ -44,13 +49,17 @@ constexpr duration_t operator-(timestamp_t left, timestamp_t right) {
return duration_t{left.timer_count - right.timer_count};
}
bool calibrateTimer(const acpi::Madt& madt);
bool calibrateTimer(const acpi::discovery_result_t& discovery);
duration_t seconds(uint64_t count);
duration_t milliseconds(uint64_t count);
duration_t microseconds(uint64_t count);
duration_t nanoseconds(uint64_t count);
seconds_nanoseconds_t toSecondsAndNanoseconds(duration_t duration);
void busyWait(duration_t duration);
timestamp_t now();
// TODO: when dynamic allocation and lists are available

View file

@ -0,0 +1,33 @@
#pragma once
#include "util/number.h"
inline uint8_t port_read_8(uint16_t port) {
uint8_t value = 0;
__asm__ volatile("inb %1, %0" : "=a"(value) : "Nd"(port));
return value;
}
inline uint16_t port_read_16(uint16_t port) {
uint16_t value = 0;
__asm__ volatile("inw %1, %0" : "=a"(value) : "Nd"(port));
return value;
}
inline uint32_t port_read_32(uint16_t port) {
uint32_t value = 0;
__asm__ volatile("inl %1, %0" : "=a"(value) : "Nd"(port));
return value;
}
inline void port_write_8(uint16_t port, uint8_t value) {
__asm__ volatile("outb %0, %1" : : "a"(value), "Nd"(port));
}
inline void port_write_16(uint16_t port, uint16_t value) {
__asm__ volatile("outw %0, %1" : : "a"(value), "Nd"(port));
}
inline void port_write_32(uint16_t port, uint32_t value) {
__asm__ volatile("outl %0, %1" : : "a"(value), "Nd"(port));
}