Skip to content

Commit b2ac58f

Browse files
KarimAllah AhmedKAGA-KOKO
authored andcommitted
KVM/SVM: Allow direct access to MSR_IA32_SPEC_CTRL
[ Based on a patch from Paolo Bonzini <[email protected]> ] ... basically doing exactly what we do for VMX: - Passthrough SPEC_CTRL to guests (if enabled in guest CPUID) - Save and restore SPEC_CTRL around VMExit and VMEntry only if the guest actually used it. Signed-off-by: KarimAllah Ahmed <[email protected]> Signed-off-by: David Woodhouse <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Reviewed-by: Darren Kenny <[email protected]> Reviewed-by: Konrad Rzeszutek Wilk <[email protected]> Cc: Andrea Arcangeli <[email protected]> Cc: Andi Kleen <[email protected]> Cc: Jun Nakajima <[email protected]> Cc: [email protected] Cc: Dave Hansen <[email protected]> Cc: Tim Chen <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: Asit Mallick <[email protected]> Cc: Arjan Van De Ven <[email protected]> Cc: Greg KH <[email protected]> Cc: Paolo Bonzini <[email protected]> Cc: Dan Williams <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Ashok Raj <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent d28b387 commit b2ac58f

File tree

1 file changed

+88
-0
lines changed

1 file changed

+88
-0
lines changed

arch/x86/kvm/svm.c

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,8 @@ struct vcpu_svm {
184184
u64 gs_base;
185185
} host;
186186

187+
u64 spec_ctrl;
188+
187189
u32 *msrpm;
188190

189191
ulong nmi_iret_rip;
@@ -249,6 +251,7 @@ static const struct svm_direct_access_msrs {
249251
{ .index = MSR_CSTAR, .always = true },
250252
{ .index = MSR_SYSCALL_MASK, .always = true },
251253
#endif
254+
{ .index = MSR_IA32_SPEC_CTRL, .always = false },
252255
{ .index = MSR_IA32_PRED_CMD, .always = false },
253256
{ .index = MSR_IA32_LASTBRANCHFROMIP, .always = false },
254257
{ .index = MSR_IA32_LASTBRANCHTOIP, .always = false },
@@ -882,6 +885,25 @@ static bool valid_msr_intercept(u32 index)
882885
return false;
883886
}
884887

888+
static bool msr_write_intercepted(struct kvm_vcpu *vcpu, unsigned msr)
889+
{
890+
u8 bit_write;
891+
unsigned long tmp;
892+
u32 offset;
893+
u32 *msrpm;
894+
895+
msrpm = is_guest_mode(vcpu) ? to_svm(vcpu)->nested.msrpm:
896+
to_svm(vcpu)->msrpm;
897+
898+
offset = svm_msrpm_offset(msr);
899+
bit_write = 2 * (msr & 0x0f) + 1;
900+
tmp = msrpm[offset];
901+
902+
BUG_ON(offset == MSR_INVALID);
903+
904+
return !!test_bit(bit_write, &tmp);
905+
}
906+
885907
static void set_msr_interception(u32 *msrpm, unsigned msr,
886908
int read, int write)
887909
{
@@ -1584,6 +1606,8 @@ static void svm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
15841606
u32 dummy;
15851607
u32 eax = 1;
15861608

1609+
svm->spec_ctrl = 0;
1610+
15871611
if (!init_event) {
15881612
svm->vcpu.arch.apic_base = APIC_DEFAULT_PHYS_BASE |
15891613
MSR_IA32_APICBASE_ENABLE;
@@ -3605,6 +3629,13 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
36053629
case MSR_VM_CR:
36063630
msr_info->data = svm->nested.vm_cr_msr;
36073631
break;
3632+
case MSR_IA32_SPEC_CTRL:
3633+
if (!msr_info->host_initiated &&
3634+
!guest_cpuid_has(vcpu, X86_FEATURE_IBRS))
3635+
return 1;
3636+
3637+
msr_info->data = svm->spec_ctrl;
3638+
break;
36083639
case MSR_IA32_UCODE_REV:
36093640
msr_info->data = 0x01000065;
36103641
break;
@@ -3696,6 +3727,33 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
36963727
case MSR_IA32_TSC:
36973728
kvm_write_tsc(vcpu, msr);
36983729
break;
3730+
case MSR_IA32_SPEC_CTRL:
3731+
if (!msr->host_initiated &&
3732+
!guest_cpuid_has(vcpu, X86_FEATURE_IBRS))
3733+
return 1;
3734+
3735+
/* The STIBP bit doesn't fault even if it's not advertised */
3736+
if (data & ~(SPEC_CTRL_IBRS | SPEC_CTRL_STIBP))
3737+
return 1;
3738+
3739+
svm->spec_ctrl = data;
3740+
3741+
if (!data)
3742+
break;
3743+
3744+
/*
3745+
* For non-nested:
3746+
* When it's written (to non-zero) for the first time, pass
3747+
* it through.
3748+
*
3749+
* For nested:
3750+
* The handling of the MSR bitmap for L2 guests is done in
3751+
* nested_svm_vmrun_msrpm.
3752+
* We update the L1 MSR bit as well since it will end up
3753+
* touching the MSR anyway now.
3754+
*/
3755+
set_msr_interception(svm->msrpm, MSR_IA32_SPEC_CTRL, 1, 1);
3756+
break;
36993757
case MSR_IA32_PRED_CMD:
37003758
if (!msr->host_initiated &&
37013759
!guest_cpuid_has(vcpu, X86_FEATURE_IBPB))
@@ -4964,6 +5022,15 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
49645022

49655023
local_irq_enable();
49665024

5025+
/*
5026+
* If this vCPU has touched SPEC_CTRL, restore the guest's value if
5027+
* it's non-zero. Since vmentry is serialising on affected CPUs, there
5028+
* is no need to worry about the conditional branch over the wrmsr
5029+
* being speculatively taken.
5030+
*/
5031+
if (svm->spec_ctrl)
5032+
wrmsrl(MSR_IA32_SPEC_CTRL, svm->spec_ctrl);
5033+
49675034
asm volatile (
49685035
"push %%" _ASM_BP "; \n\t"
49695036
"mov %c[rbx](%[svm]), %%" _ASM_BX " \n\t"
@@ -5056,6 +5123,27 @@ static void svm_vcpu_run(struct kvm_vcpu *vcpu)
50565123
#endif
50575124
);
50585125

5126+
/*
5127+
* We do not use IBRS in the kernel. If this vCPU has used the
5128+
* SPEC_CTRL MSR it may have left it on; save the value and
5129+
* turn it off. This is much more efficient than blindly adding
5130+
* it to the atomic save/restore list. Especially as the former
5131+
* (Saving guest MSRs on vmexit) doesn't even exist in KVM.
5132+
*
5133+
* For non-nested case:
5134+
* If the L01 MSR bitmap does not intercept the MSR, then we need to
5135+
* save it.
5136+
*
5137+
* For nested case:
5138+
* If the L02 MSR bitmap does not intercept the MSR, then we need to
5139+
* save it.
5140+
*/
5141+
if (!msr_write_intercepted(vcpu, MSR_IA32_SPEC_CTRL))
5142+
rdmsrl(MSR_IA32_SPEC_CTRL, svm->spec_ctrl);
5143+
5144+
if (svm->spec_ctrl)
5145+
wrmsrl(MSR_IA32_SPEC_CTRL, 0);
5146+
50595147
/* Eliminate branch target predictions from guest mode */
50605148
vmexit_fill_RSB();
50615149

0 commit comments

Comments
 (0)