Files
linux/arch/x86/lib/msr.c
Borislav Petkov 8442df2b49 x86/bugs: KVM: Add support for SRSO_MSR_FIX
Add support for

  CPUID Fn8000_0021_EAX[31] (SRSO_MSR_FIX). If this bit is 1, it
  indicates that software may use MSR BP_CFG[BpSpecReduce] to mitigate
  SRSO.

Enable BpSpecReduce to mitigate SRSO across guest/host boundaries.

Switch back to enabling the bit when virtualization is enabled and to
clear the bit when virtualization is disabled because using a MSR slot
would clear the bit when the guest is exited and any training the guest
has done, would potentially influence the host kernel when execution
enters the kernel and hasn't VMRUN the guest yet.

More detail on the public thread in Link below.

Co-developed-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Link: https://lore.kernel.org/r/20241202120416.6054-1-bp@kernel.org
2025-02-26 15:13:06 +01:00

147 lines
2.7 KiB
C

// SPDX-License-Identifier: GPL-2.0
#include <linux/export.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 = rdmsrl_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 wrmsrl_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_GPL(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_GPL(msr_clear_bit);
#ifdef CONFIG_TRACEPOINTS
void do_trace_write_msr(unsigned int 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(unsigned int 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(unsigned counter, u64 val, int failed)
{
trace_rdpmc(counter, val, failed);
}
EXPORT_SYMBOL(do_trace_rdpmc);
EXPORT_TRACEPOINT_SYMBOL(rdpmc);
#endif