[PATCH] x86/apic: Use x2apic in guest kernels even with unusable CPUs.

From: David Woodhouse
Date: Tue Sep 29 2020 - 12:17:05 EST


From: David Woodhouse <dwmw@xxxxxxxxxxxx>

If the BIOS has enabled x2apic mode, then leave it enabled and don't
fall back to xapic just because some CPUs can't be targeted.

Previously, if there were CPUs with APIC IDs > 255, the kernel would
disable x2apic and fall back to xapic. And then not use the additional
CPUs anyway, since xapic can't target them either.

In fact, xapic mode can target even *fewer* CPUs, since it can't use
the one with APIC ID 255 either. Using x2apic instead gives us at least
one more CPU without needing interrupt remapping in the guest.

Signed-off-by: David Woodhouse <dwmw@xxxxxxxxxxxx>
---
Should we do this even if the BIOS didn't enable x2apic? Probably not,
since if are that many CPUs the BIOS *should* have enabled x2apic, and
if it didn't there might be a reason for that. And this is guest BIOS
so we aren't at the mercy of the normal hardware BIOS crack den.

arch/x86/include/asm/apic.h | 1 +
arch/x86/kernel/apic/apic.c | 18 ++++++++++++++----
arch/x86/kernel/apic/x2apic_phys.c | 9 +++++++++
3 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/arch/x86/include/asm/apic.h b/arch/x86/include/asm/apic.h
index 2cc44e957c31..4b72bb805205 100644
--- a/arch/x86/include/asm/apic.h
+++ b/arch/x86/include/asm/apic.h
@@ -259,6 +259,7 @@ static inline u64 native_x2apic_icr_read(void)

extern int x2apic_mode;
extern int x2apic_phys;
+extern void __init x2apic_set_max_apicid(u32 apicid);
extern void __init check_x2apic(void);
extern void x2apic_setup(void);
static inline int x2apic_enabled(void)
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index 5f943b938167..16198aa1758b 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1838,14 +1838,24 @@ static __init void try_to_enable_x2apic(int remap_mode)
return;

if (remap_mode != IRQ_REMAP_X2APIC_MODE) {
- /* IR is required if there is APIC ID > 255 even when running
- * under KVM
+ /*
+ * If there are APIC IDs above 255, they cannot be used
+ * without interrupt remapping. In a virtual machine, but
+ * not on bare metal, X2APIC can be used anyway. In the
+ * case where BIOS has enabled X2APIC, don't disable it
+ * just because there are APIC IDs that can't be used.
+ * They couldn't be used if the kernel falls back to XAPIC
+ * anyway.
*/
if (max_physical_apicid > 255 ||
!x86_init.hyper.x2apic_available()) {
pr_info("x2apic: IRQ remapping doesn't support X2APIC mode\n");
- x2apic_disable();
- return;
+ if (!x2apic_mode) {
+ x2apic_disable();
+ return;
+ }
+
+ x2apic_set_max_apicid(255);
}

/*
diff --git a/arch/x86/kernel/apic/x2apic_phys.c b/arch/x86/kernel/apic/x2apic_phys.c
index bc9693841353..b4b4e89c1118 100644
--- a/arch/x86/kernel/apic/x2apic_phys.c
+++ b/arch/x86/kernel/apic/x2apic_phys.c
@@ -8,6 +8,12 @@
int x2apic_phys;

static struct apic apic_x2apic_phys;
+static u32 x2apic_max_apicid;
+
+void __init x2apic_set_max_apicid(u32 apicid)
+{
+ x2apic_max_apicid = apicid;
+}

static int __init set_x2apic_phys_mode(char *arg)
{
@@ -98,6 +104,9 @@ static int x2apic_phys_probe(void)
/* Common x2apic functions, also used by x2apic_cluster */
int x2apic_apic_id_valid(u32 apicid)
{
+ if (x2apic_max_apicid && apicid > x2apic_max_apicid)
+ return 0;
+
return 1;
}


Attachment: smime.p7s
Description: S/MIME cryptographic signature