# Commit d297b56682e730d598e2529cc6998151d3b6f6f8
# Date 2018-01-26 14:10:21 +0000
# Author Andrew Cooper <andrew.cooper3@citrix.com>
# Committer Andrew Cooper <andrew.cooper3@citrix.com>
x86/cpuid: Handling of IBRS/IBPB, STIBP and IBRS for guests

Intel specifies IBRS/IBPB (combined, in a single bit) and STIBP as a separate
bit.  AMD specifies IBPB alone in a 3rd bit.

AMD's IBPB is a subset of Intel's combined IBRS/IBPB.  For performance
reasons, administrators might wish to express "IBPB only" even on Intel
hardware, so we allow the AMD bit to be used for this purpose.

The behaviour of STIBP is more complicated.

It is our current understanding that STIBP will be advertised on HT-capable
hardware irrespective of whether HT is enabled, but not advertised on
HT-incapable hardware.  However, for ease of virtualisation, STIBP's
functionality is ignored rather than reserved by microcode/hardware on
HT-incapable hardware.

For guest safety, we treat STIBP as special, always override the toolstack
choice, and always advertise STIBP if IBRS is available.  This removes the
corner case where STIBP is not advertised, but the guest is running on
HT-capable hardware where it does matter.

Finally as a bugfix, update the libxc CPUID logic to understand the e8b
feature leaf, which has the side effect of also offering CLZERO to guests on
applicable hardware.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-by: Wei Liu <wei.liu2@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>

--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -1897,6 +1897,8 @@ void hvm_cpuid(unsigned int input, unsig
 
     switch ( input )
     {
+        unsigned int _eax, _ebx, _ecx, _edx;
+
     case 0x1:
         /* Fix up VLAPIC details. */
         *ebx &= 0x00FFFFFFu;
@@ -1914,6 +1916,23 @@ void hvm_cpuid(unsigned int input, unsig
                      bitmaskof(X86_FEATURE_OSXSAVE) : 0;
         }
         break;
+
+    case 0x7:
+        if ( count == 0 )
+        {
+            /*
+             * Override STIBP to match IBRS.  Guests can safely use STIBP
+             * functionality on non-HT hardware, but can't necesserily protect
+             * themselves from SP2/Spectre/Branch Target Injection if STIBP is
+             * hidden on HT-capable hardware.
+             */
+            if ( *edx & cpufeat_mask(X86_FEATURE_IBRSB) )
+                *edx |= cpufeat_mask(X86_FEATURE_STIBP);
+            else
+                *edx &= ~cpufeat_mask(X86_FEATURE_STIBP);
+        }
+        break;
+
     case 0xb:
         /* Fix the x2APIC identifier. */
         *edx = v->vcpu_id * 2;
@@ -1957,6 +1976,14 @@ void hvm_cpuid(unsigned int input, unsig
              !host_tsc_is_safe() )
             *edx &= ~bitmaskof(X86_FEATURE_RDTSCP);
         break;
+
+    case 0x80000008:
+        /* AMD's IBPB is a subset of IBRS/IBPB. */
+        _ecx = 0;
+        hvm_cpuid(7, &_eax, &_ebx, &_ecx, &_edx);
+        if ( _ebx & cpufeat_mask(X86_FEATURE_IBRSB) )
+            *ebx |= cpufeat_mask(X86_FEATURE_IBPB);
+        break;
     }
 }
 
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -751,6 +751,34 @@ static void pv_cpuid(struct cpu_user_reg
     {
         if ( !cpuid_hypervisor_leaves(a, c, &a, &b, &c, &d) )
             domain_cpuid(current->domain, a, c, &a, &b, &c, &d);
+
+        switch ( (uint32_t)regs->eax )
+        {
+            unsigned int _eax, _ebx, _ecx, _edx;
+
+        case 0x00000007:
+            if ( (uint32_t)regs->ecx == 0 )
+            {
+                /*
+                 * Override STIBP to match IBRS.  Guests can safely use STIBP
+                 * functionality on non-HT hardware, but can't necesserily protect
+                 * themselves from SP2/Spectre/Branch Target Injection if STIBP is
+                 * hidden on HT-capable hardware.
+                 */
+                if ( d & cpufeat_mask(X86_FEATURE_IBRSB) )
+                    d |= cpufeat_mask(X86_FEATURE_STIBP);
+                else
+                    d &= ~cpufeat_mask(X86_FEATURE_STIBP);
+            }
+            break;
+
+        case 0x80000008:
+            /* AMD's IBPB is a subset of IBRS/IBPB. */
+            domain_cpuid(current->domain, 7, 0, &_eax, &_ebx, &_ecx, &_edx);
+            if ( _edx & cpufeat_mask(X86_FEATURE_IBRSB) )
+                b |= cpufeat_mask(X86_FEATURE_IBPB);
+            break;
+        }
         goto out;
     }
 
@@ -799,6 +827,23 @@ static void pv_cpuid(struct cpu_user_reg
            __clear_bit(X86_FEATURE_X2APIC % 32, &c);
         __set_bit(X86_FEATURE_HYPERVISOR % 32, &c);
         break;
+ 
+    case 0x00000007:
+        if ( (uint32_t)regs->ecx == 0 )
+        {
+            d &= cpufeat_mask(X86_FEATURE_IBRSB);
+
+            /* Override STIBP to match IBRS (see above). */
+            if ( d & cpufeat_mask(X86_FEATURE_IBRSB) )
+                d |= cpufeat_mask(X86_FEATURE_STIBP);
+            else
+                d &= ~cpufeat_mask(X86_FEATURE_STIBP);
+        }
+        else
+            d = 0;
+        a = b = c = 0;
+        break;
+
     case 0x80000001:
         /* Modify Feature Information. */
         if ( is_pv_32bit_vcpu(current) )
@@ -825,7 +870,13 @@ static void pv_cpuid(struct cpu_user_reg
         __clear_bit(X86_FEATURE_NODEID_MSR % 32, &c);
         __clear_bit(X86_FEATURE_TOPOEXT % 32, &c);
         break;
-    case 7:
+
+    case 0x80000008:
+        /* AMD's IBPB is a subset of IBRS/IBPB. */
+        if ( boot_cpu_has(X86_FEATURE_IBRSB) )
+            b |= cpufeat_mask(X86_FEATURE_IBPB);
+        break;
+
     case 0xd: /* XSAVE */
     case 5: /* MONITOR/MWAIT */
     case 0xa: /* Architectural Performance Monitor Features */
