[PATCH 13/24] Implement VMREAD and VMWRITE

Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
From: Nadav Har'El
Date: Sunday, June 13, 2010 - 5:29 am

Implement the VMREAD and VMWRITE instructions. With these instructions, L1
can read and write to the VMCS it is holding. The values are read or written
to the fields of the shadow_vmcs structure introduced in the previous patch.

Signed-off-by: Nadav Har'El <nyh@il.ibm.com>
---
--- .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
@@ -299,6 +299,42 @@ struct nested_vmx {
 	int l2_vmcs_num;
 };
 
+enum vmcs_field_type {
+	VMCS_FIELD_TYPE_U16 = 0,
+	VMCS_FIELD_TYPE_U64 = 1,
+	VMCS_FIELD_TYPE_U32 = 2,
+	VMCS_FIELD_TYPE_ULONG = 3
+};
+
+#define VMCS_FIELD_LENGTH_OFFSET 13
+#define VMCS_FIELD_LENGTH_MASK 0x6000
+
+static inline int vmcs_field_type(unsigned long field)
+{
+	if (0x1 & field)	/* one of the *_HIGH fields, all are 32 bit */
+		return VMCS_FIELD_TYPE_U32;
+	return (VMCS_FIELD_LENGTH_MASK & field) >> 13;
+}
+
+static inline int vmcs_field_size(int field_type, struct kvm_vcpu *vcpu)
+{
+	switch (field_type) {
+	case VMCS_FIELD_TYPE_U16:
+		return 2;
+	case VMCS_FIELD_TYPE_U32:
+		return 4;
+	case VMCS_FIELD_TYPE_U64:
+		return 8;
+	case VMCS_FIELD_TYPE_ULONG:
+#ifdef CONFIG_X86_64
+		if (is_long_mode(vcpu))
+			return 8;
+#endif
+		return 4;
+	}
+	return 0; /* should never happen */
+}
+
 struct vcpu_vmx {
 	struct kvm_vcpu       vcpu;
 	struct list_head      local_vcpus_link;
@@ -4184,6 +4220,189 @@ static int handle_vmclear(struct kvm_vcp
 	return 1;
 }
 
+static inline bool nested_vmcs_read_any(struct kvm_vcpu *vcpu,
+					unsigned long field, u64 *ret)
+{
+	short offset = vmcs_field_to_offset(field);
+	char *p;
+
+	if (offset < 0)
+		return 0;
+	if (!to_vmx(vcpu)->nested.current_l2_page)
+		return 0;
+
+	p = ((char *)(get_shadow_vmcs(vcpu))) + offset;
+
+	switch (vmcs_field_type(field)) {
+	case VMCS_FIELD_TYPE_ULONG:
+		*ret = *((unsigned long *)p);
+		return 1;
+	case VMCS_FIELD_TYPE_U16:
+		*ret = (u16) *((unsigned long *)p);
+		return 1;
+	case VMCS_FIELD_TYPE_U32:
+		*ret = (u32) *((unsigned long *)p);
+		return 1;
+	case VMCS_FIELD_TYPE_U64:
+		*ret = *((u64 *)p);
+		return 1;
+	default:
+		return 0; /* can never happen. */
+	}
+}
+
+static int handle_vmread_reg(struct kvm_vcpu *vcpu, int reg,
+			     unsigned long field)
+{
+	u64 field_value;
+	if (!nested_vmcs_read_any(vcpu, field, &field_value))
+		return 0;
+
+#ifdef CONFIG_X86_64
+	switch (vmcs_field_type(field)) {
+	case VMCS_FIELD_TYPE_U64: case VMCS_FIELD_TYPE_ULONG:
+		if (!is_long_mode(vcpu)) {
+			kvm_register_write(vcpu, reg+1, field_value >> 32);
+			field_value = (u32)field_value;
+		}
+	}
+#endif
+	kvm_register_write(vcpu, reg, field_value);
+	return 1;
+}
+
+static int handle_vmread_mem(struct kvm_vcpu *vcpu, gva_t gva,
+			     unsigned long field)
+{
+	u64 field_value;
+	if (!nested_vmcs_read_any(vcpu, field, &field_value))
+		return 0;
+
+	/* It's ok to use *_system, because handle_vmread verifies cpl=0 */
+	kvm_write_guest_virt_system(gva, &field_value,
+			     vmcs_field_size(vmcs_field_type(field), vcpu),
+			     vcpu, NULL);
+	return 1;
+}
+
+static int handle_vmread(struct kvm_vcpu *vcpu)
+{
+	unsigned long field;
+	unsigned long exit_qualification = vmcs_readl(EXIT_QUALIFICATION);
+	u32 vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO);
+	gva_t gva = 0;
+	int read_succeed;
+
+	if (!nested_vmx_check_permission(vcpu))
+		return 1;
+
+	if (!nested_map_current(vcpu)) {
+		printk(KERN_INFO "%s invalid shadow vmcs\n", __func__);
+		set_rflags_to_vmx_fail_invalid(vcpu);
+		return 1;
+	}
+
+	/* decode instruction info to get the field to read and where to store
+	 * its value */
+	field = kvm_register_read(vcpu, VMX_OPERAND_REG2(vmx_instruction_info));
+	if (VMX_OPERAND_IS_REG(vmx_instruction_info)) {
+		read_succeed = handle_vmread_reg(vcpu,
+			VMX_OPERAND_REG(vmx_instruction_info), field);
+	} else {
+		gva = get_vmx_mem_address(vcpu, exit_qualification,
+					  vmx_instruction_info);
+		if (gva == 0)
+			return 1;
+		read_succeed = handle_vmread_mem(vcpu, gva, field);
+	}
+
+	if (read_succeed) {
+		clear_rflags_cf_zf(vcpu);
+		skip_emulated_instruction(vcpu);
+	} else {
+		set_rflags_to_vmx_fail_valid(vcpu);
+		vmcs_write32(VM_INSTRUCTION_ERROR, 12);
+	}
+
+	nested_unmap_current(vcpu);
+	return 1;
+}
+
+
+static int handle_vmwrite(struct kvm_vcpu *vcpu)
+{
+	unsigned long field;
+	u64 field_value = 0;
+	gva_t gva;
+	int field_type;
+	unsigned long exit_qualification   = vmcs_readl(EXIT_QUALIFICATION);
+	u32 vmx_instruction_info = vmcs_read32(VMX_INSTRUCTION_INFO);
+	char *p;
+	short offset;
+
+	if (!nested_vmx_check_permission(vcpu))
+		return 1;
+
+	if (!nested_map_current(vcpu)) {
+		printk(KERN_INFO "%s invalid shadow vmcs\n", __func__);
+		set_rflags_to_vmx_fail_invalid(vcpu);
+		return 1;
+	}
+
+	field = kvm_register_read(vcpu, VMX_OPERAND_REG2(vmx_instruction_info));
+	field_type = vmcs_field_type(field);
+
+	offset = vmcs_field_to_offset(field);
+	if (offset < 0) {
+		set_rflags_to_vmx_fail_invalid(vcpu);
+		return 1;
+	}
+	p = ((char *) get_shadow_vmcs(vcpu)) + offset;
+
+	if (VMX_OPERAND_IS_REG(vmx_instruction_info))
+		field_value = kvm_register_read(vcpu,
+			VMX_OPERAND_REG(vmx_instruction_info));
+	else {
+		gva  = get_vmx_mem_address(vcpu, exit_qualification,
+			vmx_instruction_info);
+		if (gva == 0)
+			return 1;
+		kvm_read_guest_virt(gva, &field_value,
+			vmcs_field_size(field_type, vcpu), vcpu, NULL);
+	}
+
+	switch (field_type) {
+	case VMCS_FIELD_TYPE_U16:
+		*(u16 *)p = field_value;
+		break;
+	case VMCS_FIELD_TYPE_U32:
+		*(u32 *)p = field_value;
+		break;
+	case VMCS_FIELD_TYPE_U64:
+#ifdef CONFIG_X86_64
+		*(unsigned long *)p = field_value;
+#else
+		*(unsigned long *)p = field_value;
+		*(((unsigned long *)p)+1) = field_value >> 32;
+#endif
+		break;
+	case VMCS_FIELD_TYPE_ULONG:
+		*(unsigned long *)p = field_value;
+		break;
+	default:
+		printk(KERN_INFO "%s invalid field\n", __func__);
+		set_rflags_to_vmx_fail_valid(vcpu);
+		vmcs_write32(VM_INSTRUCTION_ERROR, 12);
+		nested_unmap_current(vcpu);
+		return 1;
+	}
+
+	clear_rflags_cf_zf(vcpu);
+	skip_emulated_instruction(vcpu);
+	nested_unmap_current(vcpu);
+	return 1;
+}
+
 static bool verify_vmcs12_revision(struct kvm_vcpu *vcpu, gpa_t guest_vmcs_addr)
 {
 	bool ret;
@@ -4548,9 +4767,9 @@ static int (*kvm_vmx_exit_handlers[])(st
 	[EXIT_REASON_VMLAUNCH]                = handle_vmx_insn,
 	[EXIT_REASON_VMPTRLD]                 = handle_vmptrld,
 	[EXIT_REASON_VMPTRST]                 = handle_vmptrst,
-	[EXIT_REASON_VMREAD]                  = handle_vmx_insn,
+	[EXIT_REASON_VMREAD]                  = handle_vmread,
 	[EXIT_REASON_VMRESUME]                = handle_vmx_insn,
-	[EXIT_REASON_VMWRITE]                 = handle_vmx_insn,
+	[EXIT_REASON_VMWRITE]                 = handle_vmwrite,
 	[EXIT_REASON_VMOFF]                   = handle_vmoff,
 	[EXIT_REASON_VMON]                    = handle_vmon,
 	[EXIT_REASON_TPR_BELOW_THRESHOLD]     = handle_tpr_below_threshold,
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
[PATCH 0/24] Nested VMX, v5, Nadav Har'El, (Sun Jun 13, 5:22 am)
[PATCH 1/24] Move nested option from svm.c to x86.c, Nadav Har'El, (Sun Jun 13, 5:23 am)
[PATCH 3/24] Implement VMXON and VMXOFF, Nadav Har'El, (Sun Jun 13, 5:24 am)
[PATCH 4/24] Allow setting the VMXE bit in CR4, Nadav Har'El, (Sun Jun 13, 5:24 am)
[PATCH 5/24] Introduce vmcs12: a VMCS structure for L1, Nadav Har'El, (Sun Jun 13, 5:25 am)
[PATCH 6/24] Implement reading and writing of VMX MSRs, Nadav Har'El, (Sun Jun 13, 5:25 am)
[PATCH 8/24] Hold a vmcs02 for each vmcs12, Nadav Har'El, (Sun Jun 13, 5:26 am)
[PATCH 9/24] Implement VMCLEAR, Nadav Har'El, (Sun Jun 13, 5:27 am)
[PATCH 10/24] Implement VMPTRLD, Nadav Har'El, (Sun Jun 13, 5:27 am)
[PATCH 11/24] Implement VMPTRST, Nadav Har'El, (Sun Jun 13, 5:28 am)
[PATCH 12/24] Add VMCS fields to the vmcs12, Nadav Har'El, (Sun Jun 13, 5:28 am)
[PATCH 13/24] Implement VMREAD and VMWRITE, Nadav Har'El, (Sun Jun 13, 5:29 am)
[PATCH 14/24] Prepare vmcs02 from vmcs01 and vmcs12, Nadav Har'El, (Sun Jun 13, 5:29 am)
[PATCH 15/24] Move register-syncing to a function, Nadav Har'El, (Sun Jun 13, 5:30 am)
[PATCH 16/24] Implement VMLAUNCH and VMRESUME, Nadav Har'El, (Sun Jun 13, 5:30 am)
[PATCH 18/24] Exiting from L2 to L1, Nadav Har'El, (Sun Jun 13, 5:31 am)
[PATCH 20/24] Correct handling of interrupt injection, Nadav Har'El, (Sun Jun 13, 5:32 am)
[PATCH 21/24] Correct handling of exception injection, Nadav Har'El, (Sun Jun 13, 5:33 am)
[PATCH 22/24] Correct handling of idt vectoring info, Nadav Har'El, (Sun Jun 13, 5:33 am)
[PATCH 24/24] Miscellenous small corrections, Nadav Har'El, (Sun Jun 13, 5:34 am)
Re: [PATCH 3/24] Implement VMXON and VMXOFF, Avi Kivity, (Mon Jun 14, 1:21 am)
Re: [PATCH 8/24] Hold a vmcs02 for each vmcs12, Avi Kivity, (Mon Jun 14, 1:57 am)
Re: [PATCH 9/24] Implement VMCLEAR, Avi Kivity, (Mon Jun 14, 2:03 am)
Re: [PATCH 10/24] Implement VMPTRLD, Avi Kivity, (Mon Jun 14, 2:07 am)
Re: [PATCH 11/24] Implement VMPTRST, Avi Kivity, (Mon Jun 14, 2:15 am)
Re: [PATCH 12/24] Add VMCS fields to the vmcs12, Avi Kivity, (Mon Jun 14, 2:24 am)
Re: [PATCH 13/24] Implement VMREAD and VMWRITE, Avi Kivity, (Mon Jun 14, 2:36 am)
Re: [PATCH 16/24] Implement VMLAUNCH and VMRESUME, Avi Kivity, (Mon Jun 14, 4:41 am)
Re: [PATCH 18/24] Exiting from L2 to L1, Avi Kivity, (Mon Jun 14, 5:04 am)
Re: [PATCH 0/24] Nested VMX, v5, Avi Kivity, (Mon Jun 14, 5:34 am)
Re: [PATCH 0/24] Nested VMX, v5, Nadav Har'El, (Mon Jun 14, 6:03 am)
Re: [PATCH 0/24] Nested VMX, v5, Avi Kivity, (Tue Jun 15, 3:00 am)
Re: [PATCH 4/24] Allow setting the VMXE bit in CR4, Gleb Natapov, (Tue Jun 15, 4:09 am)
Re: [PATCH 9/24] Implement VMCLEAR, Gleb Natapov, (Tue Jun 15, 6:47 am)
Re: [PATCH 9/24] Implement VMCLEAR, Avi Kivity, (Tue Jun 15, 6:50 am)
Re: [PATCH 9/24] Implement VMCLEAR, Gleb Natapov, (Tue Jun 15, 6:54 am)
Re: [PATCH 1/24] Move nested option from svm.c to x86.c, Nadav Har'El, (Tue Jun 15, 7:27 am)
Re: [PATCH 4/24] Allow setting the VMXE bit in CR4, Nadav Har'El, (Tue Jun 15, 7:44 am)
Re: [PATCH 3/24] Implement VMXON and VMXOFF, Marcelo Tosatti, (Tue Jun 15, 1:18 pm)
Re: [PATCH 3/24] Implement VMXON and VMXOFF, Nadav Har'El, (Wed Jun 16, 12:50 am)
Re: [PATCH 3/24] Implement VMXON and VMXOFF, Nadav Har'El, (Wed Jun 16, 4:14 am)
Re: [PATCH 3/24] Implement VMXON and VMXOFF, Avi Kivity, (Wed Jun 16, 4:26 am)
Re: [PATCH 10/24] Implement VMPTRLD, Gleb Natapov, (Wed Jun 16, 6:36 am)
Re: [PATCH 11/24] Implement VMPTRST, Gleb Natapov, (Wed Jun 16, 6:53 am)
Re: [PATCH 12/24] Add VMCS fields to the vmcs12, Gleb Natapov, (Wed Jun 16, 7:18 am)
Re: [PATCH 13/24] Implement VMREAD and VMWRITE, Gleb Natapov, (Wed Jun 16, 7:48 am)
Re: [PATCH 13/24] Implement VMREAD and VMWRITE, Gleb Natapov, (Wed Jun 16, 8:03 am)
Re: [PATCH 11/24] Implement VMPTRST, Nadav Har'El, (Wed Jun 16, 8:33 am)
Re: [PATCH 14/24] Prepare vmcs02 from vmcs01 and vmcs12, Gleb Natapov, (Thu Jun 17, 1:50 am)
Re: [PATCH 16/24] Implement VMLAUNCH and VMRESUME, Gleb Natapov, (Thu Jun 17, 3:59 am)
Re: [PATCH 5/24] Introduce vmcs12: a VMCS structure for L1, Alexander Graf, (Wed Jun 23, 2:15 am)
RE: [PATCH 9/24] Implement VMCLEAR, Dong, Eddie, (Mon Jul 5, 7:56 pm)
RE: [PATCH 10/24] Implement VMPTRLD, Dong, Eddie, (Mon Jul 5, 8:09 pm)
RE: [PATCH 8/24] Hold a vmcs02 for each vmcs12, Dong, Eddie, (Tue Jul 6, 2:50 am)
RE: [PATCH 0/24] Nested VMX, v5, Dong, Eddie, (Fri Jul 9, 1:59 am)
Re: [PATCH 0/24] Nested VMX, v5, Nadav Har'El, (Sun Jul 11, 1:27 am)
Re: [PATCH 0/24] Nested VMX, v5, Alexander Graf, (Sun Jul 11, 4:05 am)
Re: [PATCH 0/24] Nested VMX, v5, Nadav Har'El, (Sun Jul 11, 5:49 am)
Re: [PATCH 0/24] Nested VMX, v5, Avi Kivity, (Sun Jul 11, 6:12 am)
Re: [PATCH 0/24] Nested VMX, v5, Avi Kivity, (Sun Jul 11, 6:20 am)
Re: [PATCH 0/24] Nested VMX, v5, Nadav Har'El, (Sun Jul 11, 8:39 am)
Re: [PATCH 0/24] Nested VMX, v5, Avi Kivity, (Sun Jul 11, 8:45 am)
Re: [PATCH 0/24] Nested VMX, v5, Sheng Yang, (Wed Jul 14, 8:27 pm)
Re: [PATCH 8/24] Hold a vmcs02 for each vmcs12, Nadav Har'El, (Mon Aug 2, 6:38 am)
Re: [PATCH 9/24] Implement VMCLEAR, Nadav Har'El, (Tue Aug 3, 5:12 am)
Re: [PATCH 13/24] Implement VMREAD and VMWRITE, Nadav Har'El, (Wed Aug 4, 4:46 am)
Re: [PATCH 13/24] Implement VMREAD and VMWRITE, Nadav Har'El, (Wed Aug 4, 6:42 am)
Re: [PATCH 13/24] Implement VMREAD and VMWRITE, Nadav Har'El, (Wed Aug 4, 9:09 am)
Re: [PATCH 13/24] Implement VMREAD and VMWRITE, Avi Kivity, (Wed Aug 4, 9:41 am)
Re: [PATCH 10/24] Implement VMPTRLD, Nadav Har'El, (Thu Aug 5, 4:13 am)
Re: [PATCH 10/24] Implement VMPTRLD, Nadav Har'El, (Thu Aug 5, 4:35 am)
Re: [PATCH 9/24] Implement VMCLEAR, Nadav Har'El, (Thu Aug 5, 4:50 am)
Re: [PATCH 9/24] Implement VMCLEAR, Gleb Natapov, (Thu Aug 5, 4:53 am)
Re: [PATCH 9/24] Implement VMCLEAR, Nadav Har'El, (Thu Aug 5, 5:01 am)
Re: [PATCH 9/24] Implement VMCLEAR, Avi Kivity, (Thu Aug 5, 5:03 am)
Re: [PATCH 9/24] Implement VMCLEAR, Avi Kivity, (Thu Aug 5, 5:05 am)
Re: [PATCH 9/24] Implement VMCLEAR, Nadav Har'El, (Thu Aug 5, 5:10 am)
Re: [PATCH 9/24] Implement VMCLEAR, Avi Kivity, (Thu Aug 5, 5:13 am)
Re: [PATCH 9/24] Implement VMCLEAR, Nadav Har'El, (Thu Aug 5, 5:29 am)
Re: [PATCH 18/24] Exiting from L2 to L1, Nadav Har'El, (Sun Sep 12, 7:05 am)
Re: [PATCH 18/24] Exiting from L2 to L1, Avi Kivity, (Sun Sep 12, 7:29 am)
Re: [PATCH 18/24] Exiting from L2 to L1, Nadav Har'El, (Sun Sep 12, 10:05 am)
Re: [PATCH 18/24] Exiting from L2 to L1, Avi Kivity, (Sun Sep 12, 10:21 am)
Re: [PATCH 18/24] Exiting from L2 to L1, Nadav Har'El, (Sun Sep 12, 12:51 pm)
Re: [PATCH 18/24] Exiting from L2 to L1, Sheng Yang, (Sun Sep 12, 10:53 pm)
Re: [PATCH 18/24] Exiting from L2 to L1, Avi Kivity, (Mon Sep 13, 1:48 am)
Re: [PATCH 18/24] Exiting from L2 to L1, Avi Kivity, (Mon Sep 13, 1:52 am)
Re: [PATCH 18/24] Exiting from L2 to L1, Nadav Har'El, (Mon Sep 13, 2:01 am)
Re: [PATCH 18/24] Exiting from L2 to L1, Avi Kivity, (Mon Sep 13, 2:34 am)
Re: [PATCH 18/24] Exiting from L2 to L1, Nadav Har'El, (Tue Sep 14, 6:07 am)
Re: [PATCH 16/24] Implement VMLAUNCH and VMRESUME, Nadav Har'El, (Thu Sep 16, 9:06 am)
Re: [PATCH 22/24] Correct handling of idt vectoring info, Nadav Har'El, (Sun Sep 19, 11:37 pm)
Re: [PATCH 16/24] Implement VMLAUNCH and VMRESUME, Nadav Har'El, (Sun Sep 26, 4:14 am)
Re: [PATCH 16/24] Implement VMLAUNCH and VMRESUME, Avi Kivity, (Sun Sep 26, 5:56 am)
Re: [PATCH 16/24] Implement VMLAUNCH and VMRESUME, Nadav Har'El, (Sun Sep 26, 6:06 am)
Re: [PATCH 16/24] Implement VMLAUNCH and VMRESUME, Avi Kivity, (Sun Sep 26, 6:51 am)
Re: [PATCH 0/24] Nested VMX, v5, Nadav Har'El, (Sun Oct 17, 5:03 am)
Re: [PATCH 0/24] Nested VMX, v5, Avi Kivity, (Sun Oct 17, 5:10 am)
Re: [PATCH 0/24] Nested VMX, v5, Nadav Har'El, (Sun Oct 17, 5:39 am)
Re: [PATCH 0/24] Nested VMX, v5, Avi Kivity, (Sun Oct 17, 6:35 am)