#include #include "interrupt.h" #include "kernel.h" #include "timer.h" #include "ioport.h" #include "cpu.h" #include static struct interrupt_handler timer; /* This will keep track of how many ticks that the system * has been running for */ volatile uint64_t timer_ticks = 0; static int timer_hz = 18; static uint64_t timer_ns; /* nanoseconds per time tick */ struct timespec system_time; /* global system time */ #define ONE_BILLION 1000000000ULL /* See http://wiki.osdev.org/Programmable_Interval_Timer * for a possibly better algorithm */ static void setfreq(int hz) { int enable; unsigned int divisor; if (hz < 18) hz = 18; divisor = 1193182/hz; timer_hz = 1193182 / divisor; #if 0 printk("timer hz %llu\n", (uint64_t)hz); printk("timer divisor %u\n", divisor); printk("timer hz actual %llu\n", (uint64_t)timer_hz); #endif enable = interrupts_enabled(); if (enable) disable_interrupts(); outport8(0x43, 0x34); outport8(0x40, (uint8_t)(divisor & 0xFF)); /* Set low byte of divisor */ outport8(0x40, (uint8_t)(divisor >> 8 & 0xFF)); /* Set high byte of divisor */ timer_ns = (uint64_t)1000000000ULL / timer_hz; /* now, let's disable the pit and use the RTC */ if (enable) enable_interrupts(); } static void timer_handler(struct interrupt_context *c, void *unused) { timer_ticks++; system_time.tv_nsec += timer_ns; while (system_time.tv_nsec >= ONE_BILLION) { system_time.tv_sec++; system_time.tv_nsec -= ONE_BILLION; } } void init_timer(int hz) { int enable; timer.handler = timer_handler; timer.context = 0; system_time.tv_sec = 0; system_time.tv_nsec = 0; enable = interrupts_enabled(); if (enable) disable_interrupts(); interrupt_add_handler(IRQ0, &timer); setfreq(hz); if (enable) enable_interrupts(); }