diff options
| author | Zeng Chi <zengchi@kylinos.cn> | 2026-09-21 18:24:42 +0800 |
|---|---|---|
| committer | Sean Christopherson <seanjc@google.com> | 2026-09-22 08:36:16 -0700 |
| commit | 119e9db233ad0f4cbd4cfb9f9385a7bca378b37d (patch) | |
| tree | 660d50d4139cb750fbde1ae3432452c20726c99d /arch/x86/lib/msr.c | |
| download | linux-stable-119e9db233ad0f4cbd4cfb9f9385a7bca378b37d.tar.gz linux-stable-119e9db233ad0f4cbd4cfb9f9385a7bca378b37d.zip | |
KVM: Don't pre-reserve xarray entries when storing empty/NULL attributesgrafted
Skip the xarray reservation loop when clearing all memory attributes, as
storing NULL only erases the entry and never needs to allocate, so no
reservation (and no cleanup of a failed one) is required in that case.
Suggested-by: Sean Christopherson <seanjc@google.com>
Cc: David Ballesteros <davimaba.v@proton.me>
Signed-off-by: Zeng Chi <zengchi@kylinos.cn>
Link: https://patch.msgid.link/20260921102442.1232375-1-zeng_chi911@163.com
[sean: split to separate patch]
Signed-off-by: Sean Christopherson <seanjc@google.com>
Diffstat (limited to 'arch/x86/lib/msr.c')
| -rw-r--r-- | arch/x86/lib/msr.c | 147 |
1 files changed, 147 insertions, 0 deletions
diff --git a/arch/x86/lib/msr.c b/arch/x86/lib/msr.c new file mode 100644 index 000000000..dfdd1da89 --- /dev/null +++ b/arch/x86/lib/msr.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/export.h> +#include <linux/kvm_types.h> +#include <linux/percpu.h> +#include <linux/preempt.h> +#include <asm/msr.h> +#define CREATE_TRACE_POINTS +#include <asm/msr-trace.h> + +struct msr __percpu *msrs_alloc(void) +{ + struct msr __percpu *msrs = NULL; + + msrs = alloc_percpu(struct msr); + if (!msrs) { + pr_warn("%s: error allocating msrs\n", __func__); + return NULL; + } + + return msrs; +} +EXPORT_SYMBOL(msrs_alloc); + +void msrs_free(struct msr __percpu *msrs) +{ + free_percpu(msrs); +} +EXPORT_SYMBOL(msrs_free); + +/** + * msr_read - Read an MSR with error handling + * @msr: MSR to read + * @m: value to read into + * + * It returns read data only on success, otherwise it doesn't change the output + * argument @m. + * + * Return: %0 for success, otherwise an error code + */ +static int msr_read(u32 msr, struct msr *m) +{ + int err; + u64 val; + + err = rdmsrq_safe(msr, &val); + if (!err) + m->q = val; + + return err; +} + +/** + * msr_write - Write an MSR with error handling + * + * @msr: MSR to write + * @m: value to write + * + * Return: %0 for success, otherwise an error code + */ +static int msr_write(u32 msr, struct msr *m) +{ + return wrmsrq_safe(msr, m->q); +} + +static inline int __flip_bit(u32 msr, u8 bit, bool set) +{ + struct msr m, m1; + int err = -EINVAL; + + if (bit > 63) + return err; + + err = msr_read(msr, &m); + if (err) + return err; + + m1 = m; + if (set) + m1.q |= BIT_64(bit); + else + m1.q &= ~BIT_64(bit); + + if (m1.q == m.q) + return 0; + + err = msr_write(msr, &m1); + if (err) + return err; + + return 1; +} + +/** + * msr_set_bit - Set @bit in a MSR @msr. + * @msr: MSR to write + * @bit: bit number to set + * + * Return: + * * < 0: An error was encountered. + * * = 0: Bit was already set. + * * > 0: Hardware accepted the MSR write. + */ +int msr_set_bit(u32 msr, u8 bit) +{ + return __flip_bit(msr, bit, true); +} +EXPORT_SYMBOL_FOR_KVM(msr_set_bit); + +/** + * msr_clear_bit - Clear @bit in a MSR @msr. + * @msr: MSR to write + * @bit: bit number to clear + * + * Return: + * * < 0: An error was encountered. + * * = 0: Bit was already cleared. + * * > 0: Hardware accepted the MSR write. + */ +int msr_clear_bit(u32 msr, u8 bit) +{ + return __flip_bit(msr, bit, false); +} +EXPORT_SYMBOL_FOR_KVM(msr_clear_bit); + +#ifdef CONFIG_TRACEPOINTS +void do_trace_write_msr(u32 msr, u64 val, int failed) +{ + trace_write_msr(msr, val, failed); +} +EXPORT_SYMBOL(do_trace_write_msr); +EXPORT_TRACEPOINT_SYMBOL(write_msr); + +void do_trace_read_msr(u32 msr, u64 val, int failed) +{ + trace_read_msr(msr, val, failed); +} +EXPORT_SYMBOL(do_trace_read_msr); +EXPORT_TRACEPOINT_SYMBOL(read_msr); + +void do_trace_rdpmc(u32 msr, u64 val, int failed) +{ + trace_rdpmc(msr, val, failed); +} +EXPORT_SYMBOL(do_trace_rdpmc); +EXPORT_TRACEPOINT_SYMBOL(rdpmc); + +#endif |
