Skip to content

Commit

Permalink
x86/apic: Provide apic_force_nmi_on_cpu()
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Borislav Petkov (AMD) <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
  • Loading branch information
KAGA-KOKO authored and bp3tk0v committed Oct 24, 2023
1 parent 1582c0f commit 9cab5fb
Show file tree
Hide file tree
Showing 5 changed files with 16 additions and 1 deletion.
5 changes: 4 additions & 1 deletion arch/x86/include/asm/apic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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; }
Expand Down
2 changes: 2 additions & 0 deletions arch/x86/kernel/apic/apic_flat_64.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
8 changes: 8 additions & 0 deletions arch/x86/kernel/apic/ipi.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,14 @@ void native_send_call_func_ipi(const struct cpumask *mask)
__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)
Expand Down
1 change: 1 addition & 0 deletions arch/x86/kernel/apic/x2apic_cluster.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions arch/x86/kernel/apic/x2apic_phys.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 9cab5fb

Please sign in to comment.