From: "Xin Li (Intel)" <[email protected]>

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) <[email protected]>
Signed-off-by: Sohil Mehta <[email protected]>
---
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


Reply via email to