feat/kernel: Did some lapic stuff
This commit is contained in:
parent
d5371bcbb2
commit
01e2f6a3d8
7 changed files with 193 additions and 91 deletions
|
@ -36,7 +36,7 @@ ifeq ($(BUILD_MODE),release)
|
||||||
-mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone \
|
-mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone \
|
||||||
-mcmodel=kernel -fno-unwind-tables -fno-asynchronous-unwind-tables \
|
-mcmodel=kernel -fno-unwind-tables -fno-asynchronous-unwind-tables \
|
||||||
-s -Wno-unused-variable -DBUILD_MODE=\"release\"
|
-s -Wno-unused-variable -DBUILD_MODE=\"release\"
|
||||||
NASMFLAGS :=
|
NASMFLAGS := -f elf64 -F dwarf -g
|
||||||
LDFLAGS := -nostdlib -static -z max-page-size=0x1000 -Wl,--gc-sections \
|
LDFLAGS := -nostdlib -static -z max-page-size=0x1000 -Wl,--gc-sections \
|
||||||
-T linker.ld -Wl,-m,elf_x86_64 -Wl,--strip-all
|
-T linker.ld -Wl,-m,elf_x86_64 -Wl,--strip-all
|
||||||
else
|
else
|
||||||
|
@ -45,7 +45,7 @@ else
|
||||||
-ffunction-sections -fdata-sections -m64 -march=x86-64 \
|
-ffunction-sections -fdata-sections -m64 -march=x86-64 \
|
||||||
-mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone \
|
-mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone \
|
||||||
-mcmodel=kernel -Wno-unused-variable -DBUILD_MODE=\"dev\"
|
-mcmodel=kernel -Wno-unused-variable -DBUILD_MODE=\"dev\"
|
||||||
NASMFLAGS := -F dwarf -g
|
NASMFLAGS := -f elf64 -F dwarf -g
|
||||||
LDFLAGS := -nostdlib -static -z max-page-size=0x1000 -Wl,--gc-sections \
|
LDFLAGS := -nostdlib -static -z max-page-size=0x1000 -Wl,--gc-sections \
|
||||||
-T linker.ld -Wl,-m,elf_x86_64
|
-T linker.ld -Wl,-m,elf_x86_64
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -10,20 +10,22 @@
|
||||||
#include <mm/heap.h>
|
#include <mm/heap.h>
|
||||||
#include <arch/io.h>
|
#include <arch/io.h>
|
||||||
#include <sys/apic/lapic.h>
|
#include <sys/apic/lapic.h>
|
||||||
|
#include <sys/acpi/madt.h>
|
||||||
|
#include <arch/paging.h>
|
||||||
|
#include <util/align.h>
|
||||||
|
#include <mm/pmm.h>
|
||||||
|
|
||||||
#define MAX_CPUS 256
|
#define MAX_CPUS 256
|
||||||
#define MSR_GS_BASE 0xC0000101
|
#define MSR_GS_BASE 0xC0000101
|
||||||
|
|
||||||
uint32_t cpu_count = 0;
|
uint32_t cpu_count = 0;
|
||||||
uint32_t bootstrap_lapic_id = 0;
|
uint32_t bootstrap_lapic_id = 0;
|
||||||
|
|
||||||
atomic_uint started_cpus = 0;
|
atomic_uint started_cpus = 0;
|
||||||
static cpu_local_t cpu_locals[MAX_CPUS];
|
static cpu_local_t cpu_locals[MAX_CPUS];
|
||||||
|
|
||||||
cpu_local_t *get_cpu_local(void)
|
cpu_local_t *get_cpu_local(void)
|
||||||
{
|
{
|
||||||
cpu_local_t *cpu = (cpu_local_t *)rdmsr(MSR_GS_BASE);
|
return (cpu_local_t *)rdmsr(MSR_GS_BASE);
|
||||||
return cpu;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void set_cpu_local(cpu_local_t *cpu)
|
static inline void set_cpu_local(cpu_local_t *cpu)
|
||||||
|
@ -46,29 +48,32 @@ void smp_entry(struct limine_mp_info *smp_info)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cpu)
|
if (!cpu)
|
||||||
kpanic(NULL, "CPU with LAPIC ID %u not found in cpu_locals!", lapic_id);
|
kpanic(NULL, "CPU with LAPIC ID %u not found!", lapic_id);
|
||||||
|
|
||||||
set_cpu_local(cpu);
|
set_cpu_local(cpu);
|
||||||
atomic_fetch_add(&started_cpus, 1);
|
|
||||||
|
|
||||||
log_early("CPU %d is up", cpu->cpu_index);
|
/* Setup core */
|
||||||
|
pmset(kernel_pagemap);
|
||||||
|
lapic_enable();
|
||||||
|
|
||||||
|
atomic_fetch_add(&started_cpus, 1);
|
||||||
|
log_early("CPU %d (LAPIC ID %u) is up", cpu->cpu_index, lapic_id);
|
||||||
|
|
||||||
cpu->ready = true;
|
cpu->ready = true;
|
||||||
while (1)
|
hlt();
|
||||||
__asm__ volatile("hlt");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void smp_init(void)
|
void smp_init(void)
|
||||||
{
|
{
|
||||||
bootstrap_lapic_id = mp_response->bsp_lapic_id;
|
bootstrap_lapic_id = mp_response->bsp_lapic_id;
|
||||||
cpu_count = mp_response->cpu_count;
|
cpu_count = mp_response->cpu_count;
|
||||||
|
|
||||||
log_early("%u CPUs detected", cpu_count);
|
log_early("%u CPUs detected", cpu_count);
|
||||||
|
|
||||||
|
lapic_enable();
|
||||||
|
|
||||||
for (uint32_t i = 0; i < cpu_count; i++)
|
for (uint32_t i = 0; i < cpu_count; i++)
|
||||||
{
|
{
|
||||||
struct limine_mp_info *info = mp_response->cpus[i];
|
struct limine_mp_info *info = mp_response->cpus[i];
|
||||||
|
|
||||||
memset(&cpu_locals[i], 0, sizeof(cpu_local_t));
|
memset(&cpu_locals[i], 0, sizeof(cpu_local_t));
|
||||||
cpu_locals[i].lapic_id = info->lapic_id;
|
cpu_locals[i].lapic_id = info->lapic_id;
|
||||||
cpu_locals[i].cpu_index = i;
|
cpu_locals[i].cpu_index = i;
|
||||||
|
@ -77,30 +82,28 @@ void smp_init(void)
|
||||||
if (info->lapic_id == bootstrap_lapic_id)
|
if (info->lapic_id == bootstrap_lapic_id)
|
||||||
{
|
{
|
||||||
set_cpu_local(&cpu_locals[i]);
|
set_cpu_local(&cpu_locals[i]);
|
||||||
log_early("CPU %u is the bootstrap processor", i);
|
|
||||||
atomic_fetch_add(&started_cpus, 1);
|
|
||||||
cpu_locals[i].ready = true;
|
cpu_locals[i].ready = true;
|
||||||
|
atomic_fetch_add(&started_cpus, 1);
|
||||||
|
log_early("CPU %u (LAPIC ID %u) is the bootstrap processor", i, info->lapic_id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
__atomic_store_n(&info->goto_address, smp_entry, __ATOMIC_SEQ_CST);
|
__atomic_store_n(&info->goto_address, smp_entry, __ATOMIC_SEQ_CST);
|
||||||
while (atomic_load(&started_cpus) < (i + 1))
|
|
||||||
|
volatile uint64_t timeout = 0;
|
||||||
|
while (!cpu_locals[i].ready)
|
||||||
|
{
|
||||||
__asm__ volatile("pause");
|
__asm__ volatile("pause");
|
||||||
}
|
timeout++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* trick to wait for all procs to be ready */
|
|
||||||
bool all_ready = false;
|
|
||||||
while (!all_ready)
|
|
||||||
{
|
|
||||||
all_ready = true;
|
|
||||||
for (uint32_t i = 0; i < cpu_count; i++)
|
|
||||||
{
|
|
||||||
if (!cpu_locals[i].ready)
|
if (!cpu_locals[i].ready)
|
||||||
{
|
{
|
||||||
all_ready = false;
|
log_early("warning: CPU %u (LAPIC ID %u) failed to start", i, info->lapic_id);
|
||||||
__asm__ volatile("pause");
|
}
|
||||||
break;
|
else
|
||||||
|
{
|
||||||
|
log_early("CPU %u (LAPIC ID %u) started successfully", i, info->lapic_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,12 @@ __attribute__((used, section(".limine_requests"))) static volatile struct limine
|
||||||
__attribute__((used, section(".limine_requests"))) static volatile struct limine_mp_request mp_request = {
|
__attribute__((used, section(".limine_requests"))) static volatile struct limine_mp_request mp_request = {
|
||||||
.revision = 0,
|
.revision = 0,
|
||||||
.id = LIMINE_MP_REQUEST};
|
.id = LIMINE_MP_REQUEST};
|
||||||
|
__attribute__((used, section(".limine_requests"))) static volatile struct limine_bootloader_info_request binfo_request = {
|
||||||
|
.revision = 0,
|
||||||
|
.id = LIMINE_BOOTLOADER_INFO_REQUEST};
|
||||||
|
__attribute__((used, section(".limine_requests"))) static volatile struct limine_firmware_type_request firmware_request = {
|
||||||
|
.revision = 0,
|
||||||
|
.id = LIMINE_FIRMWARE_TYPE_REQUEST};
|
||||||
__attribute__((used, section(".limine_requests_start"))) static volatile LIMINE_REQUESTS_START_MARKER;
|
__attribute__((used, section(".limine_requests_start"))) static volatile LIMINE_REQUESTS_START_MARKER;
|
||||||
__attribute__((used, section(".limine_requests_end"))) static volatile LIMINE_REQUESTS_END_MARKER;
|
__attribute__((used, section(".limine_requests_end"))) static volatile LIMINE_REQUESTS_END_MARKER;
|
||||||
|
|
||||||
|
@ -87,8 +93,18 @@ void emk_entry(void)
|
||||||
/* Just do nothing */
|
/* Just do nothing */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!binfo_request.response)
|
||||||
|
{
|
||||||
|
kpanic(NULL, "Failed to get bootloader info");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!firmware_request.response)
|
||||||
|
{
|
||||||
|
kpanic(NULL, "Failed to get firmware type");
|
||||||
|
}
|
||||||
|
|
||||||
log_early("Experimental Micro Kernel (EMK) 1.0 Copyright (c) 2025 Piraterna");
|
log_early("Experimental Micro Kernel (EMK) 1.0 Copyright (c) 2025 Piraterna");
|
||||||
log_early("Compiled at %s %s, emk1.0-%s, flanterm support: %s", __TIME__, __DATE__, BUILD_MODE, FLANTERM_SUPPORT ? "yes" : "no");
|
log_early("Compiled at %s %s, emk1.0-%s, flanterm support: %s, bootloader: %s v%s, firmware: %s", __TIME__, __DATE__, BUILD_MODE, FLANTERM_SUPPORT ? "yes" : "no", binfo_request.response->name, binfo_request.response->version, (firmware_request.response->firmware_type == LIMINE_FIRMWARE_TYPE_UEFI64 || firmware_request.response->firmware_type == LIMINE_FIRMWARE_TYPE_UEFI32) ? "UEFI" : "BIOS");
|
||||||
log_early("%s", LOG_SEPARATOR);
|
log_early("%s", LOG_SEPARATOR);
|
||||||
|
|
||||||
if (!LIMINE_BASE_REVISION_SUPPORTED)
|
if (!LIMINE_BASE_REVISION_SUPPORTED)
|
||||||
|
@ -160,15 +176,6 @@ void emk_entry(void)
|
||||||
*c = 32;
|
*c = 32;
|
||||||
kfree(c);
|
kfree(c);
|
||||||
|
|
||||||
/* Setup SMP */
|
|
||||||
if (!mp_request.response)
|
|
||||||
{
|
|
||||||
kpanic(NULL, "Failed to get MP request");
|
|
||||||
}
|
|
||||||
|
|
||||||
mp_response = mp_request.response;
|
|
||||||
smp_init();
|
|
||||||
|
|
||||||
/* Setup ACPI */
|
/* Setup ACPI */
|
||||||
rsdp_response = rsdp_request.response;
|
rsdp_response = rsdp_request.response;
|
||||||
if (!rsdp_response)
|
if (!rsdp_response)
|
||||||
|
@ -182,9 +189,18 @@ void emk_entry(void)
|
||||||
outb(0x21, 0xff);
|
outb(0x21, 0xff);
|
||||||
outb(0xA1, 0xff);
|
outb(0xA1, 0xff);
|
||||||
|
|
||||||
/* Setup APIC */
|
/* Init APIC (LAPIC for now) */
|
||||||
lapic_init();
|
lapic_init();
|
||||||
|
|
||||||
|
/* Setup SMP */
|
||||||
|
if (!mp_request.response)
|
||||||
|
{
|
||||||
|
kpanic(NULL, "Failed to get MP request");
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_response = mp_request.response;
|
||||||
|
smp_init();
|
||||||
|
|
||||||
/* 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 */
|
||||||
|
|
|
@ -135,6 +135,7 @@ void *vallocat(vctx_t *ctx, size_t pages, uint64_t flags, uint64_t phys)
|
||||||
|
|
||||||
vmap(ctx->pagemap, new->start + (i * PAGE_SIZE), page, new->flags);
|
vmap(ctx->pagemap, new->start + (i * PAGE_SIZE), page, new->flags);
|
||||||
}
|
}
|
||||||
|
memset((void *)new->start, PAGE_SIZE * pages, 0);
|
||||||
return (void *)new->start;
|
return (void *)new->start;
|
||||||
}
|
}
|
||||||
region = region->next;
|
region = region->next;
|
||||||
|
@ -160,6 +161,7 @@ void *vallocat(vctx_t *ctx, size_t pages, uint64_t flags, uint64_t phys)
|
||||||
|
|
||||||
vmap(ctx->pagemap, new->start + (i * PAGE_SIZE), page, new->flags);
|
vmap(ctx->pagemap, new->start + (i * PAGE_SIZE), page, new->flags);
|
||||||
}
|
}
|
||||||
|
memset((void *)new->start, PAGE_SIZE * pages, 0);
|
||||||
return (void *)new->start;
|
return (void *)new->start;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,28 @@
|
||||||
/* EMK 1.0 Copyright (c) 2025 Piraterna */
|
|
||||||
#include <sys/acpi.h>
|
#include <sys/acpi.h>
|
||||||
#include <boot/emk.h>
|
#include <boot/emk.h>
|
||||||
#include <lib/string.h>
|
#include <lib/string.h>
|
||||||
#include <util/log.h>
|
#include <util/log.h>
|
||||||
#include <sys/kpanic.h>
|
#include <sys/kpanic.h>
|
||||||
#include <mm/vmm.h>
|
#include <mm/vmm.h>
|
||||||
|
#include <mm/heap.h>
|
||||||
|
|
||||||
static int acpi_uses_xsdt = 0;
|
static int acpi_uses_xsdt = 0;
|
||||||
static void *acpi_rsdt_ptr = NULL;
|
static void *acpi_rsdt_ptr = NULL;
|
||||||
|
|
||||||
|
void *acpi_vtable(uint64_t phys)
|
||||||
|
{
|
||||||
|
acpi_sdt_header_t *tmp = (acpi_sdt_header_t *)vallocat(kvm_ctx, 1, VALLOC_RW, phys);
|
||||||
|
if (!tmp)
|
||||||
|
{
|
||||||
|
kpanic(NULL, "Failed to map first page of ACPI table");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t full_size = tmp->length;
|
||||||
|
uint32_t page_count = (full_size + 0xFFF) / 0x1000;
|
||||||
|
return vallocat(kvm_ctx, page_count, VALLOC_RW, phys);
|
||||||
|
}
|
||||||
|
|
||||||
void acpi_init(void)
|
void acpi_init(void)
|
||||||
{
|
{
|
||||||
if (!rsdp_response || !rsdp_response->address)
|
if (!rsdp_response || !rsdp_response->address)
|
||||||
|
@ -18,45 +32,52 @@ void acpi_init(void)
|
||||||
|
|
||||||
acpi_rsdp_t *rsdp = (acpi_rsdp_t *)vallocat(kvm_ctx, 1, VALLOC_RW, rsdp_response->address);
|
acpi_rsdp_t *rsdp = (acpi_rsdp_t *)vallocat(kvm_ctx, 1, VALLOC_RW, rsdp_response->address);
|
||||||
if (memcmp(rsdp->signature, "RSD PTR", 7) != 0)
|
if (memcmp(rsdp->signature, "RSD PTR", 7) != 0)
|
||||||
kpanic(NULL, "Invalid RSDP signature!");
|
kpanic(NULL, "Invalid RSDP signature! EMK depends on APIC 1.0 or higher");
|
||||||
|
|
||||||
if (rsdp->revision != 0)
|
if (rsdp->revision >= 2)
|
||||||
{
|
{
|
||||||
acpi_uses_xsdt = 1;
|
acpi_uses_xsdt = 1;
|
||||||
acpi_xsdp_t *xsdp = (acpi_xsdp_t *)rsdp;
|
acpi_xsdp_t *xsdp = (acpi_xsdp_t *)rsdp;
|
||||||
acpi_rsdt_ptr = (acpi_xsdt_t *)HIGHER_HALF(xsdp->xsdt_address);
|
acpi_rsdt_ptr = acpi_vtable(xsdp->xsdt_address);
|
||||||
log_early("XSDT found at %p", acpi_rsdt_ptr);
|
log_early("Using XSDT");
|
||||||
return;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
acpi_uses_xsdt = 0;
|
||||||
|
acpi_rsdt_ptr = acpi_vtable(rsdp->rsdt_address);
|
||||||
|
log_early("Using RSDT");
|
||||||
}
|
}
|
||||||
|
|
||||||
acpi_rsdt_ptr = (acpi_rsdt_t *)HIGHER_HALF(rsdp->rsdt_address);
|
|
||||||
log_early("RSDT found at %p", acpi_rsdt_ptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void *acpi_find_table(const char *name)
|
void *acpi_find_table(const char *name)
|
||||||
{
|
{
|
||||||
if (!acpi_uses_xsdt)
|
if (!acpi_rsdt_ptr || !name)
|
||||||
{
|
|
||||||
acpi_rsdt_t *rsdt = (acpi_rsdt_t *)acpi_rsdt_ptr;
|
|
||||||
uint32_t entries = (rsdt->sdt.length - sizeof(rsdt->sdt)) / 4;
|
|
||||||
for (uint32_t i = 0; i < entries; i++)
|
|
||||||
{
|
|
||||||
acpi_sdt_header_t *sdt = (acpi_sdt_header_t *)HIGHER_HALF(*((uint32_t *)rsdt->table + i));
|
|
||||||
if (!memcmp(sdt->signature, name, 4))
|
|
||||||
return (void *)sdt;
|
|
||||||
}
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
|
if (acpi_uses_xsdt)
|
||||||
|
{
|
||||||
acpi_xsdt_t *xsdt = (acpi_xsdt_t *)acpi_rsdt_ptr;
|
acpi_xsdt_t *xsdt = (acpi_xsdt_t *)acpi_rsdt_ptr;
|
||||||
log_early("XSDT address: %p", xsdt);
|
|
||||||
uint32_t entries = (xsdt->sdt.length - sizeof(xsdt->sdt)) / 8;
|
uint32_t entries = (xsdt->sdt.length - sizeof(xsdt->sdt)) / 8;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < entries; i++)
|
for (uint32_t i = 0; i < entries; i++)
|
||||||
{
|
{
|
||||||
acpi_sdt_header_t *sdt = (acpi_sdt_header_t *)HIGHER_HALF(*((uint64_t *)xsdt->table + i));
|
uint64_t phys_addr = ((uint64_t *)xsdt->table)[i];
|
||||||
|
acpi_sdt_header_t *sdt = (acpi_sdt_header_t *)acpi_vtable(phys_addr);
|
||||||
if (!memcmp(sdt->signature, name, 4))
|
if (!memcmp(sdt->signature, name, 4))
|
||||||
|
return sdt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
return (void *)sdt;
|
acpi_rsdt_t *rsdt = (acpi_rsdt_t *)acpi_rsdt_ptr;
|
||||||
|
uint32_t entries = (rsdt->sdt.length - sizeof(rsdt->sdt)) / 4;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < entries; i++)
|
||||||
|
{
|
||||||
|
uint32_t phys_addr = ((uint32_t *)rsdt->table)[i];
|
||||||
|
acpi_sdt_header_t *sdt = (acpi_sdt_header_t *)acpi_vtable(phys_addr);
|
||||||
|
if (!memcmp(sdt->signature, name, 4))
|
||||||
|
return sdt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,43 +1,75 @@
|
||||||
/* EMK 1.0 Copyright (c) 2025 Piraterna */
|
/* EMK 1.0 Copyright (c) 2025 Piraterna */
|
||||||
#include <sys/apic/lapic.h>
|
#include <sys/apic/lapic.h>
|
||||||
#include <arch/cpu.h>
|
#include <arch/cpu.h>
|
||||||
#include <sys/acpi/madt.h>
|
#include <arch/paging.h>
|
||||||
#include <util/log.h>
|
#include <util/log.h>
|
||||||
#include <mm/vmm.h>
|
|
||||||
#include <stdatomic.h>
|
#include <stdatomic.h>
|
||||||
|
#include <sys/kpanic.h>
|
||||||
|
|
||||||
atomic_uintptr_t lapic_msr = 0;
|
atomic_uintptr_t lapic_msr = 0;
|
||||||
volatile uint64_t *lapic_base = 0;
|
atomic_uintptr_t lapic_base_atomic = 0;
|
||||||
|
|
||||||
|
#define LAPIC_BASE ((volatile uint32_t *)atomic_load(&lapic_base_atomic))
|
||||||
|
|
||||||
void lapic_write(uint32_t offset, uint32_t value)
|
void lapic_write(uint32_t offset, uint32_t value)
|
||||||
{
|
{
|
||||||
if (!lapic_base)
|
volatile uint32_t *base = LAPIC_BASE;
|
||||||
|
if (!base)
|
||||||
{
|
{
|
||||||
log_early("warning: LAPIC not initialized!");
|
log_early("error: LAPIC not initialized!");
|
||||||
return;
|
kpanic(NULL, "LAPIC write attempted before initialization");
|
||||||
}
|
}
|
||||||
|
base[offset / 4] = value;
|
||||||
volatile uint32_t *reg = (volatile uint32_t *)((uint8_t *)lapic_base + offset);
|
|
||||||
atomic_store((_Atomic uint32_t *)reg, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t lapic_read(uint32_t offset)
|
uint32_t lapic_read(uint32_t offset)
|
||||||
{
|
{
|
||||||
if (!lapic_base)
|
volatile uint32_t *base = LAPIC_BASE;
|
||||||
|
if (!base)
|
||||||
{
|
{
|
||||||
log_early("warning: LAPIC not initialized!");
|
log_early("error: LAPIC not initialized!");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
return base[offset / 4];
|
||||||
volatile uint32_t *reg = (volatile uint32_t *)((uint8_t *)lapic_base + offset);
|
|
||||||
return atomic_load((_Atomic uint32_t *)reg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void lapic_init()
|
void lapic_init(void)
|
||||||
{
|
{
|
||||||
uint64_t msr = rdmsr(LAPIC_BASE);
|
uint64_t msr = rdmsr(LAPIC_BASE_MSR);
|
||||||
|
msr |= (1 << 11); // Set global LAPIC enable bit
|
||||||
|
wrmsr(LAPIC_BASE_MSR, msr);
|
||||||
atomic_store(&lapic_msr, msr);
|
atomic_store(&lapic_msr, msr);
|
||||||
lapic_base = (volatile uint64_t *)(msr & ~(0xffff));
|
|
||||||
atomic_store(&lapic_addr, (uint64_t)lapic_base);
|
uint64_t phys_addr = msr & ~0xFFFULL;
|
||||||
log_early("New LAPIC base: 0x%lx", lapic_base);
|
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)
|
||||||
|
{
|
||||||
|
log_early("error: Failed to map LAPIC base 0x%lx to 0x%lx", phys_addr, virt_addr);
|
||||||
|
kpanic(NULL, "LAPIC mapping failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
atomic_store(&lapic_base_atomic, virt_addr);
|
||||||
|
atomic_store(&lapic_addr, virt_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lapic_enable(void)
|
||||||
|
{
|
||||||
|
volatile uint32_t *base = LAPIC_BASE;
|
||||||
|
if (!base)
|
||||||
|
{
|
||||||
|
log_early("warning: lapic_enable called before lapic_init");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t svr = lapic_read(LAPIC_SVR);
|
||||||
|
svr |= (1 << 8); // Enable APIC
|
||||||
|
svr &= ~(1 << 9); // Disable focus processor checking
|
||||||
|
svr = (svr & ~0xFF) | 0xFF; // Set spurious interrupt vector to 0xFF
|
||||||
|
|
||||||
|
lapic_write(LAPIC_SVR, svr);
|
||||||
|
lapic_write(LAPIC_TPR, 0);
|
||||||
|
uint32_t id = lapic_read(LAPIC_ID) >> 24;
|
||||||
|
log_early("LAPIC enabled and initialized for CPU %u", id);
|
||||||
}
|
}
|
|
@ -4,13 +4,41 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define LAPIC_BASE 0x1b
|
#define LAPIC_BASE_MSR 0x1B
|
||||||
#define LAPIC_REGOFF_LAPICID 0x20
|
|
||||||
#define LAPIC_REGOFF_EOI 0xB0
|
// Local APIC Registers
|
||||||
#define LAPIC_REGOFF_SPIV 0xF0
|
#define LAPIC_ID 0x0020 // Local APIC ID
|
||||||
|
#define LAPIC_VER 0x0030 // Local APIC Version
|
||||||
|
#define LAPIC_TPR 0x0080 // Task Priority
|
||||||
|
#define LAPIC_EOI 0x00B0 // End of Interrupt
|
||||||
|
#define LAPIC_SVR 0x00F0 // Spurious Interrupt Vector
|
||||||
|
#define LAPIC_ESR 0x0280 // Error Status
|
||||||
|
#define LAPIC_ICRLO 0x0300 // Interrupt Command (Low)
|
||||||
|
#define LAPIC_ICRHI 0x0310 // Interrupt Command (High)
|
||||||
|
#define LAPIC_TIMER 0x0320 // LVT Timer
|
||||||
|
#define LAPIC_TICR 0x0380 // Timer Initial Count
|
||||||
|
#define LAPIC_TDCR 0x03E0 // Timer Divide Configuration
|
||||||
|
|
||||||
|
// ICR Fields
|
||||||
|
#define ICR_FIXED 0x00000000
|
||||||
|
#define ICR_INIT 0x00000500
|
||||||
|
#define ICR_STARTUP 0x00000600
|
||||||
|
#define ICR_PHYSICAL 0x00000000
|
||||||
|
#define ICR_ASSERT 0x00004000
|
||||||
|
#define ICR_EDGE 0x00000000
|
||||||
|
#define ICR_NO_SHORTHAND 0x00000000
|
||||||
|
#define ICR_SEND_PENDING 0x00001000
|
||||||
|
#define ICR_DESTINATION_SHIFT 24
|
||||||
|
|
||||||
|
// Startup vector address (must be in first 1MB, page-aligned)
|
||||||
|
#define AP_BOOT_ADDRESS 0x8000 // Example: 32KB physical address
|
||||||
|
|
||||||
|
extern volatile uint32_t *lapic_base;
|
||||||
|
extern uint64_t lapic_addr;
|
||||||
|
|
||||||
uint32_t lapic_read(uint32_t offset);
|
uint32_t lapic_read(uint32_t offset);
|
||||||
void lapic_write(uint32_t offset, uint32_t value);
|
void lapic_write(uint32_t offset, uint32_t value);
|
||||||
void lapic_init();
|
void lapic_init(void);
|
||||||
|
void lapic_enable(void);
|
||||||
|
|
||||||
#endif // LAPIC_H
|
#endif // LAPIC_H
|
Loading…
Add table
Add a link
Reference in a new issue