KVM: nVMX: Success/failure of VMX instructions.
Nadav Har'El [Wed, 25 May 2011 20:06:28 +0000 (23:06 +0300)]
VMX instructions specify success or failure by setting certain RFLAGS bits.
This patch contains common functions to do this, and they will be used in
the following patches which emulate the various VMX instructions.

Signed-off-by: Nadav Har'El <nyh@il.ibm.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>

arch/x86/include/asm/vmx.h
arch/x86/kvm/vmx.c

index 84471b8..37690bd 100644 (file)
@@ -426,4 +426,35 @@ struct vmx_msr_entry {
        u64 value;
 } __aligned(16);
 
+/*
+ * VM-instruction error numbers
+ */
+enum vm_instruction_error_number {
+       VMXERR_VMCALL_IN_VMX_ROOT_OPERATION = 1,
+       VMXERR_VMCLEAR_INVALID_ADDRESS = 2,
+       VMXERR_VMCLEAR_VMXON_POINTER = 3,
+       VMXERR_VMLAUNCH_NONCLEAR_VMCS = 4,
+       VMXERR_VMRESUME_NONLAUNCHED_VMCS = 5,
+       VMXERR_VMRESUME_AFTER_VMXOFF = 6,
+       VMXERR_ENTRY_INVALID_CONTROL_FIELD = 7,
+       VMXERR_ENTRY_INVALID_HOST_STATE_FIELD = 8,
+       VMXERR_VMPTRLD_INVALID_ADDRESS = 9,
+       VMXERR_VMPTRLD_VMXON_POINTER = 10,
+       VMXERR_VMPTRLD_INCORRECT_VMCS_REVISION_ID = 11,
+       VMXERR_UNSUPPORTED_VMCS_COMPONENT = 12,
+       VMXERR_VMWRITE_READ_ONLY_VMCS_COMPONENT = 13,
+       VMXERR_VMXON_IN_VMX_ROOT_OPERATION = 15,
+       VMXERR_ENTRY_INVALID_EXECUTIVE_VMCS_POINTER = 16,
+       VMXERR_ENTRY_NONLAUNCHED_EXECUTIVE_VMCS = 17,
+       VMXERR_ENTRY_EXECUTIVE_VMCS_POINTER_NOT_VMXON_POINTER = 18,
+       VMXERR_VMCALL_NONCLEAR_VMCS = 19,
+       VMXERR_VMCALL_INVALID_VM_EXIT_CONTROL_FIELDS = 20,
+       VMXERR_VMCALL_INCORRECT_MSEG_REVISION_ID = 22,
+       VMXERR_VMXOFF_UNDER_DUAL_MONITOR_TREATMENT_OF_SMIS_AND_SMM = 23,
+       VMXERR_VMCALL_INVALID_SMM_MONITOR_FEATURES = 24,
+       VMXERR_ENTRY_INVALID_VM_EXECUTION_CONTROL_FIELDS_IN_EXECUTIVE_VMCS = 25,
+       VMXERR_ENTRY_EVENTS_BLOCKED_BY_MOV_SS = 26,
+       VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID = 28,
+};
+
 #endif
index 33476eb..8432448 100644 (file)
@@ -4777,6 +4777,44 @@ static int get_vmx_mem_address(struct kvm_vcpu *vcpu,
 }
 
 /*
+ * The following 3 functions, nested_vmx_succeed()/failValid()/failInvalid(),
+ * set the success or error code of an emulated VMX instruction, as specified
+ * by Vol 2B, VMX Instruction Reference, "Conventions".
+ */
+static void nested_vmx_succeed(struct kvm_vcpu *vcpu)
+{
+       vmx_set_rflags(vcpu, vmx_get_rflags(vcpu)
+                       & ~(X86_EFLAGS_CF | X86_EFLAGS_PF | X86_EFLAGS_AF |
+                           X86_EFLAGS_ZF | X86_EFLAGS_SF | X86_EFLAGS_OF));
+}
+
+static void nested_vmx_failInvalid(struct kvm_vcpu *vcpu)
+{
+       vmx_set_rflags(vcpu, (vmx_get_rflags(vcpu)
+                       & ~(X86_EFLAGS_PF | X86_EFLAGS_AF | X86_EFLAGS_ZF |
+                           X86_EFLAGS_SF | X86_EFLAGS_OF))
+                       | X86_EFLAGS_CF);
+}
+
+static void nested_vmx_failValid(struct kvm_vcpu *vcpu,
+                                       u32 vm_instruction_error)
+{
+       if (to_vmx(vcpu)->nested.current_vmptr == -1ull) {
+               /*
+                * failValid writes the error number to the current VMCS, which
+                * can't be done there isn't a current VMCS.
+                */
+               nested_vmx_failInvalid(vcpu);
+               return;
+       }
+       vmx_set_rflags(vcpu, (vmx_get_rflags(vcpu)
+                       & ~(X86_EFLAGS_CF | X86_EFLAGS_PF | X86_EFLAGS_AF |
+                           X86_EFLAGS_SF | X86_EFLAGS_OF))
+                       | X86_EFLAGS_ZF);
+       get_vmcs12(vcpu)->vm_instruction_error = vm_instruction_error;
+}
+
+/*
  * The exit handlers return 1 if the exit was handled fully and guest execution
  * may resume.  Otherwise they set the kvm_run parameter to indicate what needs
  * to be done to userspace and return 0.