yeahuh / rpms / qemu-kvm

Forked from rpms/qemu-kvm 2 years ago
Clone
Pablo Greco e6a3ae
From 88ab13cec526a16cb02bf1af51bdd33230308d36 Mon Sep 17 00:00:00 2001
Pablo Greco e6a3ae
From: Paolo Bonzini <pbonzini@redhat.com>
Pablo Greco e6a3ae
Date: Fri, 22 Nov 2019 11:53:44 +0000
Pablo Greco e6a3ae
Subject: [PATCH 11/16] target/i386: add VMX features
Pablo Greco e6a3ae
Pablo Greco e6a3ae
RH-Author: Paolo Bonzini <pbonzini@redhat.com>
Pablo Greco e6a3ae
Message-id: <20191122115348.25000-12-pbonzini@redhat.com>
Pablo Greco e6a3ae
Patchwork-id: 92608
Pablo Greco e6a3ae
O-Subject: [RHEL8.2/rhel qemu-kvm PATCH 11/15] target/i386: add VMX features
Pablo Greco e6a3ae
Bugzilla: 1689270
Pablo Greco e6a3ae
RH-Acked-by: Dr. David Alan Gilbert <dgilbert@redhat.com>
Pablo Greco e6a3ae
RH-Acked-by: Eduardo Habkost <ehabkost@redhat.com>
Pablo Greco e6a3ae
RH-Acked-by: Maxim Levitsky <mlevitsk@redhat.com>
Pablo Greco e6a3ae
Pablo Greco e6a3ae
Add code to convert the VMX feature words back into MSR values,
Pablo Greco e6a3ae
allowing the user to enable/disable VMX features as they wish.  The same
Pablo Greco e6a3ae
infrastructure enables support for limiting VMX features in named
Pablo Greco e6a3ae
CPU models.
Pablo Greco e6a3ae
Pablo Greco e6a3ae
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Pablo Greco e6a3ae
(cherry picked from commit 20a78b02d31534ae478779c2f2816c273601e869)
Pablo Greco e6a3ae
Signed-off-by: Danilo C. L. de Paula <ddepaula@redhat.com>
Pablo Greco e6a3ae
---
Pablo Greco e6a3ae
 target/i386/cpu.c | 225 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
Pablo Greco e6a3ae
 target/i386/cpu.h |   9 +++
Pablo Greco e6a3ae
 target/i386/kvm.c | 162 ++++++++++++++++++++++++++++++++++++++-
Pablo Greco e6a3ae
 3 files changed, 394 insertions(+), 2 deletions(-)
Pablo Greco e6a3ae
Pablo Greco e6a3ae
diff --git a/target/i386/cpu.c b/target/i386/cpu.c
Pablo Greco e6a3ae
index 3e77830..9074a2e 100644
Pablo Greco e6a3ae
--- a/target/i386/cpu.c
Pablo Greco e6a3ae
+++ b/target/i386/cpu.c
Pablo Greco e6a3ae
@@ -1171,6 +1171,163 @@ static FeatureWordInfo feature_word_info[FEATURE_WORDS] = {
Pablo Greco e6a3ae
             .index = MSR_IA32_CORE_CAPABILITY,
Pablo Greco e6a3ae
         },
Pablo Greco e6a3ae
     },
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+    [FEAT_VMX_PROCBASED_CTLS] = {
Pablo Greco e6a3ae
+        .type = MSR_FEATURE_WORD,
Pablo Greco e6a3ae
+        .feat_names = {
Pablo Greco e6a3ae
+            NULL, NULL, "vmx-vintr-pending", "vmx-tsc-offset",
Pablo Greco e6a3ae
+            NULL, NULL, NULL, "vmx-hlt-exit",
Pablo Greco e6a3ae
+            NULL, "vmx-invlpg-exit", "vmx-mwait-exit", "vmx-rdpmc-exit",
Pablo Greco e6a3ae
+            "vmx-rdtsc-exit", NULL, NULL, "vmx-cr3-load-noexit",
Pablo Greco e6a3ae
+            "vmx-cr3-store-noexit", NULL, NULL, "vmx-cr8-load-exit",
Pablo Greco e6a3ae
+            "vmx-cr8-store-exit", "vmx-flexpriority", "vmx-vnmi-pending", "vmx-movdr-exit",
Pablo Greco e6a3ae
+            "vmx-io-exit", "vmx-io-bitmap", NULL, "vmx-mtf",
Pablo Greco e6a3ae
+            "vmx-msr-bitmap", "vmx-monitor-exit", "vmx-pause-exit", "vmx-secondary-ctls",
Pablo Greco e6a3ae
+        },
Pablo Greco e6a3ae
+        .msr = {
Pablo Greco e6a3ae
+            .index = MSR_IA32_VMX_TRUE_PROCBASED_CTLS,
Pablo Greco e6a3ae
+        }
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+    [FEAT_VMX_SECONDARY_CTLS] = {
Pablo Greco e6a3ae
+        .type = MSR_FEATURE_WORD,
Pablo Greco e6a3ae
+        .feat_names = {
Pablo Greco e6a3ae
+            "vmx-apicv-xapic", "vmx-ept", "vmx-desc-exit", "vmx-rdtscp-exit",
Pablo Greco e6a3ae
+            "vmx-apicv-x2apic", "vmx-vpid", "vmx-wbinvd-exit", "vmx-unrestricted-guest",
Pablo Greco e6a3ae
+            "vmx-apicv-register", "vmx-apicv-vid", "vmx-ple", "vmx-rdrand-exit",
Pablo Greco e6a3ae
+            "vmx-invpcid-exit", "vmx-vmfunc", "vmx-shadow-vmcs", "vmx-encls-exit",
Pablo Greco e6a3ae
+            "vmx-rdseed-exit", "vmx-pml", NULL, NULL,
Pablo Greco e6a3ae
+            "vmx-xsaves", NULL, NULL, NULL,
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+        },
Pablo Greco e6a3ae
+        .msr = {
Pablo Greco e6a3ae
+            .index = MSR_IA32_VMX_PROCBASED_CTLS2,
Pablo Greco e6a3ae
+        }
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+    [FEAT_VMX_PINBASED_CTLS] = {
Pablo Greco e6a3ae
+        .type = MSR_FEATURE_WORD,
Pablo Greco e6a3ae
+        .feat_names = {
Pablo Greco e6a3ae
+            "vmx-intr-exit", NULL, NULL, "vmx-nmi-exit",
Pablo Greco e6a3ae
+            NULL, "vmx-vnmi", "vmx-preemption-timer", "vmx-posted-intr",
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+        },
Pablo Greco e6a3ae
+        .msr = {
Pablo Greco e6a3ae
+            .index = MSR_IA32_VMX_TRUE_PINBASED_CTLS,
Pablo Greco e6a3ae
+        }
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+    [FEAT_VMX_EXIT_CTLS] = {
Pablo Greco e6a3ae
+        .type = MSR_FEATURE_WORD,
Pablo Greco e6a3ae
+        /*
Pablo Greco e6a3ae
+         * VMX_VM_EXIT_HOST_ADDR_SPACE_SIZE is copied from
Pablo Greco e6a3ae
+         * the LM CPUID bit.
Pablo Greco e6a3ae
+         */
Pablo Greco e6a3ae
+        .feat_names = {
Pablo Greco e6a3ae
+            NULL, NULL, "vmx-exit-nosave-debugctl", NULL,
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+            NULL, NULL /* vmx-exit-host-addr-space-size */, NULL, NULL,
Pablo Greco e6a3ae
+            "vmx-exit-load-perf-global-ctrl", NULL, NULL, "vmx-exit-ack-intr",
Pablo Greco e6a3ae
+            NULL, NULL, "vmx-exit-save-pat", "vmx-exit-load-pat",
Pablo Greco e6a3ae
+            "vmx-exit-save-efer", "vmx-exit-load-efer",
Pablo Greco e6a3ae
+                "vmx-exit-save-preemption-timer", "vmx-exit-clear-bndcfgs",
Pablo Greco e6a3ae
+            NULL, "vmx-exit-clear-rtit-ctl", NULL, NULL,
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+        },
Pablo Greco e6a3ae
+        .msr = {
Pablo Greco e6a3ae
+            .index = MSR_IA32_VMX_TRUE_EXIT_CTLS,
Pablo Greco e6a3ae
+        }
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+    [FEAT_VMX_ENTRY_CTLS] = {
Pablo Greco e6a3ae
+        .type = MSR_FEATURE_WORD,
Pablo Greco e6a3ae
+        .feat_names = {
Pablo Greco e6a3ae
+            NULL, NULL, "vmx-entry-noload-debugctl", NULL,
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+            NULL, "vmx-entry-ia32e-mode", NULL, NULL,
Pablo Greco e6a3ae
+            NULL, "vmx-entry-load-perf-global-ctrl", "vmx-entry-load-pat", "vmx-entry-load-efer",
Pablo Greco e6a3ae
+            "vmx-entry-load-bndcfgs", NULL, "vmx-entry-load-rtit-ctl", NULL,
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+        },
Pablo Greco e6a3ae
+        .msr = {
Pablo Greco e6a3ae
+            .index = MSR_IA32_VMX_TRUE_ENTRY_CTLS,
Pablo Greco e6a3ae
+        }
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+    [FEAT_VMX_MISC] = {
Pablo Greco e6a3ae
+        .type = MSR_FEATURE_WORD,
Pablo Greco e6a3ae
+        .feat_names = {
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+            NULL, "vmx-store-lma", "vmx-activity-hlt", "vmx-activity-shutdown",
Pablo Greco e6a3ae
+            "vmx-activity-wait-sipi", NULL, NULL, NULL,
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+            NULL, "vmx-vmwrite-vmexit-fields", "vmx-zero-len-inject", NULL,
Pablo Greco e6a3ae
+        },
Pablo Greco e6a3ae
+        .msr = {
Pablo Greco e6a3ae
+            .index = MSR_IA32_VMX_MISC,
Pablo Greco e6a3ae
+        }
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+    [FEAT_VMX_EPT_VPID_CAPS] = {
Pablo Greco e6a3ae
+        .type = MSR_FEATURE_WORD,
Pablo Greco e6a3ae
+        .feat_names = {
Pablo Greco e6a3ae
+            "vmx-ept-execonly", NULL, NULL, NULL,
Pablo Greco e6a3ae
+            NULL, NULL, "vmx-page-walk-4", "vmx-page-walk-5",
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+            "vmx-ept-2mb", "vmx-ept-1gb", NULL, NULL,
Pablo Greco e6a3ae
+            "vmx-invept", "vmx-eptad", "vmx-ept-advanced-exitinfo", NULL,
Pablo Greco e6a3ae
+            NULL, "vmx-invept-single-context", "vmx-invept-all-context", NULL,
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+            "vmx-invvpid", NULL, NULL, NULL,
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+            "vmx-invvpid-single-addr", "vmx-invept-single-context",
Pablo Greco e6a3ae
+                "vmx-invvpid-all-context", "vmx-invept-single-context-noglobals",
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+            NULL, NULL, NULL, NULL,
Pablo Greco e6a3ae
+        },
Pablo Greco e6a3ae
+        .msr = {
Pablo Greco e6a3ae
+            .index = MSR_IA32_VMX_EPT_VPID_CAP,
Pablo Greco e6a3ae
+        }
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+    [FEAT_VMX_BASIC] = {
Pablo Greco e6a3ae
+        .type = MSR_FEATURE_WORD,
Pablo Greco e6a3ae
+        .feat_names = {
Pablo Greco e6a3ae
+            [54] = "vmx-ins-outs",
Pablo Greco e6a3ae
+            [55] = "vmx-true-ctls",
Pablo Greco e6a3ae
+        },
Pablo Greco e6a3ae
+        .msr = {
Pablo Greco e6a3ae
+            .index = MSR_IA32_VMX_BASIC,
Pablo Greco e6a3ae
+        },
Pablo Greco e6a3ae
+        /* Just to be safe - we don't support setting the MSEG version field.  */
Pablo Greco e6a3ae
+        .no_autoenable_flags = MSR_VMX_BASIC_DUAL_MONITOR,
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+    [FEAT_VMX_VMFUNC] = {
Pablo Greco e6a3ae
+        .type = MSR_FEATURE_WORD,
Pablo Greco e6a3ae
+        .feat_names = {
Pablo Greco e6a3ae
+            [0] = "vmx-eptp-switching",
Pablo Greco e6a3ae
+        },
Pablo Greco e6a3ae
+        .msr = {
Pablo Greco e6a3ae
+            .index = MSR_IA32_VMX_VMFUNC,
Pablo Greco e6a3ae
+        }
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
 };
Pablo Greco e6a3ae
 
Pablo Greco e6a3ae
 typedef struct FeatureMask {
Pablo Greco e6a3ae
@@ -1191,6 +1348,74 @@ static FeatureDep feature_dependencies[] = {
Pablo Greco e6a3ae
         .from = { FEAT_7_0_EDX,             CPUID_7_0_EDX_CORE_CAPABILITY },
Pablo Greco e6a3ae
         .to = { FEAT_CORE_CAPABILITY,       ~0ull },
Pablo Greco e6a3ae
     },
Pablo Greco e6a3ae
+    {
Pablo Greco e6a3ae
+        .from = { FEAT_1_ECX,               CPUID_EXT_VMX },
Pablo Greco e6a3ae
+        .to = { FEAT_VMX_PROCBASED_CTLS,    ~0ull },
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+    {
Pablo Greco e6a3ae
+        .from = { FEAT_1_ECX,               CPUID_EXT_VMX },
Pablo Greco e6a3ae
+        .to = { FEAT_VMX_PINBASED_CTLS,     ~0ull },
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+    {
Pablo Greco e6a3ae
+        .from = { FEAT_1_ECX,               CPUID_EXT_VMX },
Pablo Greco e6a3ae
+        .to = { FEAT_VMX_EXIT_CTLS,         ~0ull },
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+    {
Pablo Greco e6a3ae
+        .from = { FEAT_1_ECX,               CPUID_EXT_VMX },
Pablo Greco e6a3ae
+        .to = { FEAT_VMX_ENTRY_CTLS,        ~0ull },
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+    {
Pablo Greco e6a3ae
+        .from = { FEAT_1_ECX,               CPUID_EXT_VMX },
Pablo Greco e6a3ae
+        .to = { FEAT_VMX_MISC,              ~0ull },
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+    {
Pablo Greco e6a3ae
+        .from = { FEAT_1_ECX,               CPUID_EXT_VMX },
Pablo Greco e6a3ae
+        .to = { FEAT_VMX_BASIC,             ~0ull },
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+    {
Pablo Greco e6a3ae
+        .from = { FEAT_8000_0001_EDX,       CPUID_EXT2_LM },
Pablo Greco e6a3ae
+        .to = { FEAT_VMX_ENTRY_CTLS,        VMX_VM_ENTRY_IA32E_MODE },
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+    {
Pablo Greco e6a3ae
+        .from = { FEAT_VMX_PROCBASED_CTLS,  VMX_CPU_BASED_ACTIVATE_SECONDARY_CONTROLS },
Pablo Greco e6a3ae
+        .to = { FEAT_VMX_SECONDARY_CTLS,    ~0ull },
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+    {
Pablo Greco e6a3ae
+        .from = { FEAT_XSAVE,               CPUID_XSAVE_XSAVES },
Pablo Greco e6a3ae
+        .to = { FEAT_VMX_SECONDARY_CTLS,    VMX_SECONDARY_EXEC_XSAVES },
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+    {
Pablo Greco e6a3ae
+        .from = { FEAT_1_ECX,               CPUID_EXT_RDRAND },
Pablo Greco e6a3ae
+        .to = { FEAT_VMX_SECONDARY_CTLS,    VMX_SECONDARY_EXEC_RDRAND_EXITING },
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+    {
Pablo Greco e6a3ae
+        .from = { FEAT_7_0_EBX,             CPUID_7_0_EBX_INVPCID },
Pablo Greco e6a3ae
+        .to = { FEAT_VMX_SECONDARY_CTLS,    VMX_SECONDARY_EXEC_ENABLE_INVPCID },
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+    {
Pablo Greco e6a3ae
+        .from = { FEAT_7_0_EBX,             CPUID_7_0_EBX_RDSEED },
Pablo Greco e6a3ae
+        .to = { FEAT_VMX_SECONDARY_CTLS,    VMX_SECONDARY_EXEC_RDSEED_EXITING },
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+    {
Pablo Greco e6a3ae
+        .from = { FEAT_8000_0001_EDX,       CPUID_EXT2_RDTSCP },
Pablo Greco e6a3ae
+        .to = { FEAT_VMX_SECONDARY_CTLS,    VMX_SECONDARY_EXEC_RDTSCP },
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+    {
Pablo Greco e6a3ae
+        .from = { FEAT_VMX_SECONDARY_CTLS,  VMX_SECONDARY_EXEC_ENABLE_EPT },
Pablo Greco e6a3ae
+        .to = { FEAT_VMX_EPT_VPID_CAPS,     0xffffffffull },
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+    {
Pablo Greco e6a3ae
+        .from = { FEAT_VMX_SECONDARY_CTLS,  VMX_SECONDARY_EXEC_ENABLE_EPT },
Pablo Greco e6a3ae
+        .to = { FEAT_VMX_SECONDARY_CTLS,    VMX_SECONDARY_EXEC_UNRESTRICTED_GUEST },
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+    {
Pablo Greco e6a3ae
+        .from = { FEAT_VMX_SECONDARY_CTLS,  VMX_SECONDARY_EXEC_ENABLE_VPID },
Pablo Greco e6a3ae
+        .to = { FEAT_VMX_EPT_VPID_CAPS,     0xffffffffull << 32 },
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
+    {
Pablo Greco e6a3ae
+        .from = { FEAT_VMX_SECONDARY_CTLS,  VMX_SECONDARY_EXEC_ENABLE_VMFUNC },
Pablo Greco e6a3ae
+        .to = { FEAT_VMX_VMFUNC,            ~0ull },
Pablo Greco e6a3ae
+    },
Pablo Greco e6a3ae
 };
Pablo Greco e6a3ae
 
Pablo Greco e6a3ae
 typedef struct X86RegisterInfo32 {
Pablo Greco e6a3ae
diff --git a/target/i386/cpu.h b/target/i386/cpu.h
Pablo Greco e6a3ae
index 2d1f247..386e821 100644
Pablo Greco e6a3ae
--- a/target/i386/cpu.h
Pablo Greco e6a3ae
+++ b/target/i386/cpu.h
Pablo Greco e6a3ae
@@ -522,6 +522,15 @@ typedef enum FeatureWord {
Pablo Greco e6a3ae
     FEAT_XSAVE_COMP_HI, /* CPUID[EAX=0xd,ECX=0].EDX */
Pablo Greco e6a3ae
     FEAT_ARCH_CAPABILITIES,
Pablo Greco e6a3ae
     FEAT_CORE_CAPABILITY,
Pablo Greco e6a3ae
+    FEAT_VMX_PROCBASED_CTLS,
Pablo Greco e6a3ae
+    FEAT_VMX_SECONDARY_CTLS,
Pablo Greco e6a3ae
+    FEAT_VMX_PINBASED_CTLS,
Pablo Greco e6a3ae
+    FEAT_VMX_EXIT_CTLS,
Pablo Greco e6a3ae
+    FEAT_VMX_ENTRY_CTLS,
Pablo Greco e6a3ae
+    FEAT_VMX_MISC,
Pablo Greco e6a3ae
+    FEAT_VMX_EPT_VPID_CAPS,
Pablo Greco e6a3ae
+    FEAT_VMX_BASIC,
Pablo Greco e6a3ae
+    FEAT_VMX_VMFUNC,
Pablo Greco e6a3ae
     FEATURE_WORDS,
Pablo Greco e6a3ae
 } FeatureWord;
Pablo Greco e6a3ae
 
Pablo Greco e6a3ae
diff --git a/target/i386/kvm.c b/target/i386/kvm.c
Pablo Greco e6a3ae
index 85abd37..512d7d5 100644
Pablo Greco e6a3ae
--- a/target/i386/kvm.c
Pablo Greco e6a3ae
+++ b/target/i386/kvm.c
Pablo Greco e6a3ae
@@ -96,6 +96,7 @@ static bool has_msr_virt_ssbd;
Pablo Greco e6a3ae
 static bool has_msr_smi_count;
Pablo Greco e6a3ae
 static bool has_msr_arch_capabs;
Pablo Greco e6a3ae
 static bool has_msr_core_capabs;
Pablo Greco e6a3ae
+static bool has_msr_vmx_vmfunc;
Pablo Greco e6a3ae
 
Pablo Greco e6a3ae
 static uint32_t has_architectural_pmu_version;
Pablo Greco e6a3ae
 static uint32_t num_architectural_pmu_gp_counters;
Pablo Greco e6a3ae
@@ -429,7 +430,8 @@ uint64_t kvm_arch_get_supported_msr_feature(KVMState *s, uint32_t index)
Pablo Greco e6a3ae
         struct kvm_msrs info;
Pablo Greco e6a3ae
         struct kvm_msr_entry entries[1];
Pablo Greco e6a3ae
     } msr_data;
Pablo Greco e6a3ae
-    uint32_t ret;
Pablo Greco e6a3ae
+    uint64_t value;
Pablo Greco e6a3ae
+    uint32_t ret, can_be_one, must_be_one;
Pablo Greco e6a3ae
 
Pablo Greco e6a3ae
     if (kvm_feature_msrs == NULL) { /* Host doesn't support feature MSRs */
Pablo Greco e6a3ae
         return 0;
Pablo Greco e6a3ae
@@ -455,7 +457,25 @@ uint64_t kvm_arch_get_supported_msr_feature(KVMState *s, uint32_t index)
Pablo Greco e6a3ae
         exit(1);
Pablo Greco e6a3ae
     }
Pablo Greco e6a3ae
 
Pablo Greco e6a3ae
-    return msr_data.entries[0].data;
Pablo Greco e6a3ae
+    value = msr_data.entries[0].data;
Pablo Greco e6a3ae
+    switch (index) {
Pablo Greco e6a3ae
+    case MSR_IA32_VMX_PROCBASED_CTLS2:
Pablo Greco e6a3ae
+    case MSR_IA32_VMX_TRUE_PINBASED_CTLS:
Pablo Greco e6a3ae
+    case MSR_IA32_VMX_TRUE_PROCBASED_CTLS:
Pablo Greco e6a3ae
+    case MSR_IA32_VMX_TRUE_ENTRY_CTLS:
Pablo Greco e6a3ae
+    case MSR_IA32_VMX_TRUE_EXIT_CTLS:
Pablo Greco e6a3ae
+        /*
Pablo Greco e6a3ae
+         * Return true for bits that can be one, but do not have to be one.
Pablo Greco e6a3ae
+         * The SDM tells us which bits could have a "must be one" setting,
Pablo Greco e6a3ae
+         * so we can do the opposite transformation in make_vmx_msr_value.
Pablo Greco e6a3ae
+         */
Pablo Greco e6a3ae
+        must_be_one = (uint32_t)value;
Pablo Greco e6a3ae
+        can_be_one = (uint32_t)(value >> 32);
Pablo Greco e6a3ae
+        return can_be_one & ~must_be_one;
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+    default:
Pablo Greco e6a3ae
+        return value;
Pablo Greco e6a3ae
+    }
Pablo Greco e6a3ae
 }
Pablo Greco e6a3ae
 
Pablo Greco e6a3ae
 
Pablo Greco e6a3ae
@@ -1430,6 +1450,9 @@ static int kvm_get_supported_msrs(KVMState *s)
Pablo Greco e6a3ae
             case MSR_IA32_CORE_CAPABILITY:
Pablo Greco e6a3ae
                 has_msr_core_capabs = true;
Pablo Greco e6a3ae
                 break;
Pablo Greco e6a3ae
+            case MSR_IA32_VMX_VMFUNC:
Pablo Greco e6a3ae
+                has_msr_vmx_vmfunc = true;
Pablo Greco e6a3ae
+                break;
Pablo Greco e6a3ae
             }
Pablo Greco e6a3ae
         }
Pablo Greco e6a3ae
     }
Pablo Greco e6a3ae
@@ -1886,6 +1909,132 @@ static int kvm_put_msr_feature_control(X86CPU *cpu)
Pablo Greco e6a3ae
     return 0;
Pablo Greco e6a3ae
 }
Pablo Greco e6a3ae
 
Pablo Greco e6a3ae
+static uint64_t make_vmx_msr_value(uint32_t index, uint32_t features)
Pablo Greco e6a3ae
+{
Pablo Greco e6a3ae
+    uint32_t default1, can_be_one, can_be_zero;
Pablo Greco e6a3ae
+    uint32_t must_be_one;
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+    switch (index) {
Pablo Greco e6a3ae
+    case MSR_IA32_VMX_TRUE_PINBASED_CTLS:
Pablo Greco e6a3ae
+        default1 = 0x00000016;
Pablo Greco e6a3ae
+        break;
Pablo Greco e6a3ae
+    case MSR_IA32_VMX_TRUE_PROCBASED_CTLS:
Pablo Greco e6a3ae
+        default1 = 0x0401e172;
Pablo Greco e6a3ae
+        break;
Pablo Greco e6a3ae
+    case MSR_IA32_VMX_TRUE_ENTRY_CTLS:
Pablo Greco e6a3ae
+        default1 = 0x000011ff;
Pablo Greco e6a3ae
+        break;
Pablo Greco e6a3ae
+    case MSR_IA32_VMX_TRUE_EXIT_CTLS:
Pablo Greco e6a3ae
+        default1 = 0x00036dff;
Pablo Greco e6a3ae
+        break;
Pablo Greco e6a3ae
+    case MSR_IA32_VMX_PROCBASED_CTLS2:
Pablo Greco e6a3ae
+        default1 = 0;
Pablo Greco e6a3ae
+        break;
Pablo Greco e6a3ae
+    default:
Pablo Greco e6a3ae
+        abort();
Pablo Greco e6a3ae
+    }
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+    /* If a feature bit is set, the control can be either set or clear.
Pablo Greco e6a3ae
+     * Otherwise the value is limited to either 0 or 1 by default1.
Pablo Greco e6a3ae
+     */
Pablo Greco e6a3ae
+    can_be_one = features | default1;
Pablo Greco e6a3ae
+    can_be_zero = features | ~default1;
Pablo Greco e6a3ae
+    must_be_one = ~can_be_zero;
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+    /*
Pablo Greco e6a3ae
+     * Bit 0:31 -> 0 if the control bit can be zero (i.e. 1 if it must be one).
Pablo Greco e6a3ae
+     * Bit 32:63 -> 1 if the control bit can be one.
Pablo Greco e6a3ae
+     */
Pablo Greco e6a3ae
+    return must_be_one | (((uint64_t)can_be_one) << 32);
Pablo Greco e6a3ae
+}
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+#define VMCS12_MAX_FIELD_INDEX (0x17)
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+static void kvm_msr_entry_add_vmx(X86CPU *cpu, FeatureWordArray f)
Pablo Greco e6a3ae
+{
Pablo Greco e6a3ae
+    uint64_t kvm_vmx_basic =
Pablo Greco e6a3ae
+        kvm_arch_get_supported_msr_feature(kvm_state,
Pablo Greco e6a3ae
+                                           MSR_IA32_VMX_BASIC);
Pablo Greco e6a3ae
+    uint64_t kvm_vmx_misc =
Pablo Greco e6a3ae
+        kvm_arch_get_supported_msr_feature(kvm_state,
Pablo Greco e6a3ae
+                                           MSR_IA32_VMX_MISC);
Pablo Greco e6a3ae
+    uint64_t kvm_vmx_ept_vpid =
Pablo Greco e6a3ae
+        kvm_arch_get_supported_msr_feature(kvm_state,
Pablo Greco e6a3ae
+                                           MSR_IA32_VMX_EPT_VPID_CAP);
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+    /*
Pablo Greco e6a3ae
+     * If the guest is 64-bit, a value of 1 is allowed for the host address
Pablo Greco e6a3ae
+     * space size vmexit control.
Pablo Greco e6a3ae
+     */
Pablo Greco e6a3ae
+    uint64_t fixed_vmx_exit = f[FEAT_8000_0001_EDX] & CPUID_EXT2_LM
Pablo Greco e6a3ae
+        ? (uint64_t)VMX_VM_EXIT_HOST_ADDR_SPACE_SIZE << 32 : 0;
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+    /*
Pablo Greco e6a3ae
+     * Bits 0-30, 32-44 and 50-53 come from the host.  KVM should
Pablo Greco e6a3ae
+     * not change them for backwards compatibility.
Pablo Greco e6a3ae
+     */
Pablo Greco e6a3ae
+    uint64_t fixed_vmx_basic = kvm_vmx_basic &
Pablo Greco e6a3ae
+        (MSR_VMX_BASIC_VMCS_REVISION_MASK |
Pablo Greco e6a3ae
+         MSR_VMX_BASIC_VMXON_REGION_SIZE_MASK |
Pablo Greco e6a3ae
+         MSR_VMX_BASIC_VMCS_MEM_TYPE_MASK);
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+    /*
Pablo Greco e6a3ae
+     * Same for bits 0-4 and 25-27.  Bits 16-24 (CR3 target count) can
Pablo Greco e6a3ae
+     * change in the future but are always zero for now, clear them to be
Pablo Greco e6a3ae
+     * future proof.  Bits 32-63 in theory could change, though KVM does
Pablo Greco e6a3ae
+     * not support dual-monitor treatment and probably never will; mask
Pablo Greco e6a3ae
+     * them out as well.
Pablo Greco e6a3ae
+     */
Pablo Greco e6a3ae
+    uint64_t fixed_vmx_misc = kvm_vmx_misc &
Pablo Greco e6a3ae
+        (MSR_VMX_MISC_PREEMPTION_TIMER_SHIFT_MASK |
Pablo Greco e6a3ae
+         MSR_VMX_MISC_MAX_MSR_LIST_SIZE_MASK);
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+    /*
Pablo Greco e6a3ae
+     * EPT memory types should not change either, so we do not bother
Pablo Greco e6a3ae
+     * adding features for them.
Pablo Greco e6a3ae
+     */
Pablo Greco e6a3ae
+    uint64_t fixed_vmx_ept_mask =
Pablo Greco e6a3ae
+            (f[FEAT_VMX_SECONDARY_CTLS] & VMX_SECONDARY_EXEC_ENABLE_EPT ?
Pablo Greco e6a3ae
+             MSR_VMX_EPT_UC | MSR_VMX_EPT_WB : 0);
Pablo Greco e6a3ae
+    uint64_t fixed_vmx_ept_vpid = kvm_vmx_ept_vpid & fixed_vmx_ept_mask;
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+    kvm_msr_entry_add(cpu, MSR_IA32_VMX_TRUE_PROCBASED_CTLS,
Pablo Greco e6a3ae
+                      make_vmx_msr_value(MSR_IA32_VMX_TRUE_PROCBASED_CTLS,
Pablo Greco e6a3ae
+                                         f[FEAT_VMX_PROCBASED_CTLS]));
Pablo Greco e6a3ae
+    kvm_msr_entry_add(cpu, MSR_IA32_VMX_TRUE_PINBASED_CTLS,
Pablo Greco e6a3ae
+                      make_vmx_msr_value(MSR_IA32_VMX_TRUE_PINBASED_CTLS,
Pablo Greco e6a3ae
+                                         f[FEAT_VMX_PINBASED_CTLS]));
Pablo Greco e6a3ae
+    kvm_msr_entry_add(cpu, MSR_IA32_VMX_TRUE_EXIT_CTLS,
Pablo Greco e6a3ae
+                      make_vmx_msr_value(MSR_IA32_VMX_TRUE_EXIT_CTLS,
Pablo Greco e6a3ae
+                                         f[FEAT_VMX_EXIT_CTLS]) | fixed_vmx_exit);
Pablo Greco e6a3ae
+    kvm_msr_entry_add(cpu, MSR_IA32_VMX_TRUE_ENTRY_CTLS,
Pablo Greco e6a3ae
+                      make_vmx_msr_value(MSR_IA32_VMX_TRUE_ENTRY_CTLS,
Pablo Greco e6a3ae
+                                         f[FEAT_VMX_ENTRY_CTLS]));
Pablo Greco e6a3ae
+    kvm_msr_entry_add(cpu, MSR_IA32_VMX_PROCBASED_CTLS2,
Pablo Greco e6a3ae
+                      make_vmx_msr_value(MSR_IA32_VMX_PROCBASED_CTLS2,
Pablo Greco e6a3ae
+                                         f[FEAT_VMX_SECONDARY_CTLS]));
Pablo Greco e6a3ae
+    kvm_msr_entry_add(cpu, MSR_IA32_VMX_EPT_VPID_CAP,
Pablo Greco e6a3ae
+                      f[FEAT_VMX_EPT_VPID_CAPS] | fixed_vmx_ept_vpid);
Pablo Greco e6a3ae
+    kvm_msr_entry_add(cpu, MSR_IA32_VMX_BASIC,
Pablo Greco e6a3ae
+                      f[FEAT_VMX_BASIC] | fixed_vmx_basic);
Pablo Greco e6a3ae
+    kvm_msr_entry_add(cpu, MSR_IA32_VMX_MISC,
Pablo Greco e6a3ae
+                      f[FEAT_VMX_MISC] | fixed_vmx_misc);
Pablo Greco e6a3ae
+    if (has_msr_vmx_vmfunc) {
Pablo Greco e6a3ae
+        kvm_msr_entry_add(cpu, MSR_IA32_VMX_VMFUNC, f[FEAT_VMX_VMFUNC]);
Pablo Greco e6a3ae
+    }
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+    /*
Pablo Greco e6a3ae
+     * Just to be safe, write these with constant values.  The CRn_FIXED1
Pablo Greco e6a3ae
+     * MSRs are generated by KVM based on the vCPU's CPUID.
Pablo Greco e6a3ae
+     */
Pablo Greco e6a3ae
+    kvm_msr_entry_add(cpu, MSR_IA32_VMX_CR0_FIXED0,
Pablo Greco e6a3ae
+                      CR0_PE_MASK | CR0_PG_MASK | CR0_NE_MASK);
Pablo Greco e6a3ae
+    kvm_msr_entry_add(cpu, MSR_IA32_VMX_CR4_FIXED0,
Pablo Greco e6a3ae
+                      CR4_VMXE_MASK);
Pablo Greco e6a3ae
+    kvm_msr_entry_add(cpu, MSR_IA32_VMX_VMCS_ENUM,
Pablo Greco e6a3ae
+                      VMCS12_MAX_FIELD_INDEX << 1);
Pablo Greco e6a3ae
+}
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
 static int kvm_put_msrs(X86CPU *cpu, int level)
Pablo Greco e6a3ae
 {
Pablo Greco e6a3ae
     CPUX86State *env = &cpu->env;
Pablo Greco e6a3ae
@@ -2112,7 +2261,16 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
Pablo Greco e6a3ae
 
Pablo Greco e6a3ae
         /* Note: MSR_IA32_FEATURE_CONTROL is written separately, see
Pablo Greco e6a3ae
          *       kvm_put_msr_feature_control. */
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
+        /*
Pablo Greco e6a3ae
+         * Older kernels do not include VMX MSRs in KVM_GET_MSR_INDEX_LIST, but
Pablo Greco e6a3ae
+         * all kernels with MSR features should have them.
Pablo Greco e6a3ae
+         */
Pablo Greco e6a3ae
+        if (kvm_feature_msrs && cpu_has_vmx(env)) {
Pablo Greco e6a3ae
+            kvm_msr_entry_add_vmx(cpu, env->features);
Pablo Greco e6a3ae
+        }
Pablo Greco e6a3ae
     }
Pablo Greco e6a3ae
+
Pablo Greco e6a3ae
     if (env->mcg_cap) {
Pablo Greco e6a3ae
         int i;
Pablo Greco e6a3ae
 
Pablo Greco e6a3ae
-- 
Pablo Greco e6a3ae
1.8.3.1
Pablo Greco e6a3ae