Enable apic and ioapic

This commit is contained in:
Thomas Lovén 2022-01-17 00:13:17 +01:00
parent 95108d1c0a
commit 1d15768efb
4 changed files with 120 additions and 2 deletions

View File

@ -30,6 +30,8 @@ void kmain(uint64_t multiboot_magic, void *multiboot_data)
cpu_init(); cpu_init();
__asm__("sti");
debug_info("Boot complete\n"); debug_info("Boot complete\n");
@ -39,7 +41,7 @@ void kmain(uint64_t multiboot_magic, void *multiboot_data)
start_scheduler(); start_scheduler();
PANIC("End of kernel function!"); PANIC("End of kernel function!");
debug_info("Broke out of panic"); debug_info("Broke out of panic");
for(;;); for(;;);
} }

86
src/kernel/cpu/apic.c Normal file
View File

@ -0,0 +1,86 @@
#include <cpu.h>
#include <memory.h>
#include <debug.h>
#include <ports.h>
#define APIC_BASE 0xFEE00000
#define APIC_MSR_ENABLE (1<<11)
#define APIC_REG(r) (((uint32_t *)P2V(APIC_BASE + (r)))[0])
union ioapic_redirection{
uint64_t val;
struct {
uint32_t l;
uint32_t h;
}__attribute__((packed));
struct {
uint8_t vector;
uint8_t flags;
uint8_t mask;
uint32_t reserved;
uint8_t target;
}__attribute__((packed));
};
static uint32_t ioapic_read(int reg)
{
uint32_t volatile *ioregsel = P2V(ioapic.addr);
uint32_t volatile *iowin = P2V(ioapic.addr + 0x10);
*ioregsel = reg;
return *iowin;
}
static void ioapic_write(int reg, uint32_t value)
{
uint32_t volatile *ioregsel = P2V(ioapic.addr);
uint32_t volatile *iowin = P2V(ioapic.addr + 0x10);
*ioregsel = reg;
*iowin = value;
}
static uint64_t ioapic_read_redirection(int irq)
{
union ioapic_redirection retval;
retval.l = ioapic_read(0x10 + 2*irq);
retval.h = ioapic_read(0x11 + 2*irq);
return retval.val;
}
static void ioapic_write_redirection(int irq, uint64_t val)
{
union ioapic_redirection value;
value.val = val;
ioapic_write(0x10 + 2*irq, value.l);
ioapic_write(0x11 + 2*irq, value.h);
}
void ioapic_init()
{
vmm_set_page(kernel_P4, (uintptr_t)P2V(ioapic.addr), ioapic.addr, PAGE_PRESENT | PAGE_WRITE | PAGE_GLOBAL);
union ioapic_redirection red;
for(int i = 0; i < 24; i++)
{
red.val = ioapic_read_redirection(i);
red.vector = IRQ_BASE+i;
red.flags = 0x0;
if(i == 1) // Mask the timer interrupt
red.mask &= ~0x1;
else // but unmask all others for testing
red.mask |= 0x1;
red.target = 0x0;
ioapic_write_redirection(i, red.val);
}
}
void apic_init()
{
// Enable local APIC
write_msr(MSR_APIC_BASE, read_msr(MSR_APIC_BASE) | APIC_MSR_ENABLE);
// Map apic offset into kernel memory
vmm_set_page(kernel_P4, (uintptr_t)P2V(APIC_BASE), APIC_BASE, PAGE_PRESENT | PAGE_WRITE | PAGE_GLOBAL);
APIC_REG(0xF0) = APIC_REG(0xF0) | (1<<8);
APIC_REG(0xB0) = 0;
}

View File

@ -7,6 +7,26 @@ struct ioapic ioapic = {0,0,0};
uint8_t irq_redirects[MAX_IRQS] = \ uint8_t irq_redirects[MAX_IRQS] = \
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23}; {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23};
#define PIC1_ADDR 0x20
#define PIC2_ADDR 0xA0
#define PIC_INITIALIZE 0x10
#define PIC_SINGLE 0x02
static void pic_disable()
{
// Absolute minimum work to initialize and disable legacy PIC.
// Both the primary and secondary PIC will think they are alone
// in a MCS-80 arch computer but that doesn't matter since all
// interrupts will be masked anyway :)
// Ref: Intel 8259A Datasheet
outb(PIC1_ADDR, PIC_INITIALIZE | PIC_SINGLE);
outb(PIC2_ADDR, PIC_INITIALIZE | PIC_SINGLE);
outb(PIC1_ADDR | 1, 0);
outb(PIC2_ADDR | 1, 0);
// Mask all interrupts
outb(PIC1_ADDR | 1, 0xFF);
outb(PIC2_ADDR | 1, 0xFF);
}
void early_cpu_init() void early_cpu_init()
{ {
interrupt_init(); interrupt_init();
@ -15,4 +35,7 @@ void early_cpu_init()
void cpu_init() void cpu_init()
{ {
acpi_parse(); acpi_parse();
pic_disable();
apic_init();
ioapic_init();
} }

View File

@ -1,8 +1,11 @@
#pragma once #pragma once
#include <stdint.h> #include <stdint.h>
#define MSR_APIC_BASE 0x0000001B
#define MAX_CPUS 16 #define MAX_CPUS 16
#define MAX_IRQS 24 #define MAX_IRQS 24
#define IRQ_BASE 0x20
struct cpu { struct cpu {
uint8_t id; uint8_t id;
@ -30,4 +33,8 @@ uint64_t read_msr(uint32_t);
uint64_t write_msr(uint32_t msr, uint64_t value); uint64_t write_msr(uint32_t msr, uint64_t value);
// cpu/acpi.c // cpu/acpi.c
void acpi_parse(); void acpi_parse();
// cpu/apic.c
void apic_init();
void ioapic_init();