]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blobdiff - arch/x86/kvm/vmx.c
KVM: modify memslots layout in struct kvm
[mirror_ubuntu-zesty-kernel.git] / arch / x86 / kvm / vmx.c
index efbb614ccd369b468c5b91ffb7646dc6b3d60449..18698799e365259ff3ba5b18ebb9f032f1ec2b27 100644 (file)
@@ -69,8 +69,10 @@ module_param(emulate_invalid_guest_state, bool, S_IRUGO);
        (X86_CR0_WP | X86_CR0_NE | X86_CR0_TS | X86_CR0_MP)
 #define KVM_VM_CR0_ALWAYS_ON                                           \
        (KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST | X86_CR0_PG | X86_CR0_PE)
-#define KVM_GUEST_CR4_MASK                                             \
-       (X86_CR4_VME | X86_CR4_PSE | X86_CR4_PAE | X86_CR4_PGE | X86_CR4_VMXE)
+#define KVM_CR4_GUEST_OWNED_BITS                                     \
+       (X86_CR4_PVI | X86_CR4_DE | X86_CR4_PCE | X86_CR4_OSFXSR      \
+        | X86_CR4_OSXMMEXCPT)
+
 #define KVM_PMODE_VM_CR4_ALWAYS_ON (X86_CR4_PAE | X86_CR4_VMXE)
 #define KVM_RMODE_VM_CR4_ALWAYS_ON (X86_CR4_VME | X86_CR4_PAE | X86_CR4_VMXE)
 
@@ -149,6 +151,8 @@ struct vcpu_vmx {
        ktime_t entry_time;
        s64 vnmi_blocked_time;
        u32 exit_reason;
+
+       bool rdtscp_enabled;
 };
 
 static inline struct vcpu_vmx *to_vmx(struct kvm_vcpu *vcpu)
@@ -223,7 +227,7 @@ static const u32 vmx_msr_index[] = {
 #ifdef CONFIG_X86_64
        MSR_SYSCALL_MASK, MSR_LSTAR, MSR_CSTAR,
 #endif
-       MSR_EFER, MSR_K6_STAR,
+       MSR_EFER, MSR_TSC_AUX, MSR_K6_STAR,
 };
 #define NR_VMX_MSR ARRAY_SIZE(vmx_msr_index)
 
@@ -360,6 +364,12 @@ static inline int cpu_has_vmx_vpid(void)
                SECONDARY_EXEC_ENABLE_VPID;
 }
 
+static inline int cpu_has_vmx_rdtscp(void)
+{
+       return vmcs_config.cpu_based_2nd_exec_ctrl &
+               SECONDARY_EXEC_RDTSCP;
+}
+
 static inline int cpu_has_virtual_nmis(void)
 {
        return vmcs_config.pin_based_exec_ctrl & PIN_BASED_VIRTUAL_NMIS;
@@ -891,6 +901,11 @@ static void vmx_queue_exception(struct kvm_vcpu *vcpu, unsigned nr,
        vmcs_write32(VM_ENTRY_INTR_INFO_FIELD, intr_info);
 }
 
+static bool vmx_rdtscp_supported(void)
+{
+       return cpu_has_vmx_rdtscp();
+}
+
 /*
  * Swap MSR entry in host/guest MSR entry array.
  */
@@ -926,6 +941,9 @@ static void setup_msrs(struct vcpu_vmx *vmx)
                index = __find_msr_index(vmx, MSR_CSTAR);
                if (index >= 0)
                        move_msr_up(vmx, index, save_nmsrs++);
+               index = __find_msr_index(vmx, MSR_TSC_AUX);
+               if (index >= 0 && vmx->rdtscp_enabled)
+                       move_msr_up(vmx, index, save_nmsrs++);
                /*
                 * MSR_K6_STAR is only needed on long mode guests, and only
                 * if efer.sce is enabled.
@@ -1015,6 +1033,10 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
        case MSR_IA32_SYSENTER_ESP:
                data = vmcs_readl(GUEST_SYSENTER_ESP);
                break;
+       case MSR_TSC_AUX:
+               if (!to_vmx(vcpu)->rdtscp_enabled)
+                       return 1;
+               /* Otherwise falls through */
        default:
                vmx_load_host_state(to_vmx(vcpu));
                msr = find_msr_entry(to_vmx(vcpu), msr_index);
@@ -1078,7 +1100,15 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 data)
                        vcpu->arch.pat = data;
                        break;
                }
-               /* Otherwise falls through to kvm_set_msr_common */
+               ret = kvm_set_msr_common(vcpu, msr_index, data);
+               break;
+       case MSR_TSC_AUX:
+               if (!vmx->rdtscp_enabled)
+                       return 1;
+               /* Check reserved bit, higher 32 bits should be zero */
+               if ((data >> 32) != 0)
+                       return 1;
+               /* Otherwise falls through */
        default:
                msr = find_msr_entry(vmx, msr_index);
                if (msr) {
@@ -1258,7 +1288,8 @@ static __init int setup_vmcs_config(struct vmcs_config *vmcs_conf)
                        SECONDARY_EXEC_ENABLE_VPID |
                        SECONDARY_EXEC_ENABLE_EPT |
                        SECONDARY_EXEC_UNRESTRICTED_GUEST |
-                       SECONDARY_EXEC_PAUSE_LOOP_EXITING;
+                       SECONDARY_EXEC_PAUSE_LOOP_EXITING |
+                       SECONDARY_EXEC_RDTSCP;
                if (adjust_vmx_controls(min2, opt2,
                                        MSR_IA32_VMX_PROCBASED_CTLS2,
                                        &_cpu_based_2nd_exec_control) < 0)
@@ -1472,8 +1503,8 @@ static void enter_pmode(struct kvm_vcpu *vcpu)
 static gva_t rmode_tss_base(struct kvm *kvm)
 {
        if (!kvm->arch.tss_addr) {
-               gfn_t base_gfn = kvm->memslots[0].base_gfn +
-                                kvm->memslots[0].npages - 3;
+               gfn_t base_gfn = kvm->memslots->memslots[0].base_gfn +
+                                kvm->memslots->memslots[0].npages - 3;
                return base_gfn << PAGE_SHIFT;
        }
        return kvm->arch.tss_addr;
@@ -1615,8 +1646,10 @@ static void vmx_flush_tlb(struct kvm_vcpu *vcpu)
 
 static void vmx_decache_cr4_guest_bits(struct kvm_vcpu *vcpu)
 {
-       vcpu->arch.cr4 &= KVM_GUEST_CR4_MASK;
-       vcpu->arch.cr4 |= vmcs_readl(GUEST_CR4) & ~KVM_GUEST_CR4_MASK;
+       ulong cr4_guest_owned_bits = vcpu->arch.cr4_guest_owned_bits;
+
+       vcpu->arch.cr4 &= ~cr4_guest_owned_bits;
+       vcpu->arch.cr4 |= vmcs_readl(GUEST_CR4) & cr4_guest_owned_bits;
 }
 
 static void ept_load_pdptrs(struct kvm_vcpu *vcpu)
@@ -1661,7 +1694,7 @@ static void ept_update_paging_mode_cr0(unsigned long *hw_cr0,
                             (CPU_BASED_CR3_LOAD_EXITING |
                              CPU_BASED_CR3_STORE_EXITING));
                vcpu->arch.cr0 = cr0;
-               vmx_set_cr4(vcpu, vcpu->arch.cr4);
+               vmx_set_cr4(vcpu, kvm_read_cr4(vcpu));
        } else if (!is_paging(vcpu)) {
                /* From nonpaging to paging */
                vmcs_write32(CPU_BASED_VM_EXEC_CONTROL,
@@ -1669,23 +1702,13 @@ static void ept_update_paging_mode_cr0(unsigned long *hw_cr0,
                             ~(CPU_BASED_CR3_LOAD_EXITING |
                               CPU_BASED_CR3_STORE_EXITING));
                vcpu->arch.cr0 = cr0;
-               vmx_set_cr4(vcpu, vcpu->arch.cr4);
+               vmx_set_cr4(vcpu, kvm_read_cr4(vcpu));
        }
 
        if (!(cr0 & X86_CR0_WP))
                *hw_cr0 &= ~X86_CR0_WP;
 }
 
-static void ept_update_paging_mode_cr4(unsigned long *hw_cr4,
-                                       struct kvm_vcpu *vcpu)
-{
-       if (!is_paging(vcpu)) {
-               *hw_cr4 &= ~X86_CR4_PAE;
-               *hw_cr4 |= X86_CR4_PSE;
-       } else if (!(vcpu->arch.cr4 & X86_CR4_PAE))
-               *hw_cr4 &= ~X86_CR4_PAE;
-}
-
 static void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
@@ -1763,8 +1786,14 @@ static void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
                    KVM_RMODE_VM_CR4_ALWAYS_ON : KVM_PMODE_VM_CR4_ALWAYS_ON);
 
        vcpu->arch.cr4 = cr4;
-       if (enable_ept)
-               ept_update_paging_mode_cr4(&hw_cr4, vcpu);
+       if (enable_ept) {
+               if (!is_paging(vcpu)) {
+                       hw_cr4 &= ~X86_CR4_PAE;
+                       hw_cr4 |= X86_CR4_PSE;
+               } else if (!(cr4 & X86_CR4_PAE)) {
+                       hw_cr4 &= ~X86_CR4_PAE;
+               }
+       }
 
        vmcs_writel(CR4_READ_SHADOW, cr4);
        vmcs_writel(GUEST_CR4, hw_cr4);
@@ -2399,14 +2428,12 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
        for (i = 0; i < NR_VMX_MSR; ++i) {
                u32 index = vmx_msr_index[i];
                u32 data_low, data_high;
-               u64 data;
                int j = vmx->nmsrs;
 
                if (rdmsr_safe(index, &data_low, &data_high) < 0)
                        continue;
                if (wrmsr_safe(index, data_low, data_high) < 0)
                        continue;
-               data = data_low | ((u64)data_high << 32);
                vmx->guest_msrs[j].index = i;
                vmx->guest_msrs[j].data = 0;
                vmx->guest_msrs[j].mask = -1ull;
@@ -2419,7 +2446,10 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
        vmcs_write32(VM_ENTRY_CONTROLS, vmcs_config.vmentry_ctrl);
 
        vmcs_writel(CR0_GUEST_HOST_MASK, ~0UL);
-       vmcs_writel(CR4_GUEST_HOST_MASK, KVM_GUEST_CR4_MASK);
+       vmx->vcpu.arch.cr4_guest_owned_bits = KVM_CR4_GUEST_OWNED_BITS;
+       if (enable_ept)
+               vmx->vcpu.arch.cr4_guest_owned_bits |= X86_CR4_PGE;
+       vmcs_writel(CR4_GUEST_HOST_MASK, ~vmx->vcpu.arch.cr4_guest_owned_bits);
 
        tsc_base = vmx->vcpu.kvm->arch.vm_init_tsc;
        rdtscll(tsc_this);
@@ -3050,7 +3080,7 @@ static int handle_dr(struct kvm_vcpu *vcpu)
                                vcpu->arch.eff_db[dr] = val;
                        break;
                case 4 ... 5:
-                       if (vcpu->arch.cr4 & X86_CR4_DE)
+                       if (kvm_read_cr4_bits(vcpu, X86_CR4_DE))
                                kvm_queue_exception(vcpu, UD_VECTOR);
                        break;
                case 6:
@@ -3987,6 +4017,33 @@ static bool vmx_gb_page_enable(void)
        return false;
 }
 
+static inline u32 bit(int bitno)
+{
+       return 1 << (bitno & 31);
+}
+
+static void vmx_cpuid_update(struct kvm_vcpu *vcpu)
+{
+       struct kvm_cpuid_entry2 *best;
+       struct vcpu_vmx *vmx = to_vmx(vcpu);
+       u32 exec_control;
+
+       vmx->rdtscp_enabled = false;
+       if (vmx_rdtscp_supported()) {
+               exec_control = vmcs_read32(SECONDARY_VM_EXEC_CONTROL);
+               if (exec_control & SECONDARY_EXEC_RDTSCP) {
+                       best = kvm_find_cpuid_entry(vcpu, 0x80000001, 0);
+                       if (best && (best->edx & bit(X86_FEATURE_RDTSCP)))
+                               vmx->rdtscp_enabled = true;
+                       else {
+                               exec_control &= ~SECONDARY_EXEC_RDTSCP;
+                               vmcs_write32(SECONDARY_VM_EXEC_CONTROL,
+                                               exec_control);
+                       }
+               }
+       }
+}
+
 static struct kvm_x86_ops vmx_x86_ops = {
        .cpu_has_kvm_support = cpu_has_kvm_support,
        .disabled_by_bios = vmx_disabled_by_bios,
@@ -4051,6 +4108,10 @@ static struct kvm_x86_ops vmx_x86_ops = {
 
        .exit_reasons_str = vmx_exit_reasons_str,
        .gb_page_enable = vmx_gb_page_enable,
+
+       .cpuid_update = vmx_cpuid_update,
+
+       .rdtscp_supported = vmx_rdtscp_supported,
 };
 
 static int __init vmx_init(void)