* [PATCH v2 0/3] x86: Write FRED RSP0 on return to userspace
@ 2024-08-22 7:39 Xin Li (Intel)
2024-08-22 7:39 ` [PATCH v2 1/3] x86/entry: Test ti_work for zero before processing individual bits Xin Li (Intel)
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Xin Li (Intel) @ 2024-08-22 7:39 UTC (permalink / raw)
To: linux-kernel
Cc: tglx, mingo, bp, dave.hansen, x86, hpa, peterz, andrew.cooper3,
seanjc
This patch set moves writing MSR_IA32_FRED_RSP0 to return to userspace
from context switch.
In the discussion of save/restore host/guest FRED RSP0 for KVM, Sean
proposed to have the kernel write MSR_IA32_FRED_RSP0 on return to
userspace, i.e., arch_exit_to_user_mode_prepare(), instead of on context
switch. [1]
hpa suggested to test ti_work for zero and then process individual bits
in arch_exit_to_user_mode_prepare. And a quick measurement shows that
in most cases, ti_work values passed to arch_exit_to_user_mode_prepare()
are zeros, e.g., 99% in kernel build tests. This zero test change was
then sent to Intel 0day tests, and no perf regression is reported.
Besides, per the discussion of how to write MSR_IA32_FRED_RSP0 with the
introduction of WRMSRNS [2], use the alternatives mechanism to choose
WRMSRNS when it's available, otherwise fallback to WRMSR.
[1] https://lore.kernel.org/lkml/ZpkfkSMPiXrS9r2K@google.com/
[2] https://lore.kernel.org/lkml/15f56e6a-6edd-43d0-8e83-bb6430096514@citrix.com/
Andrew Cooper (1):
x86/msr: Switch between WRMSRNS and WRMSR with the alternatives
mechanism
Xin Li (Intel) (2):
x86/entry: Test ti_work for zero before processing individual bits
x86/entry: Set FRED RSP0 on return to userspace instead of context
switch
arch/x86/include/asm/entry-common.h | 13 +++++++++++--
arch/x86/include/asm/fred.h | 21 ++++++++++++++++++++-
arch/x86/include/asm/msr.h | 25 +++++++++++--------------
arch/x86/include/asm/switch_to.h | 6 +-----
arch/x86/kernel/cpu/cpuid-deps.c | 1 -
arch/x86/kernel/fred.c | 3 +++
6 files changed, 46 insertions(+), 23 deletions(-)
base-commit: b34bbe44b8222d43d6311d5caa1226ebddda4bfb
--
2.46.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v2 1/3] x86/entry: Test ti_work for zero before processing individual bits
2024-08-22 7:39 [PATCH v2 0/3] x86: Write FRED RSP0 on return to userspace Xin Li (Intel)
@ 2024-08-22 7:39 ` Xin Li (Intel)
2024-08-25 17:28 ` [tip: x86/fred] " tip-bot2 for Xin Li (Intel)
2024-08-22 7:39 ` [PATCH v2 2/3] x86/msr: Switch between WRMSRNS and WRMSR with the alternatives mechanism Xin Li (Intel)
2024-08-22 7:39 ` [PATCH v2 3/3] x86/entry: Set FRED RSP0 on return to userspace instead of context switch Xin Li (Intel)
2 siblings, 1 reply; 7+ messages in thread
From: Xin Li (Intel) @ 2024-08-22 7:39 UTC (permalink / raw)
To: linux-kernel
Cc: tglx, mingo, bp, dave.hansen, x86, hpa, peterz, andrew.cooper3,
seanjc
In most cases, ti_work values passed to arch_exit_to_user_mode_prepare()
are zeros, e.g., 99% in kernel build tests. So an obvious optimization
is to test ti_work for zero before processing individual bits in it.
In addition, Intel 0day tests find no perf regression with this change.
Suggested-by: H. Peter Anvin (Intel) <hpa@zytor.com>
Signed-off-by: Xin Li (Intel) <xin@zytor.com>
---
Change since v1:
* Leave fpregs_assert_state_consistent() unconditional and independent
of ti_work. (Brian Gerst and Thomas Gleixner)
* Add arch_exit_work() to spare an extra indentation level. (Thomas Gleixner)
---
arch/x86/include/asm/entry-common.h | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/arch/x86/include/asm/entry-common.h b/arch/x86/include/asm/entry-common.h
index fb2809b20b0a..db970828f385 100644
--- a/arch/x86/include/asm/entry-common.h
+++ b/arch/x86/include/asm/entry-common.h
@@ -44,8 +44,7 @@ static __always_inline void arch_enter_from_user_mode(struct pt_regs *regs)
}
#define arch_enter_from_user_mode arch_enter_from_user_mode
-static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs,
- unsigned long ti_work)
+static inline void arch_exit_work(unsigned long ti_work)
{
if (ti_work & _TIF_USER_RETURN_NOTIFY)
fire_user_return_notifiers();
@@ -56,6 +55,13 @@ static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs,
fpregs_assert_state_consistent();
if (unlikely(ti_work & _TIF_NEED_FPU_LOAD))
switch_fpu_return();
+}
+
+static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs,
+ unsigned long ti_work)
+{
+ if (IS_ENABLED(CONFIG_X86_DEBUG_FPU) || unlikely(ti_work))
+ arch_exit_work(ti_work);
#ifdef CONFIG_COMPAT
/*
--
2.46.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 2/3] x86/msr: Switch between WRMSRNS and WRMSR with the alternatives mechanism
2024-08-22 7:39 [PATCH v2 0/3] x86: Write FRED RSP0 on return to userspace Xin Li (Intel)
2024-08-22 7:39 ` [PATCH v2 1/3] x86/entry: Test ti_work for zero before processing individual bits Xin Li (Intel)
@ 2024-08-22 7:39 ` Xin Li (Intel)
2024-08-25 17:28 ` [tip: x86/fred] " tip-bot2 for Andrew Cooper
2024-08-22 7:39 ` [PATCH v2 3/3] x86/entry: Set FRED RSP0 on return to userspace instead of context switch Xin Li (Intel)
2 siblings, 1 reply; 7+ messages in thread
From: Xin Li (Intel) @ 2024-08-22 7:39 UTC (permalink / raw)
To: linux-kernel
Cc: tglx, mingo, bp, dave.hansen, x86, hpa, peterz, andrew.cooper3,
seanjc
From: Andrew Cooper <andrew.cooper3@citrix.com>
Per the discussion about FRED MSR writes with WRMSRNS instruction [1],
use the alternatives mechanism to choose WRMSRNS when it's available,
otherwise fallback to WRMSR.
Remove the dependency on X86_FEATURE_WRMSRNS as WRMSRNS is no longer
dependent on FRED.
[1] https://lore.kernel.org/lkml/15f56e6a-6edd-43d0-8e83-bb6430096514@citrix.com/
Note, keep as DS prefix unless we get information to the contrary.
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Signed-off-by: Xin Li (Intel) <xin@zytor.com>
---
Changes since v1:
* Remove the dependency on X86_FEATURE_WRMSRNS. (Thomas Gleixner)
---
arch/x86/include/asm/msr.h | 25 +++++++++++--------------
arch/x86/include/asm/switch_to.h | 1 -
arch/x86/kernel/cpu/cpuid-deps.c | 1 -
3 files changed, 11 insertions(+), 16 deletions(-)
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index d642037f9ed5..001853541f1e 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -99,19 +99,6 @@ static __always_inline void __wrmsr(unsigned int msr, u32 low, u32 high)
: : "c" (msr), "a"(low), "d" (high) : "memory");
}
-/*
- * WRMSRNS behaves exactly like WRMSR with the only difference being
- * that it is not a serializing instruction by default.
- */
-static __always_inline void __wrmsrns(u32 msr, u32 low, u32 high)
-{
- /* Instruction opcode for WRMSRNS; supported in binutils >= 2.40. */
- asm volatile("1: .byte 0x0f,0x01,0xc6\n"
- "2:\n"
- _ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_WRMSR)
- : : "c" (msr), "a"(low), "d" (high));
-}
-
#define native_rdmsr(msr, val1, val2) \
do { \
u64 __val = __rdmsr((msr)); \
@@ -312,9 +299,19 @@ do { \
#endif /* !CONFIG_PARAVIRT_XXL */
+/* Instruction opcode for WRMSRNS supported in binutils >= 2.40 */
+#define WRMSRNS _ASM_BYTES(0x0f,0x01,0xc6)
+
+/* Non-serializing WRMSR, when available. Falls back to a serializing WRMSR. */
static __always_inline void wrmsrns(u32 msr, u64 val)
{
- __wrmsrns(msr, val, val >> 32);
+ /*
+ * WRMSR is 2 bytes. WRMSRNS is 3 bytes. Pad WRMSR with a redundant
+ * DS prefix to avoid a trailing NOP.
+ */
+ asm volatile("1: " ALTERNATIVE("ds wrmsr", WRMSRNS, X86_FEATURE_WRMSRNS)
+ "2: " _ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_WRMSR)
+ : : "c" (msr), "a" ((u32)val), "d" ((u32)(val >> 32)));
}
/*
diff --git a/arch/x86/include/asm/switch_to.h b/arch/x86/include/asm/switch_to.h
index c3bd0c0758c9..e9ded149a9e3 100644
--- a/arch/x86/include/asm/switch_to.h
+++ b/arch/x86/include/asm/switch_to.h
@@ -71,7 +71,6 @@ static inline void update_task_stack(struct task_struct *task)
this_cpu_write(cpu_tss_rw.x86_tss.sp1, task->thread.sp0);
#else
if (cpu_feature_enabled(X86_FEATURE_FRED)) {
- /* WRMSRNS is a baseline feature for FRED. */
wrmsrns(MSR_IA32_FRED_RSP0, (unsigned long)task_stack_page(task) + THREAD_SIZE);
} else if (cpu_feature_enabled(X86_FEATURE_XENPV)) {
/* Xen PV enters the kernel on the thread stack. */
diff --git a/arch/x86/kernel/cpu/cpuid-deps.c b/arch/x86/kernel/cpu/cpuid-deps.c
index b7d9f530ae16..8bd84114c2d9 100644
--- a/arch/x86/kernel/cpu/cpuid-deps.c
+++ b/arch/x86/kernel/cpu/cpuid-deps.c
@@ -83,7 +83,6 @@ static const struct cpuid_dep cpuid_deps[] = {
{ X86_FEATURE_AMX_TILE, X86_FEATURE_XFD },
{ X86_FEATURE_SHSTK, X86_FEATURE_XSAVES },
{ X86_FEATURE_FRED, X86_FEATURE_LKGS },
- { X86_FEATURE_FRED, X86_FEATURE_WRMSRNS },
{}
};
--
2.46.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v2 3/3] x86/entry: Set FRED RSP0 on return to userspace instead of context switch
2024-08-22 7:39 [PATCH v2 0/3] x86: Write FRED RSP0 on return to userspace Xin Li (Intel)
2024-08-22 7:39 ` [PATCH v2 1/3] x86/entry: Test ti_work for zero before processing individual bits Xin Li (Intel)
2024-08-22 7:39 ` [PATCH v2 2/3] x86/msr: Switch between WRMSRNS and WRMSR with the alternatives mechanism Xin Li (Intel)
@ 2024-08-22 7:39 ` Xin Li (Intel)
2024-08-25 17:28 ` [tip: x86/fred] " tip-bot2 for Xin Li (Intel)
2 siblings, 1 reply; 7+ messages in thread
From: Xin Li (Intel) @ 2024-08-22 7:39 UTC (permalink / raw)
To: linux-kernel
Cc: tglx, mingo, bp, dave.hansen, x86, hpa, peterz, andrew.cooper3,
seanjc
FRED RSP0 is a per task constant pointing to top of its kernel stack
for user level event delivery, and needs to be updated when a task is
scheduled in.
Keep FRED RSP0 in per CPU cache, and update FRED RSP0 and its copy in
per CPU cache only when switching to a new task, i.e., current stack
is changed.
An API fred_sync_rsp0() is added for KVM to stuff the cache with the
guest's FRED RSP0 when switching to host.
Suggested-by: Sean Christopherson <seanjc@google.com>
Suggested-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Xin Li (Intel) <xin@zytor.com>
---
Change since v1:
* Use per CPU cache, rather than a new TI flag. (Thomas Gleixner)
---
arch/x86/include/asm/entry-common.h | 3 +++
arch/x86/include/asm/fred.h | 21 ++++++++++++++++++++-
arch/x86/include/asm/switch_to.h | 5 +----
arch/x86/kernel/fred.c | 3 +++
4 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/arch/x86/include/asm/entry-common.h b/arch/x86/include/asm/entry-common.h
index db970828f385..77d20555e04d 100644
--- a/arch/x86/include/asm/entry-common.h
+++ b/arch/x86/include/asm/entry-common.h
@@ -8,6 +8,7 @@
#include <asm/nospec-branch.h>
#include <asm/io_bitmap.h>
#include <asm/fpu/api.h>
+#include <asm/fred.h>
/* Check that the stack and regs on entry from user mode are sane. */
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,
if (IS_ENABLED(CONFIG_X86_DEBUG_FPU) || unlikely(ti_work))
arch_exit_work(ti_work);
+ fred_update_rsp0();
+
#ifdef CONFIG_COMPAT
/*
* Compat syscalls set TS_COMPAT. Make sure we clear it before
diff --git a/arch/x86/include/asm/fred.h b/arch/x86/include/asm/fred.h
index 66d7dbe2d314..25ca00bd70e8 100644
--- a/arch/x86/include/asm/fred.h
+++ b/arch/x86/include/asm/fred.h
@@ -36,6 +36,7 @@
#ifdef CONFIG_X86_FRED
#include <linux/kernel.h>
+#include <linux/sched/task_stack.h>
#include <asm/ptrace.h>
@@ -87,12 +88,30 @@ void cpu_init_fred_exceptions(void);
void cpu_init_fred_rsps(void);
void fred_complete_exception_setup(void);
+DECLARE_PER_CPU(unsigned long, fred_rsp0);
+
+static __always_inline void fred_sync_rsp0(unsigned long rsp0)
+{
+ __this_cpu_write(fred_rsp0, rsp0);
+}
+
+static __always_inline void fred_update_rsp0(void)
+{
+ unsigned long rsp0 = (unsigned long) task_stack_page(current) + THREAD_SIZE;
+
+ if (cpu_feature_enabled(X86_FEATURE_FRED) && (__this_cpu_read(fred_rsp0) != rsp0)) {
+ wrmsrns(MSR_IA32_FRED_RSP0, rsp0);
+ __this_cpu_write(fred_rsp0, rsp0);
+ }
+}
#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) { }
static inline void cpu_init_fred_rsps(void) { }
static inline void fred_complete_exception_setup(void) { }
-static __always_inline void fred_entry_from_kvm(unsigned int type, unsigned int vector) { }
+static inline void fred_entry_from_kvm(unsigned int type, unsigned int vector) { }
+static inline void fred_sync_rsp0(unsigned long rsp0) { }
+static inline void fred_update_rsp0(void) { }
#endif /* CONFIG_X86_FRED */
#endif /* !__ASSEMBLY__ */
diff --git a/arch/x86/include/asm/switch_to.h b/arch/x86/include/asm/switch_to.h
index e9ded149a9e3..75248546403d 100644
--- a/arch/x86/include/asm/switch_to.h
+++ b/arch/x86/include/asm/switch_to.h
@@ -70,12 +70,9 @@ static inline void update_task_stack(struct task_struct *task)
#ifdef CONFIG_X86_32
this_cpu_write(cpu_tss_rw.x86_tss.sp1, task->thread.sp0);
#else
- if (cpu_feature_enabled(X86_FEATURE_FRED)) {
- wrmsrns(MSR_IA32_FRED_RSP0, (unsigned long)task_stack_page(task) + THREAD_SIZE);
- } else if (cpu_feature_enabled(X86_FEATURE_XENPV)) {
+ if (!cpu_feature_enabled(X86_FEATURE_FRED) && cpu_feature_enabled(X86_FEATURE_XENPV))
/* Xen PV enters the kernel on the thread stack. */
load_sp0(task_top_of_stack(task));
- }
#endif
}
diff --git a/arch/x86/kernel/fred.c b/arch/x86/kernel/fred.c
index 99a134fcd5bf..036d5cd47f88 100644
--- a/arch/x86/kernel/fred.c
+++ b/arch/x86/kernel/fred.c
@@ -21,6 +21,9 @@
#define FRED_STKLVL(vector, lvl) ((lvl) << (2 * (vector)))
+DEFINE_PER_CPU(unsigned long, fred_rsp0);
+EXPORT_PER_CPU_SYMBOL(fred_rsp0);
+
void cpu_init_fred_exceptions(void)
{
/* When FRED is enabled by default, remove this log message */
--
2.46.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [tip: x86/fred] x86/entry: Test ti_work for zero before processing individual bits
2024-08-22 7:39 ` [PATCH v2 1/3] x86/entry: Test ti_work for zero before processing individual bits Xin Li (Intel)
@ 2024-08-25 17:28 ` tip-bot2 for Xin Li (Intel)
0 siblings, 0 replies; 7+ messages in thread
From: tip-bot2 for Xin Li (Intel) @ 2024-08-25 17:28 UTC (permalink / raw)
To: linux-tip-commits
Cc: H. Peter Anvin (Intel), Xin Li (Intel), Thomas Gleixner, x86,
linux-kernel
The following commit has been merged into the x86/fred branch of tip:
Commit-ID: 0dfac6f267fa091aa348c6a6742b463c9e7c98e3
Gitweb: https://git.kernel.org/tip/0dfac6f267fa091aa348c6a6742b463c9e7c98e3
Author: Xin Li (Intel) <xin@zytor.com>
AuthorDate: Thu, 22 Aug 2024 00:39:04 -07:00
Committer: Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Sun, 25 Aug 2024 19:23:00 +02:00
x86/entry: Test ti_work for zero before processing individual bits
In most cases, ti_work values passed to arch_exit_to_user_mode_prepare()
are zeros, e.g., 99% in kernel build tests. So an obvious optimization is
to test ti_work for zero before processing individual bits in it.
Omit the optimization when FPU debugging is enabled, otherwise the
FPU consistency check is never executed.
Intel 0day tests did not find a perfermance regression with this change.
Suggested-by: H. Peter Anvin (Intel) <hpa@zytor.com>
Signed-off-by: Xin Li (Intel) <xin@zytor.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/all/20240822073906.2176342-2-xin@zytor.com
---
arch/x86/include/asm/entry-common.h | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/arch/x86/include/asm/entry-common.h b/arch/x86/include/asm/entry-common.h
index fb2809b..db97082 100644
--- a/arch/x86/include/asm/entry-common.h
+++ b/arch/x86/include/asm/entry-common.h
@@ -44,8 +44,7 @@ static __always_inline void arch_enter_from_user_mode(struct pt_regs *regs)
}
#define arch_enter_from_user_mode arch_enter_from_user_mode
-static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs,
- unsigned long ti_work)
+static inline void arch_exit_work(unsigned long ti_work)
{
if (ti_work & _TIF_USER_RETURN_NOTIFY)
fire_user_return_notifiers();
@@ -56,6 +55,13 @@ static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs,
fpregs_assert_state_consistent();
if (unlikely(ti_work & _TIF_NEED_FPU_LOAD))
switch_fpu_return();
+}
+
+static inline void arch_exit_to_user_mode_prepare(struct pt_regs *regs,
+ unsigned long ti_work)
+{
+ if (IS_ENABLED(CONFIG_X86_DEBUG_FPU) || unlikely(ti_work))
+ arch_exit_work(ti_work);
#ifdef CONFIG_COMPAT
/*
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [tip: x86/fred] x86/entry: Set FRED RSP0 on return to userspace instead of context switch
2024-08-22 7:39 ` [PATCH v2 3/3] x86/entry: Set FRED RSP0 on return to userspace instead of context switch Xin Li (Intel)
@ 2024-08-25 17:28 ` tip-bot2 for Xin Li (Intel)
0 siblings, 0 replies; 7+ messages in thread
From: tip-bot2 for Xin Li (Intel) @ 2024-08-25 17:28 UTC (permalink / raw)
To: linux-tip-commits
Cc: Sean Christopherson, Thomas Gleixner, Xin Li (Intel), x86,
linux-kernel
The following commit has been merged into the x86/fred branch of tip:
Commit-ID: fe85ee391966c4cf3bfe1c405314e894c951f521
Gitweb: https://git.kernel.org/tip/fe85ee391966c4cf3bfe1c405314e894c951f521
Author: Xin Li (Intel) <xin@zytor.com>
AuthorDate: Thu, 22 Aug 2024 00:39:06 -07:00
Committer: Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Sun, 25 Aug 2024 19:23:00 +02:00
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 <seanjc@google.com>
Suggested-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Xin Li (Intel) <xin@zytor.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/all/20240822073906.2176342-4-xin@zytor.com
---
arch/x86/include/asm/entry-common.h | 3 +++
arch/x86/include/asm/fred.h | 21 ++++++++++++++++++++-
arch/x86/include/asm/switch_to.h | 5 +----
arch/x86/kernel/fred.c | 3 +++
4 files changed, 27 insertions(+), 5 deletions(-)
diff --git a/arch/x86/include/asm/entry-common.h b/arch/x86/include/asm/entry-common.h
index db97082..77d2055 100644
--- a/arch/x86/include/asm/entry-common.h
+++ b/arch/x86/include/asm/entry-common.h
@@ -8,6 +8,7 @@
#include <asm/nospec-branch.h>
#include <asm/io_bitmap.h>
#include <asm/fpu/api.h>
+#include <asm/fred.h>
/* Check that the stack and regs on entry from user mode are sane. */
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,
if (IS_ENABLED(CONFIG_X86_DEBUG_FPU) || unlikely(ti_work))
arch_exit_work(ti_work);
+ fred_update_rsp0();
+
#ifdef CONFIG_COMPAT
/*
* Compat syscalls set TS_COMPAT. Make sure we clear it before
diff --git a/arch/x86/include/asm/fred.h b/arch/x86/include/asm/fred.h
index 66d7dbe..25ca00b 100644
--- a/arch/x86/include/asm/fred.h
+++ b/arch/x86/include/asm/fred.h
@@ -36,6 +36,7 @@
#ifdef CONFIG_X86_FRED
#include <linux/kernel.h>
+#include <linux/sched/task_stack.h>
#include <asm/ptrace.h>
@@ -87,12 +88,30 @@ void cpu_init_fred_exceptions(void);
void cpu_init_fred_rsps(void);
void fred_complete_exception_setup(void);
+DECLARE_PER_CPU(unsigned long, fred_rsp0);
+
+static __always_inline void fred_sync_rsp0(unsigned long rsp0)
+{
+ __this_cpu_write(fred_rsp0, rsp0);
+}
+
+static __always_inline void fred_update_rsp0(void)
+{
+ unsigned long rsp0 = (unsigned long) task_stack_page(current) + THREAD_SIZE;
+
+ if (cpu_feature_enabled(X86_FEATURE_FRED) && (__this_cpu_read(fred_rsp0) != rsp0)) {
+ wrmsrns(MSR_IA32_FRED_RSP0, rsp0);
+ __this_cpu_write(fred_rsp0, rsp0);
+ }
+}
#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) { }
static inline void cpu_init_fred_rsps(void) { }
static inline void fred_complete_exception_setup(void) { }
-static __always_inline void fred_entry_from_kvm(unsigned int type, unsigned int vector) { }
+static inline void fred_entry_from_kvm(unsigned int type, unsigned int vector) { }
+static inline void fred_sync_rsp0(unsigned long rsp0) { }
+static inline void fred_update_rsp0(void) { }
#endif /* CONFIG_X86_FRED */
#endif /* !__ASSEMBLY__ */
diff --git a/arch/x86/include/asm/switch_to.h b/arch/x86/include/asm/switch_to.h
index e9ded14..7524854 100644
--- a/arch/x86/include/asm/switch_to.h
+++ b/arch/x86/include/asm/switch_to.h
@@ -70,12 +70,9 @@ static inline void update_task_stack(struct task_struct *task)
#ifdef CONFIG_X86_32
this_cpu_write(cpu_tss_rw.x86_tss.sp1, task->thread.sp0);
#else
- if (cpu_feature_enabled(X86_FEATURE_FRED)) {
- wrmsrns(MSR_IA32_FRED_RSP0, (unsigned long)task_stack_page(task) + THREAD_SIZE);
- } else if (cpu_feature_enabled(X86_FEATURE_XENPV)) {
+ if (!cpu_feature_enabled(X86_FEATURE_FRED) && cpu_feature_enabled(X86_FEATURE_XENPV))
/* Xen PV enters the kernel on the thread stack. */
load_sp0(task_top_of_stack(task));
- }
#endif
}
diff --git a/arch/x86/kernel/fred.c b/arch/x86/kernel/fred.c
index 266c69e..8d32c3f 100644
--- a/arch/x86/kernel/fred.c
+++ b/arch/x86/kernel/fred.c
@@ -21,6 +21,9 @@
#define FRED_STKLVL(vector, lvl) ((lvl) << (2 * (vector)))
+DEFINE_PER_CPU(unsigned long, fred_rsp0);
+EXPORT_PER_CPU_SYMBOL(fred_rsp0);
+
void cpu_init_fred_exceptions(void)
{
/* When FRED is enabled by default, remove this log message */
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [tip: x86/fred] x86/msr: Switch between WRMSRNS and WRMSR with the alternatives mechanism
2024-08-22 7:39 ` [PATCH v2 2/3] x86/msr: Switch between WRMSRNS and WRMSR with the alternatives mechanism Xin Li (Intel)
@ 2024-08-25 17:28 ` tip-bot2 for Andrew Cooper
0 siblings, 0 replies; 7+ messages in thread
From: tip-bot2 for Andrew Cooper @ 2024-08-25 17:28 UTC (permalink / raw)
To: linux-tip-commits
Cc: Andrew Cooper, Xin Li (Intel), Thomas Gleixner, x86, linux-kernel
The following commit has been merged into the x86/fred branch of tip:
Commit-ID: efe508816d2caf83536ff2f308e09043380fb2b7
Gitweb: https://git.kernel.org/tip/efe508816d2caf83536ff2f308e09043380fb2b7
Author: Andrew Cooper <andrew.cooper3@citrix.com>
AuthorDate: Thu, 22 Aug 2024 00:39:05 -07:00
Committer: Thomas Gleixner <tglx@linutronix.de>
CommitterDate: Sun, 25 Aug 2024 19:23:00 +02:00
x86/msr: Switch between WRMSRNS and WRMSR with the alternatives mechanism
Per the discussion about FRED MSR writes with WRMSRNS instruction [1],
use the alternatives mechanism to choose WRMSRNS when it's available,
otherwise fallback to WRMSR.
Remove the dependency on X86_FEATURE_WRMSRNS as WRMSRNS is no longer
dependent on FRED.
[1] https://lore.kernel.org/lkml/15f56e6a-6edd-43d0-8e83-bb6430096514@citrix.com/
Use DS prefix to pad WRMSR instead of a NOP. The prefix is ignored. At
least that's the current information from the hardware folks.
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Signed-off-by: Xin Li (Intel) <xin@zytor.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/all/20240822073906.2176342-3-xin@zytor.com
---
arch/x86/include/asm/msr.h | 25 +++++++++++--------------
arch/x86/include/asm/switch_to.h | 1 -
arch/x86/kernel/cpu/cpuid-deps.c | 1 -
3 files changed, 11 insertions(+), 16 deletions(-)
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index d642037..0018535 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -99,19 +99,6 @@ static __always_inline void __wrmsr(unsigned int msr, u32 low, u32 high)
: : "c" (msr), "a"(low), "d" (high) : "memory");
}
-/*
- * WRMSRNS behaves exactly like WRMSR with the only difference being
- * that it is not a serializing instruction by default.
- */
-static __always_inline void __wrmsrns(u32 msr, u32 low, u32 high)
-{
- /* Instruction opcode for WRMSRNS; supported in binutils >= 2.40. */
- asm volatile("1: .byte 0x0f,0x01,0xc6\n"
- "2:\n"
- _ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_WRMSR)
- : : "c" (msr), "a"(low), "d" (high));
-}
-
#define native_rdmsr(msr, val1, val2) \
do { \
u64 __val = __rdmsr((msr)); \
@@ -312,9 +299,19 @@ do { \
#endif /* !CONFIG_PARAVIRT_XXL */
+/* Instruction opcode for WRMSRNS supported in binutils >= 2.40 */
+#define WRMSRNS _ASM_BYTES(0x0f,0x01,0xc6)
+
+/* Non-serializing WRMSR, when available. Falls back to a serializing WRMSR. */
static __always_inline void wrmsrns(u32 msr, u64 val)
{
- __wrmsrns(msr, val, val >> 32);
+ /*
+ * WRMSR is 2 bytes. WRMSRNS is 3 bytes. Pad WRMSR with a redundant
+ * DS prefix to avoid a trailing NOP.
+ */
+ asm volatile("1: " ALTERNATIVE("ds wrmsr", WRMSRNS, X86_FEATURE_WRMSRNS)
+ "2: " _ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_WRMSR)
+ : : "c" (msr), "a" ((u32)val), "d" ((u32)(val >> 32)));
}
/*
diff --git a/arch/x86/include/asm/switch_to.h b/arch/x86/include/asm/switch_to.h
index c3bd0c0..e9ded14 100644
--- a/arch/x86/include/asm/switch_to.h
+++ b/arch/x86/include/asm/switch_to.h
@@ -71,7 +71,6 @@ static inline void update_task_stack(struct task_struct *task)
this_cpu_write(cpu_tss_rw.x86_tss.sp1, task->thread.sp0);
#else
if (cpu_feature_enabled(X86_FEATURE_FRED)) {
- /* WRMSRNS is a baseline feature for FRED. */
wrmsrns(MSR_IA32_FRED_RSP0, (unsigned long)task_stack_page(task) + THREAD_SIZE);
} else if (cpu_feature_enabled(X86_FEATURE_XENPV)) {
/* Xen PV enters the kernel on the thread stack. */
diff --git a/arch/x86/kernel/cpu/cpuid-deps.c b/arch/x86/kernel/cpu/cpuid-deps.c
index b7d9f53..8bd8411 100644
--- a/arch/x86/kernel/cpu/cpuid-deps.c
+++ b/arch/x86/kernel/cpu/cpuid-deps.c
@@ -83,7 +83,6 @@ static const struct cpuid_dep cpuid_deps[] = {
{ X86_FEATURE_AMX_TILE, X86_FEATURE_XFD },
{ X86_FEATURE_SHSTK, X86_FEATURE_XSAVES },
{ X86_FEATURE_FRED, X86_FEATURE_LKGS },
- { X86_FEATURE_FRED, X86_FEATURE_WRMSRNS },
{}
};
^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2024-08-25 17:28 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-08-22 7:39 [PATCH v2 0/3] x86: Write FRED RSP0 on return to userspace Xin Li (Intel)
2024-08-22 7:39 ` [PATCH v2 1/3] x86/entry: Test ti_work for zero before processing individual bits Xin Li (Intel)
2024-08-25 17:28 ` [tip: x86/fred] " tip-bot2 for Xin Li (Intel)
2024-08-22 7:39 ` [PATCH v2 2/3] x86/msr: Switch between WRMSRNS and WRMSR with the alternatives mechanism Xin Li (Intel)
2024-08-25 17:28 ` [tip: x86/fred] " tip-bot2 for Andrew Cooper
2024-08-22 7:39 ` [PATCH v2 3/3] x86/entry: Set FRED RSP0 on return to userspace instead of context switch Xin Li (Intel)
2024-08-25 17:28 ` [tip: x86/fred] " tip-bot2 for Xin Li (Intel)
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox