mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-01 15:08:21 +00:00
timekeeper: redo timekeeping
This commit is contained in:
@@ -27,84 +27,84 @@
|
||||
#define HPET_CAP_LEGACYCAPABLE (1 << 15)
|
||||
#define HPET_CAP_FSPERTICK(x) (((x) >> 32) & 0xffffffff)
|
||||
|
||||
static volatile uint64_t *hpet;
|
||||
static time_t ticksperus;
|
||||
static uint64_t tickspassed;
|
||||
|
||||
// in order of preference
|
||||
#define TYPE_64BIT 0
|
||||
#define TYPE_LEGACY 1
|
||||
static int type;
|
||||
|
||||
|
||||
static MUTEX_DEFINE(init_mutex);
|
||||
static struct {
|
||||
volatile uint64_t *hpet;
|
||||
uint64_t tickspassed;
|
||||
int type;
|
||||
} hpet_private;
|
||||
|
||||
static timekeeper_source_info_t timekeeper_source_info = {
|
||||
.private = &hpet_private
|
||||
};
|
||||
|
||||
static uint64_t read64(int reg) {
|
||||
return hpet[reg];
|
||||
return hpet_private.hpet[reg];
|
||||
}
|
||||
|
||||
static void write64(int reg, uint64_t v) {
|
||||
hpet[reg] = v;
|
||||
}
|
||||
|
||||
time_t arch_hpet_ticks() {
|
||||
if (type == TYPE_64BIT) {
|
||||
return read64(HPET_REG_COUNTER);
|
||||
} else {
|
||||
uint64_t ticks;
|
||||
do {
|
||||
ticks = __atomic_load_n(&tickspassed, __ATOMIC_SEQ_CST) + (read64(HPET_REG_COUNTER) & 0xffffffff);
|
||||
} while (ticks < __atomic_load_n(&tickspassed, __ATOMIC_SEQ_CST));
|
||||
return ticks;
|
||||
}
|
||||
}
|
||||
|
||||
void arch_hpet_waitticks(time_t ticks) {
|
||||
uint64_t target = arch_hpet_ticks() + ticks;
|
||||
while (target > arch_hpet_ticks()) asm volatile("pause");
|
||||
}
|
||||
|
||||
void arch_hpet_waitus(time_t us) {
|
||||
arch_hpet_waitticks(us * ticksperus);
|
||||
hpet_private.hpet[reg] = v;
|
||||
}
|
||||
|
||||
static void counterirq(isr_t *isr, context_t *context) {
|
||||
write64(HPET_REG_CONFIG, 0);
|
||||
|
||||
__atomic_add_fetch(&tickspassed, read64(HPET_REG_COUNTER), __ATOMIC_SEQ_CST);
|
||||
__atomic_add_fetch(&hpet_private.tickspassed, read64(HPET_REG_COUNTER), __ATOMIC_SEQ_CST);
|
||||
write64(HPET_REG_COUNTER, 0);
|
||||
|
||||
write64(HPET_REG_CONFIG, 1 + ((type == TYPE_LEGACY) ? 2 : 0));
|
||||
write64(HPET_REG_CONFIG, 1 + ((hpet_private.type == TYPE_LEGACY) ? 2 : 0));
|
||||
}
|
||||
|
||||
bool arch_hpet_exists() {
|
||||
// This is assumed by arch_hpet_init below
|
||||
return true;
|
||||
}
|
||||
|
||||
time_t arch_hpet_init() {
|
||||
uacpi_table tbl;
|
||||
static bool hpet_probe(void) {
|
||||
bool usable = false;
|
||||
struct acpi_hpet *table;
|
||||
uacpi_table tbl;
|
||||
|
||||
if (uacpi_table_find_by_signature("HPET", &tbl) != UACPI_STATUS_OK) {
|
||||
printf("hpet: no timers\n");
|
||||
return 0;
|
||||
}
|
||||
if (uacpi_table_find_by_signature("HPET", &tbl) != UACPI_STATUS_OK)
|
||||
return false;
|
||||
|
||||
table = tbl.ptr;
|
||||
|
||||
if (table->address.address_space_id != ACPI_AS_ID_SYS_MEM)
|
||||
goto leave;
|
||||
|
||||
usable = true;
|
||||
leave:
|
||||
uacpi_table_unref(&tbl);
|
||||
return usable;
|
||||
}
|
||||
|
||||
static timekeeper_source_info_t *hpet_init(void) {
|
||||
uacpi_table tbl;
|
||||
struct acpi_hpet *table;
|
||||
|
||||
MUTEX_ACQUIRE(&init_mutex, false);
|
||||
if (timekeeper_source_info.ticks_per_us) {
|
||||
// already initialized by someone else
|
||||
goto leave;
|
||||
}
|
||||
|
||||
__assert(uacpi_table_find_by_signature("HPET", &tbl) == UACPI_STATUS_OK);
|
||||
table = tbl.ptr;
|
||||
printf("hpet%lu: %lu bits %lu comparators\n", table->number,
|
||||
(table->block_id & ACPI_HPET_COUNT_SIZE_CAP) ? 64 : 32,
|
||||
(table->block_id >> ACPI_HPET_NUMBER_OF_COMPARATORS_SHIFT) & ACPI_HPET_NUMBER_OF_COMPARATORS_MASK);
|
||||
__assert(table->address.address_space_id == ACPI_AS_ID_SYS_MEM);
|
||||
|
||||
uint64_t page_offset = table->address.address % PAGE_SIZE;
|
||||
hpet = vmm_map(NULL, (PAGE_SIZE + page_offset), VMM_FLAGS_PHYSICAL, ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC, (void *)(table->address.address - page_offset));
|
||||
__assert(hpet);
|
||||
hpet = (void *)((uintptr_t)hpet + page_offset);
|
||||
hpet_private.hpet = vmm_map(NULL, (PAGE_SIZE + page_offset), VMM_FLAGS_PHYSICAL, ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC, (void *)(table->address.address - page_offset));
|
||||
__assert(hpet_private.hpet);
|
||||
hpet_private.hpet = (void *)((uintptr_t)hpet_private.hpet + page_offset);
|
||||
|
||||
uint64_t capabilities = read64(HPET_REG_CAPS);
|
||||
|
||||
ticksperus = 1000000000 / HPET_CAP_FSPERTICK(capabilities);
|
||||
printf("hpet%lu: %lu ticks per us (%lu fs per tick)\n", table->number, ticksperus, HPET_CAP_FSPERTICK(capabilities));
|
||||
__assert(ticksperus);
|
||||
timekeeper_source_info.ticks_per_us = 1000000000 / HPET_CAP_FSPERTICK(capabilities);
|
||||
printf("hpet%lu: %lu ticks per us (%lu fs per tick)\n", table->number, timekeeper_source_info.ticks_per_us, HPET_CAP_FSPERTICK(capabilities));
|
||||
__assert(timekeeper_source_info.ticks_per_us);
|
||||
|
||||
write64(HPET_REG_CONFIG, 0);
|
||||
write64(HPET_REG_COUNTER, 0);
|
||||
@@ -120,7 +120,7 @@ time_t arch_hpet_init() {
|
||||
// TODO FSB mapping
|
||||
// timer 0 will be used with the timer irq replacing the PIT's as irq0.
|
||||
if (capabilities & HPET_CAP_LEGACYCAPABLE) {
|
||||
type = TYPE_LEGACY;
|
||||
hpet_private.type = TYPE_LEGACY;
|
||||
|
||||
arch_ioapic_setirq(0, isr->id & 0xff, current_cpu_id(), false);
|
||||
|
||||
@@ -139,11 +139,37 @@ time_t arch_hpet_init() {
|
||||
write64(HPET_TIMER_COMPARATOR(selectedtimer), 0x80000000);
|
||||
printf("hpet%d: timer %d on isr %d using %s\n", table->number, selectedtimer, isr->id & 0xff, "legacy replacement");
|
||||
} else {
|
||||
type = TYPE_64BIT;
|
||||
hpet_private.type = TYPE_64BIT;
|
||||
}
|
||||
|
||||
write64(HPET_REG_CONFIG, 1 + ((type == TYPE_LEGACY) ? 2 : 0));
|
||||
write64(HPET_REG_CONFIG, 1 + ((hpet_private.type == TYPE_LEGACY) ? 2 : 0));
|
||||
|
||||
uacpi_table_unref(&tbl);
|
||||
return ticksperus;
|
||||
|
||||
leave:
|
||||
MUTEX_RELEASE(&init_mutex);
|
||||
return &timekeeper_source_info;
|
||||
|
||||
}
|
||||
|
||||
time_t hpet_ticks(timekeeper_source_info_t *) {
|
||||
if (hpet_private.type == TYPE_64BIT) {
|
||||
return read64(HPET_REG_COUNTER);
|
||||
} else {
|
||||
uint64_t ticks;
|
||||
do {
|
||||
ticks = __atomic_load_n(&hpet_private.tickspassed, __ATOMIC_SEQ_CST) + (read64(HPET_REG_COUNTER) & 0xffffffff);
|
||||
} while (ticks < __atomic_load_n(&hpet_private.tickspassed, __ATOMIC_SEQ_CST));
|
||||
return ticks;
|
||||
}
|
||||
}
|
||||
|
||||
TIMEKEEPER_SOURCE(
|
||||
hpet_source,
|
||||
.name = "HPET",
|
||||
.priority = 100,
|
||||
.probe = hpet_probe,
|
||||
.init = hpet_init,
|
||||
.ticks = hpet_ticks,
|
||||
.flags = TIMEKEEPER_SOURCE_FLAGS_EARLY
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user