@@ -17,6 +17,7 @@ KVM_GOVERNED_X86_FEATURE(PFTHRESHOLD)
KVM_GOVERNED_X86_FEATURE(VGIF)
KVM_GOVERNED_X86_FEATURE(VNMI)
KVM_GOVERNED_X86_FEATURE(LAM)
+KVM_GOVERNED_X86_FEATURE(BUS_LOCK_THRESHOLD)
#undef KVM_GOVERNED_X86_FEATURE
#undef KVM_GOVERNED_FEATURE
@@ -363,6 +363,7 @@ void __nested_copy_vmcb_control_to_cache(struct kvm_vcpu *vcpu,
to->virt_ext = from->virt_ext;
to->pause_filter_count = from->pause_filter_count;
to->pause_filter_thresh = from->pause_filter_thresh;
+ to->bus_lock_counter = from->bus_lock_counter;
/* Copy asid here because nested_vmcb_check_controls will check it. */
to->asid = from->asid;
@@ -758,6 +759,16 @@ static void nested_vmcb02_prepare_control(struct vcpu_svm *svm,
}
}
+ /*
+ * If guest intercepts BUSLOCK, use guest's bus_lock_counter value,
+ * otherwise use host bus_lock_counter value.
+ */
+ if (guest_can_use(vcpu, X86_FEATURE_BUS_LOCK_THRESHOLD) &&
+ vmcb12_is_intercept(&svm->nested.ctl, INTERCEPT_BUSLOCK))
+ vmcb02->control.bus_lock_counter = svm->nested.ctl.bus_lock_counter;
+ else
+ vmcb02->control.bus_lock_counter = vmcb01->control.bus_lock_counter;
+
nested_svm_transition_tlb_flush(vcpu);
/* Enter Guest-Mode */
@@ -1035,6 +1046,12 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
}
+ if (guest_can_use(vcpu, X86_FEATURE_BUS_LOCK_THRESHOLD) &&
+ vmcb12_is_intercept(&svm->nested.ctl, INTERCEPT_BUSLOCK))
+ vmcb12->control.bus_lock_counter = vmcb02->control.bus_lock_counter;
+ else
+ vmcb01->control.bus_lock_counter = vmcb02->control.bus_lock_counter;
+
nested_svm_copy_common_state(svm->nested.vmcb02.ptr, svm->vmcb01.ptr);
svm_switch_vmcb(svm, &svm->vmcb01);
@@ -1333,6 +1350,13 @@ static int nested_svm_intercept(struct vcpu_svm *svm)
vmexit = NESTED_EXIT_DONE;
break;
}
+ case SVM_EXIT_BUS_LOCK: {
+ if (!(vmcb12_is_intercept(&svm->nested.ctl, INTERCEPT_BUSLOCK)))
+ vmexit = NESTED_EXIT_HOST;
+ else
+ vmexit = NESTED_EXIT_DONE;
+ break;
+ }
default: {
if (vmcb12_is_intercept(&svm->nested.ctl, exit_code))
vmexit = NESTED_EXIT_DONE;
@@ -1572,6 +1596,7 @@ static void nested_copy_vmcb_cache_to_control(struct vmcb_control_area *dst,
dst->virt_ext = from->virt_ext;
dst->pause_filter_count = from->pause_filter_count;
dst->pause_filter_thresh = from->pause_filter_thresh;
+ dst->bus_lock_counter = from->bus_lock_counter;
/* 'clean' and 'hv_enlightenments' are not changed by KVM */
}
@@ -4373,6 +4373,8 @@ static void svm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
set_msr_interception(vcpu, svm->msrpm, MSR_IA32_FLUSH_CMD, 0,
!!guest_cpuid_has(vcpu, X86_FEATURE_FLUSH_L1D));
+ kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_BUS_LOCK_THRESHOLD);
+
if (cpu_feature_enabled(X86_FEATURE_BUS_LOCK_THRESHOLD) &&
vcpu->kvm->arch.bus_lock_detection_enabled) {
svm_set_intercept(svm, INTERCEPT_BUSLOCK);
@@ -5183,6 +5185,9 @@ static __init void svm_set_cpu_caps(void)
if (vnmi)
kvm_cpu_cap_set(X86_FEATURE_VNMI);
+ if (cpu_feature_enabled(X86_FEATURE_BUS_LOCK_THRESHOLD))
+ kvm_cpu_cap_set(X86_FEATURE_BUS_LOCK_THRESHOLD);
+
/* Nested VM can receive #VMEXIT instead of triggering #GP */
kvm_cpu_cap_set(X86_FEATURE_SVME_ADDR_CHK);
}
@@ -150,6 +150,7 @@ struct vmcb_ctrl_area_cached {
u64 nested_cr3;
u64 virt_ext;
u32 clean;
+ u16 bus_lock_counter;
union {
#if IS_ENABLED(CONFIG_HYPERV) || IS_ENABLED(CONFIG_KVM_HYPERV)
struct hv_vmcb_enlightenments hv_enlightenments;
Expose the Bus Lock Threshold in the guest CPUID and support its functionality in nested guest. Ensure proper restoration and saving of the bus_lock_counter at VM Entry and VM Exit respectively in nested guest scenarios. Case 1: L0 supports buslock exit and L1 does not: use buslock counter from L0 and exits happen to L0 VMM. Case 2: Both L0 and L1 supports buslock exit: use L1 buslock counter value and exits happen to L1 VMM. Signed-off-by: Manali Shukla <manali.shukla@amd.com> --- arch/x86/kvm/governed_features.h | 1 + arch/x86/kvm/svm/nested.c | 25 +++++++++++++++++++++++++ arch/x86/kvm/svm/svm.c | 5 +++++ arch/x86/kvm/svm/svm.h | 1 + 4 files changed, 32 insertions(+)