1
0
Fork 0

feat/kernel: Did some lapic stuff

This commit is contained in:
Kevin Alavik 2025-05-31 18:19:56 +02:00
parent d5371bcbb2
commit 01e2f6a3d8
Signed by: cmpsb
GPG key ID: 10D1CC0526FDC6D7
7 changed files with 193 additions and 91 deletions

View file

@ -36,7 +36,7 @@ ifeq ($(BUILD_MODE),release)
-mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone \
-mcmodel=kernel -fno-unwind-tables -fno-asynchronous-unwind-tables \
-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 \
-T linker.ld -Wl,-m,elf_x86_64 -Wl,--strip-all
else
@ -45,7 +45,7 @@ else
-ffunction-sections -fdata-sections -m64 -march=x86-64 \
-mno-80387 -mno-mmx -mno-sse -mno-sse2 -mno-red-zone \
-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 \
-T linker.ld -Wl,-m,elf_x86_64
endif

View file

@ -10,20 +10,22 @@
#include <mm/heap.h>
#include <arch/io.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 MSR_GS_BASE 0xC0000101
uint32_t cpu_count = 0;
uint32_t bootstrap_lapic_id = 0;
atomic_uint started_cpus = 0;
static cpu_local_t cpu_locals[MAX_CPUS];
cpu_local_t *get_cpu_local(void)
{
cpu_local_t *cpu = (cpu_local_t *)rdmsr(MSR_GS_BASE);
return cpu;
return (cpu_local_t *)rdmsr(MSR_GS_BASE);
}
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)
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);
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;
while (1)
__asm__ volatile("hlt");
hlt();
}
void smp_init(void)
{
bootstrap_lapic_id = mp_response->bsp_lapic_id;
cpu_count = mp_response->cpu_count;
log_early("%u CPUs detected", cpu_count);
lapic_enable();
for (uint32_t i = 0; i < cpu_count; i++)
{
struct limine_mp_info *info = mp_response->cpus[i];
memset(&cpu_locals[i], 0, sizeof(cpu_local_t));
cpu_locals[i].lapic_id = info->lapic_id;
cpu_locals[i].cpu_index = i;
@ -77,30 +82,28 @@ void smp_init(void)
if (info->lapic_id == bootstrap_lapic_id)
{
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;
atomic_fetch_add(&started_cpus, 1);
log_early("CPU %u (LAPIC ID %u) is the bootstrap processor", i, info->lapic_id);
}
else
{
__atomic_store_n(&info->goto_address, smp_entry, __ATOMIC_SEQ_CST);
while (atomic_load(&started_cpus) < (i + 1))
__asm__ volatile("pause");
}
}
/* 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++)
{
volatile uint64_t timeout = 0;
while (!cpu_locals[i].ready)
{
__asm__ volatile("pause");
timeout++;
}
if (!cpu_locals[i].ready)
{
all_ready = false;
__asm__ volatile("pause");
break;
log_early("warning: CPU %u (LAPIC ID %u) failed to start", i, info->lapic_id);
}
else
{
log_early("CPU %u (LAPIC ID %u) started successfully", i, info->lapic_id);
}
}
}

View file

@ -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 = {
.revision = 0,
.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_end"))) static volatile LIMINE_REQUESTS_END_MARKER;
@ -87,8 +93,18 @@ void emk_entry(void)
/* 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("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);
if (!LIMINE_BASE_REVISION_SUPPORTED)
@ -160,15 +176,6 @@ void emk_entry(void)
*c = 32;
kfree(c);
/* Setup SMP */
if (!mp_request.response)
{
kpanic(NULL, "Failed to get MP request");
}
mp_response = mp_request.response;
smp_init();
/* Setup ACPI */
rsdp_response = rsdp_request.response;
if (!rsdp_response)
@ -182,9 +189,18 @@ void emk_entry(void)
outb(0x21, 0xff);
outb(0xA1, 0xff);
/* Setup APIC */
/* Init APIC (LAPIC for now) */
lapic_init();
/* Setup SMP */
if (!mp_request.response)
{
kpanic(NULL, "Failed to get MP request");
}
mp_response = mp_request.response;
smp_init();
/* Finished */
log_early("%s", LOG_SEPARATOR);
log_early("Finished initializing EMK v1.0, took ? seconds"); /* Still not usermode, so keep using log_early */

View file

@ -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);
}
memset((void *)new->start, PAGE_SIZE * pages, 0);
return (void *)new->start;
}
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);
}
memset((void *)new->start, PAGE_SIZE * pages, 0);
return (void *)new->start;
}

View file

@ -1,14 +1,28 @@
/* EMK 1.0 Copyright (c) 2025 Piraterna */
#include <sys/acpi.h>
#include <boot/emk.h>
#include <lib/string.h>
#include <util/log.h>
#include <sys/kpanic.h>
#include <mm/vmm.h>
#include <mm/heap.h>
static int acpi_uses_xsdt = 0;
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)
{
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);
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_xsdp_t *xsdp = (acpi_xsdp_t *)rsdp;
acpi_rsdt_ptr = (acpi_xsdt_t *)HIGHER_HALF(xsdp->xsdt_address);
log_early("XSDT found at %p", acpi_rsdt_ptr);
return;
acpi_rsdt_ptr = acpi_vtable(xsdp->xsdt_address);
log_early("Using XSDT");
}
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)
{
if (!acpi_uses_xsdt)
if (!acpi_rsdt_ptr || !name)
return NULL;
if (acpi_uses_xsdt)
{
acpi_xsdt_t *xsdt = (acpi_xsdt_t *)acpi_rsdt_ptr;
uint32_t entries = (xsdt->sdt.length - sizeof(xsdt->sdt)) / 8;
for (uint32_t i = 0; i < entries; 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))
return sdt;
}
}
else
{
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));
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 (void *)sdt;
}
return NULL;
}
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;
for (uint32_t i = 0; i < entries; i++)
{
acpi_sdt_header_t *sdt = (acpi_sdt_header_t *)HIGHER_HALF(*((uint64_t *)xsdt->table + i));
if (!memcmp(sdt->signature, name, 4))
{
return (void *)sdt;
return sdt;
}
}

View file

@ -1,43 +1,75 @@
/* EMK 1.0 Copyright (c) 2025 Piraterna */
#include <sys/apic/lapic.h>
#include <arch/cpu.h>
#include <sys/acpi/madt.h>
#include <arch/paging.h>
#include <util/log.h>
#include <mm/vmm.h>
#include <stdatomic.h>
#include <sys/kpanic.h>
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)
{
if (!lapic_base)
volatile uint32_t *base = LAPIC_BASE;
if (!base)
{
log_early("warning: LAPIC not initialized!");
return;
log_early("error: LAPIC not initialized!");
kpanic(NULL, "LAPIC write attempted before initialization");
}
volatile uint32_t *reg = (volatile uint32_t *)((uint8_t *)lapic_base + offset);
atomic_store((_Atomic uint32_t *)reg, value);
base[offset / 4] = value;
}
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;
}
volatile uint32_t *reg = (volatile uint32_t *)((uint8_t *)lapic_base + offset);
return atomic_load((_Atomic uint32_t *)reg);
return base[offset / 4];
}
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);
lapic_base = (volatile uint64_t *)(msr & ~(0xffff));
atomic_store(&lapic_addr, (uint64_t)lapic_base);
log_early("New LAPIC base: 0x%lx", lapic_base);
uint64_t phys_addr = msr & ~0xFFFULL;
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);
}

View file

@ -4,13 +4,41 @@
#include <stdint.h>
#define LAPIC_BASE 0x1b
#define LAPIC_REGOFF_LAPICID 0x20
#define LAPIC_REGOFF_EOI 0xB0
#define LAPIC_REGOFF_SPIV 0xF0
#define LAPIC_BASE_MSR 0x1B
// Local APIC Registers
#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);
void lapic_write(uint32_t offset, uint32_t value);
void lapic_init();
void lapic_init(void);
void lapic_enable(void);
#endif // LAPIC_H