Skip to content

Commit fe85ee3

Browse files
xinli-intelKAGA-KOKO
authored andcommitted
x86/entry: Set FRED RSP0 on return to userspace instead of context switch
The FRED RSP0 MSR points to the top of the kernel stack for user level event delivery. As this is the task stack it needs to be updated when a task is scheduled in. The update is done at context switch. That means it's also done when switching to kernel threads, which is pointless as those never go out to user space. For KVM threads this means there are two writes to FRED_RSP0 as KVM has to switch to the guest value before VMENTER. Defer the update to the exit to user space path and cache the per CPU FRED_RSP0 value, so redundant writes can be avoided. Provide fred_sync_rsp0() for KVM to keep the cache in sync with the actual MSR value after returning from guest to host mode. [ tglx: Massage change log ] Suggested-by: Sean Christopherson <[email protected]> Suggested-by: Thomas Gleixner <[email protected]> Signed-off-by: Xin Li (Intel) <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Link: https://lore.kernel.org/all/[email protected]
1 parent efe5088 commit fe85ee3

File tree

4 files changed

+27
-5
lines changed

4 files changed

+27
-5
lines changed

arch/x86/include/asm/entry-common.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <asm/nospec-branch.h>
99
#include <asm/io_bitmap.h>
1010
#include <asm/fpu/api.h>
11+
#include <asm/fred.h>
1112

1213
/* Check that the stack and regs on entry from user mode are sane. */
1314
static __always_inline void arch_enter_from_user_mode(struct pt_regs *regs)
@@ -63,6 +64,8 @@ static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs,
6364
if (IS_ENABLED(CONFIG_X86_DEBUG_FPU) || unlikely(ti_work))
6465
arch_exit_work(ti_work);
6566

67+
fred_update_rsp0();
68+
6669
#ifdef CONFIG_COMPAT
6770
/*
6871
* Compat syscalls set TS_COMPAT. Make sure we clear it before

arch/x86/include/asm/fred.h

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636

3737
#ifdef CONFIG_X86_FRED
3838
#include <linux/kernel.h>
39+
#include <linux/sched/task_stack.h>
3940

4041
#include <asm/ptrace.h>
4142

@@ -87,12 +88,30 @@ void cpu_init_fred_exceptions(void);
8788
void cpu_init_fred_rsps(void);
8889
void fred_complete_exception_setup(void);
8990

91+
DECLARE_PER_CPU(unsigned long, fred_rsp0);
92+
93+
static __always_inline void fred_sync_rsp0(unsigned long rsp0)
94+
{
95+
__this_cpu_write(fred_rsp0, rsp0);
96+
}
97+
98+
static __always_inline void fred_update_rsp0(void)
99+
{
100+
unsigned long rsp0 = (unsigned long) task_stack_page(current) + THREAD_SIZE;
101+
102+
if (cpu_feature_enabled(X86_FEATURE_FRED) && (__this_cpu_read(fred_rsp0) != rsp0)) {
103+
wrmsrns(MSR_IA32_FRED_RSP0, rsp0);
104+
__this_cpu_write(fred_rsp0, rsp0);
105+
}
106+
}
90107
#else /* CONFIG_X86_FRED */
91108
static __always_inline unsigned long fred_event_data(struct pt_regs *regs) { return 0; }
92109
static inline void cpu_init_fred_exceptions(void) { }
93110
static inline void cpu_init_fred_rsps(void) { }
94111
static inline void fred_complete_exception_setup(void) { }
95-
static __always_inline void fred_entry_from_kvm(unsigned int type, unsigned int vector) { }
112+
static inline void fred_entry_from_kvm(unsigned int type, unsigned int vector) { }
113+
static inline void fred_sync_rsp0(unsigned long rsp0) { }
114+
static inline void fred_update_rsp0(void) { }
96115
#endif /* CONFIG_X86_FRED */
97116
#endif /* !__ASSEMBLY__ */
98117

arch/x86/include/asm/switch_to.h

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,9 @@ static inline void update_task_stack(struct task_struct *task)
7070
#ifdef CONFIG_X86_32
7171
this_cpu_write(cpu_tss_rw.x86_tss.sp1, task->thread.sp0);
7272
#else
73-
if (cpu_feature_enabled(X86_FEATURE_FRED)) {
74-
wrmsrns(MSR_IA32_FRED_RSP0, (unsigned long)task_stack_page(task) + THREAD_SIZE);
75-
} else if (cpu_feature_enabled(X86_FEATURE_XENPV)) {
73+
if (!cpu_feature_enabled(X86_FEATURE_FRED) && cpu_feature_enabled(X86_FEATURE_XENPV))
7674
/* Xen PV enters the kernel on the thread stack. */
7775
load_sp0(task_top_of_stack(task));
78-
}
7976
#endif
8077
}
8178

arch/x86/kernel/fred.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121

2222
#define FRED_STKLVL(vector, lvl) ((lvl) << (2 * (vector)))
2323

24+
DEFINE_PER_CPU(unsigned long, fred_rsp0);
25+
EXPORT_PER_CPU_SYMBOL(fred_rsp0);
26+
2427
void cpu_init_fred_exceptions(void)
2528
{
2629
/* When FRED is enabled by default, remove this log message */

0 commit comments

Comments
 (0)