Skip to content

Commit de31b3c

Browse files
xinli-intelhansendc
authored andcommitted
x86/fred: Fix the FRED RSP0 MSR out of sync with its per-CPU cache
The FRED RSP0 MSR is only used for delivering events when running userspace. Linux leverages this property to reduce expensive MSR writes and optimize context switches. The kernel only writes the MSR when about to run userspace *and* when the MSR has actually changed since the last time userspace ran. This optimization is implemented by maintaining a per-CPU cache of FRED RSP0 and then checking that against the value for the top of current task stack before running userspace. However cpu_init_fred_exceptions() writes the MSR without updating the per-CPU cache. This means that the kernel might return to userspace with MSR_IA32_FRED_RSP0==0 when it needed to point to the top of current task stack. This would induce a double fault (#DF), which is bad. A context switch after cpu_init_fred_exceptions() can paper over the issue since it updates the cached value. That evidently happens most of the time explaining how this bug got through. Fix the bug through resynchronizing the FRED RSP0 MSR with its per-CPU cache in cpu_init_fred_exceptions(). Fixes: fe85ee3 ("x86/entry: Set FRED RSP0 on return to userspace instead of context switch") Signed-off-by: Xin Li (Intel) <[email protected]> Signed-off-by: Dave Hansen <[email protected]> Acked-by: Dave Hansen <[email protected]> Cc:[email protected] Link: https://lore.kernel.org/all/20250110174639.1250829-1-xin%40zytor.com
1 parent a9bbe34 commit de31b3c

File tree

1 file changed

+7
-1
lines changed

1 file changed

+7
-1
lines changed

arch/x86/kernel/fred.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,13 @@ void cpu_init_fred_exceptions(void)
5050
FRED_CONFIG_ENTRYPOINT(asm_fred_entrypoint_user));
5151

5252
wrmsrl(MSR_IA32_FRED_STKLVLS, 0);
53-
wrmsrl(MSR_IA32_FRED_RSP0, 0);
53+
54+
/*
55+
* Ater a CPU offline/online cycle, the FRED RSP0 MSR should be
56+
* resynchronized with its per-CPU cache.
57+
*/
58+
wrmsrl(MSR_IA32_FRED_RSP0, __this_cpu_read(fred_rsp0));
59+
5460
wrmsrl(MSR_IA32_FRED_RSP1, 0);
5561
wrmsrl(MSR_IA32_FRED_RSP2, 0);
5662
wrmsrl(MSR_IA32_FRED_RSP3, 0);

0 commit comments

Comments
 (0)