[PATCH v10 06/28] x86/fred: Export this_cpu_fred_rsp() for KVM usage
From: Sohil Mehta
Date: Fri Sep 11 2026 - 17:43:33 EST
From: "Xin Li (Intel)" <xin@xxxxxxxxx>
Introduce and export this_cpu_fred_rsp() to provide KVM with a self-
explanatory interface for retrieving per-CPU FRED regular stacks for
stack levels 1->3.
FRED introduced new fields in the VMCS host-state area for stack levels
1–>3 (HOST_IA32_FRED_RSP[123]), which correspond to the per-CPU FRED
regular stacks for stack levels 1->3. KVM must populate these fields
each time a vCPU is loaded onto a CPU to ensure a complete valid FRED
event delivery context immediately after any VM-Exits.
Signed-off-by: Xin Li (Intel) <xin@xxxxxxxxx>
Signed-off-by: Sohil Mehta <sohil.mehta@xxxxxxxxx>
---
v10:
- Replace direct, raw use of __this_cpu_ist_top_va() with a self-
explanatory this_cpu_fred_rsp() helper for better readability (Sean).
---
arch/x86/include/asm/fred.h | 10 ++++++++++
arch/x86/kernel/fred.c | 24 +++++++++++++++++++++---
2 files changed, 31 insertions(+), 3 deletions(-)
diff --git a/arch/x86/include/asm/fred.h b/arch/x86/include/asm/fred.h
index 18a2f811c358..85b851f16bae 100644
--- a/arch/x86/include/asm/fred.h
+++ b/arch/x86/include/asm/fred.h
@@ -35,6 +35,13 @@
#ifndef __ASSEMBLER__
+enum fred_stack_level {
+ FRED_STACK_LEVEL_0,
+ FRED_STACK_LEVEL_1,
+ FRED_STACK_LEVEL_2,
+ FRED_STACK_LEVEL_3
+};
+
#ifdef CONFIG_X86_FRED
#include <linux/kernel.h>
#include <linux/sched/task_stack.h>
@@ -105,6 +112,8 @@ static __always_inline void fred_update_rsp0(void)
__this_cpu_write(fred_rsp0, rsp0);
}
}
+
+unsigned long this_cpu_fred_rsp(enum fred_stack_level lvl);
#else /* CONFIG_X86_FRED */
static __always_inline unsigned long fred_event_data(struct pt_regs *regs) { return 0; }
static inline void cpu_init_fred_exceptions(void) { }
@@ -112,6 +121,7 @@ static inline void cpu_init_fred_rsps(void) { }
static inline void fred_complete_exception_setup(void) { }
static inline void fred_sync_rsp0(unsigned long rsp0) { }
static inline void fred_update_rsp0(void) { }
+static inline unsigned long this_cpu_fred_rsp(enum fred_stack_level lvl) { return 0; }
#endif /* CONFIG_X86_FRED */
#endif /* !__ASSEMBLER__ */
diff --git a/arch/x86/kernel/fred.c b/arch/x86/kernel/fred.c
index 1c452a389a70..68947c53a494 100644
--- a/arch/x86/kernel/fred.c
+++ b/arch/x86/kernel/fred.c
@@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/kernel.h>
+#include <linux/kvm_types.h>
#include <asm/desc.h>
#include <asm/fred.h>
@@ -69,6 +70,23 @@ void cpu_init_fred_exceptions(void)
setup_clear_cpu_cap(X86_FEATURE_SYSCALL32);
}
+unsigned long this_cpu_fred_rsp(enum fred_stack_level lvl)
+{
+ switch (lvl) {
+ case FRED_STACK_LEVEL_0:
+ return __this_cpu_read(fred_rsp0);
+ case FRED_STACK_LEVEL_1:
+ return __this_cpu_ist_top_va(ESTACK_DB);
+ case FRED_STACK_LEVEL_2:
+ return __this_cpu_ist_top_va(ESTACK_NMI);
+ case FRED_STACK_LEVEL_3:
+ return __this_cpu_ist_top_va(ESTACK_DF);
+ default:
+ BUG();
+ }
+}
+EXPORT_SYMBOL_FOR_KVM(this_cpu_fred_rsp);
+
/* Must be called after setup_cpu_entry_areas() */
void cpu_init_fred_rsps(void)
{
@@ -84,7 +102,7 @@ void cpu_init_fred_rsps(void)
FRED_STKLVL(X86_TRAP_DF, FRED_DF_STACK_LEVEL));
/* The FRED equivalents to IST stacks... */
- wrmsrq(MSR_IA32_FRED_RSP1, __this_cpu_ist_top_va(ESTACK_DB));
- wrmsrq(MSR_IA32_FRED_RSP2, __this_cpu_ist_top_va(ESTACK_NMI));
- wrmsrq(MSR_IA32_FRED_RSP3, __this_cpu_ist_top_va(ESTACK_DF));
+ wrmsrq(MSR_IA32_FRED_RSP1, this_cpu_fred_rsp(FRED_STACK_LEVEL_1));
+ wrmsrq(MSR_IA32_FRED_RSP2, this_cpu_fred_rsp(FRED_STACK_LEVEL_2));
+ wrmsrq(MSR_IA32_FRED_RSP3, this_cpu_fred_rsp(FRED_STACK_LEVEL_3));
}
--
2.43.0