mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-29 05:38:21 +00:00
timekeeper: redo timekeeping
This commit is contained in:
@@ -178,8 +178,6 @@ void arch_apic_initap() {
|
||||
}
|
||||
}
|
||||
|
||||
printf("processor id: %lu (APIC) %lu (ACPI)\n", current_cpu()->id, current_cpu()->acpiid);
|
||||
|
||||
isr_t *nmiisr = interrupt_allocate(nmi, NULL, IPL_MAX); // MAX IPL because NMI
|
||||
__assert(nmiisr);
|
||||
|
||||
@@ -225,16 +223,9 @@ void arch_apic_timerinit() {
|
||||
|
||||
writelapic(APIC_TIMER_DIVIDE, 11);
|
||||
|
||||
void (*uswait)(time_t) = NULL;
|
||||
|
||||
if (arch_hpet_exists())
|
||||
uswait = arch_hpet_waitus;
|
||||
|
||||
__assert(uswait);
|
||||
|
||||
writelapic(APIC_TIMER_INITIALCOUNT, 0xffffffff);
|
||||
|
||||
uswait(50000);
|
||||
timekeeper_wait_us(50000);
|
||||
|
||||
time_t ticksperus = (0xffffffff - readlapic(APIC_TIMER_COUNT)) / 50000;
|
||||
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
@@ -26,6 +26,13 @@ SECTIONS
|
||||
*(.rodata .rodata.*);
|
||||
} :rodata
|
||||
|
||||
. = ALIGN(8);
|
||||
.timekeeper_sources : {
|
||||
timekeeper_sources = .;
|
||||
*(.timekeeper_sources);
|
||||
timekeeper_sources_end = .;
|
||||
} :rodata
|
||||
|
||||
. = ALIGN(4K);
|
||||
_rodata_end = .;
|
||||
_data_start = .;
|
||||
@@ -33,13 +40,13 @@ SECTIONS
|
||||
data : {
|
||||
*(.data .data.*);
|
||||
} :data
|
||||
|
||||
|
||||
. = ALIGN(8);
|
||||
.bss : {
|
||||
*(COMMON)
|
||||
*(.bss .bss.*)
|
||||
} :data
|
||||
|
||||
. = ALIGN(4K);
|
||||
|
||||
_data_end = .;
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ void kernel_entry() {
|
||||
cpu_set(&bsp_cpu);
|
||||
logging_init();
|
||||
logging_sethook(arch_e9_putc);
|
||||
|
||||
arch_gdt_reload();
|
||||
arch_idt_setup();
|
||||
arch_idt_reload();
|
||||
@@ -60,16 +61,17 @@ void kernel_entry() {
|
||||
cmdline_parse();
|
||||
acpi_early_init();
|
||||
arch_apic_init();
|
||||
|
||||
timekeeper_early_init(0);
|
||||
|
||||
cpu_initstate();
|
||||
|
||||
// XXX fall back to another clock source
|
||||
time_t hpet_ticks_per_us = arch_hpet_init();
|
||||
__assert(hpet_ticks_per_us);
|
||||
|
||||
timekeeper_init(arch_hpet_ticks, hpet_ticks_per_us);
|
||||
|
||||
arch_apic_timerinit();
|
||||
|
||||
sched_init();
|
||||
|
||||
timekeeper_init();
|
||||
|
||||
arch_smp_wakeup();
|
||||
pci_init();
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ static void cpuwakeuphalt(struct limine_smp_info *info) {
|
||||
for (;;) CPU_HALT();
|
||||
}
|
||||
|
||||
static time_t us_offset;
|
||||
|
||||
static void cpuwakeup(struct limine_smp_info *info) {
|
||||
cpu_set((cpu_t *)info->extra_argument);
|
||||
|
||||
@@ -31,11 +33,14 @@ static void cpuwakeup(struct limine_smp_info *info) {
|
||||
arch_mmu_apswitch();
|
||||
vmm_apinit();
|
||||
|
||||
timekeeper_early_init(us_offset);
|
||||
|
||||
cpu_initstate();
|
||||
arch_apic_timerinit();
|
||||
|
||||
__atomic_add_fetch(&arch_smp_cpusawake, 1, __ATOMIC_SEQ_CST);
|
||||
timekeeper_init();
|
||||
|
||||
__atomic_add_fetch(&arch_smp_cpusawake, 1, __ATOMIC_SEQ_CST);
|
||||
sched_ap_entry();
|
||||
}
|
||||
|
||||
@@ -72,6 +77,8 @@ void arch_smp_wakeup() {
|
||||
|
||||
void (*wakeupfn)(struct limine_smp_info *) = cmdline_get("nosmp") ? cpuwakeuphalt : cpuwakeup;
|
||||
|
||||
us_offset = timespec_us(timekeeper_timefromboot());
|
||||
|
||||
// make the other processors jump to cpuwakeup()
|
||||
for (int i = 0; i < response->cpu_count; ++i) {
|
||||
// skip the bootstrap processor
|
||||
|
||||
Reference in New Issue
Block a user