apic: init apic timer using pit, not precise on qemu
This commit is contained in:
@@ -125,4 +125,59 @@ void ioapic_redirect(int gsi, int vector) {
|
||||
void enable_symmetric_io_mode() {
|
||||
outb(0x22, 0x70); // Select IMCR
|
||||
outb(0x23, 0x01); // Set to Symmetric I/O mode (bypass PIC)
|
||||
}
|
||||
|
||||
#include "../include/isr.h"
|
||||
|
||||
#define APIC_REGISTER_TIMER_DIV 0x3E0
|
||||
#define APIC_REGISTER_TIMER_INITCNT 0x380
|
||||
#define APIC_REGISTER_LVT_TIMER 0x320
|
||||
#define APIC_LVT_INT_MASKED 0x10000
|
||||
#define APIC_REGISTER_TIMER_CURRCNT 0x390
|
||||
#define APIC_LVT_TIMER_MODE_PERIODIC (1 << 17)
|
||||
|
||||
void init_pit_timer_apic(uint32_t reload_value) {
|
||||
int timerFrequency = 1193182 / reload_value;
|
||||
|
||||
outb(0x43, 0b00110100);
|
||||
|
||||
uint8_t l = (uint8_t)(timerFrequency & 0xFF);
|
||||
uint8_t h = (uint8_t)(timerFrequency >> 8 & 0xFF);
|
||||
|
||||
outb(0x40, l);
|
||||
outb(0x40, h);
|
||||
}
|
||||
|
||||
void init_apic_timer()
|
||||
{
|
||||
lapic_write(APIC_REGISTER_TIMER_DIV, 0x3);
|
||||
|
||||
// Prepare the PIT to sleep for 10ms (10000µs)
|
||||
init_pit_timer_apic(1000);
|
||||
|
||||
__asm__ __volatile__ ("sti");
|
||||
|
||||
// Set APIC init counter to -1
|
||||
lapic_write(APIC_REGISTER_TIMER_INITCNT, 0xFFFFFFFF);
|
||||
|
||||
uint32_t target_ticks = timer_ticks + 10;//+10ms
|
||||
while(timer_ticks < target_ticks)
|
||||
{}
|
||||
|
||||
// Stop the APIC timer
|
||||
lapic_write(APIC_REGISTER_LVT_TIMER, APIC_LVT_INT_MASKED);
|
||||
|
||||
// Now we know how often the APIC timer has ticked in 10ms
|
||||
uint32_t ticksIn10ms = 0xFFFFFFFF - lapic_read(APIC_REGISTER_TIMER_CURRCNT);
|
||||
|
||||
// Start timer as periodic on IRQ 0, divider 16, with the number of ticks we counted
|
||||
lapic_write(APIC_REGISTER_LVT_TIMER, 32 | APIC_LVT_TIMER_MODE_PERIODIC);
|
||||
lapic_write(APIC_REGISTER_TIMER_DIV, 0x3);
|
||||
lapic_write(APIC_REGISTER_TIMER_INITCNT, ticksIn10ms);
|
||||
}
|
||||
|
||||
void mask_pit_interrupt() {
|
||||
// Mask PIT interrupt (GSI 0, IRQ 0)
|
||||
ioapic_write(ioapic_ptr, REG_TABLE + 2 * 0, INT_DISABLED | T_IRQ0);
|
||||
ioapic_write(ioapic_ptr, REG_TABLE + 2 * 0 + 1, 0); // Clear destination field
|
||||
}
|
||||
@@ -110,8 +110,11 @@ __attribute__((interrupt)) void spurious(struct interrupt_frame *frame)
|
||||
lapic_eoi();
|
||||
}
|
||||
|
||||
uint32_t timer_ticks = 0;
|
||||
|
||||
__attribute__((interrupt)) void isr_timer(struct interrupt_frame *frame)
|
||||
{
|
||||
timer_ticks++;
|
||||
if(lapic_enabled)
|
||||
{
|
||||
lapic_eoi();
|
||||
|
||||
@@ -73,6 +73,9 @@ void kmain(unsigned int magic, unsigned int info)
|
||||
printf("IOAPIC init done\n");
|
||||
ioapic_redirect(2, 32);//timer
|
||||
ioapic_redirect(1, 33);//keyboard
|
||||
|
||||
init_apic_timer();
|
||||
mask_pit_interrupt();
|
||||
}
|
||||
|
||||
printf("done fucking with pages and memory map!\n");
|
||||
@@ -132,6 +135,11 @@ void kmain(unsigned int magic, unsigned int info)
|
||||
|
||||
while(1)
|
||||
{
|
||||
if(timer_ticks % 1000 == 0)
|
||||
{
|
||||
//printf("a second should have passed!\n");
|
||||
}
|
||||
|
||||
/* if(inportb(0x64) & 0x1)
|
||||
{
|
||||
unsigned char key = inportb(0x60);
|
||||
|
||||
Reference in New Issue
Block a user