#
core/stdarch/crates/core_arch/src/x86/
cpuid.rs

    1//! `cpuid` intrinsics
    2#![allow(clippy::module_name_repetitions)]
    3
    4use crate::arch::asm;
    5#[cfg(test)]
    6use stdarch_test::assert_instr;
    7
    8/// Result of the `cpuid` instruction.
    9#[allow(clippy::missing_inline_in_public_items)]
    10// ^^ the derived impl of Debug for CpuidResult is not #[inline] and that's OK.
    11#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
    12#[stable(feature = "simd_x86", since = "1.27.0")]
    13pub struct CpuidResult {
    14    /// EAX register.
    15    #[stable(feature = "simd_x86", since = "1.27.0")]
    16    pub eax: u32,
    17    /// EBX register.
    18    #[stable(feature = "simd_x86", since = "1.27.0")]
    19    pub ebx: u32,
    20    /// ECX register.
    21    #[stable(feature = "simd_x86", since = "1.27.0")]
    22    pub ecx: u32,
    23    /// EDX register.
    24    #[stable(feature = "simd_x86", since = "1.27.0")]
    25    pub edx: u32,
    26}
    27
    28/// Returns the result of the `cpuid` instruction for a given `leaf` (`EAX`)
    29/// and `sub_leaf` (`ECX`).
    30///
    31/// The highest-supported leaf value is returned by the first tuple argument of
    32/// [`__get_cpuid_max(0)`](fn.__get_cpuid_max.html). For leaves containing
    33/// sub-leaves, the second tuple argument returns the highest-supported
    34/// sub-leaf value.
    35///
    36/// The [CPUID Wikipedia page][wiki_cpuid] contains how to query which
    37/// information using the `EAX` and `ECX` registers, and the interpretation of
    38/// the results returned in `EAX`, `EBX`, `ECX`, and `EDX`.
    39///
    40/// The references are:
    41/// - [Intel 64 and IA-32 Architectures Software Developer's Manual Volume 2:
    42///   Instruction Set Reference, A-Z][intel64_ref].
    43/// - [AMD64 Architecture Programmer's Manual, Volume 3: General-Purpose and
    44///   System Instructions][amd64_ref].
    45///
    46/// [wiki_cpuid]: https://en.wikipedia.org/wiki/CPUID
    47/// [intel64_ref]: https://cdrdv2-public.intel.com/671110/325383-sdm-vol-2abcd.pdf
    48/// [amd64_ref]: http://support.amd.com/TechDocs/24594.pdf
    49#[inline]
    50#[cfg_attr(test, assert_instr(cpuid))]
    51#[stable(feature = "simd_x86", since = "1.27.0")]
    52pub unsafe fn __cpuid_count(leaf: u32, sub_leaf: u32) -> CpuidResult {
    53    let eax;
    54    let ebx;
    55    let ecx;
    56    let edx;
    57
    58    // LLVM sometimes reserves `ebx` for its internal use, we so we need to use
    59    // a scratch register for it instead.
    60    #[cfg(target_arch = "x86")]
    61    {
    62        asm!(
    63            "mov {0}, ebx",
    64            "cpuid",
    65            "xchg {0}, ebx",
    66            out(reg) ebx,
    67            inout("eax") leaf => eax,
    68            inout("ecx") sub_leaf => ecx,
    69            out("edx") edx,
    70            options(nostack, preserves_flags),
    71        );
    72    }
    73    #[cfg(target_arch = "x86_64")]
    74    {
    75        asm!(
    76            "mov {0:r}, rbx",
    77            "cpuid",
    78            "xchg {0:r}, rbx",
    79            out(reg) ebx,
    80            inout("eax") leaf => eax,
    81            inout("ecx") sub_leaf => ecx,
    82            out("edx") edx,
    83            options(nostack, preserves_flags),
    84        );
    85    }
    86    CpuidResult { eax, ebx, ecx, edx }
    87}
    88
    89/// See [`__cpuid_count`](fn.__cpuid_count.html).
    90#[inline]
    91#[cfg_attr(test, assert_instr(cpuid))]
    92#[stable(feature = "simd_x86", since = "1.27.0")]
    93pub unsafe fn __cpuid(leaf: u32) -> CpuidResult {
    94    __cpuid_count(leaf, 0)
    95}
    96
    97/// Returns the highest-supported `leaf` (`EAX`) and sub-leaf (`ECX`) `cpuid`
    98/// values.
    99///
    100/// If `cpuid` is supported, and `leaf` is zero, then the first tuple argument
    101/// contains the highest `leaf` value that `cpuid` supports. For `leaf`s
    102/// containing sub-leafs, the second tuple argument contains the
    103/// highest-supported sub-leaf value.
    104///
    105/// See also [`__cpuid`](fn.__cpuid.html) and
    106/// [`__cpuid_count`](fn.__cpuid_count.html).
    107#[inline]
    108#[stable(feature = "simd_x86", since = "1.27.0")]
    109pub unsafe fn __get_cpuid_max(leaf: u32) -> (u32, u32) {
    110    let CpuidResult { eax, ebx, .. } = __cpuid(leaf);
    111    (eax, ebx)
    112}