diff --git a/kernel/boot/kmain.c b/kernel/boot/kmain.c index 68605ac..9adfacd 100644 --- a/kernel/boot/kmain.c +++ b/kernel/boot/kmain.c @@ -8,6 +8,7 @@ #include #include #include +#include void thread_function() { @@ -33,6 +34,7 @@ int kmain(uint64_t multiboot_magic, void *multiboot_data) scheduler_init(); pic_init(); acpi_init(); + apic_init(); process_t *p1 = process_spawn(0); diff --git a/kernel/include/apic.h b/kernel/include/apic.h new file mode 100644 index 0000000..f72c284 --- /dev/null +++ b/kernel/include/apic.h @@ -0,0 +1,11 @@ +#pragma once +#include + +void apic_init(); +void apic_interrupt(uint8_t destination, uint8_t level, uint8_t type, uint8_t vector); +void apic_ack(); +#define APIC_INT_LEVEL_ASSERT 0x1 +#define APIC_INT_LEVEL_DEASSERT 0x0 +#define APIC_INT_TYPE_FIXED 0x0 +#define APIC_INT_TYPE_INIT 0x5 +#define APIC_INT_TYPE_STARTUP 0x6 diff --git a/kernel/include/int.h b/kernel/include/int.h index 9e173a7..608177a 100644 --- a/kernel/include/int.h +++ b/kernel/include/int.h @@ -58,6 +58,14 @@ #define INT_IRQ22 0x36 #define INT_IRQ23 0x37 +#define INT_APIC_TIMER 0x40 +#define INT_APIC_THERMAL 0x41 +#define INT_APIC_PERF 0x42 +#define INT_APIC_LINT0 0x43 +#define INT_APIC_LINT1 0x44 +#define INT_APIC_ERROR 0x45 +#define INT_APIC_SPUR 0xFF + #ifndef __ASSEMBLER__ #include diff --git a/kernel/interrupts/apic.c b/kernel/interrupts/apic.c new file mode 100644 index 0000000..213c316 --- /dev/null +++ b/kernel/interrupts/apic.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include + +#define APIC_MSR_ENABLE 0x800 + +#define APIC_BASE 0xFEE00000 + +#define R_ID 0x020 +#define R_VERSION 0x030 +#define R_EOI 0x0B0 +#define R_LDR 0x0D0 +#define R_SPURIOUS 0x0F0 +#define R_INT_CMD_LO 0x300 +#define R_INT_CMD_HI 0x310 +#define R_TIMER_LVT 0x320 +#define R_THERMAL_LVT 0x330 +#define R_PERF_LVT 0x340 +#define R_LINT0_LVT 0x350 +#define R_LINT1_LVT 0x360 +#define R_ERROR_LVT 0x370 +#define LVT_MASKED 0x10000 + +#define SPURIOUS_LVT_ENABLED 0x100 + +#define APIC(reg) apic[reg/4] +uint32_t volatile *apic = P2V(APIC_BASE); + +void apic_interrupt(uint8_t destination, uint8_t level, uint8_t type, uint8_t vector) +{ + uint64_t data = ((level & 0x1)<<14) | ((type & 0x7)<<8) | vector; + APIC(R_INT_CMD_HI) = destination << 24; + APIC(R_INT_CMD_LO) = data; +} + +void apic_ack() +{ + APIC(R_EOI) = 0; +} + +void apic_init() +{ + debug_info("APIC - APIC_BASE MSR: %x\n", msr_read(MSR_APIC_BASE)); + // Enable APIC by setting the enable bit in the APIC MSR + msr_write(MSR_APIC_BASE, msr_read(MSR_APIC_BASE) | APIC_MSR_ENABLE); + + // Make sure the APIC base addres is mapped in kernel memory + vmm_set_page(0, (uintptr_t)P2V(APIC_BASE), APIC_BASE, PAGE_PRESENT | PAGE_WRITE); + + debug_info("APIC - ID: %x\n", APIC(R_ID)); + debug_info("APIC - Version: %x\n", APIC(R_VERSION)); + + uint8_t id = APIC(R_ID) >> 24; + if(id <= 0) + APIC(R_LDR) = 1 << (24 + id); + + APIC(R_SPURIOUS) = SPURIOUS_LVT_ENABLED | INT_APIC_SPUR; + APIC(R_EOI) = 0; +}