Skip to main content

libarch/x86/
speculation.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use super::ArchCapabilitiesMsr;
6use super::cpuid::{EXTENDED_AMD_FEATURES_B, EXTENDED_FEATURES_D};
7use bitrs::layout;
8use regio::RwSafe;
9use regio::traits::ReadReg;
10use regio::x86::{Cpuid, Msr};
11
12/// Speculation control.
13///
14/// [intel/vol4]: Table 2-2.  IA-32 Architectural MSRs (Contd.).
15/// [amd/ibc]: PRESENCE.
16/// [amd/ssbd]: PRESENCE.
17pub const SPECULATION_CONTROL: Msr<0x0000_0048, SpeculationControlMsr, RwSafe> = Msr::new();
18
19layout!({
20    /// Layout for [`SPECULATION_CONTROL`].
21    pub struct SpeculationControlMsr(u64);
22    {
23        let __ @ 63..3;
24        let ssbd @ 2;
25        let stibp @ 1;
26        let ibrs @ 0;
27    }
28});
29
30impl SpeculationControlMsr {
31    pub fn is_supported(cpuid: impl Cpuid) -> bool {
32        // Intel documents that the MSR is supported only if one of the kinds of
33        // speculation it can control is itself enumerated; AMD does similarly, but
34        // that information must be cobbled together from [amd/ibc] and [amd/ssbd].
35
36        // The Intel way:
37        let intel_features = cpuid.read(EXTENDED_FEATURES_D);
38        if intel_features.ibrs_ibpb() || intel_features.stibp() || intel_features.ssbd() {
39            return true;
40        }
41
42        // The AMD way:
43        if !cpuid.supports(EXTENDED_AMD_FEATURES_B) {
44            return false;
45        }
46        let amd_features = cpuid.read(EXTENDED_AMD_FEATURES_B);
47        amd_features.ibrs() || amd_features.stibp() || amd_features.ssbd()
48    }
49}
50
51/// Virtual speculation control (e.g., for hypervisor usage).
52///
53/// [amd/ssbd]: PRESENCE.
54pub const VIRTUAL_SPECULATION_CONTROL: Msr<0xc001_011f, VirtualSpeculationControlMsr, RwSafe> =
55    Msr::new();
56
57layout!({
58    /// Layout for [`VIRTUAL_SPECULATION_CONTROL`].
59    pub struct VirtualSpeculationControlMsr(u64);
60    {
61        let __ @ 63..3;
62        let ssbd @ 2;
63        let __ @ 1..0;
64    }
65});
66
67impl VirtualSpeculationControlMsr {
68    pub fn is_supported(cpuid: impl Cpuid) -> bool {
69        // [amd/ssbd]: HYPERVISOR USAGE MODELS.
70        cpuid.supports(EXTENDED_AMD_FEATURES_B) && cpuid.read(EXTENDED_AMD_FEATURES_B).virt_ssbd()
71    }
72}
73
74/// Whether Indirect Branch Restricted Speculation (IBRS) is supported. The
75/// "always on" mode refers to an optimization in which IBRS need only be
76/// enabled once; IBRS in this mode are also referred to as "enhanced".
77///
78/// https://software.intel.com/security-software-guidance/deep-dives/deep-dive-indirect-branch-restricted-speculation.
79pub fn has_ibrs(
80    cpuid: &impl Cpuid,
81    msr: &impl ReadReg<ArchCapabilitiesMsr>,
82    always_on_mode: bool,
83) -> bool {
84    // The Intel way.
85    let intel_always_on = ArchCapabilitiesMsr::is_supported(cpuid) && msr.read().ibrs_all();
86    let intel_present = cpuid.read(EXTENDED_FEATURES_D).ibrs_ibpb();
87    if intel_present && (!always_on_mode || intel_always_on) {
88        return true;
89    }
90
91    // The AMD way.
92    if cpuid.supports(EXTENDED_AMD_FEATURES_B) {
93        let features = cpuid.read(EXTENDED_AMD_FEATURES_B);
94        if features.ibrs() && (!always_on_mode || features.ibrs_always_on()) {
95            return true;
96        }
97    }
98
99    false
100}
101
102/// Whether Single Thread Indirect Branch Predictors (STIBP) are supported. The
103/// "always on" mode refers to an optimization in which STIBP need only be
104/// enabled once.
105///
106/// https://software.intel.com/security-software-guidance/deep-dives/deep-dive-single-thread-indirect-branch-predictors.
107pub fn has_stibp(cpuid: &impl Cpuid, always_on_mode: bool) -> bool {
108    // The Intel way.
109    let intel_present = cpuid.read(EXTENDED_FEATURES_D).stibp();
110    if intel_present && !always_on_mode {
111        // Intel does not offer an "always on" mode.
112        return true;
113    }
114
115    // The AMD way.
116    if cpuid.supports(EXTENDED_AMD_FEATURES_B) {
117        let features = cpuid.read(EXTENDED_AMD_FEATURES_B);
118        if features.stibp() && (!always_on_mode || features.stibp_always_on()) {
119            return true;
120        }
121    }
122    false
123}