feat/kernel: im stuck in the apic jungle and need help
This commit is contained in:
parent
f81181ea9c
commit
322e95fe98
10 changed files with 240 additions and 71 deletions
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -27,7 +27,8 @@
|
||||||
"acpi.h": "c",
|
"acpi.h": "c",
|
||||||
"madt.h": "c",
|
"madt.h": "c",
|
||||||
"ioapic.h": "c",
|
"ioapic.h": "c",
|
||||||
"stdatomic.h": "c"
|
"stdatomic.h": "c",
|
||||||
|
"pit.h": "c"
|
||||||
},
|
},
|
||||||
"editor.formatOnPaste": true,
|
"editor.formatOnPaste": true,
|
||||||
"editor.formatOnSave": true,
|
"editor.formatOnSave": true,
|
||||||
|
|
|
@ -15,7 +15,7 @@ all: $(IMAGE_NAME).iso
|
||||||
.PHONY: run
|
.PHONY: run
|
||||||
run: $(IMAGE_NAME).iso ovmf/ovmf-code-x86_64.fd
|
run: $(IMAGE_NAME).iso ovmf/ovmf-code-x86_64.fd
|
||||||
@qemu-system-x86_64 \
|
@qemu-system-x86_64 \
|
||||||
-M q35 -serial stdio \
|
-M q35 -monitor stdio -serial file:com1.log \
|
||||||
-drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-x86_64.fd,readonly=on \
|
-drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-x86_64.fd,readonly=on \
|
||||||
-cdrom $(IMAGE_NAME).iso \
|
-cdrom $(IMAGE_NAME).iso \
|
||||||
$(QEMUFLAGS)
|
$(QEMUFLAGS)
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
#include <arch/paging.h>
|
#include <arch/paging.h>
|
||||||
#include <util/align.h>
|
#include <util/align.h>
|
||||||
#include <mm/pmm.h>
|
#include <mm/pmm.h>
|
||||||
|
#include <arch/gdt.h>
|
||||||
|
#include <arch/idt.h>
|
||||||
|
|
||||||
#define MAX_CPUS 256
|
#define MAX_CPUS 256
|
||||||
#define MSR_GS_BASE 0xC0000101
|
#define MSR_GS_BASE 0xC0000101
|
||||||
|
@ -53,6 +55,8 @@ void smp_entry(struct limine_mp_info *smp_info)
|
||||||
set_cpu_local(cpu);
|
set_cpu_local(cpu);
|
||||||
|
|
||||||
/* Setup core */
|
/* Setup core */
|
||||||
|
gdt_init();
|
||||||
|
idt_init();
|
||||||
pmset(kernel_pagemap);
|
pmset(kernel_pagemap);
|
||||||
lapic_enable();
|
lapic_enable();
|
||||||
|
|
||||||
|
|
32
kernel/src/dev/pit.c
Normal file
32
kernel/src/dev/pit.c
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
/* EMK 1.0 Copyright (c) 2025 Piraterna */
|
||||||
|
#include <dev/pit.h>
|
||||||
|
#include <arch/io.h>
|
||||||
|
#include <sys/apic/lapic.h>
|
||||||
|
#include <sys/apic/ioapic.h>
|
||||||
|
#include <util/log.h>
|
||||||
|
|
||||||
|
#define PIT_VECTOR 32
|
||||||
|
|
||||||
|
void (*pit_callback)(struct register_ctx *ctx) = NULL;
|
||||||
|
|
||||||
|
void pit_handler(struct register_ctx *frame)
|
||||||
|
{
|
||||||
|
if (pit_callback)
|
||||||
|
pit_callback(frame);
|
||||||
|
lapic_eoi();
|
||||||
|
}
|
||||||
|
|
||||||
|
void pit_init(idt_intr_handler handler)
|
||||||
|
{
|
||||||
|
if (handler)
|
||||||
|
pit_callback = handler;
|
||||||
|
|
||||||
|
outb(0x43, 0x36);
|
||||||
|
|
||||||
|
uint16_t divisor = 5966;
|
||||||
|
outb(0x40, divisor & 0xFF);
|
||||||
|
outb(0x40, (divisor >> 8) & 0xFF);
|
||||||
|
|
||||||
|
ioapic_map(0, PIT_VECTOR, pit_handler, 0);
|
||||||
|
ioapic_unmask(0);
|
||||||
|
}
|
9
kernel/src/dev/pit.h
Normal file
9
kernel/src/dev/pit.h
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
/* EMK 1.0 Copyright (c) 2025 Piraterna */
|
||||||
|
#ifndef PIT_H
|
||||||
|
#define PIT_H
|
||||||
|
|
||||||
|
#include <arch/idt.h>
|
||||||
|
|
||||||
|
void pit_init(idt_intr_handler handler);
|
||||||
|
|
||||||
|
#endif // PIT_H
|
|
@ -22,6 +22,7 @@
|
||||||
#include <sys/acpi/madt.h>
|
#include <sys/acpi/madt.h>
|
||||||
#include <sys/apic/lapic.h>
|
#include <sys/apic/lapic.h>
|
||||||
#include <sys/apic/ioapic.h>
|
#include <sys/apic/ioapic.h>
|
||||||
|
#include <dev/pit.h>
|
||||||
|
|
||||||
__attribute__((used, section(".limine_requests"))) static volatile LIMINE_BASE_REVISION(3);
|
__attribute__((used, section(".limine_requests"))) static volatile LIMINE_BASE_REVISION(3);
|
||||||
__attribute__((used, section(".limine_requests"))) static volatile struct limine_memmap_request memmap_request = {
|
__attribute__((used, section(".limine_requests"))) static volatile struct limine_memmap_request memmap_request = {
|
||||||
|
@ -66,6 +67,11 @@ struct limine_mp_response *mp_response = NULL;
|
||||||
struct flanterm_context *ft_ctx = NULL;
|
struct flanterm_context *ft_ctx = NULL;
|
||||||
#endif // FLANTERM_SUPPORT
|
#endif // FLANTERM_SUPPORT
|
||||||
|
|
||||||
|
void tick(struct register_ctx *)
|
||||||
|
{
|
||||||
|
log_early("tick");
|
||||||
|
}
|
||||||
|
|
||||||
void emk_entry(void)
|
void emk_entry(void)
|
||||||
{
|
{
|
||||||
__asm__ volatile("movq %%rsp, %0" : "=r"(kstack_top));
|
__asm__ volatile("movq %%rsp, %0" : "=r"(kstack_top));
|
||||||
|
@ -187,11 +193,8 @@ void emk_entry(void)
|
||||||
madt_init(); // Also init MADT, to prepare for APIC
|
madt_init(); // Also init MADT, to prepare for APIC
|
||||||
|
|
||||||
/* Disable legacy PIC to prepare for APIC */
|
/* Disable legacy PIC to prepare for APIC */
|
||||||
outb(0x21, 0xff);
|
outb(0x21, 0xFF);
|
||||||
outb(0xA1, 0xff);
|
outb(0xA1, 0xFF);
|
||||||
|
|
||||||
/* Setup LAPIC */
|
|
||||||
lapic_init();
|
|
||||||
|
|
||||||
/* Setup SMP */
|
/* Setup SMP */
|
||||||
if (!mp_request.response)
|
if (!mp_request.response)
|
||||||
|
@ -200,14 +203,17 @@ void emk_entry(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_response = mp_request.response;
|
mp_response = mp_request.response;
|
||||||
|
lapic_init();
|
||||||
smp_init();
|
smp_init();
|
||||||
|
|
||||||
/* Setup IOAPIC */
|
/* Setup IOAPIC */
|
||||||
ioapic_init();
|
ioapic_init();
|
||||||
|
|
||||||
|
/* Setup timer */
|
||||||
|
pit_init(tick);
|
||||||
|
|
||||||
/* Finished */
|
/* Finished */
|
||||||
log_early("%s", LOG_SEPARATOR);
|
log_early("%s", LOG_SEPARATOR);
|
||||||
log_early("Finished initializing EMK v1.0, took ? seconds"); /* Still not usermode, so keep using log_early */
|
log_early("Finished initializing EMK v1.0, took ? seconds"); /* Still not usermode, so keep using log_early */
|
||||||
|
|
||||||
hlt();
|
hlt();
|
||||||
}
|
}
|
|
@ -5,60 +5,159 @@
|
||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
#include <util/log.h>
|
#include <util/log.h>
|
||||||
#include <arch/paging.h>
|
#include <arch/paging.h>
|
||||||
#include <boot/emk.h>
|
|
||||||
#include <arch/idt.h>
|
#include <arch/idt.h>
|
||||||
#include <arch/smp.h>
|
#include <arch/smp.h>
|
||||||
|
#include <arch/io.h>
|
||||||
|
#include <sys/apic/lapic.h>
|
||||||
|
|
||||||
atomic_uintptr_t ioapic_base = 0;
|
static atomic_uintptr_t ioapic_base = 0;
|
||||||
|
|
||||||
|
// Helper function to translate IRQ to GSI based on MADT ISO entries
|
||||||
|
static uint32_t irq_to_gsi(uint32_t irq)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < madt_iso_len; i++)
|
||||||
|
{
|
||||||
|
struct acpi_madt_ioapic_src_ovr *iso = madt_iso_list[i];
|
||||||
|
if (iso->irq_source == irq)
|
||||||
|
{
|
||||||
|
return iso->gsi;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// No override; assume IRQ == GSI
|
||||||
|
return irq;
|
||||||
|
}
|
||||||
|
|
||||||
void ioapic_write(uint8_t index, uint32_t value)
|
void ioapic_write(uint8_t index, uint32_t value)
|
||||||
{
|
{
|
||||||
volatile uint32_t *ioapic = (volatile uint32_t *)atomic_load(&ioapic_base);
|
volatile uint32_t *ioapic = (volatile uint32_t *)atomic_load(&ioapic_base);
|
||||||
ioapic[IOAPIC_OFF_IOREGSEL / 4] = index; // Write register index to IOREGSEL
|
if (!ioapic)
|
||||||
ioapic[IOAPIC_OFF_IOWIN / 4] = value; // Write value to IOWIN
|
{
|
||||||
|
log_early("error: IOAPIC not initialized");
|
||||||
|
kpanic(NULL, "IOAPIC write before init");
|
||||||
|
}
|
||||||
|
ioapic[IOAPIC_OFF_IOREGSEL / 4] = index;
|
||||||
|
ioapic[IOAPIC_OFF_IOWIN / 4] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t ioapic_read(uint8_t index)
|
uint32_t ioapic_read(uint8_t index)
|
||||||
{
|
{
|
||||||
volatile uint32_t *ioapic = (volatile uint32_t *)atomic_load(&ioapic_base);
|
volatile uint32_t *ioapic = (volatile uint32_t *)atomic_load(&ioapic_base);
|
||||||
ioapic[IOAPIC_OFF_IOREGSEL / 4] = index; // Write register index to IOREGSEL
|
if (!ioapic)
|
||||||
return ioapic[IOAPIC_OFF_IOWIN / 4]; // Read value from IOWIN
|
{
|
||||||
|
log_early("error: IOAPIC not initialized");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ioapic[IOAPIC_OFF_IOREGSEL / 4] = index;
|
||||||
|
return ioapic[IOAPIC_OFF_IOWIN / 4];
|
||||||
}
|
}
|
||||||
|
|
||||||
void ioapic_map(int irq, int vec, idt_intr_handler handler)
|
void ioapic_map(int irq, int vec, idt_intr_handler handler, uint8_t dest_mode)
|
||||||
{
|
{
|
||||||
uint32_t redtble_lo = (0 << 16) | /* Unmask the entry */
|
uint32_t gsi = irq_to_gsi(irq);
|
||||||
(0 << 11) | /* Dest mode */
|
uint32_t max_irqs = ((ioapic_read(IOAPIC_IDX_IOAPICVER) >> 16) & 0xFF) + 1;
|
||||||
(0 << 8) | /* Delivery mode */
|
if (gsi >= max_irqs)
|
||||||
vec; /* Interrupt vector*/
|
{
|
||||||
ioapic_write(2 * irq, redtble_lo);
|
log_early("error: Invalid GSI %u for IRQ %d (max %u)", gsi, irq, max_irqs);
|
||||||
|
kpanic(NULL, "Invalid GSI for IOAPIC");
|
||||||
|
}
|
||||||
|
if (vec < 32 || vec > 255 || vec == LAPIC_SPURIOUS_VECTOR)
|
||||||
|
{
|
||||||
|
log_early("error: Invalid vector 0x%x for IRQ %d (GSI %u)", vec, irq, gsi);
|
||||||
|
kpanic(NULL, "Invalid vector");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t redtble_lo = (1 << 16) | // Masked by default
|
||||||
|
(dest_mode << 11) | // 0: Physical, 1: Logical
|
||||||
|
(0 << 8) | // Fixed delivery
|
||||||
|
vec;
|
||||||
uint32_t redtble_hi = (get_cpu_local()->lapic_id << 24);
|
uint32_t redtble_hi = (get_cpu_local()->lapic_id << 24);
|
||||||
ioapic_write(2 * irq + 1, redtble_hi);
|
ioapic_write(0x10 + 2 * gsi, redtble_lo);
|
||||||
idt_register_handler(vec, handler);
|
ioapic_write(0x10 + 2 * gsi + 1, redtble_hi);
|
||||||
|
|
||||||
|
if (handler)
|
||||||
|
{
|
||||||
|
idt_register_handler(vec, handler);
|
||||||
|
}
|
||||||
|
log_early("Mapped IRQ %d (GSI %u) to vector 0x%x on CPU %u", irq, gsi, vec, get_cpu_local()->lapic_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ioapic_init()
|
void ioapic_unmask(int irq)
|
||||||
|
{
|
||||||
|
uint32_t gsi = irq_to_gsi(irq);
|
||||||
|
uint32_t max_irqs = ((ioapic_read(IOAPIC_IDX_IOAPICVER) >> 16) & 0xFF) + 1;
|
||||||
|
if (gsi >= max_irqs)
|
||||||
|
{
|
||||||
|
log_early("error: Invalid GSI %u for IRQ %d (max %u)", gsi, irq, max_irqs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint32_t redtble_lo = ioapic_read(0x10 + 2 * gsi);
|
||||||
|
redtble_lo &= ~(1 << 16);
|
||||||
|
ioapic_write(0x10 + 2 * gsi, redtble_lo);
|
||||||
|
log_early("Unmasked IRQ %d (GSI %u)", irq, gsi);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ioapic_init(void)
|
||||||
{
|
{
|
||||||
if (madt_ioapic_len < 1)
|
if (madt_ioapic_len < 1)
|
||||||
{
|
{
|
||||||
kpanic(NULL, "No I/O APIC's available");
|
log_early("error: No IOAPIC entries in MADT");
|
||||||
|
kpanic(NULL, "No IOAPIC available");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set base of I/O APIC */
|
uint64_t phys_addr = madt_ioapic_list[0]->ioapic_addr;
|
||||||
uint64_t base = madt_ioapic_list[0]->ioapic_addr;
|
if (phys_addr & 0xFFF)
|
||||||
log_early("I/O APIC phys addr: 0x%lx", base);
|
{
|
||||||
uint64_t virt_addr = (uint64_t)HIGHER_HALF(base);
|
log_early("error: IOAPIC base 0x%lx not page-aligned", phys_addr);
|
||||||
|
kpanic(NULL, "Invalid IOAPIC alignment");
|
||||||
int ret = vmap(pmget(), virt_addr, base, VMM_PRESENT | VMM_WRITE | VMM_NX);
|
}
|
||||||
|
uint64_t virt_addr = (uint64_t)HIGHER_HALF(phys_addr);
|
||||||
|
int ret = vmap(pmget(), virt_addr, phys_addr, VMM_PRESENT | VMM_WRITE | VMM_NX);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
{
|
{
|
||||||
log_early("error: Failed to map I/O APIC base 0x%lx to 0x%lx", base, virt_addr);
|
log_early("error: Failed to map IOAPIC 0x%lx to 0x%lx (%d)", phys_addr, virt_addr, ret);
|
||||||
kpanic(NULL, "I/O APIC mapping failed");
|
kpanic(NULL, "IOAPIC mapping failed");
|
||||||
}
|
}
|
||||||
atomic_store(&ioapic_base, virt_addr);
|
atomic_store(&ioapic_base, virt_addr);
|
||||||
|
|
||||||
// Read IOAPICVER register to get the maximum redirection entry
|
|
||||||
uint32_t ioapic_ver = ioapic_read(IOAPIC_IDX_IOAPICVER);
|
uint32_t ioapic_ver = ioapic_read(IOAPIC_IDX_IOAPICVER);
|
||||||
uint32_t max_irqs = ((ioapic_ver >> 16) & 0xFF) + 1;
|
uint32_t max_irqs = ((ioapic_ver >> 16) & 0xFF) + 1;
|
||||||
log_early("I/O APIC supports %u IRQs", max_irqs);
|
|
||||||
|
// Initialize all GSIs, respecting ISO overrides
|
||||||
|
for (uint32_t gsi = 0; gsi < max_irqs; gsi++)
|
||||||
|
{
|
||||||
|
uint32_t vec = 32 + gsi;
|
||||||
|
if (vec == LAPIC_SPURIOUS_VECTOR)
|
||||||
|
{
|
||||||
|
vec++;
|
||||||
|
}
|
||||||
|
// Check if this GSI is overridden
|
||||||
|
int is_overridden = 0;
|
||||||
|
uint32_t irq = gsi; // Default: GSI == IRQ
|
||||||
|
for (uint32_t i = 0; i < madt_iso_len; i++)
|
||||||
|
{
|
||||||
|
if (madt_iso_list[i]->gsi == gsi)
|
||||||
|
{
|
||||||
|
is_overridden = 1;
|
||||||
|
irq = madt_iso_list[i]->irq_source;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t redtble_lo = (1 << 16) | // Masked by default
|
||||||
|
(0 << 11) | // Physical mode
|
||||||
|
(0 << 8) | // Fixed delivery
|
||||||
|
vec;
|
||||||
|
uint32_t redtble_hi = (get_cpu_local()->lapic_id << 24);
|
||||||
|
ioapic_write(0x10 + 2 * gsi, redtble_lo);
|
||||||
|
ioapic_write(0x10 + 2 * gsi + 1, redtble_hi);
|
||||||
|
if (is_overridden)
|
||||||
|
{
|
||||||
|
log_early("Initialized IRQ %u (GSI %u) to vector 0x%x", irq, gsi, vec);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
log_early("Initialized GSI %u to vector 0x%x", gsi, vec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log_early("IOAPIC init at 0x%lx (virt 0x%lx) with %u IRQs", phys_addr, virt_addr, max_irqs);
|
||||||
}
|
}
|
|
@ -4,12 +4,15 @@
|
||||||
|
|
||||||
#include <arch/idt.h>
|
#include <arch/idt.h>
|
||||||
|
|
||||||
// I/O APIC Registers
|
|
||||||
#define IOAPIC_OFF_IOREGSEL 0x0
|
#define IOAPIC_OFF_IOREGSEL 0x0
|
||||||
#define IOAPIC_OFF_IOWIN 0x10
|
#define IOAPIC_OFF_IOWIN 0x10
|
||||||
|
|
||||||
|
#define IOAPIC_IDX_IOAPICID 0x00
|
||||||
#define IOAPIC_IDX_IOAPICVER 0x01
|
#define IOAPIC_IDX_IOAPICVER 0x01
|
||||||
|
#define IOAPIC_IDX_RED_TBL 0x10
|
||||||
|
|
||||||
void ioapic_init();
|
void ioapic_init();
|
||||||
void ioapic_map(int irq, int vec, idt_intr_handler handler);
|
void ioapic_map(int irq, int vec, idt_intr_handler handler, uint8_t dest_mode);
|
||||||
|
void ioapic_unmask(int irq);
|
||||||
|
|
||||||
#endif // IOAPIC_H
|
#endif // IOAPIC_H
|
|
@ -9,8 +9,8 @@
|
||||||
#define LAPIC_REG_ALIGN 16
|
#define LAPIC_REG_ALIGN 16
|
||||||
#define LAPIC_REG_SIZE 4
|
#define LAPIC_REG_SIZE 4
|
||||||
|
|
||||||
atomic_uintptr_t lapic_msr = 0;
|
static atomic_uintptr_t lapic_msr = 0;
|
||||||
atomic_uintptr_t lapic_base = 0;
|
static atomic_uintptr_t lapic_base = 0;
|
||||||
|
|
||||||
#define LAPIC_BASE ((volatile uint32_t *)atomic_load(&lapic_base))
|
#define LAPIC_BASE ((volatile uint32_t *)atomic_load(&lapic_base))
|
||||||
|
|
||||||
|
@ -19,16 +19,15 @@ void lapic_write(uint32_t offset, uint32_t value)
|
||||||
volatile uint32_t *base = LAPIC_BASE;
|
volatile uint32_t *base = LAPIC_BASE;
|
||||||
if (!base)
|
if (!base)
|
||||||
{
|
{
|
||||||
log_early("error: LAPIC not initialized!");
|
log_early("error: LAPIC not initialized");
|
||||||
kpanic(NULL, "LAPIC write attempted before initialization");
|
kpanic(NULL, "LAPIC write before init");
|
||||||
}
|
}
|
||||||
if (offset % LAPIC_REG_ALIGN != 0)
|
if (offset % LAPIC_REG_ALIGN != 0)
|
||||||
{
|
{
|
||||||
log_early("error: Misaligned LAPIC offset 0x%x", offset);
|
log_early("error: Misaligned LAPIC offset 0x%x", offset);
|
||||||
kpanic(NULL, "Invalid LAPIC register offset");
|
kpanic(NULL, "Invalid LAPIC offset");
|
||||||
}
|
}
|
||||||
volatile uint32_t *reg = base + (offset / LAPIC_REG_SIZE);
|
base[offset / LAPIC_REG_SIZE] = value;
|
||||||
*reg = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t lapic_read(uint32_t offset)
|
uint32_t lapic_read(uint32_t offset)
|
||||||
|
@ -36,37 +35,51 @@ uint32_t lapic_read(uint32_t offset)
|
||||||
volatile uint32_t *base = LAPIC_BASE;
|
volatile uint32_t *base = LAPIC_BASE;
|
||||||
if (!base)
|
if (!base)
|
||||||
{
|
{
|
||||||
log_early("error: LAPIC not initialized!");
|
log_early("error: LAPIC not initialized");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (offset % LAPIC_REG_ALIGN != 0)
|
if (offset % LAPIC_REG_ALIGN != 0)
|
||||||
{
|
{
|
||||||
log_early("error: Misaligned LAPIC offset 0x%x", offset);
|
log_early("error: Misaligned LAPIC offset 0x%x", offset);
|
||||||
kpanic(NULL, "Invalid LAPIC register offset");
|
kpanic(NULL, "Invalid LAPIC offset");
|
||||||
}
|
}
|
||||||
volatile uint32_t *reg = base + (offset / LAPIC_REG_SIZE);
|
return base[offset / LAPIC_REG_SIZE];
|
||||||
return *reg;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lapic_init(void)
|
void lapic_init(void)
|
||||||
{
|
{
|
||||||
uint64_t msr = rdmsr(LAPIC_BASE_MSR);
|
uint64_t msr = rdmsr(LAPIC_BASE_MSR);
|
||||||
msr |= (1 << 11); // Set global LAPIC enable bit
|
if (!(msr & (1ULL << 11)))
|
||||||
|
{
|
||||||
|
log_early("LAPIC disabled in MSR, enabling");
|
||||||
|
}
|
||||||
|
msr |= (1ULL << 11);
|
||||||
wrmsr(LAPIC_BASE_MSR, msr);
|
wrmsr(LAPIC_BASE_MSR, msr);
|
||||||
atomic_store(&lapic_msr, msr);
|
atomic_store(&lapic_msr, msr);
|
||||||
|
|
||||||
uint64_t phys_addr = msr & ~0xFFFULL;
|
uint64_t phys_addr = msr & ~0xFFFULL;
|
||||||
|
if (phys_addr & 0xFFF)
|
||||||
|
{
|
||||||
|
log_early("error: LAPIC base 0x%lx not page-aligned", phys_addr);
|
||||||
|
kpanic(NULL, "Invalid LAPIC alignment");
|
||||||
|
}
|
||||||
uint64_t virt_addr = (uint64_t)HIGHER_HALF(phys_addr);
|
uint64_t virt_addr = (uint64_t)HIGHER_HALF(phys_addr);
|
||||||
|
|
||||||
int ret = vmap(pmget(), virt_addr, phys_addr, VMM_PRESENT | VMM_WRITE | VMM_NX);
|
int ret = vmap(pmget(), virt_addr, phys_addr, VMM_PRESENT | VMM_WRITE | VMM_NX);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
{
|
{
|
||||||
log_early("error: Failed to map LAPIC base 0x%lx to 0x%lx", phys_addr, virt_addr);
|
log_early("error: Failed to map LAPIC 0x%lx to 0x%lx (%d)", phys_addr, virt_addr, ret);
|
||||||
kpanic(NULL, "LAPIC mapping failed");
|
kpanic(NULL, "LAPIC mapping failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
atomic_store(&lapic_base, virt_addr);
|
atomic_store(&lapic_base, virt_addr);
|
||||||
atomic_store(&lapic_addr, virt_addr);
|
|
||||||
|
uint32_t id = lapic_read(LAPIC_ID) >> 24;
|
||||||
|
if (id > 255)
|
||||||
|
{
|
||||||
|
log_early("error: Invalid LAPIC ID %u", id);
|
||||||
|
kpanic(NULL, "Invalid LAPIC ID");
|
||||||
|
}
|
||||||
|
log_early("LAPIC init: CPU %u at 0x%lx (virt 0x%lx)", id, phys_addr, virt_addr);
|
||||||
|
lapic_write(LAPIC_EOI, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void lapic_eoi(void)
|
void lapic_eoi(void)
|
||||||
|
@ -79,17 +92,19 @@ void lapic_enable(void)
|
||||||
volatile uint32_t *base = LAPIC_BASE;
|
volatile uint32_t *base = LAPIC_BASE;
|
||||||
if (!base)
|
if (!base)
|
||||||
{
|
{
|
||||||
log_early("warning: lapic_enable called before lapic_init");
|
log_early("warning: lapic_enable before init");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t svr = lapic_read(LAPIC_SVR);
|
uint32_t svr = lapic_read(LAPIC_SVR);
|
||||||
svr |= (1 << 8); // Enable APIC
|
svr |= (1 << 8);
|
||||||
svr &= ~(1 << 9); // Disable focus processor checking
|
svr &= ~(1 << 9);
|
||||||
svr = (svr & ~0xFF) | 0xFF; // Set spurious interrupt vector to 0xFF
|
svr = (svr & ~0xFF) | LAPIC_SPURIOUS_VECTOR;
|
||||||
|
|
||||||
lapic_write(LAPIC_SVR, svr);
|
lapic_write(LAPIC_SVR, svr);
|
||||||
|
|
||||||
|
lapic_write(LAPIC_LVT_TIMER, (1 << 16));
|
||||||
lapic_write(LAPIC_TPR, 0);
|
lapic_write(LAPIC_TPR, 0);
|
||||||
|
|
||||||
uint32_t id = lapic_read(LAPIC_ID) >> 24;
|
uint32_t id = lapic_read(LAPIC_ID) >> 24;
|
||||||
log_early("LAPIC enabled and initialized for CPU %u", id);
|
log_early("LAPIC enabled: CPU %u, spurious vector 0x%x", id, LAPIC_SPURIOUS_VECTOR);
|
||||||
}
|
}
|
|
@ -7,17 +7,18 @@
|
||||||
#define LAPIC_BASE_MSR 0x1B
|
#define LAPIC_BASE_MSR 0x1B
|
||||||
|
|
||||||
// Local APIC Registers
|
// Local APIC Registers
|
||||||
#define LAPIC_ID 0x0020 // Local APIC ID
|
#define LAPIC_ID 0x0020 // Local APIC ID
|
||||||
#define LAPIC_VER 0x0030 // Local APIC Version
|
#define LAPIC_VER 0x0030 // Local APIC Version
|
||||||
#define LAPIC_TPR 0x0080 // Task Priority
|
#define LAPIC_TPR 0x0080 // Task Priority
|
||||||
#define LAPIC_EOI 0x00B0 // End of Interrupt
|
#define LAPIC_EOI 0x00B0 // End of Interrupt
|
||||||
#define LAPIC_SVR 0x00F0 // Spurious Interrupt Vector
|
#define LAPIC_SVR 0x00F0 // Spurious Interrupt Vector
|
||||||
#define LAPIC_ESR 0x0280 // Error Status
|
#define LAPIC_ESR 0x0280 // Error Status
|
||||||
#define LAPIC_ICRLO 0x0300 // Interrupt Command (Low)
|
#define LAPIC_ICRLO 0x0300 // Interrupt Command (Low)
|
||||||
#define LAPIC_ICRHI 0x0310 // Interrupt Command (High)
|
#define LAPIC_ICRHI 0x0310 // Interrupt Command (High)
|
||||||
#define LAPIC_TIMER 0x0320 // LVT Timer
|
#define LAPIC_LVT_TIMER 0x0320 // LVT Timer
|
||||||
#define LAPIC_TICR 0x0380 // Timer Initial Count
|
#define LAPIC_LVT_LINT0 0x350 // LINT0
|
||||||
#define LAPIC_TDCR 0x03E0 // Timer Divide Configuration
|
#define LAPIC_TICR 0x0380 // Timer Initial Count
|
||||||
|
#define LAPIC_TDCR 0x03E0 // Timer Divide Configuration
|
||||||
|
|
||||||
// ICR Fields
|
// ICR Fields
|
||||||
#define ICR_FIXED 0x00000000
|
#define ICR_FIXED 0x00000000
|
||||||
|
@ -30,8 +31,7 @@
|
||||||
#define ICR_SEND_PENDING 0x00001000
|
#define ICR_SEND_PENDING 0x00001000
|
||||||
#define ICR_DESTINATION_SHIFT 24
|
#define ICR_DESTINATION_SHIFT 24
|
||||||
|
|
||||||
// Startup vector address (must be in first 1MB, page-aligned)
|
#define LAPIC_SPURIOUS_VECTOR 0xFF
|
||||||
#define AP_BOOT_ADDRESS 0x8000 // Example: 32KB physical address
|
|
||||||
|
|
||||||
extern uint64_t lapic_addr;
|
extern uint64_t lapic_addr;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue