* [PATCH v3 00/16] x86/msr: Inline rdmsr/wrmsr instructions
@ 2026-02-18 8:21 Juergen Gross
2026-02-18 8:21 ` [PATCH v3 06/16] x86/msr: Move MSR trace calls one function level up Juergen Gross
` (5 more replies)
0 siblings, 6 replies; 10+ messages in thread
From: Juergen Gross @ 2026-02-18 8:21 UTC (permalink / raw)
To: linux-kernel, x86, linux-coco, kvm, linux-hyperv, virtualization,
llvm
Cc: Juergen Gross, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, H. Peter Anvin, Kiryl Shutsemau, Rick Edgecombe,
Sean Christopherson, Paolo Bonzini, K. Y. Srinivasan,
Haiyang Zhang, Wei Liu, Dexuan Cui, Long Li, Vitaly Kuznetsov,
Boris Ostrovsky, xen-devel, Ajay Kaher, Alexey Makhalov,
Broadcom internal kernel review list, Andy Lutomirski,
Peter Zijlstra, Xin Li, Nathan Chancellor, Nick Desaulniers,
Bill Wendling, Justin Stitt, Josh Poimboeuf
When building a kernel with CONFIG_PARAVIRT_XXL the paravirt
infrastructure will always use functions for reading or writing MSRs,
even when running on bare metal.
Switch to inline RDMSR/WRMSR instructions in this case, reducing the
paravirt overhead.
The first patch is a prerequisite fix for alternative patching. Its
is needed due to the initial indirect call needs to be padded with
NOPs in some cases with the following patches.
In order to make this less intrusive, some further reorganization of
the MSR access helpers is done in the patches 1-6.
The next 4 patches are converting the non-paravirt case to use direct
inlining of the MSR access instructions, including the WRMSRNS
instruction and the immediate variants of RDMSR and WRMSR if possible.
Patches 11-13 are some further preparations for making the real switch
to directly patch in the native MSR instructions easier.
Patch 14 is switching the paravirt MSR function interface from normal
call ABI to one more similar to the native MSR instructions.
Patch 15 is a little cleanup patch.
Patch 16 is the final step for patching in the native MSR instructions
when not running as a Xen PV guest.
This series has been tested to work with Xen PV and on bare metal.
Note that there is more room for improvement. This series is sent out
to get a first impression how the code will basically look like.
Right now the same problem is solved differently for the paravirt and
the non-paravirt cases. In case this is not desired, there are two
possibilities to merge the two implementations. Both solutions have
the common idea to have rather similar code for paravirt and
non-paravirt variants, but just use a different main macro for
generating the respective code. For making the code of both possible
scenarios more similar, the following variants are possible:
1. Remove the micro-optimizations of the non-paravirt case, making
it similar to the paravirt code in my series. This has the
advantage of being more simple, but might have a very small
negative performance impact (probably not really detectable).
2. Add the same micro-optimizations to the paravirt case, requiring
to enhance paravirt patching to support a to be patched indirect
call in the middle of the initial code snipplet.
In both cases the native MSR function variants would no longer be
usable in the paravirt case, but this would mostly affect Xen, as it
would need to open code the WRMSR/RDMSR instructions to be used
instead the native_*msr*() functions.
Changes since V2:
- switch back to the paravirt approach
Changes since V1:
- Use Xin Li's approach for inlining
- Several new patches
Juergen Gross (16):
x86/alternative: Support alt_replace_call() with instructions after
call
coco/tdx: Rename MSR access helpers
x86/sev: Replace call of native_wrmsr() with native_wrmsrq()
KVM: x86: Remove the KVM private read_msr() function
x86/msr: Minimize usage of native_*() msr access functions
x86/msr: Move MSR trace calls one function level up
x86/opcode: Add immediate form MSR instructions
x86/extable: Add support for immediate form MSR instructions
x86/msr: Use the alternatives mechanism for WRMSR
x86/msr: Use the alternatives mechanism for RDMSR
x86/alternatives: Add ALTERNATIVE_4()
x86/paravirt: Split off MSR related hooks into new header
x86/paravirt: Prepare support of MSR instruction interfaces
x86/paravirt: Switch MSR access pv_ops functions to instruction
interfaces
x86/msr: Reduce number of low level MSR access helpers
x86/paravirt: Use alternatives for MSR access with paravirt
arch/x86/coco/sev/internal.h | 7 +-
arch/x86/coco/tdx/tdx.c | 8 +-
arch/x86/hyperv/ivm.c | 2 +-
arch/x86/include/asm/alternative.h | 6 +
arch/x86/include/asm/fred.h | 2 +-
arch/x86/include/asm/kvm_host.h | 10 -
arch/x86/include/asm/msr.h | 345 ++++++++++++++++------
arch/x86/include/asm/paravirt-msr.h | 148 ++++++++++
arch/x86/include/asm/paravirt.h | 67 -----
arch/x86/include/asm/paravirt_types.h | 57 ++--
arch/x86/include/asm/qspinlock_paravirt.h | 4 +-
arch/x86/kernel/alternative.c | 5 +-
arch/x86/kernel/cpu/mshyperv.c | 7 +-
arch/x86/kernel/kvmclock.c | 2 +-
arch/x86/kernel/paravirt.c | 42 ++-
arch/x86/kvm/svm/svm.c | 16 +-
arch/x86/kvm/vmx/tdx.c | 2 +-
arch/x86/kvm/vmx/vmx.c | 8 +-
arch/x86/lib/x86-opcode-map.txt | 5 +-
arch/x86/mm/extable.c | 35 ++-
arch/x86/xen/enlighten_pv.c | 52 +++-
arch/x86/xen/pmu.c | 4 +-
tools/arch/x86/lib/x86-opcode-map.txt | 5 +-
tools/objtool/check.c | 1 +
24 files changed, 576 insertions(+), 264 deletions(-)
create mode 100644 arch/x86/include/asm/paravirt-msr.h
--
2.53.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v3 06/16] x86/msr: Move MSR trace calls one function level up
2026-02-18 8:21 [PATCH v3 00/16] x86/msr: Inline rdmsr/wrmsr instructions Juergen Gross
@ 2026-02-18 8:21 ` Juergen Gross
2026-02-18 8:21 ` [PATCH v3 12/16] x86/paravirt: Split off MSR related hooks into new header Juergen Gross
` (4 subsequent siblings)
5 siblings, 0 replies; 10+ messages in thread
From: Juergen Gross @ 2026-02-18 8:21 UTC (permalink / raw)
To: linux-kernel, x86, virtualization
Cc: Juergen Gross, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, H. Peter Anvin, Ajay Kaher, Alexey Makhalov,
Broadcom internal kernel review list
In order to prepare paravirt inlining of the MSR access instructions
move the calls of MSR trace functions one function level up.
Introduce {read|write}_msr[_safe]() helpers allowing to have common
definitions in msr.h doing the trace calls.
Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: H. Peter Anvin (Intel) <hpa@zytor.com>
---
arch/x86/include/asm/msr.h | 102 ++++++++++++++++++++------------
arch/x86/include/asm/paravirt.h | 38 +++---------
2 files changed, 73 insertions(+), 67 deletions(-)
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index 9c2ea29e12a9..71f41af11591 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -103,14 +103,7 @@ static __always_inline u64 native_rdmsrq(u32 msr)
static inline u64 native_read_msr(u32 msr)
{
- u64 val;
-
- val = __rdmsr(msr);
-
- if (tracepoint_enabled(read_msr))
- do_trace_read_msr(msr, val, 0);
-
- return val;
+ return __rdmsr(msr);
}
static inline int native_read_msr_safe(u32 msr, u64 *p)
@@ -123,8 +116,6 @@ static inline int native_read_msr_safe(u32 msr, u64 *p)
_ASM_EXTABLE_TYPE_REG(1b, 2b, EX_TYPE_RDMSR_SAFE, %[err])
: [err] "=r" (err), EAX_EDX_RET(val, low, high)
: "c" (msr));
- if (tracepoint_enabled(read_msr))
- do_trace_read_msr(msr, EAX_EDX_VAL(val, low, high), err);
*p = EAX_EDX_VAL(val, low, high);
@@ -135,9 +126,6 @@ static inline int native_read_msr_safe(u32 msr, u64 *p)
static inline void notrace native_write_msr(u32 msr, u64 val)
{
native_wrmsrq(msr, val);
-
- if (tracepoint_enabled(write_msr))
- do_trace_write_msr(msr, val, 0);
}
/* Can be uninlined because referenced by paravirt */
@@ -151,8 +139,6 @@ static inline int notrace native_write_msr_safe(u32 msr, u64 val)
: [err] "=a" (err)
: "c" (msr), "0" ((u32)val), "d" ((u32)(val >> 32))
: "memory");
- if (tracepoint_enabled(write_msr))
- do_trace_write_msr(msr, val, err);
return err;
}
@@ -173,59 +159,96 @@ static inline u64 native_read_pmc(int counter)
#include <asm/paravirt.h>
#else
#include <linux/errno.h>
+static __always_inline u64 read_msr(u32 msr)
+{
+ return native_read_msr(msr);
+}
+
+static __always_inline int read_msr_safe(u32 msr, u64 *p)
+{
+ return native_read_msr_safe(msr, p);
+}
+
+static __always_inline void write_msr(u32 msr, u64 val)
+{
+ native_write_msr(msr, val);
+}
+
+static __always_inline int write_msr_safe(u32 msr, u64 val)
+{
+ return native_write_msr_safe(msr, val);
+}
+
+static __always_inline u64 rdpmc(int counter)
+{
+ return native_read_pmc(counter);
+}
+
+#endif /* !CONFIG_PARAVIRT_XXL */
+
/*
* Access to machine-specific registers (available on 586 and better only)
* Note: the rd* operations modify the parameters directly (without using
* pointer indirection), this allows gcc to optimize better
*/
+#define rdmsrq(msr, val) \
+do { \
+ (val) = read_msr(msr); \
+ if (tracepoint_enabled(read_msr)) \
+ do_trace_read_msr(msr, val, 0); \
+} while (0)
+
#define rdmsr(msr, low, high) \
do { \
- u64 __val = native_read_msr((msr)); \
+ u64 __val; \
+ rdmsrq(msr, __val); \
(void)((low) = (u32)__val); \
(void)((high) = (u32)(__val >> 32)); \
} while (0)
-static inline void wrmsr(u32 msr, u32 low, u32 high)
+/* rdmsr with exception handling */
+static inline int rdmsrq_safe(u32 msr, u64 *p)
{
- native_write_msr(msr, (u64)high << 32 | low);
-}
+ int err;
-#define rdmsrq(msr, val) \
- ((val) = native_read_msr((msr)))
+ err = read_msr_safe(msr, p);
-static inline void wrmsrq(u32 msr, u64 val)
-{
- native_write_msr(msr, val);
-}
+ if (tracepoint_enabled(read_msr))
+ do_trace_read_msr(msr, *p, err);
-/* wrmsr with exception handling */
-static inline int wrmsrq_safe(u32 msr, u64 val)
-{
- return native_write_msr_safe(msr, val);
+ return err;
}
-/* rdmsr with exception handling */
#define rdmsr_safe(msr, low, high) \
({ \
u64 __val; \
- int __err = native_read_msr_safe((msr), &__val); \
+ int __err = rdmsrq_safe((msr), &__val); \
(*low) = (u32)__val; \
(*high) = (u32)(__val >> 32); \
__err; \
})
-static inline int rdmsrq_safe(u32 msr, u64 *p)
+static inline void wrmsrq(u32 msr, u64 val)
{
- return native_read_msr_safe(msr, p);
+ write_msr(msr, val);
+
+ if (tracepoint_enabled(write_msr))
+ do_trace_write_msr(msr, val, 0);
}
-static __always_inline u64 rdpmc(int counter)
+/* wrmsr with exception handling */
+static inline int wrmsrq_safe(u32 msr, u64 val)
{
- return native_read_pmc(counter);
-}
+ int err;
-#endif /* !CONFIG_PARAVIRT_XXL */
+ err = write_msr_safe(msr, val);
+
+ if (tracepoint_enabled(write_msr))
+ do_trace_write_msr(msr, val, err);
+
+ return err;
+}
/* Instruction opcode for WRMSRNS supported in binutils >= 2.40 */
#define ASM_WRMSRNS _ASM_BYTES(0x0f,0x01,0xc6)
@@ -242,6 +265,11 @@ static __always_inline void wrmsrns(u32 msr, u64 val)
: : "c" (msr), "a" ((u32)val), "d" ((u32)(val >> 32)));
}
+static inline void wrmsr(u32 msr, u32 low, u32 high)
+{
+ wrmsrq(msr, (u64)high << 32 | low);
+}
+
/*
* Dual u32 version of wrmsrq_safe():
*/
diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
index cdfe4007443e..6b3aed5c2309 100644
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -150,46 +150,24 @@ static inline int paravirt_write_msr_safe(u32 msr, u64 val)
return PVOP_CALL2(int, pv_ops, cpu.write_msr_safe, msr, val);
}
-#define rdmsr(msr, val1, val2) \
-do { \
- u64 _l = paravirt_read_msr(msr); \
- val1 = (u32)_l; \
- val2 = _l >> 32; \
-} while (0)
-
-static __always_inline void wrmsr(u32 msr, u32 low, u32 high)
+static __always_inline u64 read_msr(u32 msr)
{
- paravirt_write_msr(msr, (u64)high << 32 | low);
+ return paravirt_read_msr(msr);
}
-#define rdmsrq(msr, val) \
-do { \
- val = paravirt_read_msr(msr); \
-} while (0)
-
-static inline void wrmsrq(u32 msr, u64 val)
+static __always_inline int read_msr_safe(u32 msr, u64 *p)
{
- paravirt_write_msr(msr, val);
+ return paravirt_read_msr_safe(msr, p);
}
-static inline int wrmsrq_safe(u32 msr, u64 val)
+static __always_inline void write_msr(u32 msr, u64 val)
{
- return paravirt_write_msr_safe(msr, val);
+ paravirt_write_msr(msr, val);
}
-/* rdmsr with exception handling */
-#define rdmsr_safe(msr, a, b) \
-({ \
- u64 _l; \
- int _err = paravirt_read_msr_safe((msr), &_l); \
- (*a) = (u32)_l; \
- (*b) = (u32)(_l >> 32); \
- _err; \
-})
-
-static __always_inline int rdmsrq_safe(u32 msr, u64 *p)
+static __always_inline int write_msr_safe(u32 msr, u64 val)
{
- return paravirt_read_msr_safe(msr, p);
+ return paravirt_write_msr_safe(msr, val);
}
static __always_inline u64 rdpmc(int counter)
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 12/16] x86/paravirt: Split off MSR related hooks into new header
2026-02-18 8:21 [PATCH v3 00/16] x86/msr: Inline rdmsr/wrmsr instructions Juergen Gross
2026-02-18 8:21 ` [PATCH v3 06/16] x86/msr: Move MSR trace calls one function level up Juergen Gross
@ 2026-02-18 8:21 ` Juergen Gross
2026-02-18 8:21 ` [PATCH v3 13/16] x86/paravirt: Prepare support of MSR instruction interfaces Juergen Gross
` (3 subsequent siblings)
5 siblings, 0 replies; 10+ messages in thread
From: Juergen Gross @ 2026-02-18 8:21 UTC (permalink / raw)
To: linux-kernel, x86, virtualization
Cc: Juergen Gross, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
Dave Hansen, H. Peter Anvin, Ajay Kaher, Alexey Makhalov,
Broadcom internal kernel review list, Boris Ostrovsky,
Josh Poimboeuf, Peter Zijlstra, xen-devel
Move the WRMSR, RDMSR and RDPMC related parts of paravirt.h and
paravirt_types.h into a new header file paravirt-msr.h.
Signed-off-by: Juergen Gross <jgross@suse.com>
---
V3:
- new patch
---
arch/x86/include/asm/msr.h | 2 +-
arch/x86/include/asm/paravirt-msr.h | 46 +++++++++++++++++++++++++++
arch/x86/include/asm/paravirt.h | 45 --------------------------
arch/x86/include/asm/paravirt_types.h | 13 --------
arch/x86/kernel/paravirt.c | 14 +++++---
arch/x86/xen/enlighten_pv.c | 11 ++++---
tools/objtool/check.c | 1 +
7 files changed, 63 insertions(+), 69 deletions(-)
create mode 100644 arch/x86/include/asm/paravirt-msr.h
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index 990268dea5ad..66f57265f2f8 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -308,7 +308,7 @@ static inline u64 native_read_pmc(int counter)
}
#ifdef CONFIG_PARAVIRT_XXL
-#include <asm/paravirt.h>
+#include <asm/paravirt-msr.h>
#else
static __always_inline u64 read_msr(u32 msr)
{
diff --git a/arch/x86/include/asm/paravirt-msr.h b/arch/x86/include/asm/paravirt-msr.h
new file mode 100644
index 000000000000..b299864b438a
--- /dev/null
+++ b/arch/x86/include/asm/paravirt-msr.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _ASM_X86_PARAVIRT_MSR_H
+#define _ASM_X86_PARAVIRT_MSR_H
+
+#include <asm/paravirt_types.h>
+
+struct pv_msr_ops {
+ /* Unsafe MSR operations. These will warn or panic on failure. */
+ u64 (*read_msr)(u32 msr);
+ void (*write_msr)(u32 msr, u64 val);
+
+ /* Safe MSR operations. Returns 0 or -EIO. */
+ int (*read_msr_safe)(u32 msr, u64 *val);
+ int (*write_msr_safe)(u32 msr, u64 val);
+
+ u64 (*read_pmc)(int counter);
+} __no_randomize_layout;
+
+extern struct pv_msr_ops pv_ops_msr;
+
+static __always_inline u64 read_msr(u32 msr)
+{
+ return PVOP_CALL1(u64, pv_ops_msr, read_msr, msr);
+}
+
+static __always_inline void write_msr(u32 msr, u64 val)
+{
+ PVOP_VCALL2(pv_ops_msr, write_msr, msr, val);
+}
+
+static __always_inline int read_msr_safe(u32 msr, u64 *val)
+{
+ return PVOP_CALL2(int, pv_ops_msr, read_msr_safe, msr, val);
+}
+
+static __always_inline int write_msr_safe(u32 msr, u64 val)
+{
+ return PVOP_CALL2(int, pv_ops_msr, write_msr_safe, msr, val);
+}
+
+static __always_inline u64 rdpmc(int counter)
+{
+ return PVOP_CALL1(u64, pv_ops_msr, read_pmc, counter);
+}
+
+#endif /* _ASM_X86_PARAVIRT_MSR_H */
diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
index 6b3aed5c2309..fcda593dd5c9 100644
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -130,51 +130,6 @@ static inline void __write_cr4(unsigned long x)
PVOP_VCALL1(pv_ops, cpu.write_cr4, x);
}
-static inline u64 paravirt_read_msr(u32 msr)
-{
- return PVOP_CALL1(u64, pv_ops, cpu.read_msr, msr);
-}
-
-static inline void paravirt_write_msr(u32 msr, u64 val)
-{
- PVOP_VCALL2(pv_ops, cpu.write_msr, msr, val);
-}
-
-static inline int paravirt_read_msr_safe(u32 msr, u64 *val)
-{
- return PVOP_CALL2(int, pv_ops, cpu.read_msr_safe, msr, val);
-}
-
-static inline int paravirt_write_msr_safe(u32 msr, u64 val)
-{
- return PVOP_CALL2(int, pv_ops, cpu.write_msr_safe, msr, val);
-}
-
-static __always_inline u64 read_msr(u32 msr)
-{
- return paravirt_read_msr(msr);
-}
-
-static __always_inline int read_msr_safe(u32 msr, u64 *p)
-{
- return paravirt_read_msr_safe(msr, p);
-}
-
-static __always_inline void write_msr(u32 msr, u64 val)
-{
- paravirt_write_msr(msr, val);
-}
-
-static __always_inline int write_msr_safe(u32 msr, u64 val)
-{
- return paravirt_write_msr_safe(msr, val);
-}
-
-static __always_inline u64 rdpmc(int counter)
-{
- return PVOP_CALL1(u64, pv_ops, cpu.read_pmc, counter);
-}
-
static inline void paravirt_alloc_ldt(struct desc_struct *ldt, unsigned entries)
{
PVOP_VCALL2(pv_ops, cpu.alloc_ldt, ldt, entries);
diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h
index 4f5ae0068aab..1e7188247c1f 100644
--- a/arch/x86/include/asm/paravirt_types.h
+++ b/arch/x86/include/asm/paravirt_types.h
@@ -67,19 +67,6 @@ struct pv_cpu_ops {
void (*cpuid)(unsigned int *eax, unsigned int *ebx,
unsigned int *ecx, unsigned int *edx);
- /* Unsafe MSR operations. These will warn or panic on failure. */
- u64 (*read_msr)(u32 msr);
- void (*write_msr)(u32 msr, u64 val);
-
- /*
- * Safe MSR operations.
- * Returns 0 or -EIO.
- */
- int (*read_msr_safe)(u32 msr, u64 *val);
- int (*write_msr_safe)(u32 msr, u64 val);
-
- u64 (*read_pmc)(int counter);
-
void (*start_context_switch)(struct task_struct *prev);
void (*end_context_switch)(struct task_struct *next);
#endif
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index 792fa96b3233..089a87ac1582 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -109,11 +109,6 @@ struct paravirt_patch_template pv_ops = {
.cpu.read_cr0 = native_read_cr0,
.cpu.write_cr0 = native_write_cr0,
.cpu.write_cr4 = native_write_cr4,
- .cpu.read_msr = native_read_msr,
- .cpu.write_msr = native_write_msr,
- .cpu.read_msr_safe = native_read_msr_safe,
- .cpu.write_msr_safe = native_write_msr_safe,
- .cpu.read_pmc = native_read_pmc,
.cpu.load_tr_desc = native_load_tr_desc,
.cpu.set_ldt = native_set_ldt,
.cpu.load_gdt = native_load_gdt,
@@ -215,6 +210,15 @@ struct paravirt_patch_template pv_ops = {
};
#ifdef CONFIG_PARAVIRT_XXL
+struct pv_msr_ops pv_ops_msr = {
+ .read_msr = native_read_msr,
+ .write_msr = native_write_msr,
+ .read_msr_safe = native_read_msr_safe,
+ .write_msr_safe = native_write_msr_safe,
+ .read_pmc = native_read_pmc,
+};
+EXPORT_SYMBOL(pv_ops_msr);
+
NOKPROBE_SYMBOL(native_load_idt);
#endif
diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c
index 0a6a50f3e9a9..b94437f26cc0 100644
--- a/arch/x86/xen/enlighten_pv.c
+++ b/arch/x86/xen/enlighten_pv.c
@@ -1366,11 +1366,6 @@ asmlinkage __visible void __init xen_start_kernel(struct start_info *si)
pv_ops.cpu.read_cr0 = xen_read_cr0;
pv_ops.cpu.write_cr0 = xen_write_cr0;
pv_ops.cpu.write_cr4 = xen_write_cr4;
- pv_ops.cpu.read_msr = xen_read_msr;
- pv_ops.cpu.write_msr = xen_write_msr;
- pv_ops.cpu.read_msr_safe = xen_read_msr_safe;
- pv_ops.cpu.write_msr_safe = xen_write_msr_safe;
- pv_ops.cpu.read_pmc = xen_read_pmc;
pv_ops.cpu.load_tr_desc = paravirt_nop;
pv_ops.cpu.set_ldt = xen_set_ldt;
pv_ops.cpu.load_gdt = xen_load_gdt;
@@ -1391,6 +1386,12 @@ asmlinkage __visible void __init xen_start_kernel(struct start_info *si)
pv_ops.cpu.start_context_switch = xen_start_context_switch;
pv_ops.cpu.end_context_switch = xen_end_context_switch;
+ pv_ops_msr.read_msr = xen_read_msr;
+ pv_ops_msr.write_msr = xen_write_msr;
+ pv_ops_msr.read_msr_safe = xen_read_msr_safe;
+ pv_ops_msr.write_msr_safe = xen_write_msr_safe;
+ pv_ops_msr.read_pmc = xen_read_pmc;
+
xen_init_irq_ops();
/*
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index 37f87c4a0134..d400cb435757 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -529,6 +529,7 @@ static struct {
} pv_ops_tables[] = {
{ .name = "pv_ops", },
{ .name = "pv_ops_lock", },
+ { .name = "pv_ops_msr", },
{ .name = NULL, .idx_off = -1 }
};
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 13/16] x86/paravirt: Prepare support of MSR instruction interfaces
2026-02-18 8:21 [PATCH v3 00/16] x86/msr: Inline rdmsr/wrmsr instructions Juergen Gross
2026-02-18 8:21 ` [PATCH v3 06/16] x86/msr: Move MSR trace calls one function level up Juergen Gross
2026-02-18 8:21 ` [PATCH v3 12/16] x86/paravirt: Split off MSR related hooks into new header Juergen Gross
@ 2026-02-18 8:21 ` Juergen Gross
2026-02-18 8:21 ` [PATCH v3 14/16] x86/paravirt: Switch MSR access pv_ops functions to " Juergen Gross
` (2 subsequent siblings)
5 siblings, 0 replies; 10+ messages in thread
From: Juergen Gross @ 2026-02-18 8:21 UTC (permalink / raw)
To: linux-kernel, x86, virtualization
Cc: Juergen Gross, Ajay Kaher, Alexey Makhalov,
Broadcom internal kernel review list, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, Dave Hansen, H. Peter Anvin
Make the paravirt callee-save infrastructure more generic by allowing
arbitrary register interfaces via prologue and epilogue helper macros.
Signed-off-by: Juergen Gross <jgross@suse.com>
---
V3:
- carved out from patch 5 of V1
---
arch/x86/include/asm/paravirt_types.h | 43 ++++++++++++++---------
arch/x86/include/asm/qspinlock_paravirt.h | 4 +--
2 files changed, 29 insertions(+), 18 deletions(-)
diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h
index 1e7188247c1f..999a5abe54ed 100644
--- a/arch/x86/include/asm/paravirt_types.h
+++ b/arch/x86/include/asm/paravirt_types.h
@@ -457,27 +457,38 @@ extern struct paravirt_patch_template pv_ops;
#define PV_SAVE_ALL_CALLER_REGS "pushl %ecx;"
#define PV_RESTORE_ALL_CALLER_REGS "popl %ecx;"
#else
+/* Save and restore caller-save registers, except %rax, %rcx and %rdx. */
+#define PV_SAVE_COMMON_CALLER_REGS \
+ "push %rsi;" \
+ "push %rdi;" \
+ "push %r8;" \
+ "push %r9;" \
+ "push %r10;" \
+ "push %r11;"
+
+#define PV_RESTORE_COMMON_CALLER_REGS \
+ "pop %r11;" \
+ "pop %r10;" \
+ "pop %r9;" \
+ "pop %r8;" \
+ "pop %rdi;" \
+ "pop %rsi;"
+
/* save and restore all caller-save registers, except return value */
#define PV_SAVE_ALL_CALLER_REGS \
"push %rcx;" \
"push %rdx;" \
- "push %rsi;" \
- "push %rdi;" \
- "push %r8;" \
- "push %r9;" \
- "push %r10;" \
- "push %r11;"
+ PV_SAVE_COMMON_CALLER_REGS
+
#define PV_RESTORE_ALL_CALLER_REGS \
- "pop %r11;" \
- "pop %r10;" \
- "pop %r9;" \
- "pop %r8;" \
- "pop %rdi;" \
- "pop %rsi;" \
+ PV_RESTORE_COMMON_CALLER_REGS \
"pop %rdx;" \
"pop %rcx;"
#endif
+#define PV_PROLOGUE_ALL(func) PV_SAVE_ALL_CALLER_REGS
+#define PV_EPILOGUE_ALL(func) PV_RESTORE_ALL_CALLER_REGS
+
/*
* Generate a thunk around a function which saves all caller-save
* registers except for the return value. This allows C functions to
@@ -491,7 +502,7 @@ extern struct paravirt_patch_template pv_ops;
* functions.
*/
#define PV_THUNK_NAME(func) "__raw_callee_save_" #func
-#define __PV_CALLEE_SAVE_REGS_THUNK(func, section) \
+#define __PV_CALLEE_SAVE_REGS_THUNK(func, section, helper) \
extern typeof(func) __raw_callee_save_##func; \
\
asm(".pushsection " section ", \"ax\";" \
@@ -501,16 +512,16 @@ extern struct paravirt_patch_template pv_ops;
PV_THUNK_NAME(func) ":" \
ASM_ENDBR \
FRAME_BEGIN \
- PV_SAVE_ALL_CALLER_REGS \
+ PV_PROLOGUE_##helper(func) \
"call " #func ";" \
- PV_RESTORE_ALL_CALLER_REGS \
+ PV_EPILOGUE_##helper(func) \
FRAME_END \
ASM_RET \
".size " PV_THUNK_NAME(func) ", .-" PV_THUNK_NAME(func) ";" \
".popsection")
#define PV_CALLEE_SAVE_REGS_THUNK(func) \
- __PV_CALLEE_SAVE_REGS_THUNK(func, ".text")
+ __PV_CALLEE_SAVE_REGS_THUNK(func, ".text", ALL)
/* Get a reference to a callee-save function */
#define PV_CALLEE_SAVE(func) \
diff --git a/arch/x86/include/asm/qspinlock_paravirt.h b/arch/x86/include/asm/qspinlock_paravirt.h
index 0a985784be9b..002b17f0735e 100644
--- a/arch/x86/include/asm/qspinlock_paravirt.h
+++ b/arch/x86/include/asm/qspinlock_paravirt.h
@@ -14,7 +14,7 @@ void __lockfunc __pv_queued_spin_unlock_slowpath(struct qspinlock *lock, u8 lock
*/
#ifdef CONFIG_64BIT
-__PV_CALLEE_SAVE_REGS_THUNK(__pv_queued_spin_unlock_slowpath, ".spinlock.text");
+__PV_CALLEE_SAVE_REGS_THUNK(__pv_queued_spin_unlock_slowpath, ".spinlock.text", ALL);
#define __pv_queued_spin_unlock __pv_queued_spin_unlock
/*
@@ -61,7 +61,7 @@ DEFINE_ASM_FUNC(__raw_callee_save___pv_queued_spin_unlock,
#else /* CONFIG_64BIT */
extern void __lockfunc __pv_queued_spin_unlock(struct qspinlock *lock);
-__PV_CALLEE_SAVE_REGS_THUNK(__pv_queued_spin_unlock, ".spinlock.text");
+__PV_CALLEE_SAVE_REGS_THUNK(__pv_queued_spin_unlock, ".spinlock.text", ALL);
#endif /* CONFIG_64BIT */
#endif
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 14/16] x86/paravirt: Switch MSR access pv_ops functions to instruction interfaces
2026-02-18 8:21 [PATCH v3 00/16] x86/msr: Inline rdmsr/wrmsr instructions Juergen Gross
` (2 preceding siblings ...)
2026-02-18 8:21 ` [PATCH v3 13/16] x86/paravirt: Prepare support of MSR instruction interfaces Juergen Gross
@ 2026-02-18 8:21 ` Juergen Gross
2026-02-18 8:21 ` [PATCH v3 16/16] x86/paravirt: Use alternatives for MSR access with paravirt Juergen Gross
2026-02-18 20:37 ` [PATCH v3 00/16] x86/msr: Inline rdmsr/wrmsr instructions H. Peter Anvin
5 siblings, 0 replies; 10+ messages in thread
From: Juergen Gross @ 2026-02-18 8:21 UTC (permalink / raw)
To: linux-kernel, x86, virtualization
Cc: Juergen Gross, Ajay Kaher, Alexey Makhalov,
Broadcom internal kernel review list, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, Dave Hansen, H. Peter Anvin,
Boris Ostrovsky, xen-devel
In order to prepare for inlining RDMSR/WRMSR instructions via
alternatives directly when running not in a Xen PV guest, switch the
interfaces of the MSR related pvops callbacks to ones similar of the
related instructions.
In order to prepare for supporting the immediate variants of RDMSR/WRMSR
use a 64-bit interface instead of the 32-bit one of RDMSR/WRMSR.
Signed-off-by: Juergen Gross <jgross@suse.com>
---
V3:
- former patch 5 of V1 has been split
- use 64-bit interface (Xin Li)
---
arch/x86/include/asm/paravirt-msr.h | 49 ++++++++++++++++++++++++-----
arch/x86/kernel/paravirt.c | 36 ++++++++++++++++++---
arch/x86/xen/enlighten_pv.c | 45 +++++++++++++++++++-------
3 files changed, 107 insertions(+), 23 deletions(-)
diff --git a/arch/x86/include/asm/paravirt-msr.h b/arch/x86/include/asm/paravirt-msr.h
index b299864b438a..4ce690b05600 100644
--- a/arch/x86/include/asm/paravirt-msr.h
+++ b/arch/x86/include/asm/paravirt-msr.h
@@ -6,36 +6,69 @@
struct pv_msr_ops {
/* Unsafe MSR operations. These will warn or panic on failure. */
- u64 (*read_msr)(u32 msr);
- void (*write_msr)(u32 msr, u64 val);
+ struct paravirt_callee_save read_msr;
+ struct paravirt_callee_save write_msr;
/* Safe MSR operations. Returns 0 or -EIO. */
- int (*read_msr_safe)(u32 msr, u64 *val);
- int (*write_msr_safe)(u32 msr, u64 val);
+ struct paravirt_callee_save read_msr_safe;
+ struct paravirt_callee_save write_msr_safe;
u64 (*read_pmc)(int counter);
} __no_randomize_layout;
extern struct pv_msr_ops pv_ops_msr;
+#define PV_PROLOGUE_MSR(func) \
+ PV_SAVE_COMMON_CALLER_REGS \
+ PV_PROLOGUE_MSR_##func
+
+#define PV_EPILOGUE_MSR(func) PV_RESTORE_COMMON_CALLER_REGS
+
+#define PV_CALLEE_SAVE_REGS_MSR_THUNK(func) \
+ __PV_CALLEE_SAVE_REGS_THUNK(func, ".text", MSR)
+
static __always_inline u64 read_msr(u32 msr)
{
- return PVOP_CALL1(u64, pv_ops_msr, read_msr, msr);
+ u64 val;
+
+ asm volatile(PARAVIRT_CALL
+ : "=a" (val), ASM_CALL_CONSTRAINT
+ : paravirt_ptr(pv_ops_msr, read_msr), "c" (msr)
+ : "rdx");
+
+ return val;
}
static __always_inline void write_msr(u32 msr, u64 val)
{
- PVOP_VCALL2(pv_ops_msr, write_msr, msr, val);
+ asm volatile(PARAVIRT_CALL
+ : ASM_CALL_CONSTRAINT
+ : paravirt_ptr(pv_ops_msr, write_msr), "c" (msr), "a" (val)
+ : "memory", "rdx");
}
static __always_inline int read_msr_safe(u32 msr, u64 *val)
{
- return PVOP_CALL2(int, pv_ops_msr, read_msr_safe, msr, val);
+ int err;
+
+ asm volatile(PARAVIRT_CALL
+ : [err] "=d" (err), "=a" (*val), ASM_CALL_CONSTRAINT
+ : paravirt_ptr(pv_ops_msr, read_msr_safe), "c" (msr));
+
+ return err ? -EIO : 0;
}
static __always_inline int write_msr_safe(u32 msr, u64 val)
{
- return PVOP_CALL2(int, pv_ops_msr, write_msr_safe, msr, val);
+ int err;
+
+ asm volatile(PARAVIRT_CALL
+ : [err] "=a" (err), ASM_CALL_CONSTRAINT
+ : paravirt_ptr(pv_ops_msr, write_msr_safe),
+ "c" (msr), "a" (val)
+ : "memory", "rdx");
+
+ return err ? -EIO : 0;
}
static __always_inline u64 rdpmc(int counter)
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index 089a87ac1582..c0d78e4536c9 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -49,12 +49,40 @@ unsigned long pv_native_save_fl(void);
void pv_native_irq_disable(void);
void pv_native_irq_enable(void);
unsigned long pv_native_read_cr2(void);
+void pv_native_rdmsr(void);
+void pv_native_wrmsr(void);
+void pv_native_rdmsr_safe(void);
+void pv_native_wrmsr_safe(void);
DEFINE_ASM_FUNC(_paravirt_ident_64, "mov %rdi, %rax", .text);
DEFINE_ASM_FUNC(pv_native_save_fl, "pushf; pop %rax", .noinstr.text);
DEFINE_ASM_FUNC(pv_native_irq_disable, "cli", .noinstr.text);
DEFINE_ASM_FUNC(pv_native_irq_enable, "sti", .noinstr.text);
DEFINE_ASM_FUNC(pv_native_read_cr2, "mov %cr2, %rax", .noinstr.text);
+DEFINE_ASM_FUNC(pv_native_rdmsr,
+ "1: rdmsr\n"
+ "shl $32, %rdx; or %rdx, %rax\n"
+ "2:\n"
+ _ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_RDMSR), .noinstr.text);
+DEFINE_ASM_FUNC(pv_native_wrmsr,
+ "mov %rax, %rdx; shr $32, %rdx\n"
+ "1: wrmsr\n"
+ "2:\n"
+ _ASM_EXTABLE_TYPE(1b, 2b, EX_TYPE_WRMSR), .noinstr.text);
+DEFINE_ASM_FUNC(pv_native_rdmsr_safe,
+ "1: rdmsr\n"
+ "shl $32, %rdx; or %rdx, %rax\n"
+ "xor %edx, %edx\n"
+ "2:\n"
+ _ASM_EXTABLE_TYPE_REG(1b, 2b, EX_TYPE_RDMSR_SAFE, %%edx),
+ .noinstr.text);
+DEFINE_ASM_FUNC(pv_native_wrmsr_safe,
+ "mov %rax, %rdx; shr $32, %rdx\n"
+ "1: wrmsr\n"
+ "xor %eax, %eax\n"
+ "2:\n"
+ _ASM_EXTABLE_TYPE_REG(1b, 2b, EX_TYPE_WRMSR_SAFE, %%eax),
+ .noinstr.text);
#endif
static noinstr void pv_native_safe_halt(void)
@@ -211,10 +239,10 @@ struct paravirt_patch_template pv_ops = {
#ifdef CONFIG_PARAVIRT_XXL
struct pv_msr_ops pv_ops_msr = {
- .read_msr = native_read_msr,
- .write_msr = native_write_msr,
- .read_msr_safe = native_read_msr_safe,
- .write_msr_safe = native_write_msr_safe,
+ .read_msr = __PV_IS_CALLEE_SAVE(pv_native_rdmsr),
+ .write_msr = __PV_IS_CALLEE_SAVE(pv_native_wrmsr),
+ .read_msr_safe = __PV_IS_CALLEE_SAVE(pv_native_rdmsr_safe),
+ .write_msr_safe = __PV_IS_CALLEE_SAVE(pv_native_wrmsr_safe),
.read_pmc = native_read_pmc,
};
EXPORT_SYMBOL(pv_ops_msr);
diff --git a/arch/x86/xen/enlighten_pv.c b/arch/x86/xen/enlighten_pv.c
index b94437f26cc0..fed312a17033 100644
--- a/arch/x86/xen/enlighten_pv.c
+++ b/arch/x86/xen/enlighten_pv.c
@@ -1154,15 +1154,32 @@ static void xen_do_write_msr(u32 msr, u64 val, int *err)
}
}
-static int xen_read_msr_safe(u32 msr, u64 *val)
+/*
+ * Prototypes for functions called via PV_CALLEE_SAVE_REGS_THUNK() in order
+ * to avoid warnings with "-Wmissing-prototypes".
+ */
+struct xen_rdmsr_safe_ret {
+ u64 val;
+ int err;
+};
+struct xen_rdmsr_safe_ret xen_read_msr_safe(u32 msr);
+int xen_write_msr_safe(u32 msr, u64 val);
+u64 xen_read_msr(u32 msr);
+void xen_write_msr(u32 msr, u64 val);
+#define PV_PROLOGUE_RDMSR "mov %ecx, %edi;"
+#define PV_PROLOGUE_WRMSR "mov %ecx, %edi; mov %rax, %rsi;"
+
+__visible struct xen_rdmsr_safe_ret xen_read_msr_safe(u32 msr)
{
- int err = 0;
+ struct xen_rdmsr_safe_ret ret = { 0, 0 };
- *val = xen_do_read_msr(msr, &err);
- return err;
+ ret.val = xen_do_read_msr(msr, &ret.err);
+ return ret;
}
+#define PV_PROLOGUE_MSR_xen_read_msr_safe PV_PROLOGUE_RDMSR
+PV_CALLEE_SAVE_REGS_MSR_THUNK(xen_read_msr_safe);
-static int xen_write_msr_safe(u32 msr, u64 val)
+__visible int xen_write_msr_safe(u32 msr, u64 val)
{
int err = 0;
@@ -1170,20 +1187,26 @@ static int xen_write_msr_safe(u32 msr, u64 val)
return err;
}
+#define PV_PROLOGUE_MSR_xen_write_msr_safe PV_PROLOGUE_WRMSR
+PV_CALLEE_SAVE_REGS_MSR_THUNK(xen_write_msr_safe);
-static u64 xen_read_msr(u32 msr)
+__visible u64 xen_read_msr(u32 msr)
{
int err = 0;
return xen_do_read_msr(msr, xen_msr_safe ? &err : NULL);
}
+#define PV_PROLOGUE_MSR_xen_read_msr PV_PROLOGUE_RDMSR
+PV_CALLEE_SAVE_REGS_MSR_THUNK(xen_read_msr);
-static void xen_write_msr(u32 msr, u64 val)
+__visible void xen_write_msr(u32 msr, u64 val)
{
int err;
xen_do_write_msr(msr, val, xen_msr_safe ? &err : NULL);
}
+#define PV_PROLOGUE_MSR_xen_write_msr PV_PROLOGUE_WRMSR
+PV_CALLEE_SAVE_REGS_MSR_THUNK(xen_write_msr);
/* This is called once we have the cpu_possible_mask */
void __init xen_setup_vcpu_info_placement(void)
@@ -1386,10 +1409,10 @@ asmlinkage __visible void __init xen_start_kernel(struct start_info *si)
pv_ops.cpu.start_context_switch = xen_start_context_switch;
pv_ops.cpu.end_context_switch = xen_end_context_switch;
- pv_ops_msr.read_msr = xen_read_msr;
- pv_ops_msr.write_msr = xen_write_msr;
- pv_ops_msr.read_msr_safe = xen_read_msr_safe;
- pv_ops_msr.write_msr_safe = xen_write_msr_safe;
+ pv_ops_msr.read_msr = PV_CALLEE_SAVE(xen_read_msr);
+ pv_ops_msr.write_msr = PV_CALLEE_SAVE(xen_write_msr);
+ pv_ops_msr.read_msr_safe = PV_CALLEE_SAVE(xen_read_msr_safe);
+ pv_ops_msr.write_msr_safe = PV_CALLEE_SAVE(xen_write_msr_safe);
pv_ops_msr.read_pmc = xen_read_pmc;
xen_init_irq_ops();
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v3 16/16] x86/paravirt: Use alternatives for MSR access with paravirt
2026-02-18 8:21 [PATCH v3 00/16] x86/msr: Inline rdmsr/wrmsr instructions Juergen Gross
` (3 preceding siblings ...)
2026-02-18 8:21 ` [PATCH v3 14/16] x86/paravirt: Switch MSR access pv_ops functions to " Juergen Gross
@ 2026-02-18 8:21 ` Juergen Gross
2026-02-18 13:49 ` kernel test robot
2026-02-18 20:37 ` [PATCH v3 00/16] x86/msr: Inline rdmsr/wrmsr instructions H. Peter Anvin
5 siblings, 1 reply; 10+ messages in thread
From: Juergen Gross @ 2026-02-18 8:21 UTC (permalink / raw)
To: linux-kernel, x86, virtualization
Cc: Juergen Gross, Ajay Kaher, Alexey Makhalov,
Broadcom internal kernel review list, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, Dave Hansen, H. Peter Anvin
When not running as Xen PV guest, patch in the optimal MSR instructions
via alternative and use direct calls otherwise.
This will especially have positive effects for performance when not
running as a Xen PV guest with paravirtualization enabled, as there
will be no call overhead for MSR access functions any longer.
Signed-off-by: Juergen Gross <jgross@suse.com>
---
V3:
- new patch
---
arch/x86/include/asm/paravirt-msr.h | 101 ++++++++++++++++++++++----
arch/x86/include/asm/paravirt_types.h | 1 +
2 files changed, 86 insertions(+), 16 deletions(-)
diff --git a/arch/x86/include/asm/paravirt-msr.h b/arch/x86/include/asm/paravirt-msr.h
index 4ce690b05600..122a7525ae17 100644
--- a/arch/x86/include/asm/paravirt-msr.h
+++ b/arch/x86/include/asm/paravirt-msr.h
@@ -27,33 +27,103 @@ extern struct pv_msr_ops pv_ops_msr;
#define PV_CALLEE_SAVE_REGS_MSR_THUNK(func) \
__PV_CALLEE_SAVE_REGS_THUNK(func, ".text", MSR)
+#define ASM_CLRERR "xor %[err],%[err]\n"
+
+#define PV_RDMSR_VAR(__msr, __val, __type, __func, __err) \
+ asm volatile( \
+ "1:\n" \
+ ALTERNATIVE_2(PARAVIRT_CALL, \
+ RDMSR_AND_SAVE_RESULT ASM_CLRERR, X86_FEATURE_ALWAYS, \
+ ALT_CALL_INSTR, ALT_XEN_CALL) \
+ "2:\n" \
+ _ASM_EXTABLE_TYPE_REG(1b, 2b, __type, %[err]) \
+ : [err] "=d" (__err), [val] "=a" (__val), \
+ ASM_CALL_CONSTRAINT \
+ : paravirt_ptr(pv_ops_msr, __func), "c" (__msr) \
+ : "cc")
+
+#define PV_RDMSR_CONST(__msr, __val, __type, __func, __err) \
+ asm volatile( \
+ "1:\n" \
+ ALTERNATIVE_3(PARAVIRT_CALL, \
+ RDMSR_AND_SAVE_RESULT ASM_CLRERR, X86_FEATURE_ALWAYS, \
+ ASM_RDMSR_IMM ASM_CLRERR, X86_FEATURE_MSR_IMM, \
+ ALT_CALL_INSTR, ALT_XEN_CALL) \
+ "2:\n" \
+ _ASM_EXTABLE_TYPE_REG(1b, 2b, __type, %[err]) \
+ : [err] "=d" (__err), [val] "=a" (__val), \
+ ASM_CALL_CONSTRAINT \
+ : paravirt_ptr(pv_ops_msr, __func), \
+ "c" (__msr), [msr] "i" (__msr) \
+ : "cc")
+
+#define PV_WRMSR_VAR(__msr, __val, __type, __func, __err) \
+({ \
+ unsigned long rdx = rdx; \
+ asm volatile( \
+ "1:\n" \
+ ALTERNATIVE_3(PARAVIRT_CALL, \
+ "wrmsr;" ASM_CLRERR, X86_FEATURE_ALWAYS, \
+ ASM_WRMSRNS ASM_CLRERR, X86_FEATURE_WRMSRNS, \
+ ALT_CALL_INSTR, ALT_XEN_CALL) \
+ "2:\n" \
+ _ASM_EXTABLE_TYPE_REG(1b, 2b, __type, %[err]) \
+ : [err] "=a" (__err), "=d" (rdx), ASM_CALL_CONSTRAINT \
+ : paravirt_ptr(pv_ops_msr, __func), \
+ "0" (__val), "1" ((__val) >> 32), "c" (__msr) \
+ : "memory", "cc"); \
+})
+
+#define PV_WRMSR_CONST(__msr, __val, __type, __func, __err) \
+({ \
+ unsigned long rdx = rdx; \
+ asm volatile( \
+ "1:\n" \
+ ALTERNATIVE_4(PARAVIRT_CALL, \
+ "wrmsr;" ASM_CLRERR, X86_FEATURE_ALWAYS, \
+ ASM_WRMSRNS ASM_CLRERR, X86_FEATURE_WRMSRNS, \
+ ASM_WRMSRNS_IMM ASM_CLRERR, X86_FEATURE_MSR_IMM,\
+ ALT_CALL_INSTR, ALT_XEN_CALL) \
+ "2:\n" \
+ _ASM_EXTABLE_TYPE_REG(1b, 2b, __type, %[err]) \
+ : [err] "=a" (__err), "=d" (rdx), ASM_CALL_CONSTRAINT \
+ : paravirt_ptr(pv_ops_msr, __func), \
+ [val] "0" (__val), "1" ((__val) >> 32), \
+ "c" (__msr), [msr] "i" (__msr) \
+ : "memory", "cc"); \
+})
+
static __always_inline u64 read_msr(u32 msr)
{
u64 val;
+ int err;
- asm volatile(PARAVIRT_CALL
- : "=a" (val), ASM_CALL_CONSTRAINT
- : paravirt_ptr(pv_ops_msr, read_msr), "c" (msr)
- : "rdx");
+ if (__builtin_constant_p(msr))
+ PV_RDMSR_CONST(msr, val, EX_TYPE_RDMSR, read_msr, err);
+ else
+ PV_RDMSR_VAR(msr, val, EX_TYPE_RDMSR, read_msr, err);
return val;
}
static __always_inline void write_msr(u32 msr, u64 val)
{
- asm volatile(PARAVIRT_CALL
- : ASM_CALL_CONSTRAINT
- : paravirt_ptr(pv_ops_msr, write_msr), "c" (msr), "a" (val)
- : "memory", "rdx");
+ int err;
+
+ if (__builtin_constant_p(msr))
+ PV_WRMSR_CONST(msr, val, EX_TYPE_WRMSR, write_msr, err);
+ else
+ PV_WRMSR_VAR(msr, val, EX_TYPE_WRMSR, write_msr, err);
}
static __always_inline int read_msr_safe(u32 msr, u64 *val)
{
int err;
- asm volatile(PARAVIRT_CALL
- : [err] "=d" (err), "=a" (*val), ASM_CALL_CONSTRAINT
- : paravirt_ptr(pv_ops_msr, read_msr_safe), "c" (msr));
+ if (__builtin_constant_p(msr))
+ PV_RDMSR_CONST(msr, *val, EX_TYPE_RDMSR_SAFE, read_msr_safe, err);
+ else
+ PV_RDMSR_VAR(msr, *val, EX_TYPE_RDMSR_SAFE, read_msr_safe, err);
return err ? -EIO : 0;
}
@@ -62,11 +132,10 @@ static __always_inline int write_msr_safe(u32 msr, u64 val)
{
int err;
- asm volatile(PARAVIRT_CALL
- : [err] "=a" (err), ASM_CALL_CONSTRAINT
- : paravirt_ptr(pv_ops_msr, write_msr_safe),
- "c" (msr), "a" (val)
- : "memory", "rdx");
+ if (__builtin_constant_p(msr))
+ PV_WRMSR_CONST(msr, val, EX_TYPE_WRMSR_SAFE, write_msr_safe, err);
+ else
+ PV_WRMSR_VAR(msr, val, EX_TYPE_WRMSR_SAFE, write_msr_safe, err);
return err ? -EIO : 0;
}
diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h
index 999a5abe54ed..bdaecc54c6ee 100644
--- a/arch/x86/include/asm/paravirt_types.h
+++ b/arch/x86/include/asm/paravirt_types.h
@@ -451,6 +451,7 @@ extern struct paravirt_patch_template pv_ops;
#endif /* __ASSEMBLER__ */
#define ALT_NOT_XEN ALT_NOT(X86_FEATURE_XENPV)
+#define ALT_XEN_CALL ALT_DIRECT_CALL(X86_FEATURE_XENPV)
#ifdef CONFIG_X86_32
/* save and restore all caller-save registers, except return value */
--
2.53.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v3 16/16] x86/paravirt: Use alternatives for MSR access with paravirt
2026-02-18 8:21 ` [PATCH v3 16/16] x86/paravirt: Use alternatives for MSR access with paravirt Juergen Gross
@ 2026-02-18 13:49 ` kernel test robot
2026-02-18 15:49 ` Juergen Gross
0 siblings, 1 reply; 10+ messages in thread
From: kernel test robot @ 2026-02-18 13:49 UTC (permalink / raw)
To: Juergen Gross, linux-kernel, x86, virtualization
Cc: llvm, oe-kbuild-all, Juergen Gross, Ajay Kaher, Alexey Makhalov,
Broadcom internal kernel review list, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, Dave Hansen, H. Peter Anvin
Hi Juergen,
kernel test robot noticed the following build errors:
[auto build test ERROR on linus/master]
[also build test ERROR on next-20260217]
[cannot apply to tip/x86/core kvm/queue kvm/next kvm/linux-next tip/x86/tdx v6.19]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Juergen-Gross/x86-alternative-Support-alt_replace_call-with-instructions-after-call/20260218-163031
base: linus/master
patch link: https://lore.kernel.org/r/20260218082133.400602-17-jgross%40suse.com
patch subject: [PATCH v3 16/16] x86/paravirt: Use alternatives for MSR access with paravirt
config: x86_64-randconfig-001-20260218 (https://download.01.org/0day-ci/archive/20260218/202602182111.84MpXRx4-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260218/202602182111.84MpXRx4-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202602182111.84MpXRx4-lkp@intel.com/
All errors (new ones prefixed by >>):
In file included from arch/x86/kernel/asm-offsets.c:9:
In file included from include/linux/crypto.h:18:
In file included from include/linux/slab.h:17:
In file included from include/linux/gfp.h:7:
In file included from include/linux/mmzone.h:22:
In file included from include/linux/mm_types.h:16:
In file included from include/linux/uprobes.h:18:
In file included from include/linux/timer.h:6:
In file included from include/linux/ktime.h:25:
In file included from include/linux/jiffies.h:10:
In file included from include/linux/time.h:60:
In file included from include/linux/time32.h:13:
In file included from include/linux/timex.h:67:
In file included from arch/x86/include/asm/timex.h:6:
In file included from arch/x86/include/asm/tsc.h:11:
In file included from arch/x86/include/asm/msr.h:300:
>> arch/x86/include/asm/paravirt-msr.h:114:23: error: unsupported inline asm: input with type 'u64' (aka 'unsigned long long') matching output with type 'int'
114 | PV_WRMSR_CONST(msr, val, EX_TYPE_WRMSR, write_msr, err);
| ^~~ ~~~
arch/x86/include/asm/paravirt-msr.h:91:16: note: expanded from macro 'PV_WRMSR_CONST'
89 | : [err] "=a" (__err), "=d" (rdx), ASM_CALL_CONSTRAINT \
| ~~~~~
90 | : paravirt_ptr(pv_ops_msr, __func), \
91 | [val] "0" (__val), "1" ((__val) >> 32), \
| ^~~~~
arch/x86/include/asm/paravirt-msr.h:116:21: error: unsupported inline asm: input with type 'u64' (aka 'unsigned long long') matching output with type 'int'
116 | PV_WRMSR_VAR(msr, val, EX_TYPE_WRMSR, write_msr, err);
| ^~~ ~~~
arch/x86/include/asm/paravirt-msr.h:73:10: note: expanded from macro 'PV_WRMSR_VAR'
71 | : [err] "=a" (__err), "=d" (rdx), ASM_CALL_CONSTRAINT \
| ~~~~~
72 | : paravirt_ptr(pv_ops_msr, __func), \
73 | "0" (__val), "1" ((__val) >> 32), "c" (__msr) \
| ^~~~~
arch/x86/include/asm/paravirt-msr.h:136:23: error: unsupported inline asm: input with type 'u64' (aka 'unsigned long long') matching output with type 'int'
136 | PV_WRMSR_CONST(msr, val, EX_TYPE_WRMSR_SAFE, write_msr_safe, err);
| ^~~ ~~~
arch/x86/include/asm/paravirt-msr.h:91:16: note: expanded from macro 'PV_WRMSR_CONST'
89 | : [err] "=a" (__err), "=d" (rdx), ASM_CALL_CONSTRAINT \
| ~~~~~
90 | : paravirt_ptr(pv_ops_msr, __func), \
91 | [val] "0" (__val), "1" ((__val) >> 32), \
| ^~~~~
arch/x86/include/asm/paravirt-msr.h:138:21: error: unsupported inline asm: input with type 'u64' (aka 'unsigned long long') matching output with type 'int'
138 | PV_WRMSR_VAR(msr, val, EX_TYPE_WRMSR_SAFE, write_msr_safe, err);
| ^~~ ~~~
arch/x86/include/asm/paravirt-msr.h:73:10: note: expanded from macro 'PV_WRMSR_VAR'
71 | : [err] "=a" (__err), "=d" (rdx), ASM_CALL_CONSTRAINT \
| ~~~~~
72 | : paravirt_ptr(pv_ops_msr, __func), \
73 | "0" (__val), "1" ((__val) >> 32), "c" (__msr) \
| ^~~~~
In file included from arch/x86/kernel/asm-offsets.c:10:
In file included from include/crypto/aria.h:22:
In file included from include/linux/module.h:20:
In file included from include/linux/elf.h:6:
In file included from arch/x86/include/asm/elf.h:10:
In file included from arch/x86/include/asm/ia32.h:7:
In file included from include/linux/compat.h:17:
In file included from include/linux/fs.h:5:
In file included from include/linux/fs/super.h:5:
In file included from include/linux/fs/super_types.h:13:
In file included from include/linux/percpu-rwsem.h:7:
In file included from include/linux/rcuwait.h:6:
In file included from include/linux/sched/signal.h:6:
include/linux/signal.h:98:11: warning: array index 3 is past the end of the array (that has type 'unsigned long[1]') [-Warray-bounds]
98 | return (set->sig[3] | set->sig[2] |
| ^ ~
arch/x86/include/asm/signal.h:24:2: note: array 'sig' declared here
24 | unsigned long sig[_NSIG_WORDS];
| ^
In file included from arch/x86/kernel/asm-offsets.c:10:
In file included from include/crypto/aria.h:22:
In file included from include/linux/module.h:20:
In file included from include/linux/elf.h:6:
In file included from arch/x86/include/asm/elf.h:10:
In file included from arch/x86/include/asm/ia32.h:7:
In file included from include/linux/compat.h:17:
In file included from include/linux/fs.h:5:
In file included from include/linux/fs/super.h:5:
In file included from include/linux/fs/super_types.h:13:
In file included from include/linux/percpu-rwsem.h:7:
In file included from include/linux/rcuwait.h:6:
In file included from include/linux/sched/signal.h:6:
include/linux/signal.h:98:25: warning: array index 2 is past the end of the array (that has type 'unsigned long[1]') [-Warray-bounds]
98 | return (set->sig[3] | set->sig[2] |
| ^ ~
arch/x86/include/asm/signal.h:24:2: note: array 'sig' declared here
24 | unsigned long sig[_NSIG_WORDS];
| ^
In file included from arch/x86/kernel/asm-offsets.c:10:
In file included from include/crypto/aria.h:22:
In file included from include/linux/module.h:20:
In file included from include/linux/elf.h:6:
In file included from arch/x86/include/asm/elf.h:10:
In file included from arch/x86/include/asm/ia32.h:7:
In file included from include/linux/compat.h:17:
In file included from include/linux/fs.h:5:
In file included from include/linux/fs/super.h:5:
In file included from include/linux/fs/super_types.h:13:
In file included from include/linux/percpu-rwsem.h:7:
In file included from include/linux/rcuwait.h:6:
In file included from include/linux/sched/signal.h:6:
include/linux/signal.h:99:4: warning: array index 1 is past the end of the array (that has type 'unsigned long[1]') [-Warray-bounds]
99 | set->sig[1] | set->sig[0]) == 0;
| ^ ~
arch/x86/include/asm/signal.h:24:2: note: array 'sig' declared here
24 | unsigned long sig[_NSIG_WORDS];
| ^
In file included from arch/x86/kernel/asm-offsets.c:10:
In file included from include/crypto/aria.h:22:
In file included from include/linux/module.h:20:
In file included from include/linux/elf.h:6:
In file included from arch/x86/include/asm/elf.h:10:
In file included from arch/x86/include/asm/ia32.h:7:
In file included from include/linux/compat.h:17:
In file included from include/linux/fs.h:5:
vim +114 arch/x86/include/asm/paravirt-msr.h
108
109 static __always_inline void write_msr(u32 msr, u64 val)
110 {
111 int err;
112
113 if (__builtin_constant_p(msr))
> 114 PV_WRMSR_CONST(msr, val, EX_TYPE_WRMSR, write_msr, err);
115 else
116 PV_WRMSR_VAR(msr, val, EX_TYPE_WRMSR, write_msr, err);
117 }
118
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 16/16] x86/paravirt: Use alternatives for MSR access with paravirt
2026-02-18 13:49 ` kernel test robot
@ 2026-02-18 15:49 ` Juergen Gross
0 siblings, 0 replies; 10+ messages in thread
From: Juergen Gross @ 2026-02-18 15:49 UTC (permalink / raw)
To: kernel test robot, linux-kernel, x86, virtualization
Cc: llvm, oe-kbuild-all, Ajay Kaher, Alexey Makhalov,
Broadcom internal kernel review list, Thomas Gleixner,
Ingo Molnar, Borislav Petkov, Dave Hansen, H. Peter Anvin
[-- Attachment #1.1.1: Type: text/plain, Size: 10125 bytes --]
On 18.02.26 14:49, kernel test robot wrote:
> Hi Juergen,
>
> kernel test robot noticed the following build errors:
>
> [auto build test ERROR on linus/master]
> [also build test ERROR on next-20260217]
> [cannot apply to tip/x86/core kvm/queue kvm/next kvm/linux-next tip/x86/tdx v6.19]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>
> url: https://github.com/intel-lab-lkp/linux/commits/Juergen-Gross/x86-alternative-Support-alt_replace_call-with-instructions-after-call/20260218-163031
> base: linus/master
> patch link: https://lore.kernel.org/r/20260218082133.400602-17-jgross%40suse.com
> patch subject: [PATCH v3 16/16] x86/paravirt: Use alternatives for MSR access with paravirt
> config: x86_64-randconfig-001-20260218 (https://download.01.org/0day-ci/archive/20260218/202602182111.84MpXRx4-lkp@intel.com/config)
> compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260218/202602182111.84MpXRx4-lkp@intel.com/reproduce)
>
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202602182111.84MpXRx4-lkp@intel.com/
>
> All errors (new ones prefixed by >>):
>
> In file included from arch/x86/kernel/asm-offsets.c:9:
> In file included from include/linux/crypto.h:18:
> In file included from include/linux/slab.h:17:
> In file included from include/linux/gfp.h:7:
> In file included from include/linux/mmzone.h:22:
> In file included from include/linux/mm_types.h:16:
> In file included from include/linux/uprobes.h:18:
> In file included from include/linux/timer.h:6:
> In file included from include/linux/ktime.h:25:
> In file included from include/linux/jiffies.h:10:
> In file included from include/linux/time.h:60:
> In file included from include/linux/time32.h:13:
> In file included from include/linux/timex.h:67:
> In file included from arch/x86/include/asm/timex.h:6:
> In file included from arch/x86/include/asm/tsc.h:11:
> In file included from arch/x86/include/asm/msr.h:300:
>>> arch/x86/include/asm/paravirt-msr.h:114:23: error: unsupported inline asm: input with type 'u64' (aka 'unsigned long long') matching output with type 'int'
> 114 | PV_WRMSR_CONST(msr, val, EX_TYPE_WRMSR, write_msr, err);
> | ^~~ ~~~
> arch/x86/include/asm/paravirt-msr.h:91:16: note: expanded from macro 'PV_WRMSR_CONST'
> 89 | : [err] "=a" (__err), "=d" (rdx), ASM_CALL_CONSTRAINT \
> | ~~~~~
> 90 | : paravirt_ptr(pv_ops_msr, __func), \
> 91 | [val] "0" (__val), "1" ((__val) >> 32), \
> | ^~~~~
> arch/x86/include/asm/paravirt-msr.h:116:21: error: unsupported inline asm: input with type 'u64' (aka 'unsigned long long') matching output with type 'int'
> 116 | PV_WRMSR_VAR(msr, val, EX_TYPE_WRMSR, write_msr, err);
> | ^~~ ~~~
> arch/x86/include/asm/paravirt-msr.h:73:10: note: expanded from macro 'PV_WRMSR_VAR'
> 71 | : [err] "=a" (__err), "=d" (rdx), ASM_CALL_CONSTRAINT \
> | ~~~~~
> 72 | : paravirt_ptr(pv_ops_msr, __func), \
> 73 | "0" (__val), "1" ((__val) >> 32), "c" (__msr) \
> | ^~~~~
> arch/x86/include/asm/paravirt-msr.h:136:23: error: unsupported inline asm: input with type 'u64' (aka 'unsigned long long') matching output with type 'int'
> 136 | PV_WRMSR_CONST(msr, val, EX_TYPE_WRMSR_SAFE, write_msr_safe, err);
> | ^~~ ~~~
> arch/x86/include/asm/paravirt-msr.h:91:16: note: expanded from macro 'PV_WRMSR_CONST'
> 89 | : [err] "=a" (__err), "=d" (rdx), ASM_CALL_CONSTRAINT \
> | ~~~~~
> 90 | : paravirt_ptr(pv_ops_msr, __func), \
> 91 | [val] "0" (__val), "1" ((__val) >> 32), \
> | ^~~~~
> arch/x86/include/asm/paravirt-msr.h:138:21: error: unsupported inline asm: input with type 'u64' (aka 'unsigned long long') matching output with type 'int'
> 138 | PV_WRMSR_VAR(msr, val, EX_TYPE_WRMSR_SAFE, write_msr_safe, err);
> | ^~~ ~~~
> arch/x86/include/asm/paravirt-msr.h:73:10: note: expanded from macro 'PV_WRMSR_VAR'
> 71 | : [err] "=a" (__err), "=d" (rdx), ASM_CALL_CONSTRAINT \
> | ~~~~~
> 72 | : paravirt_ptr(pv_ops_msr, __func), \
> 73 | "0" (__val), "1" ((__val) >> 32), "c" (__msr) \
> | ^~~~~
> In file included from arch/x86/kernel/asm-offsets.c:10:
> In file included from include/crypto/aria.h:22:
> In file included from include/linux/module.h:20:
> In file included from include/linux/elf.h:6:
> In file included from arch/x86/include/asm/elf.h:10:
> In file included from arch/x86/include/asm/ia32.h:7:
> In file included from include/linux/compat.h:17:
> In file included from include/linux/fs.h:5:
> In file included from include/linux/fs/super.h:5:
> In file included from include/linux/fs/super_types.h:13:
> In file included from include/linux/percpu-rwsem.h:7:
> In file included from include/linux/rcuwait.h:6:
> In file included from include/linux/sched/signal.h:6:
> include/linux/signal.h:98:11: warning: array index 3 is past the end of the array (that has type 'unsigned long[1]') [-Warray-bounds]
> 98 | return (set->sig[3] | set->sig[2] |
> | ^ ~
> arch/x86/include/asm/signal.h:24:2: note: array 'sig' declared here
> 24 | unsigned long sig[_NSIG_WORDS];
> | ^
> In file included from arch/x86/kernel/asm-offsets.c:10:
> In file included from include/crypto/aria.h:22:
> In file included from include/linux/module.h:20:
> In file included from include/linux/elf.h:6:
> In file included from arch/x86/include/asm/elf.h:10:
> In file included from arch/x86/include/asm/ia32.h:7:
> In file included from include/linux/compat.h:17:
> In file included from include/linux/fs.h:5:
> In file included from include/linux/fs/super.h:5:
> In file included from include/linux/fs/super_types.h:13:
> In file included from include/linux/percpu-rwsem.h:7:
> In file included from include/linux/rcuwait.h:6:
> In file included from include/linux/sched/signal.h:6:
> include/linux/signal.h:98:25: warning: array index 2 is past the end of the array (that has type 'unsigned long[1]') [-Warray-bounds]
> 98 | return (set->sig[3] | set->sig[2] |
> | ^ ~
> arch/x86/include/asm/signal.h:24:2: note: array 'sig' declared here
> 24 | unsigned long sig[_NSIG_WORDS];
> | ^
> In file included from arch/x86/kernel/asm-offsets.c:10:
> In file included from include/crypto/aria.h:22:
> In file included from include/linux/module.h:20:
> In file included from include/linux/elf.h:6:
> In file included from arch/x86/include/asm/elf.h:10:
> In file included from arch/x86/include/asm/ia32.h:7:
> In file included from include/linux/compat.h:17:
> In file included from include/linux/fs.h:5:
> In file included from include/linux/fs/super.h:5:
> In file included from include/linux/fs/super_types.h:13:
> In file included from include/linux/percpu-rwsem.h:7:
> In file included from include/linux/rcuwait.h:6:
> In file included from include/linux/sched/signal.h:6:
> include/linux/signal.h:99:4: warning: array index 1 is past the end of the array (that has type 'unsigned long[1]') [-Warray-bounds]
> 99 | set->sig[1] | set->sig[0]) == 0;
> | ^ ~
> arch/x86/include/asm/signal.h:24:2: note: array 'sig' declared here
> 24 | unsigned long sig[_NSIG_WORDS];
> | ^
> In file included from arch/x86/kernel/asm-offsets.c:10:
> In file included from include/crypto/aria.h:22:
> In file included from include/linux/module.h:20:
> In file included from include/linux/elf.h:6:
> In file included from arch/x86/include/asm/elf.h:10:
> In file included from arch/x86/include/asm/ia32.h:7:
> In file included from include/linux/compat.h:17:
> In file included from include/linux/fs.h:5:
>
>
> vim +114 arch/x86/include/asm/paravirt-msr.h
>
> 108
> 109 static __always_inline void write_msr(u32 msr, u64 val)
> 110 {
> 111 int err;
> 112
> 113 if (__builtin_constant_p(msr))
> > 114 PV_WRMSR_CONST(msr, val, EX_TYPE_WRMSR, write_msr, err);
> 115 else
> 116 PV_WRMSR_VAR(msr, val, EX_TYPE_WRMSR, write_msr, err);
> 117 }
> 118
>
Will be fixed in V4.
Juergen
[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 00/16] x86/msr: Inline rdmsr/wrmsr instructions
2026-02-18 8:21 [PATCH v3 00/16] x86/msr: Inline rdmsr/wrmsr instructions Juergen Gross
` (4 preceding siblings ...)
2026-02-18 8:21 ` [PATCH v3 16/16] x86/paravirt: Use alternatives for MSR access with paravirt Juergen Gross
@ 2026-02-18 20:37 ` H. Peter Anvin
2026-02-19 6:28 ` Jürgen Groß
5 siblings, 1 reply; 10+ messages in thread
From: H. Peter Anvin @ 2026-02-18 20:37 UTC (permalink / raw)
To: Juergen Gross, linux-kernel, x86, linux-coco, kvm, linux-hyperv,
virtualization, llvm
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
Kiryl Shutsemau, Rick Edgecombe, Sean Christopherson,
Paolo Bonzini, K. Y. Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, Long Li, Vitaly Kuznetsov, Boris Ostrovsky, xen-devel,
Ajay Kaher, Alexey Makhalov, Broadcom internal kernel review list,
Andy Lutomirski, Peter Zijlstra, Xin Li, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Josh Poimboeuf,
andy.cooper
On February 18, 2026 12:21:17 AM PST, Juergen Gross <jgross@suse.com> wrote:
>When building a kernel with CONFIG_PARAVIRT_XXL the paravirt
>infrastructure will always use functions for reading or writing MSRs,
>even when running on bare metal.
>
>Switch to inline RDMSR/WRMSR instructions in this case, reducing the
>paravirt overhead.
>
>The first patch is a prerequisite fix for alternative patching. Its
>is needed due to the initial indirect call needs to be padded with
>NOPs in some cases with the following patches.
>
>In order to make this less intrusive, some further reorganization of
>the MSR access helpers is done in the patches 1-6.
>
>The next 4 patches are converting the non-paravirt case to use direct
>inlining of the MSR access instructions, including the WRMSRNS
>instruction and the immediate variants of RDMSR and WRMSR if possible.
>
>Patches 11-13 are some further preparations for making the real switch
>to directly patch in the native MSR instructions easier.
>
>Patch 14 is switching the paravirt MSR function interface from normal
>call ABI to one more similar to the native MSR instructions.
>
>Patch 15 is a little cleanup patch.
>
>Patch 16 is the final step for patching in the native MSR instructions
>when not running as a Xen PV guest.
>
>This series has been tested to work with Xen PV and on bare metal.
>
>Note that there is more room for improvement. This series is sent out
>to get a first impression how the code will basically look like.
Does that mean you are considering this patchset an RFC? If so, you should put that in the subject header.
>Right now the same problem is solved differently for the paravirt and
>the non-paravirt cases. In case this is not desired, there are two
>possibilities to merge the two implementations. Both solutions have
>the common idea to have rather similar code for paravirt and
>non-paravirt variants, but just use a different main macro for
>generating the respective code. For making the code of both possible
>scenarios more similar, the following variants are possible:
>
>1. Remove the micro-optimizations of the non-paravirt case, making
> it similar to the paravirt code in my series. This has the
> advantage of being more simple, but might have a very small
> negative performance impact (probably not really detectable).
>
>2. Add the same micro-optimizations to the paravirt case, requiring
> to enhance paravirt patching to support a to be patched indirect
> call in the middle of the initial code snipplet.
>
>In both cases the native MSR function variants would no longer be
>usable in the paravirt case, but this would mostly affect Xen, as it
>would need to open code the WRMSR/RDMSR instructions to be used
>instead the native_*msr*() functions.
>
>Changes since V2:
>- switch back to the paravirt approach
>
>Changes since V1:
>- Use Xin Li's approach for inlining
>- Several new patches
>
>Juergen Gross (16):
> x86/alternative: Support alt_replace_call() with instructions after
> call
> coco/tdx: Rename MSR access helpers
> x86/sev: Replace call of native_wrmsr() with native_wrmsrq()
> KVM: x86: Remove the KVM private read_msr() function
> x86/msr: Minimize usage of native_*() msr access functions
> x86/msr: Move MSR trace calls one function level up
> x86/opcode: Add immediate form MSR instructions
> x86/extable: Add support for immediate form MSR instructions
> x86/msr: Use the alternatives mechanism for WRMSR
> x86/msr: Use the alternatives mechanism for RDMSR
> x86/alternatives: Add ALTERNATIVE_4()
> x86/paravirt: Split off MSR related hooks into new header
> x86/paravirt: Prepare support of MSR instruction interfaces
> x86/paravirt: Switch MSR access pv_ops functions to instruction
> interfaces
> x86/msr: Reduce number of low level MSR access helpers
> x86/paravirt: Use alternatives for MSR access with paravirt
>
> arch/x86/coco/sev/internal.h | 7 +-
> arch/x86/coco/tdx/tdx.c | 8 +-
> arch/x86/hyperv/ivm.c | 2 +-
> arch/x86/include/asm/alternative.h | 6 +
> arch/x86/include/asm/fred.h | 2 +-
> arch/x86/include/asm/kvm_host.h | 10 -
> arch/x86/include/asm/msr.h | 345 ++++++++++++++++------
> arch/x86/include/asm/paravirt-msr.h | 148 ++++++++++
> arch/x86/include/asm/paravirt.h | 67 -----
> arch/x86/include/asm/paravirt_types.h | 57 ++--
> arch/x86/include/asm/qspinlock_paravirt.h | 4 +-
> arch/x86/kernel/alternative.c | 5 +-
> arch/x86/kernel/cpu/mshyperv.c | 7 +-
> arch/x86/kernel/kvmclock.c | 2 +-
> arch/x86/kernel/paravirt.c | 42 ++-
> arch/x86/kvm/svm/svm.c | 16 +-
> arch/x86/kvm/vmx/tdx.c | 2 +-
> arch/x86/kvm/vmx/vmx.c | 8 +-
> arch/x86/lib/x86-opcode-map.txt | 5 +-
> arch/x86/mm/extable.c | 35 ++-
> arch/x86/xen/enlighten_pv.c | 52 +++-
> arch/x86/xen/pmu.c | 4 +-
> tools/arch/x86/lib/x86-opcode-map.txt | 5 +-
> tools/objtool/check.c | 1 +
> 24 files changed, 576 insertions(+), 264 deletions(-)
> create mode 100644 arch/x86/include/asm/paravirt-msr.h
>
Could you clarify *on the high design level* what "go back to the paravirt approach" means, and the motivation for that?
Note that for Xen *most* MSRs fall in one of two categories: those that are dropped entirely and those that are just passed straight on to the hardware.
I don't know if anyone cares about optimizing PV Xen anymore, but at least in theory Xen can un-paravirtualize most sites.
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v3 00/16] x86/msr: Inline rdmsr/wrmsr instructions
2026-02-18 20:37 ` [PATCH v3 00/16] x86/msr: Inline rdmsr/wrmsr instructions H. Peter Anvin
@ 2026-02-19 6:28 ` Jürgen Groß
0 siblings, 0 replies; 10+ messages in thread
From: Jürgen Groß @ 2026-02-19 6:28 UTC (permalink / raw)
To: H. Peter Anvin, linux-kernel, x86, linux-coco, kvm, linux-hyperv,
virtualization, llvm
Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
Kiryl Shutsemau, Rick Edgecombe, Sean Christopherson,
Paolo Bonzini, K. Y. Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, Long Li, Vitaly Kuznetsov, Boris Ostrovsky, xen-devel,
Ajay Kaher, Alexey Makhalov, Broadcom internal kernel review list,
Andy Lutomirski, Peter Zijlstra, Xin Li, Nathan Chancellor,
Nick Desaulniers, Bill Wendling, Justin Stitt, Josh Poimboeuf,
andy.cooper
[-- Attachment #1.1.1: Type: text/plain, Size: 6721 bytes --]
On 18.02.26 21:37, H. Peter Anvin wrote:
> On February 18, 2026 12:21:17 AM PST, Juergen Gross <jgross@suse.com> wrote:
>> When building a kernel with CONFIG_PARAVIRT_XXL the paravirt
>> infrastructure will always use functions for reading or writing MSRs,
>> even when running on bare metal.
>>
>> Switch to inline RDMSR/WRMSR instructions in this case, reducing the
>> paravirt overhead.
>>
>> The first patch is a prerequisite fix for alternative patching. Its
>> is needed due to the initial indirect call needs to be padded with
>> NOPs in some cases with the following patches.
>>
>> In order to make this less intrusive, some further reorganization of
>> the MSR access helpers is done in the patches 1-6.
>>
>> The next 4 patches are converting the non-paravirt case to use direct
>> inlining of the MSR access instructions, including the WRMSRNS
>> instruction and the immediate variants of RDMSR and WRMSR if possible.
>>
>> Patches 11-13 are some further preparations for making the real switch
>> to directly patch in the native MSR instructions easier.
>>
>> Patch 14 is switching the paravirt MSR function interface from normal
>> call ABI to one more similar to the native MSR instructions.
>>
>> Patch 15 is a little cleanup patch.
>>
>> Patch 16 is the final step for patching in the native MSR instructions
>> when not running as a Xen PV guest.
>>
>> This series has been tested to work with Xen PV and on bare metal.
>>
>> Note that there is more room for improvement. This series is sent out
>> to get a first impression how the code will basically look like.
>
> Does that mean you are considering this patchset an RFC? If so, you should put that in the subject header.
It is one possible solution.
>
>> Right now the same problem is solved differently for the paravirt and
>> the non-paravirt cases. In case this is not desired, there are two
>> possibilities to merge the two implementations. Both solutions have
>> the common idea to have rather similar code for paravirt and
>> non-paravirt variants, but just use a different main macro for
>> generating the respective code. For making the code of both possible
>> scenarios more similar, the following variants are possible:
>>
>> 1. Remove the micro-optimizations of the non-paravirt case, making
>> it similar to the paravirt code in my series. This has the
>> advantage of being more simple, but might have a very small
>> negative performance impact (probably not really detectable).
>>
>> 2. Add the same micro-optimizations to the paravirt case, requiring
>> to enhance paravirt patching to support a to be patched indirect
>> call in the middle of the initial code snipplet.
>>
>> In both cases the native MSR function variants would no longer be
>> usable in the paravirt case, but this would mostly affect Xen, as it
>> would need to open code the WRMSR/RDMSR instructions to be used
>> instead the native_*msr*() functions.
>>
>> Changes since V2:
>> - switch back to the paravirt approach
>>
>> Changes since V1:
>> - Use Xin Li's approach for inlining
>> - Several new patches
>>
>> Juergen Gross (16):
>> x86/alternative: Support alt_replace_call() with instructions after
>> call
>> coco/tdx: Rename MSR access helpers
>> x86/sev: Replace call of native_wrmsr() with native_wrmsrq()
>> KVM: x86: Remove the KVM private read_msr() function
>> x86/msr: Minimize usage of native_*() msr access functions
>> x86/msr: Move MSR trace calls one function level up
>> x86/opcode: Add immediate form MSR instructions
>> x86/extable: Add support for immediate form MSR instructions
>> x86/msr: Use the alternatives mechanism for WRMSR
>> x86/msr: Use the alternatives mechanism for RDMSR
>> x86/alternatives: Add ALTERNATIVE_4()
>> x86/paravirt: Split off MSR related hooks into new header
>> x86/paravirt: Prepare support of MSR instruction interfaces
>> x86/paravirt: Switch MSR access pv_ops functions to instruction
>> interfaces
>> x86/msr: Reduce number of low level MSR access helpers
>> x86/paravirt: Use alternatives for MSR access with paravirt
>>
>> arch/x86/coco/sev/internal.h | 7 +-
>> arch/x86/coco/tdx/tdx.c | 8 +-
>> arch/x86/hyperv/ivm.c | 2 +-
>> arch/x86/include/asm/alternative.h | 6 +
>> arch/x86/include/asm/fred.h | 2 +-
>> arch/x86/include/asm/kvm_host.h | 10 -
>> arch/x86/include/asm/msr.h | 345 ++++++++++++++++------
>> arch/x86/include/asm/paravirt-msr.h | 148 ++++++++++
>> arch/x86/include/asm/paravirt.h | 67 -----
>> arch/x86/include/asm/paravirt_types.h | 57 ++--
>> arch/x86/include/asm/qspinlock_paravirt.h | 4 +-
>> arch/x86/kernel/alternative.c | 5 +-
>> arch/x86/kernel/cpu/mshyperv.c | 7 +-
>> arch/x86/kernel/kvmclock.c | 2 +-
>> arch/x86/kernel/paravirt.c | 42 ++-
>> arch/x86/kvm/svm/svm.c | 16 +-
>> arch/x86/kvm/vmx/tdx.c | 2 +-
>> arch/x86/kvm/vmx/vmx.c | 8 +-
>> arch/x86/lib/x86-opcode-map.txt | 5 +-
>> arch/x86/mm/extable.c | 35 ++-
>> arch/x86/xen/enlighten_pv.c | 52 +++-
>> arch/x86/xen/pmu.c | 4 +-
>> tools/arch/x86/lib/x86-opcode-map.txt | 5 +-
>> tools/objtool/check.c | 1 +
>> 24 files changed, 576 insertions(+), 264 deletions(-)
>> create mode 100644 arch/x86/include/asm/paravirt-msr.h
>>
>
> Could you clarify *on the high design level* what "go back to the paravirt approach" means, and the motivation for that?
This is related to V2 of this series, where I used a static branch for
special casing Xen PV.
Peter Zijlstra commented on that asking to try harder using the pv_ops
hooks for Xen PV, too.
> Note that for Xen *most* MSRs fall in one of two categories: those that are dropped entirely and those that are just passed straight on to the hardware.
>
> I don't know if anyone cares about optimizing PV Xen anymore, but at least in theory Xen can un-paravirtualize most sites.
The problem with that is, that this would need to be taken care at the
callers' sites, "poisoning" a lot of code with Xen specific paths. Or we'd
need to use the native variants explicitly at all places where Xen PV
would just use the MSR instructions itself. But please be aware, that
there are plans to introduce a hypercall for Xen to speed up MSR accesses,
which would reduce the "passed through to hardware" cases to 0.
Juergen
[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-02-19 6:28 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-18 8:21 [PATCH v3 00/16] x86/msr: Inline rdmsr/wrmsr instructions Juergen Gross
2026-02-18 8:21 ` [PATCH v3 06/16] x86/msr: Move MSR trace calls one function level up Juergen Gross
2026-02-18 8:21 ` [PATCH v3 12/16] x86/paravirt: Split off MSR related hooks into new header Juergen Gross
2026-02-18 8:21 ` [PATCH v3 13/16] x86/paravirt: Prepare support of MSR instruction interfaces Juergen Gross
2026-02-18 8:21 ` [PATCH v3 14/16] x86/paravirt: Switch MSR access pv_ops functions to " Juergen Gross
2026-02-18 8:21 ` [PATCH v3 16/16] x86/paravirt: Use alternatives for MSR access with paravirt Juergen Gross
2026-02-18 13:49 ` kernel test robot
2026-02-18 15:49 ` Juergen Gross
2026-02-18 20:37 ` [PATCH v3 00/16] x86/msr: Inline rdmsr/wrmsr instructions H. Peter Anvin
2026-02-19 6:28 ` Jürgen Groß
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox