From a3969eea54a8114fe8957036048f4f6a8028739d Mon Sep 17 00:00:00 2001 From: Matheus Date: Sat, 22 Apr 2023 19:21:30 -0300 Subject: [PATCH] kernel: initial hpet support --- kernel-src/arch/x86-64/hpet.c | 55 +++++++++++++++++++++++++++ kernel-src/arch/x86-64/main.c | 2 + kernel-src/include/time.h | 11 ++++++ kernel-src/include/x86-64/arch/acpi.h | 18 +++++++++ kernel-src/include/x86-64/arch/hpet.h | 12 ++++++ 5 files changed, 98 insertions(+) create mode 100644 kernel-src/arch/x86-64/hpet.c create mode 100644 kernel-src/include/time.h create mode 100644 kernel-src/include/x86-64/arch/hpet.h diff --git a/kernel-src/arch/x86-64/hpet.c b/kernel-src/arch/x86-64/hpet.c new file mode 100644 index 00000000..113974d5 --- /dev/null +++ b/kernel-src/arch/x86-64/hpet.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include + +#define HPET_REG_CAPS 0 +#define HPET_REG_CONFIG 2 +#define HPET_REG_INTSTATUS 4 +#define HPET_REG_COUNTER 0x1e + +#define CAP_FSPERTICK(x) (((x) >> 32) & 0xffffffff) + +// XXX there might be several hpets in a system. +static volatile uint64_t *hpet; +static time_t ticksperus; + +static uint64_t read64(int reg) { + return hpet[reg]; +} + +static void write64(int reg, uint64_t v) { + hpet[reg] = v; +} + +void arch_hpet_waitticks(time_t ticks) { + uint64_t target = read64(HPET_REG_COUNTER) + ticks; + while (target > read64(HPET_REG_COUNTER)) asm volatile("pause"); +} + +void arch_hpet_waitus(time_t us) { + arch_hpet_waitticks(us * ticksperus); +} + +bool arch_hpet_exists() { + return arch_acpi_findtable("HPET", 0) != NULL; +} + +void arch_hpet_init() { + __assert(arch_hpet_exists()); + hpet_t *table = arch_acpi_findtable("HPET", 0); + printf("hpet%lu: %lu bits %lu comparators\n", table->hpetnum, 32 + table->countersize * 32, table->comparatorcount); + __assert(table->countersize); // XXX not rely on hpet being 64 bits + __assert(table->addrid == 0); + __assert((table->addr & PAGE_SIZE) == 0); + hpet = vmm_map(NULL, PAGE_SIZE, VMM_FLAGS_PHYSICAL, ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC, (void *)table->addr); + __assert(hpet); + ticksperus = 1000000000 / CAP_FSPERTICK(read64(HPET_REG_CAPS)); + printf("hpet%lu: %lu ticks per us (%lu fs per tick)\n", table->hpetnum, ticksperus, CAP_FSPERTICK(read64(HPET_REG_CAPS))); + __assert(ticksperus); + + write64(HPET_REG_CONFIG, 0); + write64(HPET_REG_COUNTER, 0); + write64(HPET_REG_CONFIG, 1); +} diff --git a/kernel-src/arch/x86-64/main.c b/kernel-src/arch/x86-64/main.c index ef786a40..fa5eec79 100644 --- a/kernel-src/arch/x86-64/main.c +++ b/kernel-src/arch/x86-64/main.c @@ -11,6 +11,7 @@ #include #include #include +#include static cpu_t bsp_cpu; @@ -29,5 +30,6 @@ void kernel_entry() { arch_acpi_init(); arch_apic_init(); arch_apic_initap(); + arch_hpet_init(); __assert(!"kernel entry end"); } diff --git a/kernel-src/include/time.h b/kernel-src/include/time.h new file mode 100644 index 00000000..cbfa12a5 --- /dev/null +++ b/kernel-src/include/time.h @@ -0,0 +1,11 @@ +#ifndef _TIME_H +#define _TIME_H + +typedef long time_t; + +typedef struct { + time_t s; + time_t ns; +} timespec_t; + +#endif diff --git a/kernel-src/include/x86-64/arch/acpi.h b/kernel-src/include/x86-64/arch/acpi.h index 28d47077..26ca91e6 100644 --- a/kernel-src/include/x86-64/arch/acpi.h +++ b/kernel-src/include/x86-64/arch/acpi.h @@ -45,6 +45,24 @@ typedef struct { uint32_t flags; } __attribute__((packed)) madt_t; +typedef struct { + sdtheader_t header; + uint8_t hwrev; + uint8_t comparatorcount:5; + uint8_t countersize:1; + uint8_t reserved:1; + uint8_t legacy_replacement:1; + uint16_t pcivendor; + uint8_t addrid; + uint8_t bitwidth; + uint8_t bitoffset; + uint8_t reserved2; + uint64_t addr; + uint8_t hpetnum; + uint16_t mintick; + uint8_t pageprot; +} __attribute__((packed)) hpet_t; + #define ACPI_MADT_TYPE_LAPIC 0 #define ACPI_MADT_TYPE_IOAPIC 1 #define ACPI_MADT_TYPE_OVERRIDE 2 diff --git a/kernel-src/include/x86-64/arch/hpet.h b/kernel-src/include/x86-64/arch/hpet.h new file mode 100644 index 00000000..1d02040b --- /dev/null +++ b/kernel-src/include/x86-64/arch/hpet.h @@ -0,0 +1,12 @@ +#ifndef _HPET_H +#define _HPET_h + +#include +#include + +void arch_hpet_waitticks(time_t ticks); +void arch_hpet_waitus(time_t us); +bool arch_hpet_exists(); +void arch_hpet_init(); + +#endif