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

