[arch][x86] add x2apic mode to the local apic driver
Fill in some more x86 feature bits while at it.
This commit is contained in:
@@ -25,6 +25,7 @@
|
||||
#define LOCAL_TRACE 1
|
||||
|
||||
static bool lapic_present = false;
|
||||
static bool lapic_x2apic = false;
|
||||
static volatile uint32_t *lapic_mmio;
|
||||
|
||||
// local apic registers
|
||||
@@ -69,13 +70,38 @@ enum lapic_regs {
|
||||
};
|
||||
|
||||
static uint32_t lapic_read(enum lapic_regs reg) {
|
||||
return mmio_read32(lapic_mmio + reg / 4);
|
||||
LTRACEF("reg %#x\n", reg);
|
||||
DEBUG_ASSERT(reg != LAPIC_ICRLO && reg != LAPIC_ICRHI);
|
||||
if (lapic_x2apic) {
|
||||
// TODO: do we need barriers here?
|
||||
return read_msr(X86_MSR_IA32_X2APIC_BASE + reg / 0x10);
|
||||
} else {
|
||||
return mmio_read32(lapic_mmio + reg / 4);
|
||||
}
|
||||
}
|
||||
|
||||
static void lapic_write(enum lapic_regs reg, uint32_t val) {
|
||||
mmio_write32(lapic_mmio + reg / 4, val);
|
||||
LTRACEF("reg %#x val %#x\n", reg, val);
|
||||
DEBUG_ASSERT(reg != LAPIC_ICRLO && reg != LAPIC_ICRHI);
|
||||
if (lapic_x2apic) {
|
||||
write_msr(X86_MSR_IA32_X2APIC_BASE + reg / 0x10, val);
|
||||
} else {
|
||||
mmio_write32(lapic_mmio + reg / 4, val);
|
||||
}
|
||||
}
|
||||
|
||||
// special case to write to the ICR register
|
||||
static void lapic_write_icr(uint32_t low, uint32_t apic_id) {
|
||||
LTRACEF("%#x apic_id %#x\n", low, apic_id);
|
||||
if (lapic_x2apic) {
|
||||
write_msr(X86_MSR_IA32_X2APIC_BASE + 0x30, ((uint64_t)apic_id << 32) | low);
|
||||
} else {
|
||||
lapic_write(LAPIC_ICRHI, apic_id << 24);
|
||||
lapic_write(LAPIC_ICRLO, low);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void lapic_init(void) {
|
||||
// discover the presence of the local apic and map it
|
||||
LTRACE_ENTRY;
|
||||
@@ -91,23 +117,33 @@ void lapic_init_postvm(uint level) {
|
||||
dprintf(INFO, "X86: local apic detected\n");
|
||||
|
||||
// IA32_APIC_BASE_MSR
|
||||
uint64_t apic_base = read_msr(0x1b);
|
||||
uint64_t apic_base = read_msr(X86_MSR_IA32_APIC_BASE);
|
||||
LTRACEF("raw apic base msr %#llx\n", apic_base);
|
||||
|
||||
// make sure it's enabled
|
||||
if ((apic_base & 0x800) == 0) {
|
||||
if ((apic_base & (1u<<11)) == 0) {
|
||||
dprintf(INFO, "X86: enabling lapic\n");
|
||||
apic_base |= 0x800;
|
||||
apic_base |= (1u<<11);
|
||||
write_msr(0x1b, apic_base);
|
||||
}
|
||||
|
||||
apic_base &= ~0xfff;
|
||||
dprintf(INFO, "X86: lapic physical address %#llx\n", apic_base);
|
||||
dprintf(INFO, "X86: lapic physical address %#llx\n", apic_base & ~0xfff);
|
||||
|
||||
// see if x2APIC mode is supported and enable
|
||||
if (x86_feature_test(X86_FEATURE_X2APIC)) {
|
||||
lapic_x2apic = true;
|
||||
dprintf(INFO, "X86: local apic supports x2APIC mode\n");
|
||||
|
||||
write_msr(X86_MSR_IA32_APIC_BASE, apic_base | (1u<<10));
|
||||
}
|
||||
|
||||
// map the lapic into the kernel since it's not guaranteed that the physmap covers it
|
||||
status_t err = vmm_alloc_physical(vmm_get_kernel_aspace(), "lapic", PAGE_SIZE, (void **)&lapic_mmio, 0,
|
||||
apic_base & ~0xfff, /* vmm_flags */ 0, ARCH_MMU_FLAG_UNCACHED_DEVICE);
|
||||
ASSERT(err == NO_ERROR);
|
||||
if (!lapic_mmio) {
|
||||
dprintf(INFO, "X86: mapping lapic into kernel\n");
|
||||
status_t err = vmm_alloc_physical(vmm_get_kernel_aspace(), "lapic", PAGE_SIZE, (void **)&lapic_mmio, 0,
|
||||
apic_base & ~0xfff, /* vmm_flags */ 0, ARCH_MMU_FLAG_UNCACHED_DEVICE);
|
||||
ASSERT(err == NO_ERROR);
|
||||
}
|
||||
|
||||
// Read the local apic id and version and features
|
||||
uint32_t id = lapic_read(LAPIC_ID);
|
||||
@@ -120,37 +156,39 @@ void lapic_init_postvm(uint level) {
|
||||
if (eas) {
|
||||
dprintf(INFO, "X86: local apic EAS features %#x\n", lapic_read(LAPIC_EXT_FEATURES));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
LK_INIT_HOOK(lapic, lapic_init_postvm, LK_INIT_LEVEL_VM);
|
||||
|
||||
void lapic_eoi(unsigned int vector) {
|
||||
LTRACEF("vector %#x\n", vector);
|
||||
if (lapic_present) {
|
||||
lapic_write(LAPIC_EOI, 0);
|
||||
if (!lapic_present) {
|
||||
return;
|
||||
}
|
||||
|
||||
lapic_write(LAPIC_EOI, 0);
|
||||
}
|
||||
|
||||
void lapic_send_init_ipi(uint32_t apic_id, bool level) {
|
||||
if (lapic_present) {
|
||||
lapic_write(LAPIC_ICRHI, apic_id << 24);
|
||||
lapic_write(LAPIC_ICRLO, (5u << 8) | (level ? (1u << 14) : 0));
|
||||
if (!lapic_present) {
|
||||
return;
|
||||
}
|
||||
|
||||
lapic_write_icr((5u << 8) | (level ? (1u << 14) : 0), apic_id);
|
||||
}
|
||||
|
||||
void lapic_send_startup_ipi(uint32_t apic_id, uint32_t startup_vector) {
|
||||
if (lapic_present) {
|
||||
lapic_write(LAPIC_ICRHI, apic_id << 24);
|
||||
lapic_write(LAPIC_ICRLO, (6u << 8) | (startup_vector >> 12));
|
||||
if (!lapic_present) {
|
||||
return;
|
||||
}
|
||||
|
||||
lapic_write_icr((6u << 8) | (startup_vector >> 12), apic_id);
|
||||
}
|
||||
|
||||
void lapic_send_ipi(uint32_t apic_id, uint32_t vector) {
|
||||
if (lapic_present) {
|
||||
lapic_write(LAPIC_ICRHI, apic_id << 24);
|
||||
// XXX add correct flag bits
|
||||
lapic_write(LAPIC_ICRLO, vector);
|
||||
if (!lapic_present) {
|
||||
return;
|
||||
}
|
||||
|
||||
lapic_write_icr(vector, apic_id);
|
||||
}
|
||||
Reference in New Issue
Block a user