]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - arch/x86/kvm/vmx.c
kvm: nVMX: Fetch VM_INSTRUCTION_ERROR from vmcs02 on vmx->fail
[mirror_ubuntu-artful-kernel.git] / arch / x86 / kvm / vmx.c
index cf1b16dbc98a90d4035a480362a549f299faf55f..6fcc819c945fef04f8c0ad4db78e8024c10bce49 100644 (file)
@@ -187,6 +187,7 @@ struct vmcs {
  */
 struct loaded_vmcs {
        struct vmcs *vmcs;
+       struct vmcs *shadow_vmcs;
        int cpu;
        int launched;
        struct list_head loaded_vmcss_on_cpu_link;
@@ -411,7 +412,6 @@ struct nested_vmx {
         * memory during VMXOFF, VMCLEAR, VMPTRLD.
         */
        struct vmcs12 *cached_vmcs12;
-       struct vmcs *current_shadow_vmcs;
        /*
         * Indicates if the shadow vmcs must be updated with the
         * data hold by vmcs12
@@ -421,7 +421,6 @@ struct nested_vmx {
        /* vmcs02_list cache of VMCSs recently used to run L2 guests */
        struct list_head vmcs02_pool;
        int vmcs02_num;
-       u64 vmcs01_tsc_offset;
        bool change_vmcs01_virtual_x2apic_mode;
        /* L2 must run next, and mustn't decide to exit to L1. */
        bool nested_run_pending;
@@ -925,10 +924,10 @@ static unsigned long *vmx_io_bitmap_a;
 static unsigned long *vmx_io_bitmap_b;
 static unsigned long *vmx_msr_bitmap_legacy;
 static unsigned long *vmx_msr_bitmap_longmode;
+static unsigned long *vmx_msr_bitmap_legacy_x2apic_apicv;
+static unsigned long *vmx_msr_bitmap_longmode_x2apic_apicv;
 static unsigned long *vmx_msr_bitmap_legacy_x2apic;
 static unsigned long *vmx_msr_bitmap_longmode_x2apic;
-static unsigned long *vmx_msr_bitmap_legacy_x2apic_apicv_inactive;
-static unsigned long *vmx_msr_bitmap_longmode_x2apic_apicv_inactive;
 static unsigned long *vmx_vmread_bitmap;
 static unsigned long *vmx_vmwrite_bitmap;
 
@@ -1419,6 +1418,8 @@ static void vmcs_clear(struct vmcs *vmcs)
 static inline void loaded_vmcs_init(struct loaded_vmcs *loaded_vmcs)
 {
        vmcs_clear(loaded_vmcs->vmcs);
+       if (loaded_vmcs->shadow_vmcs && loaded_vmcs->launched)
+               vmcs_clear(loaded_vmcs->shadow_vmcs);
        loaded_vmcs->cpu = -1;
        loaded_vmcs->launched = 0;
 }
@@ -2528,14 +2529,14 @@ static void vmx_set_msr_bitmap(struct kvm_vcpu *vcpu)
                  SECONDARY_EXEC_VIRTUALIZE_X2APIC_MODE)) {
                if (enable_apicv && kvm_vcpu_apicv_active(vcpu)) {
                        if (is_long_mode(vcpu))
-                               msr_bitmap = vmx_msr_bitmap_longmode_x2apic;
+                               msr_bitmap = vmx_msr_bitmap_longmode_x2apic_apicv;
                        else
-                               msr_bitmap = vmx_msr_bitmap_legacy_x2apic;
+                               msr_bitmap = vmx_msr_bitmap_legacy_x2apic_apicv;
                } else {
                        if (is_long_mode(vcpu))
-                               msr_bitmap = vmx_msr_bitmap_longmode_x2apic_apicv_inactive;
+                               msr_bitmap = vmx_msr_bitmap_longmode_x2apic;
                        else
-                               msr_bitmap = vmx_msr_bitmap_legacy_x2apic_apicv_inactive;
+                               msr_bitmap = vmx_msr_bitmap_legacy_x2apic;
                }
        } else {
                if (is_long_mode(vcpu))
@@ -2604,20 +2605,6 @@ static u64 guest_read_tsc(struct kvm_vcpu *vcpu)
        return kvm_scale_tsc(vcpu, host_tsc) + tsc_offset;
 }
 
-/*
- * Like guest_read_tsc, but always returns L1's notion of the timestamp
- * counter, even if a nested guest (L2) is currently running.
- */
-static u64 vmx_read_l1_tsc(struct kvm_vcpu *vcpu, u64 host_tsc)
-{
-       u64 tsc_offset;
-
-       tsc_offset = is_guest_mode(vcpu) ?
-               to_vmx(vcpu)->nested.vmcs01_tsc_offset :
-               vmcs_read64(TSC_OFFSET);
-       return host_tsc + tsc_offset;
-}
-
 /*
  * writes 'offset' into guest's timestamp counter offset register
  */
@@ -2631,7 +2618,6 @@ static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
                 * to the newly set TSC to get L2's TSC.
                 */
                struct vmcs12 *vmcs12;
-               to_vmx(vcpu)->nested.vmcs01_tsc_offset = offset;
                /* recalculate vmcs02.TSC_OFFSET: */
                vmcs12 = get_vmcs12(vcpu);
                vmcs_write64(TSC_OFFSET, offset +
@@ -2644,19 +2630,6 @@ static void vmx_write_tsc_offset(struct kvm_vcpu *vcpu, u64 offset)
        }
 }
 
-static void vmx_adjust_tsc_offset_guest(struct kvm_vcpu *vcpu, s64 adjustment)
-{
-       u64 offset = vmcs_read64(TSC_OFFSET);
-
-       vmcs_write64(TSC_OFFSET, offset + adjustment);
-       if (is_guest_mode(vcpu)) {
-               /* Even when running L2, the adjustment needs to apply to L1 */
-               to_vmx(vcpu)->nested.vmcs01_tsc_offset += adjustment;
-       } else
-               trace_kvm_write_tsc_offset(vcpu->vcpu_id, offset,
-                                          offset + adjustment);
-}
-
 static bool guest_cpuid_has_vmx(struct kvm_vcpu *vcpu)
 {
        struct kvm_cpuid_entry2 *best = kvm_find_cpuid_entry(vcpu, 1, 0);
@@ -3562,6 +3535,7 @@ static void free_loaded_vmcs(struct loaded_vmcs *loaded_vmcs)
        loaded_vmcs_clear(loaded_vmcs);
        free_vmcs(loaded_vmcs->vmcs);
        loaded_vmcs->vmcs = NULL;
+       WARN_ON(loaded_vmcs->shadow_vmcs != NULL);
 }
 
 static void free_kvm_area(void)
@@ -4694,14 +4668,14 @@ static void vmx_disable_intercept_for_msr(u32 msr, bool longmode_only)
 static void vmx_enable_intercept_msr_read_x2apic(u32 msr, bool apicv_active)
 {
        if (apicv_active) {
-               __vmx_enable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic,
+               __vmx_enable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic_apicv,
                                msr, MSR_TYPE_R);
-               __vmx_enable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic,
+               __vmx_enable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic_apicv,
                                msr, MSR_TYPE_R);
        } else {
-               __vmx_enable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic_apicv_inactive,
+               __vmx_enable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic,
                                msr, MSR_TYPE_R);
-               __vmx_enable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic_apicv_inactive,
+               __vmx_enable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic,
                                msr, MSR_TYPE_R);
        }
 }
@@ -4709,14 +4683,14 @@ static void vmx_enable_intercept_msr_read_x2apic(u32 msr, bool apicv_active)
 static void vmx_disable_intercept_msr_read_x2apic(u32 msr, bool apicv_active)
 {
        if (apicv_active) {
-               __vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic,
+               __vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic_apicv,
                                msr, MSR_TYPE_R);
-               __vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic,
+               __vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic_apicv,
                                msr, MSR_TYPE_R);
        } else {
-               __vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic_apicv_inactive,
+               __vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic,
                                msr, MSR_TYPE_R);
-               __vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic_apicv_inactive,
+               __vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic,
                                msr, MSR_TYPE_R);
        }
 }
@@ -4724,14 +4698,14 @@ static void vmx_disable_intercept_msr_read_x2apic(u32 msr, bool apicv_active)
 static void vmx_disable_intercept_msr_write_x2apic(u32 msr, bool apicv_active)
 {
        if (apicv_active) {
-               __vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic,
+               __vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic_apicv,
                                msr, MSR_TYPE_W);
-               __vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic,
+               __vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic_apicv,
                                msr, MSR_TYPE_W);
        } else {
-               __vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic_apicv_inactive,
+               __vmx_disable_intercept_for_msr(vmx_msr_bitmap_legacy_x2apic,
                                msr, MSR_TYPE_W);
-               __vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic_apicv_inactive,
+               __vmx_disable_intercept_for_msr(vmx_msr_bitmap_longmode_x2apic,
                                msr, MSR_TYPE_W);
        }
 }
@@ -6390,28 +6364,28 @@ static __init int hardware_setup(void)
        if (!vmx_msr_bitmap_legacy)
                goto out1;
 
-       vmx_msr_bitmap_legacy_x2apic =
+       vmx_msr_bitmap_legacy_x2apic_apicv =
                                (unsigned long *)__get_free_page(GFP_KERNEL);
-       if (!vmx_msr_bitmap_legacy_x2apic)
+       if (!vmx_msr_bitmap_legacy_x2apic_apicv)
                goto out2;
 
-       vmx_msr_bitmap_legacy_x2apic_apicv_inactive =
+       vmx_msr_bitmap_legacy_x2apic =
                                (unsigned long *)__get_free_page(GFP_KERNEL);
-       if (!vmx_msr_bitmap_legacy_x2apic_apicv_inactive)
+       if (!vmx_msr_bitmap_legacy_x2apic)
                goto out3;
 
        vmx_msr_bitmap_longmode = (unsigned long *)__get_free_page(GFP_KERNEL);
        if (!vmx_msr_bitmap_longmode)
                goto out4;
 
-       vmx_msr_bitmap_longmode_x2apic =
+       vmx_msr_bitmap_longmode_x2apic_apicv =
                                (unsigned long *)__get_free_page(GFP_KERNEL);
-       if (!vmx_msr_bitmap_longmode_x2apic)
+       if (!vmx_msr_bitmap_longmode_x2apic_apicv)
                goto out5;
 
-       vmx_msr_bitmap_longmode_x2apic_apicv_inactive =
+       vmx_msr_bitmap_longmode_x2apic =
                                (unsigned long *)__get_free_page(GFP_KERNEL);
-       if (!vmx_msr_bitmap_longmode_x2apic_apicv_inactive)
+       if (!vmx_msr_bitmap_longmode_x2apic)
                goto out6;
 
        vmx_vmread_bitmap = (unsigned long *)__get_free_page(GFP_KERNEL);
@@ -6502,13 +6476,13 @@ static __init int hardware_setup(void)
        vmx_disable_intercept_for_msr(MSR_IA32_SYSENTER_EIP, false);
        vmx_disable_intercept_for_msr(MSR_IA32_BNDCFGS, true);
 
-       memcpy(vmx_msr_bitmap_legacy_x2apic,
+       memcpy(vmx_msr_bitmap_legacy_x2apic_apicv,
                        vmx_msr_bitmap_legacy, PAGE_SIZE);
-       memcpy(vmx_msr_bitmap_longmode_x2apic,
+       memcpy(vmx_msr_bitmap_longmode_x2apic_apicv,
                        vmx_msr_bitmap_longmode, PAGE_SIZE);
-       memcpy(vmx_msr_bitmap_legacy_x2apic_apicv_inactive,
+       memcpy(vmx_msr_bitmap_legacy_x2apic,
                        vmx_msr_bitmap_legacy, PAGE_SIZE);
-       memcpy(vmx_msr_bitmap_longmode_x2apic_apicv_inactive,
+       memcpy(vmx_msr_bitmap_longmode_x2apic,
                        vmx_msr_bitmap_longmode, PAGE_SIZE);
 
        set_bit(0, vmx_vpid_bitmap); /* 0 is reserved for host */
@@ -6586,15 +6560,15 @@ out9:
 out8:
        free_page((unsigned long)vmx_vmread_bitmap);
 out7:
-       free_page((unsigned long)vmx_msr_bitmap_longmode_x2apic_apicv_inactive);
-out6:
        free_page((unsigned long)vmx_msr_bitmap_longmode_x2apic);
+out6:
+       free_page((unsigned long)vmx_msr_bitmap_longmode_x2apic_apicv);
 out5:
        free_page((unsigned long)vmx_msr_bitmap_longmode);
 out4:
-       free_page((unsigned long)vmx_msr_bitmap_legacy_x2apic_apicv_inactive);
-out3:
        free_page((unsigned long)vmx_msr_bitmap_legacy_x2apic);
+out3:
+       free_page((unsigned long)vmx_msr_bitmap_legacy_x2apic_apicv);
 out2:
        free_page((unsigned long)vmx_msr_bitmap_legacy);
 out1:
@@ -6607,10 +6581,10 @@ out:
 
 static __exit void hardware_unsetup(void)
 {
+       free_page((unsigned long)vmx_msr_bitmap_legacy_x2apic_apicv);
        free_page((unsigned long)vmx_msr_bitmap_legacy_x2apic);
-       free_page((unsigned long)vmx_msr_bitmap_legacy_x2apic_apicv_inactive);
+       free_page((unsigned long)vmx_msr_bitmap_longmode_x2apic_apicv);
        free_page((unsigned long)vmx_msr_bitmap_longmode_x2apic);
-       free_page((unsigned long)vmx_msr_bitmap_longmode_x2apic_apicv_inactive);
        free_page((unsigned long)vmx_msr_bitmap_legacy);
        free_page((unsigned long)vmx_msr_bitmap_longmode);
        free_page((unsigned long)vmx_io_bitmap_b);
@@ -6696,6 +6670,7 @@ static struct loaded_vmcs *nested_get_current_vmcs02(struct vcpu_vmx *vmx)
        if (!item)
                return NULL;
        item->vmcs02.vmcs = alloc_vmcs();
+       item->vmcs02.shadow_vmcs = NULL;
        if (!item->vmcs02.vmcs) {
                kfree(item);
                return NULL;
@@ -7072,7 +7047,7 @@ static int handle_vmon(struct kvm_vcpu *vcpu)
                shadow_vmcs->revision_id |= (1u << 31);
                /* init shadow vmcs */
                vmcs_clear(shadow_vmcs);
-               vmx->nested.current_shadow_vmcs = shadow_vmcs;
+               vmx->vmcs01.shadow_vmcs = shadow_vmcs;
        }
 
        INIT_LIST_HEAD(&(vmx->nested.vmcs02_pool));
@@ -7174,8 +7149,11 @@ static void free_nested(struct vcpu_vmx *vmx)
                free_page((unsigned long)vmx->nested.msr_bitmap);
                vmx->nested.msr_bitmap = NULL;
        }
-       if (enable_shadow_vmcs)
-               free_vmcs(vmx->nested.current_shadow_vmcs);
+       if (enable_shadow_vmcs) {
+               vmcs_clear(vmx->vmcs01.shadow_vmcs);
+               free_vmcs(vmx->vmcs01.shadow_vmcs);
+               vmx->vmcs01.shadow_vmcs = NULL;
+       }
        kfree(vmx->nested.cached_vmcs12);
        /* Unpin physical memory we referred to in current vmcs02 */
        if (vmx->nested.apic_access_page) {
@@ -7352,7 +7330,7 @@ static void copy_shadow_to_vmcs12(struct vcpu_vmx *vmx)
        int i;
        unsigned long field;
        u64 field_value;
-       struct vmcs *shadow_vmcs = vmx->nested.current_shadow_vmcs;
+       struct vmcs *shadow_vmcs = vmx->vmcs01.shadow_vmcs;
        const unsigned long *fields = shadow_read_write_fields;
        const int num_fields = max_shadow_read_write_fields;
 
@@ -7401,7 +7379,7 @@ static void copy_vmcs12_to_shadow(struct vcpu_vmx *vmx)
        int i, q;
        unsigned long field;
        u64 field_value = 0;
-       struct vmcs *shadow_vmcs = vmx->nested.current_shadow_vmcs;
+       struct vmcs *shadow_vmcs = vmx->vmcs01.shadow_vmcs;
 
        vmcs_load(shadow_vmcs);
 
@@ -7591,7 +7569,7 @@ static int handle_vmptrld(struct kvm_vcpu *vcpu)
                        vmcs_set_bits(SECONDARY_VM_EXEC_CONTROL,
                                      SECONDARY_EXEC_SHADOW_VMCS);
                        vmcs_write64(VMCS_LINK_POINTER,
-                                    __pa(vmx->nested.current_shadow_vmcs));
+                                    __pa(vmx->vmcs01.shadow_vmcs));
                        vmx->nested.sync_shadow_vmcs = true;
                }
        }
@@ -7659,7 +7637,7 @@ static int handle_invept(struct kvm_vcpu *vcpu)
 
        types = (vmx->nested.nested_vmx_ept_caps >> VMX_EPT_EXTENT_SHIFT) & 6;
 
-       if (!(types & (1UL << type))) {
+       if (type >= 32 || !(types & (1 << type))) {
                nested_vmx_failValid(vcpu,
                                VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
                skip_emulated_instruction(vcpu);
@@ -7722,7 +7700,7 @@ static int handle_invvpid(struct kvm_vcpu *vcpu)
 
        types = (vmx->nested.nested_vmx_vpid_caps >> 8) & 0x7;
 
-       if (!(types & (1UL << type))) {
+       if (type >= 32 || !(types & (1 << type))) {
                nested_vmx_failValid(vcpu,
                        VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID);
                skip_emulated_instruction(vcpu);
@@ -9156,6 +9134,7 @@ static struct kvm_vcpu *vmx_create_vcpu(struct kvm *kvm, unsigned int id)
 
        vmx->loaded_vmcs = &vmx->vmcs01;
        vmx->loaded_vmcs->vmcs = alloc_vmcs();
+       vmx->loaded_vmcs->shadow_vmcs = NULL;
        if (!vmx->loaded_vmcs->vmcs)
                goto free_msrs;
        if (!vmm_exclusive)
@@ -10061,9 +10040,9 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
 
        if (vmcs12->cpu_based_vm_exec_control & CPU_BASED_USE_TSC_OFFSETING)
                vmcs_write64(TSC_OFFSET,
-                       vmx->nested.vmcs01_tsc_offset + vmcs12->tsc_offset);
+                       vcpu->arch.tsc_offset + vmcs12->tsc_offset);
        else
-               vmcs_write64(TSC_OFFSET, vmx->nested.vmcs01_tsc_offset);
+               vmcs_write64(TSC_OFFSET, vcpu->arch.tsc_offset);
        if (kvm_has_tsc_control)
                decache_tsc_multiplier(vmx);
 
@@ -10293,8 +10272,6 @@ static int nested_vmx_run(struct kvm_vcpu *vcpu, bool launch)
 
        enter_guest_mode(vcpu);
 
-       vmx->nested.vmcs01_tsc_offset = vmcs_read64(TSC_OFFSET);
-
        if (!(vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS))
                vmx->nested.vmcs01_debugctl = vmcs_read64(GUEST_IA32_DEBUGCTL);
 
@@ -10778,6 +10755,7 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
        struct vmcs12 *vmcs12 = get_vmcs12(vcpu);
+       u32 vm_inst_error = 0;
 
        /* trying to cancel vmlaunch/vmresume is a bug */
        WARN_ON_ONCE(vmx->nested.nested_run_pending);
@@ -10790,6 +10768,9 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
                                 vmcs12->vm_exit_msr_store_count))
                nested_vmx_abort(vcpu, VMX_ABORT_SAVE_GUEST_MSR_FAIL);
 
+       if (unlikely(vmx->fail))
+               vm_inst_error = vmcs_read32(VM_INSTRUCTION_ERROR);
+
        vmx_load_vmcs01(vcpu);
 
        if ((exit_reason == EXIT_REASON_EXTERNAL_INTERRUPT)
@@ -10818,7 +10799,7 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
        load_vmcs12_host_state(vcpu, vmcs12);
 
        /* Update any VMCS fields that might have changed while L2 ran */
-       vmcs_write64(TSC_OFFSET, vmx->nested.vmcs01_tsc_offset);
+       vmcs_write64(TSC_OFFSET, vcpu->arch.tsc_offset);
        if (vmx->hv_deadline_tsc == -1)
                vmcs_clear_bits(PIN_BASED_VM_EXEC_CONTROL,
                                PIN_BASED_VMX_PREEMPTION_TIMER);
@@ -10866,7 +10847,7 @@ static void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 exit_reason,
         */
        if (unlikely(vmx->fail)) {
                vmx->fail = 0;
-               nested_vmx_failValid(vcpu, vmcs_read32(VM_INSTRUCTION_ERROR));
+               nested_vmx_failValid(vcpu, vm_inst_error);
        } else
                nested_vmx_succeed(vcpu);
        if (enable_shadow_vmcs)
@@ -11339,8 +11320,6 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = {
        .has_wbinvd_exit = cpu_has_vmx_wbinvd_exit,
 
        .write_tsc_offset = vmx_write_tsc_offset,
-       .adjust_tsc_offset_guest = vmx_adjust_tsc_offset_guest,
-       .read_l1_tsc = vmx_read_l1_tsc,
 
        .set_tdp_cr3 = vmx_set_cr3,