port apic and hpet to mmio API, apic_msis
This commit is contained in:
+46
-29
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user