[PATCH v3 2/5] KVM: nVMX: support restore of VMX capability MSRs

2016-11-29 Thread David Matlack
The VMX capability MSRs advertise the set of features the KVM virtual
CPU can support. This set of features varies across different host CPUs
and KVM versions. This patch aims to addresses both sources of
differences, allowing VMs to be migrated across CPUs and KVM versions
without guest-visible changes to these MSRs. Note that cross-KVM-
version migration is only supported from this point forward.

When the VMX capability MSRs are restored, they are audited to check
that the set of features advertised are a subset of what KVM and the
CPU support.

Since the VMX capability MSRs are read-only, they do not need to be on
the default MSR save/restore lists. The userspace hypervisor can set
the values of these MSRs or read them from KVM at VCPU creation time,
and restore the same value after every save/restore.

Signed-off-by: David Matlack 
---
 arch/x86/include/asm/vmx.h |  31 +
 arch/x86/kvm/vmx.c | 290 +
 2 files changed, 297 insertions(+), 24 deletions(-)

diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index a002b07..a4ca897 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -25,6 +25,7 @@
 #define VMX_H
 
 
+#include 
 #include 
 #include 
 
@@ -110,6 +111,36 @@
 #define VMX_MISC_SAVE_EFER_LMA 0x0020
 #define VMX_MISC_ACTIVITY_HLT  0x0040
 
+static inline u32 vmx_basic_vmcs_revision_id(u64 vmx_basic)
+{
+   return vmx_basic & GENMASK_ULL(30, 0);
+}
+
+static inline u32 vmx_basic_vmcs_size(u64 vmx_basic)
+{
+   return (vmx_basic & GENMASK_ULL(44, 32)) >> 32;
+}
+
+static inline int vmx_misc_preemption_timer_rate(u64 vmx_misc)
+{
+   return vmx_misc & VMX_MISC_PREEMPTION_TIMER_RATE_MASK;
+}
+
+static inline int vmx_misc_cr3_count(u64 vmx_misc)
+{
+   return (vmx_misc & GENMASK_ULL(24, 16)) >> 16;
+}
+
+static inline int vmx_misc_max_msr(u64 vmx_misc)
+{
+   return (vmx_misc & GENMASK_ULL(27, 25)) >> 25;
+}
+
+static inline int vmx_misc_mseg_revid(u64 vmx_misc)
+{
+   return (vmx_misc & GENMASK_ULL(63, 32)) >> 32;
+}
+
 /* VMCS Encodings */
 enum vmcs_field {
VIRTUAL_PROCESSOR_ID= 0x,
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 0beb56a..01a2b9e 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -465,6 +465,12 @@ struct nested_vmx {
u32 nested_vmx_misc_high;
u32 nested_vmx_ept_caps;
u32 nested_vmx_vpid_caps;
+   u64 nested_vmx_basic;
+   u64 nested_vmx_cr0_fixed0;
+   u64 nested_vmx_cr0_fixed1;
+   u64 nested_vmx_cr4_fixed0;
+   u64 nested_vmx_cr4_fixed1;
+   u64 nested_vmx_vmcs_enum;
 };
 
 #define POSTED_INTR_ON  0
@@ -2826,6 +2832,36 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx 
*vmx)
VMX_MISC_EMULATED_PREEMPTION_TIMER_RATE |
VMX_MISC_ACTIVITY_HLT;
vmx->nested.nested_vmx_misc_high = 0;
+
+   /*
+* This MSR reports some information about VMX support. We
+* should return information about the VMX we emulate for the
+* guest, and the VMCS structure we give it - not about the
+* VMX support of the underlying hardware.
+*/
+   vmx->nested.nested_vmx_basic =
+   VMCS12_REVISION |
+   VMX_BASIC_TRUE_CTLS |
+   ((u64)VMCS12_SIZE << VMX_BASIC_VMCS_SIZE_SHIFT) |
+   (VMX_BASIC_MEM_TYPE_WB << VMX_BASIC_MEM_TYPE_SHIFT);
+
+   if (cpu_has_vmx_basic_inout())
+   vmx->nested.nested_vmx_basic |= VMX_BASIC_INOUT;
+
+   /*
+* These MSRs specify bits which the guest must keep fixed (on or off)
+* while L1 is in VMXON mode (in L1's root mode, or running an L2).
+* We picked the standard core2 setting.
+*/
+#define VMXON_CR0_ALWAYSON (X86_CR0_PE | X86_CR0_PG | X86_CR0_NE)
+#define VMXON_CR4_ALWAYSON X86_CR4_VMXE
+   vmx->nested.nested_vmx_cr0_fixed0 = VMXON_CR0_ALWAYSON;
+   vmx->nested.nested_vmx_cr0_fixed1 = -1ULL;
+   vmx->nested.nested_vmx_cr4_fixed0 = VMXON_CR4_ALWAYSON;
+   vmx->nested.nested_vmx_cr4_fixed1 = -1ULL;
+
+   /* highest index: VMX_PREEMPTION_TIMER_VALUE */
+   vmx->nested.nested_vmx_vmcs_enum = 0x2e;
 }
 
 static inline bool vmx_control_verify(u32 control, u32 low, u32 high)
@@ -2841,24 +2877,233 @@ static inline u64 vmx_control_msr(u32 low, u32 high)
return low | ((u64)high << 32);
 }
 
-/* Returns 0 on success, non-0 otherwise. */
-static int vmx_get_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
+static bool is_bitwise_subset(u64 superset, u64 subset, u64 mask)
+{
+   superset &= mask;
+   subset &= mask;
+
+   return (superset | subset) == superset;
+}
+
+static int vmx_restore_vmx_basic(struct vcpu_vmx *vmx, u64 data)
+{
+   const u64 feature_and_reserved =
+   /* feature (except bit 48; see below) */
+   BIT_ULL(49) | BIT_ULL(54) | 

[PATCH v3 2/5] KVM: nVMX: support restore of VMX capability MSRs

2016-11-29 Thread David Matlack
The VMX capability MSRs advertise the set of features the KVM virtual
CPU can support. This set of features varies across different host CPUs
and KVM versions. This patch aims to addresses both sources of
differences, allowing VMs to be migrated across CPUs and KVM versions
without guest-visible changes to these MSRs. Note that cross-KVM-
version migration is only supported from this point forward.

When the VMX capability MSRs are restored, they are audited to check
that the set of features advertised are a subset of what KVM and the
CPU support.

Since the VMX capability MSRs are read-only, they do not need to be on
the default MSR save/restore lists. The userspace hypervisor can set
the values of these MSRs or read them from KVM at VCPU creation time,
and restore the same value after every save/restore.

Signed-off-by: David Matlack 
---
 arch/x86/include/asm/vmx.h |  31 +
 arch/x86/kvm/vmx.c | 290 +
 2 files changed, 297 insertions(+), 24 deletions(-)

diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index a002b07..a4ca897 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -25,6 +25,7 @@
 #define VMX_H
 
 
+#include 
 #include 
 #include 
 
@@ -110,6 +111,36 @@
 #define VMX_MISC_SAVE_EFER_LMA 0x0020
 #define VMX_MISC_ACTIVITY_HLT  0x0040
 
+static inline u32 vmx_basic_vmcs_revision_id(u64 vmx_basic)
+{
+   return vmx_basic & GENMASK_ULL(30, 0);
+}
+
+static inline u32 vmx_basic_vmcs_size(u64 vmx_basic)
+{
+   return (vmx_basic & GENMASK_ULL(44, 32)) >> 32;
+}
+
+static inline int vmx_misc_preemption_timer_rate(u64 vmx_misc)
+{
+   return vmx_misc & VMX_MISC_PREEMPTION_TIMER_RATE_MASK;
+}
+
+static inline int vmx_misc_cr3_count(u64 vmx_misc)
+{
+   return (vmx_misc & GENMASK_ULL(24, 16)) >> 16;
+}
+
+static inline int vmx_misc_max_msr(u64 vmx_misc)
+{
+   return (vmx_misc & GENMASK_ULL(27, 25)) >> 25;
+}
+
+static inline int vmx_misc_mseg_revid(u64 vmx_misc)
+{
+   return (vmx_misc & GENMASK_ULL(63, 32)) >> 32;
+}
+
 /* VMCS Encodings */
 enum vmcs_field {
VIRTUAL_PROCESSOR_ID= 0x,
diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index 0beb56a..01a2b9e 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -465,6 +465,12 @@ struct nested_vmx {
u32 nested_vmx_misc_high;
u32 nested_vmx_ept_caps;
u32 nested_vmx_vpid_caps;
+   u64 nested_vmx_basic;
+   u64 nested_vmx_cr0_fixed0;
+   u64 nested_vmx_cr0_fixed1;
+   u64 nested_vmx_cr4_fixed0;
+   u64 nested_vmx_cr4_fixed1;
+   u64 nested_vmx_vmcs_enum;
 };
 
 #define POSTED_INTR_ON  0
@@ -2826,6 +2832,36 @@ static void nested_vmx_setup_ctls_msrs(struct vcpu_vmx 
*vmx)
VMX_MISC_EMULATED_PREEMPTION_TIMER_RATE |
VMX_MISC_ACTIVITY_HLT;
vmx->nested.nested_vmx_misc_high = 0;
+
+   /*
+* This MSR reports some information about VMX support. We
+* should return information about the VMX we emulate for the
+* guest, and the VMCS structure we give it - not about the
+* VMX support of the underlying hardware.
+*/
+   vmx->nested.nested_vmx_basic =
+   VMCS12_REVISION |
+   VMX_BASIC_TRUE_CTLS |
+   ((u64)VMCS12_SIZE << VMX_BASIC_VMCS_SIZE_SHIFT) |
+   (VMX_BASIC_MEM_TYPE_WB << VMX_BASIC_MEM_TYPE_SHIFT);
+
+   if (cpu_has_vmx_basic_inout())
+   vmx->nested.nested_vmx_basic |= VMX_BASIC_INOUT;
+
+   /*
+* These MSRs specify bits which the guest must keep fixed (on or off)
+* while L1 is in VMXON mode (in L1's root mode, or running an L2).
+* We picked the standard core2 setting.
+*/
+#define VMXON_CR0_ALWAYSON (X86_CR0_PE | X86_CR0_PG | X86_CR0_NE)
+#define VMXON_CR4_ALWAYSON X86_CR4_VMXE
+   vmx->nested.nested_vmx_cr0_fixed0 = VMXON_CR0_ALWAYSON;
+   vmx->nested.nested_vmx_cr0_fixed1 = -1ULL;
+   vmx->nested.nested_vmx_cr4_fixed0 = VMXON_CR4_ALWAYSON;
+   vmx->nested.nested_vmx_cr4_fixed1 = -1ULL;
+
+   /* highest index: VMX_PREEMPTION_TIMER_VALUE */
+   vmx->nested.nested_vmx_vmcs_enum = 0x2e;
 }
 
 static inline bool vmx_control_verify(u32 control, u32 low, u32 high)
@@ -2841,24 +2877,233 @@ static inline u64 vmx_control_msr(u32 low, u32 high)
return low | ((u64)high << 32);
 }
 
-/* Returns 0 on success, non-0 otherwise. */
-static int vmx_get_vmx_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
+static bool is_bitwise_subset(u64 superset, u64 subset, u64 mask)
+{
+   superset &= mask;
+   subset &= mask;
+
+   return (superset | subset) == superset;
+}
+
+static int vmx_restore_vmx_basic(struct vcpu_vmx *vmx, u64 data)
+{
+   const u64 feature_and_reserved =
+   /* feature (except bit 48; see below) */
+   BIT_ULL(49) | BIT_ULL(54) | BIT_ULL(55) |
+