blob: 4fa3803543ee24c0ebbab3ba6b4e075479e4c6f0 [file]
// Copyright 2026 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use super::ArchCapabilitiesMsr;
use super::cpuid::{EXTENDED_AMD_FEATURES_B, EXTENDED_FEATURES_D};
use bitrs::layout;
use regio::RwSafe;
use regio::traits::ReadReg;
use regio::x86::{Cpuid, Msr};
/// Speculation control.
///
/// [intel/vol4]: Table 2-2. IA-32 Architectural MSRs (Contd.).
/// [amd/ibc]: PRESENCE.
/// [amd/ssbd]: PRESENCE.
pub const SPECULATION_CONTROL: Msr<0x0000_0048, SpeculationControlMsr, RwSafe> = Msr::new();
layout!({
/// Layout for [`SPECULATION_CONTROL`].
pub struct SpeculationControlMsr(u64);
{
let __ @ 63..3;
let ssbd @ 2;
let stibp @ 1;
let ibrs @ 0;
}
});
impl SpeculationControlMsr {
pub fn is_supported(cpuid: impl Cpuid) -> bool {
// Intel documents that the MSR is supported only if one of the kinds of
// speculation it can control is itself enumerated; AMD does similarly, but
// that information must be cobbled together from [amd/ibc] and [amd/ssbd].
// The Intel way:
let intel_features = cpuid.read(EXTENDED_FEATURES_D);
if intel_features.ibrs_ibpb() || intel_features.stibp() || intel_features.ssbd() {
return true;
}
// The AMD way:
if !cpuid.supports(EXTENDED_AMD_FEATURES_B) {
return false;
}
let amd_features = cpuid.read(EXTENDED_AMD_FEATURES_B);
amd_features.ibrs() || amd_features.stibp() || amd_features.ssbd()
}
}
/// Virtual speculation control (e.g., for hypervisor usage).
///
/// [amd/ssbd]: PRESENCE.
pub const VIRTUAL_SPECULATION_CONTROL: Msr<0xc001_011f, VirtualSpeculationControlMsr, RwSafe> =
Msr::new();
layout!({
/// Layout for [`VIRTUAL_SPECULATION_CONTROL`].
pub struct VirtualSpeculationControlMsr(u64);
{
let __ @ 63..3;
let ssbd @ 2;
let __ @ 1..0;
}
});
impl VirtualSpeculationControlMsr {
pub fn is_supported(cpuid: impl Cpuid) -> bool {
// [amd/ssbd]: HYPERVISOR USAGE MODELS.
cpuid.supports(EXTENDED_AMD_FEATURES_B) && cpuid.read(EXTENDED_AMD_FEATURES_B).virt_ssbd()
}
}
/// Whether Indirect Branch Restricted Speculation (IBRS) is supported. The
/// "always on" mode refers to an optimization in which IBRS need only be
/// enabled once; IBRS in this mode are also referred to as "enhanced".
///
/// https://software.intel.com/security-software-guidance/deep-dives/deep-dive-indirect-branch-restricted-speculation.
pub fn has_ibrs(
cpuid: &impl Cpuid,
msr: &impl ReadReg<ArchCapabilitiesMsr>,
always_on_mode: bool,
) -> bool {
// The Intel way.
let intel_always_on = ArchCapabilitiesMsr::is_supported(cpuid) && msr.read().ibrs_all();
let intel_present = cpuid.read(EXTENDED_FEATURES_D).ibrs_ibpb();
if intel_present && (!always_on_mode || intel_always_on) {
return true;
}
// The AMD way.
if cpuid.supports(EXTENDED_AMD_FEATURES_B) {
let features = cpuid.read(EXTENDED_AMD_FEATURES_B);
if features.ibrs() && (!always_on_mode || features.ibrs_always_on()) {
return true;
}
}
false
}
/// Whether Single Thread Indirect Branch Predictors (STIBP) are supported. The
/// "always on" mode refers to an optimization in which STIBP need only be
/// enabled once.
///
/// https://software.intel.com/security-software-guidance/deep-dives/deep-dive-single-thread-indirect-branch-predictors.
pub fn has_stibp(cpuid: &impl Cpuid, always_on_mode: bool) -> bool {
// The Intel way.
let intel_present = cpuid.read(EXTENDED_FEATURES_D).stibp();
if intel_present && !always_on_mode {
// Intel does not offer an "always on" mode.
return true;
}
// The AMD way.
if cpuid.supports(EXTENDED_AMD_FEATURES_B) {
let features = cpuid.read(EXTENDED_AMD_FEATURES_B);
if features.stibp() && (!always_on_mode || features.stibp_always_on()) {
return true;
}
}
false
}