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