KVM: x86: handle wrap around 32-bit address space
[linux-2.6-microblaze.git] / arch / x86 / kvm / vmx / vmx.c
index e1f5fc9..f519fc7 100644 (file)
@@ -1555,7 +1555,7 @@ static int vmx_rtit_ctl_check(struct kvm_vcpu *vcpu, u64 data)
 
 static int skip_emulated_instruction(struct kvm_vcpu *vcpu)
 {
-       unsigned long rip;
+       unsigned long rip, orig_rip;
 
        /*
         * Using VMCS.VM_EXIT_INSTRUCTION_LEN on EPT misconfig depends on
@@ -1567,8 +1567,17 @@ static int skip_emulated_instruction(struct kvm_vcpu *vcpu)
         */
        if (!static_cpu_has(X86_FEATURE_HYPERVISOR) ||
            to_vmx(vcpu)->exit_reason != EXIT_REASON_EPT_MISCONFIG) {
-               rip = kvm_rip_read(vcpu);
-               rip += vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
+               orig_rip = kvm_rip_read(vcpu);
+               rip = orig_rip + vmcs_read32(VM_EXIT_INSTRUCTION_LEN);
+#ifdef CONFIG_X86_64
+               /*
+                * We need to mask out the high 32 bits of RIP if not in 64-bit
+                * mode, but just finding out that we are in 64-bit mode is
+                * quite expensive.  Only do it if there was a carry.
+                */
+               if (unlikely(((rip ^ orig_rip) >> 31) == 3) && !is_64_bit_mode(vcpu))
+                       rip = (u32)rip;
+#endif
                kvm_rip_write(vcpu, rip);
        } else {
                if (!kvm_emulate_instruction(vcpu, EMULTYPE_SKIP))