The PIT code is as follows:
Code: Select all
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
/*
* CLOSEST(x, a, b) determines whether x is closer to a or b.
* If x is closer to b then CLOSEST(x, a, b) > 0.
* If x is closer to a then CLOSEST(x, a, b) < 0.
* If x is equally close to both a and b then CLOSEST(x, a, b) = 0.
*/
#define CLOSEST(x, low, high) \
((x) - (low) > (high) - (x) ? 1 : (x) - (low) < (high) - (x) ? -1 : 0)
#define RELOAD(frequency) (PIT_MAX_FREQUENCY / (frequency))
#define FREQ(reload) (PIT_MAX_FREQUENCY / (reload))
static struct timespec irq_interval = {0};
static struct timespec pit_timer = {0};
static uint32_t pit_frequency;
static uint16_t pit_reload;
static void irq0_handler(unsigned irq_line);
void pit_init(void) { irq_set_handler(0, irq0_handler); }
void pit_set_frequency(uint32_t frequency) {
frequency = MIN(MAX(frequency, PIT_MIN_FREQUENCY), PIT_MAX_FREQUENCY);
pit_reload = MIN(RELOAD(frequency), UINT16_MAX);
if (CLOSEST(frequency, FREQ(pit_reload), FREQ(pit_reload + 1)) > 0)
++pit_reload;
pit_frequency = FREQ(pit_reload);
irq_interval.tv_nsec = 1000000000 / pit_frequency;
__asm__("cli");
port_out8(PORT_PIT_CMD, pit_cmd(0, PIT_ACCESS_FULL, 2));
port_out8(PORT_PIT_CH0_DATA, (pit_reload >> 0) & 0xFF);
port_out8(PORT_PIT_CH0_DATA, (pit_reload >> 8) & 0xFF);
__asm__("sti");
}
const struct timespec *pit_get_global_timer(void) { return &pit_timer; }
static void irq0_handler(unsigned irq_line) {
bext_timespec_add(&pit_timer, &irq_interval);
pic_send_eoi(irq_line);
}
Code: Select all
void kernel_main(void) {
putchar('\f');
gdt_init();
idt_init();
pic_init();
pit_init();
pit_set_frequency(10000);
for (;;) {
volatile const struct timespec *timer = pit_get_global_timer();
bext_printf_basic(
"%us %uns\r", (unsigned)timer->tv_sec, (unsigned)timer->tv_nsec
);
}
}