From 7f0b5edd8c23ce1b285d00f7f376e5ad5a23c6ef Mon Sep 17 00:00:00 2001 From: Ederson de Souza Date: Tue, 28 May 2024 21:23:28 -0700 Subject: [PATCH] arch/x86: Make irq_offload SMP-safe on x86_64 The irq_offload mechanism was using the same entry of the IDT vector for all CPUs on SMP systems. This caused race conditions when two CPUs were doing irq_offload() calls. This patch addresses that by adding one indirection layer: the irq_offload() now sets a per CPU entry with the routine and parameter to be run. Then a software interrupt is generated, and a default handler will do the appropriate dispatching. Finally, test "kernel/smp_abort" is enabled for x86 as it should work now. Fixes #72172. Signed-off-by: Ederson de Souza --- arch/x86/core/intel64/irq_offload.c | 32 +++++++++++++++++++++++++--- tests/kernel/smp_abort/testcase.yaml | 1 - 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/arch/x86/core/intel64/irq_offload.c b/arch/x86/core/intel64/irq_offload.c index 0146321f7d9..c2771d735cf 100644 --- a/arch/x86/core/intel64/irq_offload.c +++ b/arch/x86/core/intel64/irq_offload.c @@ -9,6 +9,7 @@ */ #include +#include #include #include @@ -17,12 +18,37 @@ extern void (*x86_irq_funcs[NR_IRQ_VECTORS])(const void *arg); extern const void *x86_irq_args[NR_IRQ_VECTORS]; +static void (*irq_offload_funcs[CONFIG_MP_NUM_CPUS])(const void *arg); +static const void *irq_offload_args[CONFIG_MP_NUM_CPUS]; + +static void dispatcher(const void *arg) +{ + uint8_t cpu_id = _current_cpu->id; + + if (irq_offload_funcs[cpu_id] != NULL) { + irq_offload_funcs[cpu_id](irq_offload_args[cpu_id]); + } +} void arch_irq_offload(irq_offload_routine_t routine, const void *parameter) { - x86_irq_funcs[CONFIG_IRQ_OFFLOAD_VECTOR - IV_IRQS] = routine; - x86_irq_args[CONFIG_IRQ_OFFLOAD_VECTOR - IV_IRQS] = parameter; + int key = arch_irq_lock(); + uint8_t cpu_id = _current_cpu->id; + + irq_offload_funcs[cpu_id] = routine; + irq_offload_args[cpu_id] = parameter; + __asm__ volatile("int %0" : : "i" (CONFIG_IRQ_OFFLOAD_VECTOR) : "memory"); - x86_irq_funcs[CONFIG_IRQ_OFFLOAD_VECTOR - IV_IRQS] = NULL; + + arch_irq_unlock(key); } + +int irq_offload_init(void) +{ + x86_irq_funcs[CONFIG_IRQ_OFFLOAD_VECTOR - IV_IRQS] = dispatcher; + + return 0; +} + +SYS_INIT(irq_offload_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); diff --git a/tests/kernel/smp_abort/testcase.yaml b/tests/kernel/smp_abort/testcase.yaml index 3903e477e17..3b5a006991a 100644 --- a/tests/kernel/smp_abort/testcase.yaml +++ b/tests/kernel/smp_abort/testcase.yaml @@ -1,6 +1,5 @@ tests: kernel.smp_abort: - arch_exclude: x86 # Buggy irq_offload(), see #71172 tags: - kernel - smp