diff --git a/src/arch/x86_64/hpet.c b/src/arch/x86_64/hpet.c new file mode 100644 index 00000000..2f8eafde --- /dev/null +++ b/src/arch/x86_64/hpet.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include +#include +#include +#include + +#define REGISTER_CAPABILITIES 0 +#define REGISTER_CONFIGURATION 0x10 +#define REGISTER_INTERRUPT 0x20 +#define REGISTER_COUNTER 0xF0 +#define REGISTER_N_CONFIG 0x100 +#define REGISTER_N_COMPARATOR 0x108 +#define REGISTER_N_FSB 0x110 + +static uint16_t mintick; +static void* volatile hpetaddr; +static uint32_t period; +static uint64_t nsperiod; +static uint8_t compcount; +static uint64_t ticksper100ns; + +static inline void writetocompn(size_t n, size_t offset, uint64_t data){ + *(uint64_t* volatile)(hpetaddr + 0x20*n + offset) = data; +} + +static inline uint64_t readfromcompn(size_t n, size_t offset){ + return *(uint64_t* volatile)(hpetaddr + 0x100 + 0x20*n + offset); +} + +static inline uint64_t readfromreg(size_t offset){ + return *(uint64_t* volatile)(hpetaddr + offset); +} + +static inline void writetoreg(size_t offset, uint64_t data){ + *(uint64_t* volatile)(hpetaddr + offset) = data; +} + +static void wait_ticks(size_t ticks){ + + size_t end = readfromreg(REGISTER_COUNTER) + ticks; + + while(readfromreg(REGISTER_COUNTER) < end) asm("pause"); +} + +void hpet_wait_us(size_t us){ + + size_t usticks = ticksper100ns*10; + + wait_ticks(usticks*us); + +} + +void hpet_wait_ms(size_t ms){ + size_t msticks = ticksper100ns*10000; + + wait_ticks(ms*msticks); + +} + +void hpet_wait_s(size_t s){ + size_t sticks = ticksper100ns*10000000; + + wait_ticks(s*sticks); + +} + +void hpet_init(){ + + hpet_t* hpet = acpi_gettable("HPET", 0); + + if(!hpet) + _panic("No HPET found!\n", 0); + + printf("HPET table at %p\n", hpet); + + mintick = hpet->mintick; + + if(hpet->spacetype == 1) _panic("I/O space hpet not supported", 0); + + printf("HPET configuration space is at %p\n", hpet->address); + + // seabios doesn't report this in the memory map..... + + hpetaddr = vmm_alloc(1, 0); + vmm_map((void*)hpet->address, hpetaddr, 1, ARCH_MMU_MAP_READ | ARCH_MMU_MAP_WRITE); + + uint64_t capabilities = readfromreg(REGISTER_CAPABILITIES); + + compcount = (capabilities >> 8) & 0b11111; + period = (capabilities >> 32) & 0xFFFFFFFF; + nsperiod = period / 1000000; + ticksper100ns = 100000000 / period; + + printf("%lu comparators at %lu femtosecond ticks (%lu ns, %lu ticks per 100 ns)\n", compcount, period, nsperiod, ticksper100ns); + + // configure so we don't use legacy replacement and clear the counter + + writetoreg(REGISTER_CONFIGURATION, 0); // stop it + writetoreg(REGISTER_COUNTER, 0); + writetoreg(REGISTER_CONFIGURATION, 1); // turn it back on + + // TODO add interrupt support. for now only direct reads to the + // counter will be supported. + // (this should be enough for calibrating the CPU specific timers) + +} diff --git a/src/arch/x86_64/include/arch/acpi.h b/src/arch/x86_64/include/arch/acpi.h index d5c00b45..289a14b1 100644 --- a/src/arch/x86_64/include/arch/acpi.h +++ b/src/arch/x86_64/include/arch/acpi.h @@ -60,6 +60,22 @@ typedef struct { mcfgentry entries[]; } __attribute__((packed)) mcfg_t; + +typedef struct { + sdt_t header; + uint8_t revid; + uint8_t flags; + uint16_t vendor; + uint8_t spacetype; + uint8_t bitwidth; + uint8_t bitoffset; + uint8_t reserved; + uint64_t address; + uint8_t hpetnum; + uint16_t mintick; + uint8_t protection; +} __attribute__((packed)) hpet_t; + void* acpi_gettable(char* sig, size_t n); void acpi_init(); bool acpi_checksumok(sdt_t* table); diff --git a/src/arch/x86_64/include/arch/hpet.h b/src/arch/x86_64/include/arch/hpet.h new file mode 100644 index 00000000..93cb1388 --- /dev/null +++ b/src/arch/x86_64/include/arch/hpet.h @@ -0,0 +1,10 @@ +#ifndef _HPET_H_INCLUDE +#define _HPET_H_INCLUDE + +void hpet_init(); + +void hpet_wait_us(size_t us); +void hpet_wait_ms(size_t ms); +void hpet_wait_s(size_t s); + +#endif diff --git a/src/arch/x86_64/include/arch/pci.h b/src/arch/x86_64/include/arch/pci.h index 9d26017b..877246f9 100644 --- a/src/arch/x86_64/include/arch/pci.h +++ b/src/arch/x86_64/include/arch/pci.h @@ -50,7 +50,7 @@ typedef struct _pci_enumeration{ pci_common* header; } pci_enumeration; - +uint64_t pci_msi_build(uint64_t* data, uint8_t vector, uint8_t processor, uint8_t edgetrigger, uint8_t deassert); void pci_enumerate(); #endif diff --git a/src/arch/x86_64/main.c b/src/arch/x86_64/main.c index aaf89b05..7f69d928 100644 --- a/src/arch/x86_64/main.c +++ b/src/arch/x86_64/main.c @@ -13,6 +13,9 @@ #include #include #include +#include +#include +#include static volatile struct limine_terminal_request liminettyr = { .id = LIMINE_TERMINAL_REQUEST, @@ -67,6 +70,8 @@ void kmain(){ apic_lapicinit(); pci_enumerate(); + + hpet_init(); smp_init(); diff --git a/src/arch/x86_64/pci.c b/src/arch/x86_64/pci.c index fe6d695d..640e1f62 100644 --- a/src/arch/x86_64/pci.c +++ b/src/arch/x86_64/pci.c @@ -122,7 +122,10 @@ static void legacy_enumeration(){ } - +uint64_t pci_msi_build(uint64_t* data, uint8_t vector, uint8_t processor, uint8_t edgetrigger, uint8_t deassert){ + *data = vector | (edgetrigger << 15) | (deassert << 14); + return (0xFEE00000 | (processor << 12)); +} void pci_enumerate(){