port apic and hpet to mmio API, apic_msis

This commit is contained in:
2026-10-14 23:57:35 +02:00
parent d7857f18cd
commit d84232c394
8 changed files with 197 additions and 52 deletions
+46 -29
View File
@@ -4,37 +4,48 @@
#include <zinnia/mmio.h>
#include <zinnia/percpu.h>
#include <zinnia/pmap.h>
#include <zinnia/utils.h>
#include <zinnia/vma.h>
#include <stdint.h>
#include <x86_64/apic.h>
#include <x86_64/asm.h>
#include <x86_64/defs.h>
#include <x86_64/percpu.h>
static uint64_t lapic_read_reg(struct local_apic* lapic, uint32_t reg) {
static uint32_t lapic_msr(size_t offset) {
return 0x800 + (offset >> 4);
}
static uint32_t lapic_read_reg(struct local_apic* lapic, mmio_reg32 reg) {
if (lapic->xapic_regs)
return mmio_reg_read(lapic->xapic_regs, reg);
else
return asm_rdmsr(lapic_msr(reg.offset));
}
static void lapic_write_reg(struct local_apic* lapic, mmio_reg32 reg, uint32_t value) {
if (lapic->xapic_regs)
mmio_reg_write(lapic->xapic_regs, reg, value);
else
asm_wrmsr(lapic_msr(reg.offset), value);
}
static uint64_t lapic_read_icr(struct local_apic* lapic) {
if (lapic->xapic_regs) {
if (reg == APIC_REG_ICR) {
uint64_t lo, hi;
lo = mmio_read32(lapic->xapic_regs + APIC_REG_ICR);
hi = mmio_read32(lapic->xapic_regs + APIC_REG_ICR_HI);
return (hi << 32) | lo;
} else {
return mmio_read32(lapic->xapic_regs + reg);
}
uint64_t lo = mmio_reg_read(lapic->xapic_regs, APIC_REG_ICR_LO);
uint64_t hi = mmio_reg_read(lapic->xapic_regs, APIC_REG_ICR_HI);
return (hi << 32) | lo;
} else {
return asm_rdmsr(0x800 + (reg >> 4));
return asm_rdmsr(lapic_msr(APIC_REG_ICR.offset));
}
}
static void lapic_write_reg(struct local_apic* lapic, uint32_t reg, uint64_t value) {
static void lapic_write_icr(struct local_apic* lapic, uint64_t value) {
if (lapic->xapic_regs) {
if (reg == APIC_REG_ICR) {
mmio_write32(lapic->xapic_regs + APIC_REG_ICR_HI, value >> 32);
mmio_write32(lapic->xapic_regs + APIC_REG_ICR, (uint32_t)value);
} else {
mmio_write32(lapic->xapic_regs + reg, (uint32_t)value);
}
mmio_reg_write(lapic->xapic_regs, APIC_REG_ICR_HI, (uint32_t)(value >> 32));
mmio_reg_write(lapic->xapic_regs, APIC_REG_ICR_LO, (uint32_t)value);
} else {
asm_wrmsr(0x800 + (reg >> 4), value);
asm_wrmsr(lapic_msr(APIC_REG_ICR.offset), value);
}
}
@@ -56,12 +67,15 @@ void lapic_init(struct local_apic* lapic) {
lapic->id = lapic_read_reg(lapic, APIC_REG_ID);
if (lapic->xapic_regs)
lapic->id >>= 24;
lapic->id = mmio_field_get(APIC_ID_XAPIC, lapic->id);
// Reset the TPR.
lapic_write_reg(lapic, APIC_REG_TPR, 0);
// Enable APIC bit in the SIVR.
lapic_write_reg(lapic, APIC_REG_SIVR, (lapic_read_reg(lapic, APIC_REG_SIVR) & ~0xFF) | 0x100 | IDT_SPURIOUS);
uint32_t sivr = lapic_read_reg(lapic, APIC_REG_SIVR);
sivr |= mmio_field(APIC_SIVR_VECTOR, IDT_SPURIOUS);
sivr |= mmio_field(APIC_SIVR_ENABLE, 1);
lapic_write_reg(lapic, APIC_REG_SIVR, sivr);
if (lapic->xapic_regs) {
lapic_write_reg(lapic, APIC_REG_DFR, 0xF000'0000);
@@ -88,6 +102,9 @@ void lapic_eoi(struct local_apic* lapic) {
lapic_write_reg(lapic, APIC_REG_EOI, 0);
}
constexpr uint64_t the_icr =
mmio_field(APIC_ICR_VECTOR, 128) | mmio_field(APIC_ICR_DELIVERY_MODE, APIC_DELIVERY_STARTUP);
void lapic_send_ipi(
struct local_apic* lapic,
uint32_t target,
@@ -97,21 +114,21 @@ void lapic_send_ipi(
enum apic_level level,
enum apic_trigger_mode trigger_mode
) {
uint64_t icr = vector;
icr |= (uint64_t)delivery_mode << 8;
icr |= (uint64_t)dest_mode << 11;
icr |= (uint64_t)level << 14;
icr |= (uint64_t)trigger_mode << 15;
uint64_t icr = mmio_field(APIC_ICR_VECTOR, vector);
icr |= mmio_field(APIC_ICR_DELIVERY_MODE, delivery_mode);
icr |= mmio_field(APIC_ICR_DEST_MODE, dest_mode);
icr |= mmio_field(APIC_ICR_LEVEL, level);
icr |= mmio_field(APIC_ICR_TRIGGER_MODE, trigger_mode);
if (lapic->xapic_regs)
icr |= (uint64_t)(uint8_t)target << 56;
icr |= mmio_field(APIC_ICR_DEST_XAPIC, target);
else
icr |= (uint64_t)target << 32;
icr |= mmio_field(APIC_ICR_DEST_X2APIC, target);
lapic_write_reg(lapic, APIC_REG_ICR, icr);
lapic_write_icr(lapic, icr);
if (lapic->xapic_regs) {
while (lapic_read_reg(lapic, APIC_REG_ICR) & (APIC_DELIVERY_STATUS_PENDING << 12))
while (mmio_field_get(APIC_ICR_DELIVERY_STATUS, lapic_read_icr(lapic)) == APIC_DELIVERY_STATUS_PENDING)
asm volatile("pause");
}
}