Enable and calibrate apic timer
This commit is contained in:
parent
2e8efd4117
commit
7e3febe699
@ -26,4 +26,5 @@ void cpu_init() {
|
|||||||
pic_disable();
|
pic_disable();
|
||||||
apic_init();
|
apic_init();
|
||||||
ioapic_init();
|
ioapic_init();
|
||||||
|
timer_init();
|
||||||
}
|
}
|
77
src/kernel/cpu/timer.c
Normal file
77
src/kernel/cpu/timer.c
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <cpu.h>
|
||||||
|
#include <ports.h>
|
||||||
|
|
||||||
|
#define PC_SPKR 0x61
|
||||||
|
#define PIT_CH2 0x42
|
||||||
|
#define PIT_CMD 0x43
|
||||||
|
|
||||||
|
#define PIT_FREQ 1193182
|
||||||
|
|
||||||
|
#define APIC_TIMER_DIVIDER 0x3E0
|
||||||
|
#define APIC_TIMER_INIT 0x380
|
||||||
|
#define APIC_TIMER_CURRENT 0x390
|
||||||
|
|
||||||
|
volatile uint32_t apic_ticks_per_us = 1;
|
||||||
|
|
||||||
|
static void pit_setup(uint8_t ms) {
|
||||||
|
// Disable the pc speaker output
|
||||||
|
uint8_t spkr = inb(PC_SPKR);
|
||||||
|
spkr &= ~0x1;
|
||||||
|
outb(PC_SPKR, spkr);
|
||||||
|
|
||||||
|
// Set up PIT for a single interrupt on CH2
|
||||||
|
outb(PIT_CMD, 0x80 | 0x30);
|
||||||
|
|
||||||
|
// Set up CH2 for counting down from a number of ms
|
||||||
|
uint64_t count = PIT_FREQ * ms/1000;
|
||||||
|
outb(PIT_CH2, count & 0xFF);
|
||||||
|
outb(PIT_CH2, (count >> 8) & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pit_wait() {
|
||||||
|
|
||||||
|
// Enable pc speaker
|
||||||
|
uint8_t spkr = inb(PC_SPKR);
|
||||||
|
spkr |= 0x1;
|
||||||
|
outb(PC_SPKR, spkr);
|
||||||
|
|
||||||
|
// Wait until there's a speaker output
|
||||||
|
while(!(inb(PC_SPKR) & 0x20));
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t calibrate_apic_timer() {
|
||||||
|
pit_setup(10);
|
||||||
|
|
||||||
|
APIC_REG(APIC_TIMER_DIVIDER) = 0xB;
|
||||||
|
APIC_REG(APIC_LVT(LVT_TIMER)) = 1<<16; // Mask
|
||||||
|
APIC_REG(APIC_TIMER_INIT) = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
pit_wait();
|
||||||
|
|
||||||
|
uint32_t ticks = APIC_REG(APIC_TIMER_CURRENT);
|
||||||
|
return (0xFFFFFFFF-ticks)/10/1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_apic_timer(uint64_t us) {
|
||||||
|
APIC_REG(APIC_TIMER_DIVIDER) = 0xB;
|
||||||
|
APIC_REG(APIC_TIMER_INIT) = us*apic_ticks_per_us;
|
||||||
|
APIC_REG(APIC_LVT(LVT_TIMER)) = 0x0 | IRQ_INTERRUPT(IRQ_TIMER);
|
||||||
|
}
|
||||||
|
|
||||||
|
volatile int ctr = 0;
|
||||||
|
|
||||||
|
registers *apic_timer_handler(registers *r) {
|
||||||
|
|
||||||
|
ctr++;
|
||||||
|
__asm__("cli");
|
||||||
|
reset_apic_timer(1000);
|
||||||
|
irq_ack();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void timer_init() {
|
||||||
|
apic_ticks_per_us = calibrate_apic_timer();
|
||||||
|
bind_interrupt(IRQ_INTERRUPT(IRQ_TIMER), apic_timer_handler);
|
||||||
|
reset_apic_timer(1000);
|
||||||
|
}
|
@ -11,6 +11,7 @@
|
|||||||
#define IRQ_INTERRUPT(irq) (IRQ_BASE + (irq))
|
#define IRQ_INTERRUPT(irq) (IRQ_BASE + (irq))
|
||||||
|
|
||||||
#define IRQ_PS2_KBD 0x1
|
#define IRQ_PS2_KBD 0x1
|
||||||
|
#define IRQ_TIMER 0x20
|
||||||
#define IRQ_SPURIOUS 0xFF
|
#define IRQ_SPURIOUS 0xFF
|
||||||
|
|
||||||
#define APIC_BASE 0xFEE00000
|
#define APIC_BASE 0xFEE00000
|
||||||
@ -91,4 +92,6 @@ void irq_ack();
|
|||||||
void irq_mask(int irq);
|
void irq_mask(int irq);
|
||||||
void irq_unmask(int irq);
|
void irq_unmask(int irq);
|
||||||
void ioapic_init();
|
void ioapic_init();
|
||||||
void apic_init();
|
|
||||||
|
// cpu/timer.c
|
||||||
|
void timer_init();
|
Loading…
x
Reference in New Issue
Block a user