Files
my-os-project2/kernel/hal/x86_64/apic.c
2025-08-22 12:37:48 +02:00

126 lines
3.5 KiB
C

#include <stdint.h>
#include <stddef.h>
#include "apic.h"
#include "uacpi/tables.h"
#include "uacpi/acpi.h"
#include "kprintf.h"
#include "hal/hal.h"
#include "dlmalloc/malloc.h"
#include "bootinfo/bootinfo.h"
#include "assert.h"
#include "util/util.h"
#include "cpu.h"
#include "util/mmio.h"
#include "acpi.h"
typedef struct LApic {
struct LApic *next;
uint8_t id;
} LApic;
uint8_t *IOAPIC;
uint8_t *LAPIC;
LApic *LAPICS = NULL;
void ioapic_write(uint8_t *base, uint8_t reg, uint32_t data) {
mmiowrite32(base + IOAPIC_IOREGSEL, reg);
mmiowrite32(base + IOAPIC_IOWIN, data);
}
uint32_t ioapic_read(uint8_t *base, uint8_t reg) {
mmiowrite32(base + IOAPIC_IOREGSEL, reg);
return mmioread32(base + IOAPIC_IOWIN);
}
void ioapic_setentry(uint8_t *base, uint8_t idx, uint64_t data) {
ioapic_write(base, IOAPIC_IOREDTBL + idx * 2, (uint32_t) data);
ioapic_write(base, IOAPIC_IOREDTBL + idx * 2 + 1, (uint32_t) (data >> 32));
}
void ioapic_init(void) {
uint32_t x = ioapic_read(IOAPIC, IOAPIC_IOAPICVER);
uint32_t count = ((x >> 16) & 0xff) + 1;
LOG("hal", "IOAPIC pins = %d\n", count);
for (uint32_t i = 0; i < count; i++) {
ioapic_setentry(IOAPIC, i, 1 << 16);
}
}
uint32_t lapic_read(uint32_t reg) {
return mmioread32(LAPIC + reg);
}
void lapic_write(uint32_t reg, uint32_t data) {
mmiowrite32(LAPIC + reg, data);
}
void lapic_init(void) {
lapic_write(LAPIC_TPR, 0);
lapic_write(LAPIC_DFR, 0xffffffff);
lapic_write(LAPIC_LDR, 0x01000000);
lapic_write(LAPIC_SVR, 0x100 | 0xff);
}
uint32_t lapic_getid(void) {
return lapic_read(LAPIC_ID) >> 24;
}
void lapic_sendinit(uint32_t id) {
lapic_write(LAPIC_ICRHI, id << ICR_DEST_SHIFT);
lapic_write(LAPIC_ICRLO, ICR_INIT | ICR_PHYS | ICR_ASSERT | ICR_EDGE | ICR_NO_SHORTHAND);
while (lapic_read(LAPIC_ICRLO) & ICR_SEND_PENDING);
}
void lapic_sendstartup(uint32_t id, uint32_t vec) {
lapic_write(LAPIC_ICRHI, id << ICR_DEST_SHIFT);
lapic_write(LAPIC_ICRLO, vec | ICR_STARTUP | ICR_PHYS | ICR_ASSERT | ICR_EDGE | ICR_NO_SHORTHAND);
while (lapic_read(LAPIC_ICRLO) & ICR_SEND_PENDING);
}
void apic_init(void) {
uacpi_status r;
uacpi_table madt;
r = uacpi_table_find_by_signature("APIC", &madt);
if (r != UACPI_STATUS_OK) {
ERR("hal", "could not find MADT\n");
hal_hang();
}
MADT = madt.ptr;
LAPIC = (uint8_t *)(MADT->local_interrupt_controller_address + BOOT_INFO.hhdm_off);
uint64_t cur = (uint64_t)&MADT->entries;
uint64_t end = cur + MADT->hdr.length;
while (cur < end) {
struct acpi_entry_hdr *ent = (struct acpi_entry_hdr *)cur;
if (ent->type == ACPI_MADT_ENTRY_TYPE_IOAPIC) {
struct acpi_madt_ioapic *ioapic = (struct acpi_madt_ioapic *)ent;
IOAPIC = (uint8_t *)(ioapic->address + BOOT_INFO.hhdm_off);
LOG("hal", "IOAPIC p=%p v=%p id=%d gsi=%d\n", ioapic->address, IOAPIC, ioapic->id, ioapic->gsi_base);
} else if (ent->type == ACPI_MADT_ENTRY_TYPE_LAPIC) {
struct acpi_madt_lapic *lapic = (struct acpi_madt_lapic *)ent;
LApic *new = dlmalloc(sizeof(*new));
ASSERT("hal", new != NULL, "out of memory\n");
new->id = lapic->id;
LL_APPEND(LAPICS, new);
LOG("hal", "LAPIC id=%d\n", lapic->id);
} else if (ent->type == ACPI_MADT_ENTRY_TYPE_LAPIC_ADDRESS_OVERRIDE) {
struct acpi_madt_lapic_address_override *override= (struct acpi_madt_lapic_address_override *)ent;
uint8_t *prev = LAPIC;
LAPIC = (uint8_t *)(override->address + BOOT_INFO.hhdm_off);
LOG("hal", "LAPIC override %p -> %p (v)\n", prev, LAPIC);
}
cur += ent->length;
}
lapic_init();
ioapic_init();
}