KVM: nSVM: Implement Enlightened MSR-Bitmap feature
Similar to nVMX commit 502d2bf5f2
("KVM: nVMX: Implement Enlightened MSR
Bitmap feature"), add support for the feature for nSVM (Hyper-V on KVM).
Notable differences from nVMX implementation:
- As the feature uses SW reserved fields in VMCB control, KVM needs to
make sure it's dealing with a Hyper-V guest (kvm_hv_hypercall_enabled()).
- 'msrpm_base_pa' needs to be always be overwritten in
nested_svm_vmrun_msrpm(), even when the update is skipped. As an
optimization, nested_vmcb02_prepare_control() copies it from VMCB01
so when MSR-Bitmap feature for L2 is disabled nothing needs to be done.
- 'struct vmcb_ctrl_area_cached' needs to be extended with clean
fields/sw reserved data and __nested_copy_vmcb_control_to_cache() needs to
copy it so nested_svm_vmrun_msrpm() can use it later.
Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Message-Id: <20220202095100.129834-5-vkuznets@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
9e083ec7bb
commit
66c03a926f
@ -2453,10 +2453,6 @@ int kvm_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid,
|
||||
if (kvm_x86_ops.nested_ops->get_evmcs_version)
|
||||
evmcs_ver = kvm_x86_ops.nested_ops->get_evmcs_version(vcpu);
|
||||
|
||||
/* Skip NESTED_FEATURES if eVMCS is not supported */
|
||||
if (!evmcs_ver)
|
||||
--nent;
|
||||
|
||||
if (cpuid->nent < nent)
|
||||
return -E2BIG;
|
||||
|
||||
@ -2556,8 +2552,7 @@ int kvm_get_hv_cpuid(struct kvm_vcpu *vcpu, struct kvm_cpuid2 *cpuid,
|
||||
|
||||
case HYPERV_CPUID_NESTED_FEATURES:
|
||||
ent->eax = evmcs_ver;
|
||||
if (evmcs_ver)
|
||||
ent->eax |= HV_X64_NESTED_MSR_BITMAP;
|
||||
ent->eax |= HV_X64_NESTED_MSR_BITMAP;
|
||||
|
||||
break;
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "cpuid.h"
|
||||
#include "lapic.h"
|
||||
#include "svm.h"
|
||||
#include "hyperv.h"
|
||||
|
||||
#define CC KVM_NESTED_VMENTER_CONSISTENCY_CHECK
|
||||
|
||||
@ -165,15 +166,31 @@ void recalc_intercepts(struct vcpu_svm *svm)
|
||||
vmcb_set_intercept(c, INTERCEPT_VMSAVE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Merge L0's (KVM) and L1's (Nested VMCB) MSR permission bitmaps. The function
|
||||
* is optimized in that it only merges the parts where KVM MSR permission bitmap
|
||||
* may contain zero bits.
|
||||
*/
|
||||
static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm)
|
||||
{
|
||||
/*
|
||||
* This function merges the msr permission bitmaps of kvm and the
|
||||
* nested vmcb. It is optimized in that it only merges the parts where
|
||||
* the kvm msr permission bitmap may contain zero bits
|
||||
*/
|
||||
struct hv_enlightenments *hve =
|
||||
(struct hv_enlightenments *)svm->nested.ctl.reserved_sw;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* MSR bitmap update can be skipped when:
|
||||
* - MSR bitmap for L1 hasn't changed.
|
||||
* - Nested hypervisor (L1) is attempting to launch the same L2 as
|
||||
* before.
|
||||
* - Nested hypervisor (L1) is using Hyper-V emulation interface and
|
||||
* tells KVM (L0) there were no changes in MSR bitmap for L2.
|
||||
*/
|
||||
if (!svm->nested.force_msr_bitmap_recalc &&
|
||||
kvm_hv_hypercall_enabled(&svm->vcpu) &&
|
||||
hve->hv_enlightenments_control.msr_bitmap &&
|
||||
(svm->nested.ctl.clean & BIT(VMCB_HV_NESTED_ENLIGHTENMENTS)))
|
||||
goto set_msrpm_base_pa;
|
||||
|
||||
if (!(vmcb12_is_intercept(&svm->nested.ctl, INTERCEPT_MSR_PROT)))
|
||||
return true;
|
||||
|
||||
@ -195,6 +212,7 @@ static bool nested_svm_vmrun_msrpm(struct vcpu_svm *svm)
|
||||
|
||||
svm->nested.force_msr_bitmap_recalc = false;
|
||||
|
||||
set_msrpm_base_pa:
|
||||
svm->vmcb->control.msrpm_base_pa = __sme_set(__pa(svm->nested.msrpm));
|
||||
|
||||
return true;
|
||||
@ -300,7 +318,8 @@ static bool nested_vmcb_check_controls(struct kvm_vcpu *vcpu)
|
||||
}
|
||||
|
||||
static
|
||||
void __nested_copy_vmcb_control_to_cache(struct vmcb_ctrl_area_cached *to,
|
||||
void __nested_copy_vmcb_control_to_cache(struct kvm_vcpu *vcpu,
|
||||
struct vmcb_ctrl_area_cached *to,
|
||||
struct vmcb_control_area *from)
|
||||
{
|
||||
unsigned int i;
|
||||
@ -333,12 +352,19 @@ void __nested_copy_vmcb_control_to_cache(struct vmcb_ctrl_area_cached *to,
|
||||
to->asid = from->asid;
|
||||
to->msrpm_base_pa &= ~0x0fffULL;
|
||||
to->iopm_base_pa &= ~0x0fffULL;
|
||||
|
||||
/* Hyper-V extensions (Enlightened VMCB) */
|
||||
if (kvm_hv_hypercall_enabled(vcpu)) {
|
||||
to->clean = from->clean;
|
||||
memcpy(to->reserved_sw, from->reserved_sw,
|
||||
sizeof(struct hv_enlightenments));
|
||||
}
|
||||
}
|
||||
|
||||
void nested_copy_vmcb_control_to_cache(struct vcpu_svm *svm,
|
||||
struct vmcb_control_area *control)
|
||||
{
|
||||
__nested_copy_vmcb_control_to_cache(&svm->nested.ctl, control);
|
||||
__nested_copy_vmcb_control_to_cache(&svm->vcpu, &svm->nested.ctl, control);
|
||||
}
|
||||
|
||||
static void __nested_copy_vmcb_save_to_cache(struct vmcb_save_area_cached *to,
|
||||
@ -1305,6 +1331,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;
|
||||
/* 'clean' and 'reserved_sw' are not changed by KVM */
|
||||
}
|
||||
|
||||
static int svm_get_nested_state(struct kvm_vcpu *vcpu,
|
||||
@ -1437,7 +1464,7 @@ static int svm_set_nested_state(struct kvm_vcpu *vcpu,
|
||||
goto out_free;
|
||||
|
||||
ret = -EINVAL;
|
||||
__nested_copy_vmcb_control_to_cache(&ctl_cached, ctl);
|
||||
__nested_copy_vmcb_control_to_cache(vcpu, &ctl_cached, ctl);
|
||||
if (!__nested_vmcb_check_controls(vcpu, &ctl_cached))
|
||||
goto out_free;
|
||||
|
||||
|
@ -137,6 +137,8 @@ struct vmcb_ctrl_area_cached {
|
||||
u32 event_inj_err;
|
||||
u64 nested_cr3;
|
||||
u64 virt_ext;
|
||||
u32 clean;
|
||||
u8 reserved_sw[32];
|
||||
};
|
||||
|
||||
struct svm_nested_state {
|
||||
|
Loading…
Reference in New Issue
Block a user