diff --git a/arch/x86_64/acpi/apic.cpp b/arch/x86_64/acpi/apic.cpp index 19d247f..139a290 100644 --- a/arch/x86_64/acpi/apic.cpp +++ b/arch/x86_64/acpi/apic.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -16,6 +17,7 @@ #define IA32_APIC_BASE_MSR_ENABLE 0x800 static int apic_enabled = 0; +static unsigned int bsp_id = (unsigned int)-1; using namespace arch::acpi; @@ -118,12 +120,26 @@ static void ioapic_init(uintptr_t base, unsigned int int_base) queue_push_back(&io_apics, &apic->io_entry); } +static int lapic_clock_irq(void) +{ + if (this_cpu() == bsp_id) { + clock_advance(1); + } + + return 0; +} + +static struct irq_hook lapic_clock_irq_hook = { + {}, + lapic_clock_irq, +}; + void local_apic_config_timer(void) { local_apic lapic(lapic_base); lapic.write(local_apic::TIMER_DIV, 0x3); lapic.write(local_apic::TIMER_INITCOUNT, (uint32_t)-1); - pit_wait(100); + clock_wait(10); lapic.write(local_apic::LVT_TIMER, APIC_LVT_INT_MASKED); /* mask IRQ0 to block interrupts from the PIT. */ @@ -132,7 +148,8 @@ void local_apic_config_timer(void) uint32_t total_ticks = 0xFFFFFFFF - lapic.read(local_apic::TIMER_CURCOUNT); - total_ticks /= 100; + /* convert to LAPIC ticks per kernel clock tick */ + total_ticks /= 10; lapic.write(local_apic::LVT_TIMER, IRQ0 | APIC_LVT_TIMER_MODE_PERIODIC); lapic.write(local_apic::TIMER_DIV, 0x3); @@ -189,8 +206,6 @@ static void init_all_ioapic(struct acpi_madt *madt) kern_status_t apic_init(void) { - static unsigned int bsp_id = (unsigned int)-1; - /* the bootstrap processor will be the first one ro call apic_init(). it is responsible for initialising the I/O APICs */ if (bsp_id == (unsigned int)-1) { @@ -214,8 +229,13 @@ kern_status_t apic_init(void) apic_enabled = 1; irq_enable(); - pit_start(1000); + pit_start(HZ); + return KERN_OK; + local_apic_config_timer(); + pit_stop(); + + hook_irq(IRQ0, &lapic_clock_irq_hook); return KERN_OK; } diff --git a/arch/x86_64/init.c b/arch/x86_64/init.c index 5d5f579..5091116 100644 --- a/arch/x86_64/init.c +++ b/arch/x86_64/init.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -46,6 +47,7 @@ int ml_init(uintptr_t arg) bootstrap_cpu_init(); vgacon_init(); + clock_calibrate(500); print_kernel_banner(); diff --git a/arch/x86_64/pit.c b/arch/x86_64/pit.c index 311c03c..f0d2ab3 100644 --- a/arch/x86_64/pit.c +++ b/arch/x86_64/pit.c @@ -1,13 +1,42 @@ #include +#include #include #include #include -static unsigned long long tick_counter = 0; +#define PIT_COUNTER0 0x40 +#define PIT_CMD 0x43 + +#define CMD_BINARY 0x00 // Use Binary counter values +#define CMD_BCD 0x01 // Use Binary Coded Decimal counter values + +#define CMD_MODE0 0x00 // Interrupt on Terminal Count +#define CMD_MODE1 0x02 // Hardware Retriggerable One-Shot +#define CMD_MODE2 0x04 // Rate Generator +#define CMD_MODE3 0x06 // Square Wave +#define CMD_MODE4 0x08 // Software Trigerred Strobe +#define CMD_MODE5 0x0a // Hardware Trigerred Strobe + +#define CMD_LATCH 0x00 +#define CMD_RW_LOW 0x10 // Least Significant Byte +#define CMD_RW_HI 0x20 // Most Significant Byte +#define CMD_RW_BOTH 0x30 // Least followed by Most Significant Byte + +#define CMD_COUNTER0 0x00 +#define CMD_COUNTER1 0x40 +#define CMD_COUNTER2 0x80 +#define CMD_READBACK 0xc0 + +#define PIT_FREQUENCY 1193182 + + +static volatile unsigned long long ticks = 0; static int pit_callback(void) { - tick_counter++; + clock_advance(1); + ticks++; + return 0; } @@ -17,39 +46,20 @@ static struct irq_hook pit_irq_hook = { void pit_start(unsigned int hz) { - tick_counter = 0; - - unsigned int divisor = 1193180 / hz; - - outportb(0x43, 0x36); - uint8_t lo = (uint8_t)(divisor & 0xFF); - uint8_t hi = (uint8_t)((divisor >> 8) & 0xFF); - - outportb(0x40, lo); - outportb(0x40, hi); - hook_irq(IRQ0, &pit_irq_hook); + + unsigned int divisor = PIT_FREQUENCY / hz; + outportb(PIT_CMD, CMD_BINARY | CMD_MODE2 | CMD_RW_BOTH | CMD_COUNTER0); + outportb(PIT_COUNTER0, divisor); + outportb(PIT_COUNTER0, divisor >> 8); } void pit_stop(void) { - /* lowest possible frequency */ - unsigned int divisor = 1193180; - - outportb(0x43, 0x36); - uint8_t lo = (uint8_t)(divisor & 0xFF); - uint8_t hi = (uint8_t)((divisor >> 8) & 0xFF); - - outportb(0x40, lo); - outportb(0x40, hi); + unsigned int divisor = PIT_FREQUENCY / 20; + outportb(PIT_CMD, CMD_BINARY | CMD_MODE4 | CMD_RW_BOTH | CMD_COUNTER0); + outportb(PIT_COUNTER0, divisor); + outportb(PIT_COUNTER0, divisor >> 8); unhook_irq(IRQ0, &pit_irq_hook); } - -void pit_wait(unsigned int ticks) -{ - unsigned long long end = tick_counter + ticks; - - while (READ_ONCE(tick_counter) < end) { - } -} diff --git a/include/socks/clock.h b/include/socks/clock.h new file mode 100644 index 0000000..b474646 --- /dev/null +++ b/include/socks/clock.h @@ -0,0 +1,27 @@ +#ifndef SOCKS_CLOCK_H_ +#define SOCKS_CLOCK_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +#define HZ (clock_hz()) + +typedef uint64_t clock_ticks_t; + +extern volatile clock_ticks_t clock_ticks; + +extern clock_ticks_t clock_hz(void); + +extern void clock_calibrate(clock_ticks_t hz); +extern void clock_advance(clock_ticks_t ticks); +extern void clock_wait(clock_ticks_t ticks); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/kernel/clock.c b/kernel/clock.c new file mode 100644 index 0000000..e095f83 --- /dev/null +++ b/kernel/clock.c @@ -0,0 +1,29 @@ +#include +#include +#include + +static clock_ticks_t ticks_per_sec = 0; +volatile clock_ticks_t clock_ticks = 0; + +clock_ticks_t clock_hz(void) +{ + return ticks_per_sec; +} + +void clock_calibrate(clock_ticks_t hz) +{ + ticks_per_sec = hz; +} + +void clock_advance(clock_ticks_t ticks) +{ + clock_ticks += ticks; +} + +void clock_wait(clock_ticks_t ticks) +{ + clock_ticks_t end = clock_ticks + ticks; + while (clock_ticks < end) { + + } +}