diff mbox

[10/24] Implement VMPTRLD

Message ID 201006131227.o5DCRfIJ012978@rice.haifa.ibm.com (mailing list archive)
State New, archived
Headers show

Commit Message

Nadav Har'El June 13, 2010, 12:27 p.m. UTC
None
diff mbox

Patch

--- .before/arch/x86/kvm/vmx.c	2010-06-13 15:01:29.000000000 +0300
+++ .after/arch/x86/kvm/vmx.c	2010-06-13 15:01:29.000000000 +0300
@@ -3829,6 +3829,26 @@  static int read_guest_vmcs_gpa(struct kv
 	return 0;
 }
 
+static void set_rflags_to_vmx_fail_invalid(struct kvm_vcpu *vcpu)
+{
+	unsigned long rflags;
+	rflags = vmx_get_rflags(vcpu);
+	rflags |= X86_EFLAGS_CF;
+	rflags &= ~X86_EFLAGS_PF & ~X86_EFLAGS_AF & ~X86_EFLAGS_ZF &
+		~X86_EFLAGS_SF & ~X86_EFLAGS_OF;
+	vmx_set_rflags(vcpu, rflags);
+}
+
+static void set_rflags_to_vmx_fail_valid(struct kvm_vcpu *vcpu)
+{
+	unsigned long rflags;
+	rflags = vmx_get_rflags(vcpu);
+	rflags |= X86_EFLAGS_ZF;
+	rflags &= ~X86_EFLAGS_PF & ~X86_EFLAGS_AF & ~X86_EFLAGS_CF &
+		~X86_EFLAGS_SF & ~X86_EFLAGS_OF;
+	vmx_set_rflags(vcpu, rflags);
+}
+
 static void clear_rflags_cf_zf(struct kvm_vcpu *vcpu)
 {
 	unsigned long rflags;
@@ -3869,6 +3889,57 @@  static int handle_vmclear(struct kvm_vcp
 	return 1;
 }
 
+static bool verify_vmcs12_revision(struct kvm_vcpu *vcpu, gpa_t guest_vmcs_addr)
+{
+	bool ret;
+	struct vmcs12 *vmcs12;
+	struct page *vmcs_page = nested_get_page(vcpu, guest_vmcs_addr);
+	if (vmcs_page == NULL)
+		return 0;
+	vmcs12 = (struct vmcs12 *)kmap_atomic(vmcs_page, KM_USER0);
+	if (vmcs12->revision_id == VMCS12_REVISION)
+		ret = 1;
+	else {
+		set_rflags_to_vmx_fail_valid(vcpu);
+		ret = 0;
+	}
+	kunmap_atomic(vmcs12, KM_USER0);
+	kvm_release_page_dirty(vmcs_page);
+	return ret;
+}
+
+/* Emulate the VMPTRLD instruction */
+static int handle_vmptrld(struct kvm_vcpu *vcpu)
+{
+	struct vcpu_vmx *vmx = to_vmx(vcpu);
+	gpa_t guest_vmcs_addr;
+
+	if (!nested_vmx_check_permission(vcpu))
+		return 1;
+
+	if (read_guest_vmcs_gpa(vcpu, &guest_vmcs_addr)) {
+		set_rflags_to_vmx_fail_invalid(vcpu);
+		return 1;
+	}
+
+	if (!verify_vmcs12_revision(vcpu, guest_vmcs_addr))
+		return 1;
+
+	if (vmx->nested.current_vmptr != guest_vmcs_addr) {
+		vmx->nested.current_vmptr = guest_vmcs_addr;
+
+		if (nested_create_current_vmcs(vcpu)) {
+			printk(KERN_ERR "%s error could not allocate memory",
+				__func__);
+			return -ENOMEM;
+		}
+	}
+
+	clear_rflags_cf_zf(vcpu);
+	skip_emulated_instruction(vcpu);
+	return 1;
+}
+
 static int handle_invlpg(struct kvm_vcpu *vcpu)
 {
 	unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
@@ -4153,7 +4224,7 @@  static int (*kvm_vmx_exit_handlers[])(st
 	[EXIT_REASON_VMCALL]                  = handle_vmcall,
 	[EXIT_REASON_VMCLEAR]	              = handle_vmclear,
 	[EXIT_REASON_VMLAUNCH]                = handle_vmx_insn,
-	[EXIT_REASON_VMPTRLD]                 = handle_vmx_insn,
+	[EXIT_REASON_VMPTRLD]                 = handle_vmptrld,
 	[EXIT_REASON_VMPTRST]                 = handle_vmx_insn,
 	[EXIT_REASON_VMREAD]                  = handle_vmx_insn,
 	[EXIT_REASON_VMRESUME]                = handle_vmx_insn,