From 649c4c56a4329e1d5ce9b60f5b054bdb9707f454 Mon Sep 17 00:00:00 2001 From: Ruslan Isaev Date: Sat, 30 Aug 2025 20:57:44 +0300 Subject: [PATCH] apic: fix timer and keyboard handling --- include/apic.h | 9 +++++- src/kernel/apic.c | 67 +++++++++++++++++++++++++++++++++++++++------ src/kernel/isr.c | 8 ++++++ src/kernel/kernel.c | 5 ++++ 4 files changed, 79 insertions(+), 10 deletions(-) diff --git a/include/apic.h b/include/apic.h index 338e597..c2466f3 100644 --- a/include/apic.h +++ b/include/apic.h @@ -10,4 +10,11 @@ void enable_apic(); void lapic_write(uint32_t reg_offset, uint32_t value); uint32_t lapic_read(uint32_t reg_offset); -void lapic_eoi(); \ No newline at end of file +void lapic_eoi(); + +void ioapic_init(); +uint32_t ioapic_read(void *ioapicaddr, uint32_t reg); +void ioapic_write(void *ioapicaddr, uint32_t reg, uint32_t value); +void ioapic_redirect(int gsi, int vector); + +void enable_symmetric_io_mode(); \ No newline at end of file diff --git a/src/kernel/apic.c b/src/kernel/apic.c index 05514ae..6dabd5f 100644 --- a/src/kernel/apic.c +++ b/src/kernel/apic.c @@ -9,7 +9,15 @@ #define LAPIC_EOI_REG 0x0B0 // End-of-Interrupt Register #define LAPIC_SPURIOUS_REG 0x0F0 // Spurious Interrupt Vector Register -#define PAGE_PRESENT (1 << 0) +#define IOAPIC_REGSEL 0x00 +#define IOAPIC_IOWIN 0x10 + +#define REG_VER 0x1 +#define REG_ID 0x0 +#define T_IRQ0 32 +#define REG_TABLE 0x10 +#define INT_DISABLED 0x10000 + #define PAGE_WRITE (1 << 1) #define PAGE_WRITE_THROUGH (1 << 3) #define PAGE_CACHE_DISABLE (1 << 4) @@ -18,6 +26,7 @@ const unsigned int APIC_PAGE_FLAGS = PAGE_PRESENT | PAGE_WRITE | PAGE_WRITE_THRO bool lapic_enabled = false; volatile uint32_t* lapic_ptr = NULL; +volatile uint32_t* ioapic_ptr = NULL; bool check_apic() { @@ -29,7 +38,7 @@ bool check_apic() void cpu_set_apic_base(uintptr_t apic) { uint32_t edx = 0; - uint32_t eax = (apic & 0xfffff0000) | IA32_APIC_BASE_MSR_ENABLE; + uint32_t eax = (apic & 0xfffff000) | IA32_APIC_BASE_MSR_ENABLE; #ifdef __PHYSICAL_MEMORY_EXTENSION__ edx = (apic >> 32) & 0x0f; @@ -61,19 +70,59 @@ uintptr_t cpu_get_apic_base() { lapic_ptr = (uint32_t*)cpu_get_apic_base(); /* Set the Spurious Interrupt Vector Register bit 8 to start receiving interrupts */ - lapic_write(0xF0, lapic_read(0xF0) | 0x100); + lapic_write(LAPIC_SPURIOUS_REG, 0x1FF); } void lapic_write(uint32_t offset, uint32_t value) { - uint32_t volatile *ptr = (uint32_t volatile *)(lapic_ptr + offset); - *ptr = value; - } - + *(volatile uint32_t*)((uintptr_t)lapic_ptr + offset) = value; +} + uint32_t lapic_read(uint32_t offset) { - uint32_t volatile *ptr = (uint32_t volatile *)(lapic_ptr + offset); - return *ptr; + return *(volatile uint32_t*)((uintptr_t)lapic_ptr + offset); } void lapic_eoi() { lapic_write(LAPIC_EOI_REG, 0); +} + +void ioapic_init() +{ + ioapic_ptr = (uint32_t*)0xFEC00000; + + map_page((void*)ioapic_ptr, (void*)ioapic_ptr, APIC_PAGE_FLAGS); + + int maxintr = (ioapic_read(ioapic_ptr, REG_VER) >> 16) & 0xFF; + + // Mark all interrupts edge-triggered, active high, disabled, + // and not routed to any CPUs. + for(int i = 0; i <= maxintr; i++){ + ioapic_write(ioapic_ptr, REG_TABLE+2*i, INT_DISABLED | (T_IRQ0 + i)); + ioapic_write(ioapic_ptr, REG_TABLE+2*i+1, 0); + } +} + +uint32_t ioapic_read(void *ioapicaddr, uint32_t reg) +{ + *(volatile uint32_t*)((uintptr_t)ioapicaddr + IOAPIC_REGSEL) = (reg & 0xff); + return *(volatile uint32_t*)((uintptr_t)ioapicaddr + IOAPIC_IOWIN); +} + +void ioapic_write(void *ioapicaddr, uint32_t reg, uint32_t value) +{ + *(volatile uint32_t*)((uintptr_t)ioapicaddr + IOAPIC_REGSEL) = (reg & 0xff); + *(volatile uint32_t*)((uintptr_t)ioapicaddr + IOAPIC_IOWIN) = value; +} + +uint32_t get_lapic_id() { + return lapic_read(LAPIC_ID_REG) >> 24; +} + +void ioapic_redirect(int gsi, int vector) { + ioapic_write(ioapic_ptr, REG_TABLE + 2 * gsi, vector); + ioapic_write(ioapic_ptr, REG_TABLE + 2 * gsi + 1, get_lapic_id() << 24); +} + +void enable_symmetric_io_mode() { + outb(0x22, 0x70); // Select IMCR + outb(0x23, 0x01); // Set to Symmetric I/O mode (bypass PIC) } \ No newline at end of file diff --git a/src/kernel/isr.c b/src/kernel/isr.c index 21f057c..24cbffc 100644 --- a/src/kernel/isr.c +++ b/src/kernel/isr.c @@ -19,6 +19,7 @@ struct interrupt_frame uword_t ss; }; +__attribute__((interrupt)) void spurious(struct interrupt_frame *frame); __attribute__((interrupt)) void isr_timer(struct interrupt_frame *frame); void isr_custom(); void default_handler(); @@ -68,6 +69,8 @@ void isr_install() { idt_set_descriptor(0x80, (uint32)sys_exit_handler, 0xEE); + idt_set_descriptor(255, (uint32)spurious, 0x8E); + idt_set(); // Load with ASM printf("isr_install done\n"); } @@ -102,6 +105,11 @@ void handle_page_fault(uint32_t error_code, uint32_t faulting_address) asm("hlt"); } +__attribute__((interrupt)) void spurious(struct interrupt_frame *frame) +{ + lapic_eoi(); +} + __attribute__((interrupt)) void isr_timer(struct interrupt_frame *frame) { if(lapic_enabled) diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 4b70b1e..05d6eaf 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -67,7 +67,12 @@ void kmain(unsigned int magic, unsigned int info) else { pic_disable(); + enable_symmetric_io_mode(); enable_apic(); + ioapic_init(); + printf("IOAPIC init done\n"); + ioapic_redirect(2, 32);//timer + ioapic_redirect(1, 33);//keyboard } printf("done fucking with pages and memory map!\n");