KVM: x86: add support for emulating UMIP
authorPaolo Bonzini <pbonzini@redhat.com>
Tue, 12 Jul 2016 08:36:41 +0000 (10:36 +0200)
committerPaolo Bonzini <pbonzini@redhat.com>
Thu, 14 Dec 2017 08:26:39 +0000 (09:26 +0100)
The User-Mode Instruction Prevention feature present in recent Intel
processor prevents a group of instructions (sgdt, sidt, sldt, smsw, and
str) from being executed with CPL > 0. Otherwise, a general protection
fault is issued.

UMIP instructions in general are also able to trigger vmexits, so we can
actually emulate UMIP on older processors.  This commit sets up the
infrastructure so that kvm-intel.ko and kvm-amd.ko can set the UMIP
feature bit for CPUID even if the feature is not actually available
in hardware.

Reviewed-by: Wanpeng Li <wanpeng.li@hotmail.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/include/asm/kvm_host.h
arch/x86/kvm/cpuid.c
arch/x86/kvm/svm.c
arch/x86/kvm/vmx.c

index ff79134d1d71afa003403e976095e7c523f441c8..515db75081d13107bb18d9e87bc3e007702f22b9 100644 (file)
@@ -1017,6 +1017,7 @@ struct kvm_x86_ops {
        void (*handle_external_intr)(struct kvm_vcpu *vcpu);
        bool (*mpx_supported)(void);
        bool (*xsaves_supported)(void);
+       bool (*umip_emulated)(void);
 
        int (*check_nested_events)(struct kvm_vcpu *vcpu, bool external_intr);
 
index 77fb8732b47b30858be387db45413ac396e4385b..2b3b06458f6f67dd693cafc2c2dc202cfe94956a 100644 (file)
@@ -327,6 +327,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
        unsigned f_invpcid = kvm_x86_ops->invpcid_supported() ? F(INVPCID) : 0;
        unsigned f_mpx = kvm_mpx_supported() ? F(MPX) : 0;
        unsigned f_xsaves = kvm_x86_ops->xsaves_supported() ? F(XSAVES) : 0;
+       unsigned f_umip = kvm_x86_ops->umip_emulated() ? F(UMIP) : 0;
 
        /* cpuid 1.edx */
        const u32 kvm_cpuid_1_edx_x86_features =
@@ -473,6 +474,7 @@ static inline int __do_cpuid_ent(struct kvm_cpuid_entry2 *entry, u32 function,
                        entry->ebx |= F(TSC_ADJUST);
                        entry->ecx &= kvm_cpuid_7_0_ecx_x86_features;
                        cpuid_mask(&entry->ecx, CPUID_7_ECX);
+                       entry->ecx |= f_umip;
                        /* PKU is not yet implemented for shadow paging. */
                        if (!tdp_enabled || !boot_cpu_has(X86_FEATURE_OSPKE))
                                entry->ecx &= ~F(PKU);
index eb714f1cdf7eee4ca9036005c3ab72ef9228ae9b..1f3e7f210374a1d927e45d968fe747194d5298c3 100644 (file)
@@ -5204,6 +5204,11 @@ static bool svm_xsaves_supported(void)
        return false;
 }
 
+static bool svm_umip_emulated(void)
+{
+       return false;
+}
+
 static bool svm_has_wbinvd_exit(void)
 {
        return true;
@@ -5597,6 +5602,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
        .invpcid_supported = svm_invpcid_supported,
        .mpx_supported = svm_mpx_supported,
        .xsaves_supported = svm_xsaves_supported,
+       .umip_emulated = svm_umip_emulated,
 
        .set_supported_cpuid = svm_set_supported_cpuid,
 
index 8eba631c4dbd509d8687c6135e8dba267042f5e0..b989cfe412b13b6aaf656e34c7b3ce8fe394d94f 100644 (file)
@@ -9155,6 +9155,11 @@ static bool vmx_xsaves_supported(void)
                SECONDARY_EXEC_XSAVES;
 }
 
+static bool vmx_umip_emulated(void)
+{
+       return false;
+}
+
 static void vmx_recover_nmi_blocking(struct vcpu_vmx *vmx)
 {
        u32 exit_intr_info;
@@ -12170,6 +12175,7 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = {
        .handle_external_intr = vmx_handle_external_intr,
        .mpx_supported = vmx_mpx_supported,
        .xsaves_supported = vmx_xsaves_supported,
+       .umip_emulated = vmx_umip_emulated,
 
        .check_nested_events = vmx_check_nested_events,