1//! `cpuid` intrinsics
2#![allow(clippy::module_name_repetitions)]
34use crate::arch::asm;
5#[cfg(test)]
6use stdarch_test::assert_instr;
78/// 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(#[automatically_derived]
#[allow(clippy::missing_inline_in_public_items)]
#[stable(feature = "simd_x86", since = "1.27.0")]
impl crate::marker::Copy for CpuidResult { }Copy, #[automatically_derived]
#[allow(clippy::missing_inline_in_public_items)]
#[stable(feature = "simd_x86", since = "1.27.0")]
impl crate::clone::Clone for CpuidResult {
#[inline]
fn clone(&self) -> CpuidResult {
let _: crate::clone::AssertParamIsClone<u32>;
*self
}
}Clone, #[automatically_derived]
#[allow(clippy::missing_inline_in_public_items)]
#[stable(feature = "simd_x86", since = "1.27.0")]
impl crate::fmt::Debug for CpuidResult {
#[inline]
fn fmt(&self, f: &mut crate::fmt::Formatter) -> crate::fmt::Result {
crate::fmt::Formatter::debug_struct_field4_finish(f, "CpuidResult",
"eax", &self.eax, "ebx", &self.ebx, "ecx", &self.ecx, "edx",
&&self.edx)
}
}Debug, #[automatically_derived]
#[allow(clippy::missing_inline_in_public_items)]
#[stable(feature = "simd_x86", since = "1.27.0")]
impl crate::cmp::Eq for CpuidResult {
#[inline]
#[doc(hidden)]
#[coverage(off)]
fn assert_fields_are_eq(&self) {
let _: crate::cmp::AssertParamIsEq<u32>;
}
}Eq, #[automatically_derived]
#[allow(clippy::missing_inline_in_public_items)]
#[stable(feature = "simd_x86", since = "1.27.0")]
impl crate::cmp::Ord for CpuidResult {
#[inline]
fn cmp(&self, other: &CpuidResult) -> crate::cmp::Ordering {
match crate::cmp::Ord::cmp(&self.eax, &other.eax) {
crate::cmp::Ordering::Equal =>
match crate::cmp::Ord::cmp(&self.ebx, &other.ebx) {
crate::cmp::Ordering::Equal =>
match crate::cmp::Ord::cmp(&self.ecx, &other.ecx) {
crate::cmp::Ordering::Equal =>
crate::cmp::Ord::cmp(&self.edx, &other.edx),
cmp => cmp,
},
cmp => cmp,
},
cmp => cmp,
}
}
}Ord, #[automatically_derived]
#[allow(clippy::missing_inline_in_public_items)]
#[stable(feature = "simd_x86", since = "1.27.0")]
impl crate::cmp::PartialEq for CpuidResult {
#[inline]
fn eq(&self, other: &CpuidResult) -> bool {
self.eax == other.eax && self.ebx == other.ebx &&
self.ecx == other.ecx && self.edx == other.edx
}
}PartialEq, #[automatically_derived]
#[allow(clippy::missing_inline_in_public_items)]
#[stable(feature = "simd_x86", since = "1.27.0")]
impl crate::cmp::PartialOrd for CpuidResult {
#[inline]
fn partial_cmp(&self, other: &CpuidResult)
-> crate::option::Option<crate::cmp::Ordering> {
crate::option::Option::Some(crate::cmp::Ord::cmp(self, other))
}
}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")]
16pub eax: u32,
17/// EBX register.
18#[stable(feature = "simd_x86", since = "1.27.0")]
19pub ebx: u32,
20/// ECX register.
21#[stable(feature = "simd_x86", since = "1.27.0")]
22pub ecx: u32,
23/// EDX register.
24#[stable(feature = "simd_x86", since = "1.27.0")]
25pub edx: u32,
26}
2728/// Returns the result of the `cpuid` instruction for a given `leaf` (`EAX`)
29/// and `sub_leaf` (`ECX`).
30///
31/// There are two types of information leaves - basic leaves (with `leaf < 0x8000000`)
32/// and extended leaves (with `leaf >= 0x80000000`). The highest supported basic and
33/// extended leaves can be obtained by calling CPUID with `0` and `0x80000000`,
34/// respectively, and reading the value in the `EAX` register. If the leaf supports
35/// more than one sub-leaf, then the procedure of obtaining the highest supported
36/// sub-leaf, as well as the behavior if a invalid sub-leaf value is passed, depends
37/// on the specific leaf.
38///
39/// If the `leaf` value is higher than the maximum supported basic or extended leaf
40/// for the processor, this returns the information for the highest supported basic
41/// information leaf (with the passed `sub_leaf` value). If the `leaf` value is less
42/// than or equal to the highest basic or extended leaf value, but the leaf is not
43/// supported on the processor, all zeros are returned.
44///
45/// The [CPUID Wikipedia page][wiki_cpuid] contains information on how to query which
46/// information using the `EAX` and `ECX` registers, and the interpretation of
47/// the results returned in `EAX`, `EBX`, `ECX`, and `EDX`.
48///
49/// The references are:
50/// - [Intel 64 and IA-32 Architectures Software Developer's Manual Volume 2:
51/// Instruction Set Reference, A-Z][intel64_ref].
52/// - [AMD64 Architecture Programmer's Manual, Volume 3: General-Purpose and
53/// System Instructions][amd64_ref].
54///
55/// [wiki_cpuid]: https://en.wikipedia.org/wiki/CPUID
56/// [intel64_ref]: https://cdrdv2-public.intel.com/671110/325383-sdm-vol-2abcd.pdf
57/// [amd64_ref]: https://docs.amd.com/v/u/en-US/24594_3.37
58#[inline]
59#[cfg_attr(test, assert_instr(cpuid))]
60#[stable(feature = "simd_x86", since = "1.27.0")]
61pub fn __cpuid_count(leaf: u32, sub_leaf: u32) -> CpuidResult {
62if falsecfg!(target_env = "sgx") {
63{
crate::panicking::panic_fmt(format_args!("`__cpuid` cannot be used in SGX"));
};panic!("`__cpuid` cannot be used in SGX");
64 }
6566let eax;
67let ebx;
68let ecx;
69let edx;
7071// LLVM sometimes reserves `ebx` for its internal use, we so we need to use
72 // a scratch register for it instead.
73#[cfg(target_arch = "x86")]
74unsafe {
75asm!(
76"mov {0}, ebx",
77"cpuid",
78"xchg {0}, ebx",
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#[cfg(target_arch = "x86_64")]
87unsafe {
88asm!(
89"mov {0:r}, rbx",
90"cpuid",
91"xchg {0:r}, rbx",
92 out(reg) ebx,
93 inout("eax") leaf => eax,
94 inout("ecx") sub_leaf => ecx,
95 out("edx") edx,
96 options(nostack, preserves_flags),
97 );
98 }
99CpuidResult { eax, ebx, ecx, edx }
100}
101102/// Calls CPUID with the provided `leaf` value, with `sub_leaf` set to 0.
103/// See [`__cpuid_count`](fn.__cpuid_count.html).
104#[inline]
105#[cfg_attr(test, assert_instr(cpuid))]
106#[stable(feature = "simd_x86", since = "1.27.0")]
107pub fn __cpuid(leaf: u32) -> CpuidResult {
108__cpuid_count(leaf, 0)
109}
110111/// Returns the EAX and EBX register after calling CPUID with the provided `leaf`,
112/// with `sub_leaf` set to 0.
113///
114/// If `leaf` if 0 or `0x80000000`, the first tuple argument contains the maximum
115/// supported basic or extended leaf, respectively.
116///
117/// See also [`__cpuid`](fn.__cpuid.html) and
118/// [`__cpuid_count`](fn.__cpuid_count.html).
119#[inline]
120#[stable(feature = "simd_x86", since = "1.27.0")]
121pub fn __get_cpuid_max(leaf: u32) -> (u32, u32) {
122let CpuidResult { eax, ebx, .. } = __cpuid(leaf);
123 (eax, ebx)
124}