#include #include #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" #define IOAPIC_IOREGSEL 0x00 #define IOAPIC_IOWIN 0x10 #define IOAPIC_IOAPICID 0x00 #define IOAPIC_IOAPICVER 0x01 #define IOAPIC_IOAPICARB 0x02 #define IOAPIC_IOREDTBL 0x10 #define LAPIC_ID 0x0020 #define LAPIC_VER 0x0030 #define LAPIC_TPR 0x0080 #define LAPIC_APR 0x0090 #define LAPIC_PPR 0x00A0 #define LAPIC_EOI 0x00B0 #define LAPIC_RRD 0x00C0 #define LAPIC_LDR 0x00D0 #define LAPIC_DFR 0x00E0 #define LAPIC_SVR 0x00F0 #define LAPIC_ISR 0x0100 #define LAPIC_TMR 0x0180 #define LAPIC_IRR 0x0200 #define LAPIC_ESR 0x0280 #define LAPIC_ICRLO 0x0300 #define LAPIC_ICRHI 0x0310 #define LAPIC_TIMER 0x0320 #define LAPIC_THERMAL 0x0330 #define LAPIC_PERF 0x0340 #define LAPIC_LINT0 0x0350 #define LAPIC_LINT1 0x0360 #define LAPIC_ERROR 0x0370 #define LAPIC_TICR 0x0380 #define LAPIC_TCCR 0x0390 #define LAPIC_TDCR 0x03E0 #define ICR_FIXED 0x00000000 #define ICR_LOWEST 0x00000100 #define ICR_SMI 0x00000200 #define ICR_NMI 0x00000400 #define ICR_INIT 0x00000500 #define ICR_STARTUP 0x00000600 #define ICR_PHYS 0x00000000 #define ICR_LOGC 0x00000800 #define ICR_IDLE 0x00000000 #define ICR_SEND_PENDING 0x00001000 #define ICR_DEASSERT 0x00000000 #define ICR_ASSERT 0x00004000 #define ICR_EDGE 0x00000000 #define ICR_LEVEL 0x00008000 #define ICR_NO_SHORTHAND 0x00000000 #define ICR_SELF 0x00040000 #define ICR_ALL_INC_SELF 0x00080000 #define ICR_ALL_EXCL_SELF 0x000C0000 #define ICR_DEST_SHIFT 24 typedef struct LApic { struct LApic *next; uint8_t id; } LApic; struct acpi_madt *MADT = NULL; 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(); }