forked from rpms/kernel
226 lines
7.4 KiB
Diff
226 lines
7.4 KiB
Diff
From ce57ab2e87f50d1176abea086f4aad38ba87886b Mon Sep 17 00:00:00 2001
|
|
From: Daniel Sneddon <daniel.sneddon@linux.intel.com>
|
|
Date: Tue, 16 Aug 2022 16:19:42 -0700
|
|
Subject: [PATCH 25/36] x86/apic: Don't disable x2APIC if locked
|
|
|
|
The APIC supports two modes, legacy APIC (or xAPIC), and Extended APIC
|
|
(or x2APIC). X2APIC mode is mostly compatible with legacy APIC, but
|
|
it disables the memory-mapped APIC interface in favor of one that uses
|
|
MSRs. The APIC mode is controlled by the EXT bit in the APIC MSR.
|
|
|
|
The MMIO/xAPIC interface has some problems, most notably the APIC LEAK
|
|
[1]. This bug allows an attacker to use the APIC MMIO interface to
|
|
extract data from the SGX enclave.
|
|
|
|
Introduce support for a new feature that will allow the BIOS to lock
|
|
the APIC in x2APIC mode. If the APIC is locked in x2APIC mode and the
|
|
kernel tries to disable the APIC or revert to legacy APIC mode a GP
|
|
fault will occur.
|
|
|
|
Introduce support for a new MSR (IA32_XAPIC_DISABLE_STATUS) and handle
|
|
the new locked mode when the LEGACY_XAPIC_DISABLED bit is set by
|
|
preventing the kernel from trying to disable the x2APIC.
|
|
|
|
On platforms with the IA32_XAPIC_DISABLE_STATUS MSR, if SGX or TDX are
|
|
enabled the LEGACY_XAPIC_DISABLED will be set by the BIOS. If
|
|
legacy APIC is required, then it SGX and TDX need to be disabled in the
|
|
BIOS.
|
|
|
|
[1]: https://aepicleak.com/aepicleak.pdf
|
|
|
|
Signed-off-by: Daniel Sneddon <daniel.sneddon@linux.intel.com>
|
|
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
|
|
Acked-by: Dave Hansen <dave.hansen@linux.intel.com>
|
|
Tested-by: Neelima Krishnan <neelima.krishnan@intel.com>
|
|
Link: https://lkml.kernel.org/r/20220816231943.1152579-1-daniel.sneddon@linux.intel.com
|
|
(cherry picked from commit b8d1d163604bd1e600b062fb00de5dc42baa355f)
|
|
Signed-off-by: Mridula Shastry <mridula.c.shastry@oracle.com>
|
|
Reviewed-by: Todd Vierling <todd.vierling@oracle.com>
|
|
---
|
|
.../admin-guide/kernel-parameters.txt | 4 ++
|
|
arch/x86/Kconfig | 7 ++-
|
|
arch/x86/include/asm/cpu.h | 2 +
|
|
arch/x86/include/asm/msr-index.h | 13 ++++++
|
|
arch/x86/kernel/apic/apic.c | 44 +++++++++++++++++--
|
|
5 files changed, 65 insertions(+), 5 deletions(-)
|
|
|
|
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
|
|
index 25f0b3a543e9..73a92fb9e3c6 100644
|
|
--- a/Documentation/admin-guide/kernel-parameters.txt
|
|
+++ b/Documentation/admin-guide/kernel-parameters.txt
|
|
@@ -3355,6 +3355,10 @@
|
|
|
|
nox2apic [X86-64,APIC] Do not enable x2APIC mode.
|
|
|
|
+ NOTE: this parameter will be ignored on systems with the
|
|
+ LEGACY_XAPIC_DISABLED bit set in the
|
|
+ IA32_XAPIC_DISABLE_STATUS MSR.
|
|
+
|
|
cpu0_hotplug [X86] Turn on CPU0 hotplug feature when
|
|
CONFIG_BOOTPARAM_HOTPLUG_CPU0 is off.
|
|
Some features depend on CPU0. Known dependencies are:
|
|
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
|
|
index 5af5427c50ae..585893a349b6 100644
|
|
--- a/arch/x86/Kconfig
|
|
+++ b/arch/x86/Kconfig
|
|
@@ -449,6 +449,11 @@ config X86_X2APIC
|
|
This allows 32-bit apic IDs (so it can support very large systems),
|
|
and accesses the local apic via MSRs not via mmio.
|
|
|
|
+ Some Intel systems circa 2022 and later are locked into x2APIC mode
|
|
+ and can not fall back to the legacy APIC modes if SGX or TDX are
|
|
+ enabled in the BIOS. They will be unable to boot without enabling
|
|
+ this option.
|
|
+
|
|
If you don't know what to do here, say N.
|
|
|
|
config X86_MPPARSE
|
|
@@ -1979,7 +1984,7 @@ endchoice
|
|
|
|
config X86_SGX
|
|
bool "Software Guard eXtensions (SGX)"
|
|
- depends on X86_64 && CPU_SUP_INTEL
|
|
+ depends on X86_64 && CPU_SUP_INTEL && X86_X2APIC
|
|
depends on CRYPTO=y
|
|
depends on CRYPTO_SHA256=y
|
|
select SRCU
|
|
diff --git a/arch/x86/include/asm/cpu.h b/arch/x86/include/asm/cpu.h
|
|
index 2d62a3f122ee..66f9715b01c9 100644
|
|
--- a/arch/x86/include/asm/cpu.h
|
|
+++ b/arch/x86/include/asm/cpu.h
|
|
@@ -92,4 +92,6 @@ static inline bool intel_cpu_signatures_match(unsigned int s1, unsigned int p1,
|
|
return p1 & p2;
|
|
}
|
|
|
|
+extern u64 x86_read_arch_cap_msr(void);
|
|
+
|
|
#endif /* _ASM_X86_CPU_H */
|
|
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
|
|
index e30f8e289deb..9b0d407dd1ae 100644
|
|
--- a/arch/x86/include/asm/msr-index.h
|
|
+++ b/arch/x86/include/asm/msr-index.h
|
|
@@ -153,6 +153,11 @@
|
|
* Return Stack Buffer Predictions.
|
|
*/
|
|
|
|
+#define ARCH_CAP_XAPIC_DISABLE BIT(21) /*
|
|
+ * IA32_XAPIC_DISABLE_STATUS MSR
|
|
+ * supported
|
|
+ */
|
|
+
|
|
#define MSR_IA32_FLUSH_CMD 0x0000010b
|
|
#define L1D_FLUSH BIT(0) /*
|
|
* Writeback and invalidate the
|
|
@@ -1015,4 +1020,12 @@
|
|
#define MSR_IA32_HW_FEEDBACK_PTR 0x17d0
|
|
#define MSR_IA32_HW_FEEDBACK_CONFIG 0x17d1
|
|
|
|
+/* x2APIC locked status */
|
|
+#define MSR_IA32_XAPIC_DISABLE_STATUS 0xBD
|
|
+#define LEGACY_XAPIC_DISABLED BIT(0) /*
|
|
+ * x2APIC mode is locked and
|
|
+ * disabling x2APIC will cause
|
|
+ * a #GP
|
|
+ */
|
|
+
|
|
#endif /* _ASM_X86_MSR_INDEX_H */
|
|
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
|
|
index b191e575e53c..d73f1037961a 100644
|
|
--- a/arch/x86/kernel/apic/apic.c
|
|
+++ b/arch/x86/kernel/apic/apic.c
|
|
@@ -57,6 +57,7 @@
|
|
#include <asm/cpu_device_id.h>
|
|
#include <asm/intel-family.h>
|
|
#include <asm/irq_regs.h>
|
|
+#include <asm/cpu.h>
|
|
|
|
unsigned int num_processors;
|
|
|
|
@@ -1734,11 +1735,26 @@ EXPORT_SYMBOL_GPL(x2apic_mode);
|
|
|
|
enum {
|
|
X2APIC_OFF,
|
|
- X2APIC_ON,
|
|
X2APIC_DISABLED,
|
|
+ /* All states below here have X2APIC enabled */
|
|
+ X2APIC_ON,
|
|
+ X2APIC_ON_LOCKED
|
|
};
|
|
static int x2apic_state;
|
|
|
|
+static bool x2apic_hw_locked(void)
|
|
+{
|
|
+ u64 ia32_cap;
|
|
+ u64 msr;
|
|
+
|
|
+ ia32_cap = x86_read_arch_cap_msr();
|
|
+ if (ia32_cap & ARCH_CAP_XAPIC_DISABLE) {
|
|
+ rdmsrl(MSR_IA32_XAPIC_DISABLE_STATUS, msr);
|
|
+ return (msr & LEGACY_XAPIC_DISABLED);
|
|
+ }
|
|
+ return false;
|
|
+}
|
|
+
|
|
static void __x2apic_disable(void)
|
|
{
|
|
u64 msr;
|
|
@@ -1776,6 +1792,10 @@ static int __init setup_nox2apic(char *str)
|
|
apicid);
|
|
return 0;
|
|
}
|
|
+ if (x2apic_hw_locked()) {
|
|
+ pr_warn("APIC locked in x2apic mode, can't disable\n");
|
|
+ return 0;
|
|
+ }
|
|
pr_warn("x2apic already enabled.\n");
|
|
__x2apic_disable();
|
|
}
|
|
@@ -1790,10 +1810,18 @@ early_param("nox2apic", setup_nox2apic);
|
|
void x2apic_setup(void)
|
|
{
|
|
/*
|
|
- * If x2apic is not in ON state, disable it if already enabled
|
|
+ * Try to make the AP's APIC state match that of the BSP, but if the
|
|
+ * BSP is unlocked and the AP is locked then there is a state mismatch.
|
|
+ * Warn about the mismatch in case a GP fault occurs due to a locked AP
|
|
+ * trying to be turned off.
|
|
+ */
|
|
+ if (x2apic_state != X2APIC_ON_LOCKED && x2apic_hw_locked())
|
|
+ pr_warn("x2apic lock mismatch between BSP and AP.\n");
|
|
+ /*
|
|
+ * If x2apic is not in ON or LOCKED state, disable it if already enabled
|
|
* from BIOS.
|
|
*/
|
|
- if (x2apic_state != X2APIC_ON) {
|
|
+ if (x2apic_state < X2APIC_ON) {
|
|
__x2apic_disable();
|
|
return;
|
|
}
|
|
@@ -1814,6 +1842,11 @@ static __init void x2apic_disable(void)
|
|
if (x2apic_id >= 255)
|
|
panic("Cannot disable x2apic, id: %08x\n", x2apic_id);
|
|
|
|
+ if (x2apic_hw_locked()) {
|
|
+ pr_warn("Cannot disable locked x2apic, id: %08x\n", x2apic_id);
|
|
+ return;
|
|
+ }
|
|
+
|
|
__x2apic_disable();
|
|
register_lapic_address(mp_lapic_addr);
|
|
}
|
|
@@ -1872,7 +1905,10 @@ void __init check_x2apic(void)
|
|
if (x2apic_enabled()) {
|
|
pr_info("x2apic: enabled by BIOS, switching to x2apic ops\n");
|
|
x2apic_mode = 1;
|
|
- x2apic_state = X2APIC_ON;
|
|
+ if (x2apic_hw_locked())
|
|
+ x2apic_state = X2APIC_ON_LOCKED;
|
|
+ else
|
|
+ x2apic_state = X2APIC_ON;
|
|
} else if (!boot_cpu_has(X86_FEATURE_X2APIC)) {
|
|
x2apic_state = X2APIC_DISABLED;
|
|
}
|
|
--
|
|
2.39.3
|
|
|