x86/apic: Provide apic_force_nmi_on_cpu()
authorThomas Gleixner <tglx@linutronix.de>
Mon, 2 Oct 2023 12:00:07 +0000 (14:00 +0200)
committerBorislav Petkov (AMD) <bp@alien8.de>
Tue, 24 Oct 2023 13:05:55 +0000 (15:05 +0200)
When SMT siblings are soft-offlined and parked in one of the play_dead()
variants they still react on NMI, which is problematic on affected Intel
CPUs. The default play_dead() variant uses MWAIT on modern CPUs, which is
not guaranteed to be safe when updated concurrently.

Right now late loading is prevented when not all SMT siblings are online,
but as they still react on NMI, it is possible to bring them out of their
park position into a trivial rendezvous handler.

Provide a function which allows to do that. I does sanity checks whether
the target is in the cpus_booted_once_mask and whether the APIC driver
supports it.

Mark X2APIC and XAPIC as capable, but exclude 32bit and the UV and NUMACHIP
variants as that needs feedback from the relevant experts.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Link: https://lore.kernel.org/r/20231002115903.603100036@linutronix.de
arch/x86/include/asm/apic.h
arch/x86/kernel/apic/apic_flat_64.c
arch/x86/kernel/apic/ipi.c
arch/x86/kernel/apic/x2apic_cluster.c
arch/x86/kernel/apic/x2apic_phys.c

index 5af4ec1a0f71cf9e232aa394981e53ede090d088..17f2f28a495ec6f9e7bc54d659fba260ea30d96d 100644 (file)
@@ -276,7 +276,8 @@ struct apic {
 
        u32     disable_esr             : 1,
                dest_mode_logical       : 1,
-               x2apic_set_max_apicid   : 1;
+               x2apic_set_max_apicid   : 1,
+               nmi_to_offline_cpu      : 1;
 
        u32     (*calc_dest_apicid)(unsigned int cpu);
 
@@ -542,6 +543,8 @@ extern bool default_check_apicid_used(physid_mask_t *map, int apicid);
 extern void default_ioapic_phys_id_map(physid_mask_t *phys_map, physid_mask_t *retmap);
 extern int default_cpu_present_to_apicid(int mps_cpu);
 
+void apic_send_nmi_to_offline_cpu(unsigned int cpu);
+
 #else /* CONFIG_X86_LOCAL_APIC */
 
 static inline unsigned int read_apic_id(void) { return 0; }
index 032a84e2c3ccc7e345ed0c05193965549989510f..cd16228611ce8fcd356e281c1003391963674049 100644 (file)
@@ -103,6 +103,7 @@ static struct apic apic_flat __ro_after_init = {
        .send_IPI_allbutself            = default_send_IPI_allbutself,
        .send_IPI_all                   = default_send_IPI_all,
        .send_IPI_self                  = default_send_IPI_self,
+       .nmi_to_offline_cpu             = true,
 
        .read                           = native_apic_mem_read,
        .write                          = native_apic_mem_write,
@@ -175,6 +176,7 @@ static struct apic apic_physflat __ro_after_init = {
        .send_IPI_allbutself            = default_send_IPI_allbutself,
        .send_IPI_all                   = default_send_IPI_all,
        .send_IPI_self                  = default_send_IPI_self,
+       .nmi_to_offline_cpu             = true,
 
        .read                           = native_apic_mem_read,
        .write                          = native_apic_mem_write,
index a44ba7209ef3a854e36444af9ad53c7314772fbb..edad86f32e38cb5fb36656494f4d2472d8ab7030 100644 (file)
@@ -97,6 +97,14 @@ sendmask:
        __apic_send_IPI_mask(mask, CALL_FUNCTION_VECTOR);
 }
 
+void apic_send_nmi_to_offline_cpu(unsigned int cpu)
+{
+       if (WARN_ON_ONCE(!apic->nmi_to_offline_cpu))
+               return;
+       if (WARN_ON_ONCE(!cpumask_test_cpu(cpu, &cpus_booted_once_mask)))
+               return;
+       apic->send_IPI(cpu, NMI_VECTOR);
+}
 #endif /* CONFIG_SMP */
 
 static inline int __prepare_ICR2(unsigned int mask)
index affbff65e49713d80e88f4097e83b031494c369d..a8306089c91bca12277b904e1b79ad38f1b85122 100644 (file)
@@ -251,6 +251,7 @@ static struct apic apic_x2apic_cluster __ro_after_init = {
        .send_IPI_allbutself            = x2apic_send_IPI_allbutself,
        .send_IPI_all                   = x2apic_send_IPI_all,
        .send_IPI_self                  = x2apic_send_IPI_self,
+       .nmi_to_offline_cpu             = true,
 
        .read                           = native_apic_msr_read,
        .write                          = native_apic_msr_write,
index 788cdb4ee394dae662e4618644e8e240b3666429..c8ac1b12b8ac6c2f8e68cecbc61237e30195babc 100644 (file)
@@ -166,6 +166,7 @@ static struct apic apic_x2apic_phys __ro_after_init = {
        .send_IPI_allbutself            = x2apic_send_IPI_allbutself,
        .send_IPI_all                   = x2apic_send_IPI_all,
        .send_IPI_self                  = x2apic_send_IPI_self,
+       .nmi_to_offline_cpu             = true,
 
        .read                           = native_apic_msr_read,
        .write                          = native_apic_msr_write,