cpu/x86/lapic: Support switching to X2APIC mode

The options X2APIC_ONLY and X2APIC_RUNTIME were already user-visible
choices in menuconfig, but the functionality was not actually provided
except for platforms where FSP presumably enabled X2APIC.

Add the logic and related logging for switching to X2APIC operation.

TEST: qemu-system-x86_64 -M Q35 -accel kvm -bios coreboot.rom -serial
stdio -smp 2

PARALLEL_MP, and either X2APIC_ONLY or X2APIC_RUNTIME, need to be
selected for the build of emulation/qemu-q35.

Change-Id: I19a990ba287d21ccddaa64601923f1c4830e95e9
Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/55262
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Arthur Heymans <arthur@aheymans.xyz>
Reviewed-by: Wonkyu Kim <wonkyu.kim@intel.com>
This commit is contained in:
Kyösti Mälkki 2021-06-06 17:07:25 +03:00
parent ceaf959678
commit c8d26c0158
4 changed files with 39 additions and 11 deletions

View File

@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <assert.h>
#include <cpu/cpu.h>
#include <cpu/x86/lapic.h>
#include <cpu/x86/lapic_def.h>
@ -10,23 +11,52 @@
void enable_lapic(void)
{
uintptr_t apic_base;
bool use_x2apic;
msr_t msr;
msr = rdmsr(LAPIC_BASE_MSR);
msr.hi &= 0xffffff00;
msr.lo &= ~LAPIC_BASE_MSR_ADDR_MASK;
msr.lo |= LAPIC_DEFAULT_BASE;
msr.lo |= LAPIC_BASE_MSR_ENABLE;
wrmsr(LAPIC_BASE_MSR, msr);
if (!(msr.lo & LAPIC_BASE_MSR_ENABLE)) {
msr.hi &= 0xffffff00;
msr.lo &= ~LAPIC_BASE_MSR_ADDR_MASK;
msr.lo |= LAPIC_DEFAULT_BASE;
msr.lo |= LAPIC_BASE_MSR_ENABLE;
wrmsr(LAPIC_BASE_MSR, msr);
msr = rdmsr(LAPIC_BASE_MSR);
}
ASSERT(msr.lo & LAPIC_BASE_MSR_ENABLE);
apic_base = msr.lo & LAPIC_BASE_MSR_ADDR_MASK;
ASSERT(apic_base == LAPIC_DEFAULT_BASE);
if (CONFIG(XAPIC_ONLY)) {
use_x2apic = false;
} else {
use_x2apic = !!(cpu_get_feature_flags_ecx() & CPUID_X2APIC);
ASSERT(CONFIG(X2APIC_RUNTIME) || use_x2apic);
}
if (use_x2apic == !!(msr.lo & LAPIC_BASE_MSR_X2APIC_MODE)) {
printk(BIOS_INFO, "LAPIC 0x%x in %s mode.\n", lapicid(),
use_x2apic ? "X2APIC" : "XAPIC");
} else if (use_x2apic) {
msr.lo |= LAPIC_BASE_MSR_X2APIC_MODE;
wrmsr(LAPIC_BASE_MSR, msr);
msr = rdmsr(LAPIC_BASE_MSR);
ASSERT(!!(msr.lo & LAPIC_BASE_MSR_X2APIC_MODE));
printk(BIOS_INFO, "LAPIC 0x%x switched to X2APIC mode.\n", lapicid());
} else {
die("Switching from X2APIC to XAPIC mode is not implemented.");
}
printk(BIOS_INFO, "Setting up local APIC 0x%x\n", lapicid());
}
void disable_lapic(void)
{
msr_t msr;
msr = rdmsr(LAPIC_BASE_MSR);
msr.lo &= ~LAPIC_BASE_MSR_ENABLE;
msr.lo &= ~(LAPIC_BASE_MSR_ENABLE | LAPIC_BASE_MSR_X2APIC_MODE);
wrmsr(LAPIC_BASE_MSR, msr);
}

View File

@ -454,9 +454,6 @@ static enum cb_err start_aps(struct bus *cpu_bus, int ap_count, atomic_t *num_ap
printk(BIOS_DEBUG, "Attempting to start %d APs\n", ap_count);
int x2apic_mode = is_x2apic_mode();
printk(BIOS_DEBUG, "Starting CPUs in %s mode\n", x2apic_mode ? "x2apic" : "xapic");
if (lapic_busy()) {
printk(BIOS_DEBUG, "Waiting for ICR not to be busy...\n");
if (apic_wait_timeout(1000 /* 1 ms */, 50) != CB_SUCCESS) {

View File

@ -59,7 +59,7 @@ static __always_inline void x2apic_send_ipi(uint32_t icrlow, uint32_t apicid)
wrmsr(X2APIC_MSR_ICR_ADDRESS, icr);
}
static inline bool is_x2apic_mode(void)
static __always_inline bool is_x2apic_mode(void)
{
if (CONFIG(XAPIC_ONLY))
return false;

View File

@ -24,6 +24,7 @@
#define CPUID_VMX (1 << 5)
#define CPUID_SMX (1 << 6)
#define CPUID_DCA (1 << 18)
#define CPUID_X2APIC (1 << 21)
#define CPUID_AES (1 << 25)
#define SGX_GLOBAL_ENABLE (1 << 18)
#define PLATFORM_INFO_SET_TDP (1 << 29)