[PATCH 20/22] KVM: nVMX: Add util to create vmcs02 vmread/vmwrite bitmaps

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



These bitmaps are based on vmcs12 vmread/vmwrite bitmaps and which
VMCS fields are supported by vmcs12 & physical CPU.

This is done as a preparation for VMCS shadowing virtualization.

Signed-off-by: Liran Alon <liran.alon@xxxxxxxxxx>
Signed-off-by: Jim Mattson <jmattson@xxxxxxxxxx>
---
 arch/x86/kvm/vmx.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 97 insertions(+)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index e3f3bb5102f0..94922adf6f47 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -11162,6 +11162,103 @@ static inline bool nested_vmx_prepare_msr_bitmap(struct kvm_vcpu *vcpu,
 	return true;
 }
 
+/*
+ * For all valid VMCS fields in a group (having the same width and
+ * type), clear the permission bit in the vmcs02 bitmap if it is clear
+ * in the vmcs12 bitmap and the field is supported by kvm and the
+ * physical CPU. All other permission bits are set.
+ */
+static void nested_vmx_setup_shadow_bitmap_group(struct kvm_vcpu *vcpu,
+						 unsigned long *vmcs02_bitmap,
+						 unsigned long *vmcs12_bitmap,
+						 unsigned long base)
+{
+	unsigned long offset = base / BITS_PER_LONG;
+	unsigned long val = ~0l;
+	unsigned long bit;
+	struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+	for_each_clear_bit(bit, vmcs12_bitmap + offset,
+			   nested_vmcs_fields_per_group(vmx)) {
+		unsigned long field = base + bit;
+
+		if (vmcs_field_to_offset(field) >= 0 &&
+		    cpu_has_vmcs_field(field))
+			val &= ~(1ul << bit);
+	}
+
+	vmcs02_bitmap[offset] = val;
+}
+
+/*
+ * Set up a vmcs02 vmread/vmwrite bitmap based on a vmcs12
+ * vmread/vmwrite bitmap. Only fields supported by kvm and the
+ * physical CPU may be shadowed (i.e. have a clear permission bit).
+ */
+static bool nested_vmx_setup_shadow_bitmap(struct kvm_vcpu *vcpu,
+					   unsigned long *vmcs02_bitmap,
+					   gpa_t vmcs12_bitmap_gpa,
+					   bool is_write_bitmap)
+{
+	struct page *page;
+	unsigned long *vmcs12_bitmap;
+	enum vmcs_field_width width;
+	enum vmcs_field_type type;
+	bool intercept_read_only_fields;
+
+	page = kvm_vcpu_gpa_to_page(vcpu, vmcs12_bitmap_gpa);
+	if (is_error_page(page))
+		return false;
+
+	/*
+	 * If L1 cannot VMWRITE into read-only VMCS fields,
+	 * then L0 needs to intercept VMWRITEs to these fields
+	 * in order to simulate VMWRITE failure for L2.
+	 */
+	intercept_read_only_fields =
+		is_write_bitmap &&
+		!nested_cpu_has_vmwrite_any_field(vcpu);
+
+	vmcs12_bitmap = (unsigned long *)kmap(page);
+	for (width = 0; width < VMCS_FIELD_WIDTHS; width++) {
+		for (type = 0; type < VMCS_FIELD_TYPES; type++) {
+			unsigned long base = encode_vmcs_field(width, type, 0, false);
+			if (intercept_read_only_fields &&
+			    (type == VMCS_FIELD_TYPE_READ_ONLY_DATA))
+				vmcs02_bitmap[base / BITS_PER_LONG] = ~0l;
+			else
+				nested_vmx_setup_shadow_bitmap_group(vcpu,
+							     vmcs02_bitmap,
+							     vmcs12_bitmap,
+							     base);
+		}
+	}
+	kunmap(page);
+
+	kvm_release_page_clean(page);
+
+	return true;
+}
+
+/*
+ * Set up the vmcs02 vmread and vmwrite permission bitmaps based on
+ * the corresponding vmcs12 permission bitmaps.
+ */
+static inline bool nested_vmx_setup_shadow_bitmaps(struct kvm_vcpu *vcpu,
+						   struct vmcs12 *vmcs12)
+{
+	struct vcpu_vmx *vmx = to_vmx(vcpu);
+
+	return nested_vmx_setup_shadow_bitmap(vcpu,
+					      vmx->nested.vmread_bitmap,
+					      vmcs12->vmread_bitmap,
+					      false) &&
+		nested_vmx_setup_shadow_bitmap(vcpu,
+					       vmx->nested.vmwrite_bitmap,
+					       vmcs12->vmwrite_bitmap,
+					       true);
+}
+
 static void nested_cache_shadow_vmcs12(struct kvm_vcpu *vcpu,
 				       struct vmcs12 *vmcs12)
 {
-- 
1.9.1




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux