From: Andrew Cooper <andrew.cooper3@citrix.com>
Subject: x86/spec-ctrl: Synthesise ITS_NO to guests on unaffected hardware

It is easier to express feature word 17 in terms of word 16 + [32, 64) as
that's how the layout is given in documentation.

This is part of XSA-469 / CVE-2024-28956

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>

--- a/xen/include/asm-x86/cpufeature.h
+++ b/xen/include/asm-x86/cpufeature.h
@@ -154,6 +154,7 @@
 #define cpu_has_gds_no          boot_cpu_has(X86_FEATURE_GDS_NO)
 #define cpu_has_rfds_no         boot_cpu_has(X86_FEATURE_RFDS_NO)
 #define cpu_has_rfds_clear      boot_cpu_has(X86_FEATURE_RFDS_CLEAR)
+#define cpu_has_its_no          boot_cpu_has(X86_FEATURE_ITS_NO)
 
 /* Synthesized. */
 #define cpu_has_arch_perfmon    boot_cpu_has(X86_FEATURE_ARCH_PERFMON)
--- a/xen/arch/x86/spec_ctrl.c
+++ b/xen/arch/x86/spec_ctrl.c
@@ -1694,6 +1694,90 @@ static void __init bhi_calculations(void
     }
 }
 
+/*
+ * https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/advisory-guidance/indirect-target-selection.html
+ */
+static void __init its_calculations(void)
+{
+    /*
+     * Indirect Target Selection is a Branch Prediction bug whereby certain
+     * indirect branches (including RETs) get predicted using a direct branch
+     * target, rather than a suitable indirect target, bypassing hardware
+     * isolation protections.
+     *
+     * ITS affects Core (but not Atom) processors starting from the
+     * introduction of eIBRS, up to but not including Golden Cove cores
+     * (checked here with BHI_CTRL).
+     *
+     * The ITS_NO feature is not expected to be enumerated by hardware, and is
+     * only for VMMs to synthesise for guests.
+     *
+     * ITS comes in 3 flavours:
+     *
+     *   1) Across-IBPB.  Indirect branches after the IBPB can be controlled
+     *      by direct targets which existed prior to the IBPB.  This is
+     *      addressed in the IPU 2025.1 microcode drop, and has no other
+     *      software interaction.
+     *
+     *   2) Guest/Host.  Indirect branches in the VMM can be controlled by
+     *      direct targets from the guest.  This applies equally to PV guests
+     *      (Ring3) and HVM guests (VMX), and applies to all Skylake-uarch
+     *      cores with eIBRS.
+     *
+     *   3) Intra-mode.  Indirect branches in the VMM can be controlled by
+     *      other execution in the same mode.
+     */
+
+    /*
+     * If we can see ITS_NO, or we're virtualised, do nothing.  We are or may
+     * migrate somewhere unsafe.
+     */
+    if ( cpu_has_its_no || cpu_has_hypervisor )
+        return;
+
+    /* ITS is only known to affect Intel processors at this time. */
+    if ( boot_cpu_data.x86_vendor != X86_VENDOR_INTEL )
+        return;
+
+    /*
+     * ITS does not exist on:
+     *  - non-Family 6 CPUs
+     *  - those without eIBRS
+     *  - those with BHI_CTRL
+     * but we still need to synthesise ITS_NO.
+     */
+    if ( boot_cpu_data.x86 != 6 || !cpu_has_eibrs ||
+         boot_cpu_has(X86_FEATURE_BHI_CTRL) )
+        goto synthesise;
+
+    switch ( boot_cpu_data.x86_model )
+    {
+        /* These Skylake-uarch cores suffer cases #2 and #3. */
+    case 0x55: /* Skylake X / Cascadelake X / Cooperlake X */
+    case 0x8e: /* Kabylake L / Amberlake L / Coffeelake L / Whiskeylake L */
+    case 0x9e: /* Kabylake / Coffeelake */
+    case 0xa5: /* Cometlake */
+    case 0xa6: /* Cometlake L */
+        return;
+
+        /* These Sunny/Willow/Cypress Cove cores suffer case #3. */
+    case 0x6a: /* Icelake X */
+    case 0x6c: /* Icelake D */
+    case 0x7e: /* Icelake L */
+    case 0x8c: /* Tigerlake L */
+    case 0x8d: /* Tigerlake */
+    case 0xa7: /* Rocketlake */
+        return;
+
+    default:
+        break;
+    }
+
+    /* Platforms remaining are not believed to be vulnerable to ITS. */
+ synthesise:
+    setup_force_cpu_cap(X86_FEATURE_ITS_NO);
+}
+
 void spec_ctrl_init_domain(struct domain *d)
 {
     bool pv = is_pv_domain(d);
@@ -2153,6 +2237,8 @@ void __init init_speculation_mitigations
 
     bhi_calculations();
 
+    its_calculations();
+
     print_details(thunk);
 
     /*
--- a/xen/include/public/arch-x86/cpufeatureset.h
+++ b/xen/include/public/arch-x86/cpufeatureset.h
@@ -328,7 +328,8 @@ XEN_CPUFEATURE(GDS_NO,             16*32
 XEN_CPUFEATURE(RFDS_NO,            16*32+27) /*A  No Register File Data Sampling */
 XEN_CPUFEATURE(RFDS_CLEAR,         16*32+28) /*!A Register File(s) cleared by VERW */
 
-/* Intel-defined CPU features, MSR_ARCH_CAPS 0x10a.edx, word 17 */
+/* Intel-defined CPU features, MSR_ARCH_CAPS 0x10a.edx, word 17 (express in terms of word 16) */
+XEN_CPUFEATURE(ITS_NO,             16*32+62) /*!A No Indirect Target Selection */
 
 #endif /* XEN_CPUFEATURE */
 
--- a/xen/tools/gen-cpuid.py
+++ b/xen/tools/gen-cpuid.py
@@ -48,7 +48,7 @@ def parse_definitions(state):
         "\s+/\*([\w!]*) .*$")
 
     word_regex = re.compile(
-        r"^/\* .* word (\d*) \*/$")
+        r"^/\* .* word (\d*) .*\*/$")
     last_word = -1
 
     this = sys.modules[__name__]
