Skip to content

Commit 3dcee13

Browse files
committed
[cpuid] Improve docs, implement __get_cpuid_max
Closes #174 .
1 parent 64c4b0c commit 3dcee13

File tree

1 file changed

+44
-18
lines changed

1 file changed

+44
-18
lines changed

src/x86/cpuid.rs

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,21 @@ pub struct CpuidResult {
1919
pub edx: u32,
2020
}
2121

22-
/// `cpuid` instruction.
22+
/// Returns the result of the `cpuid` instruction for a given `leaf` (`EAX`)
23+
/// and
24+
/// `sub_leaf` (`ECX`).
2325
///
24-
/// The [CPUID Wikipedia page][wiki_cpuid] contains how to query which
25-
/// information using the `eax` and `ecx` registers, and the format in
26-
/// which this information is returned in `eax...edx`.
26+
/// The highest-supported leaf value is returned by the first tuple argument of
27+
/// [`__get_cpuid_max(0)`](fn.__get_cpuid_max.html). For leaves containung
28+
/// sub-leaves, the second tuple argument returns the highest-supported
29+
/// sub-leaf
30+
/// value.
2731
///
28-
/// The `has_cpuid()` intrinsics can be used to query whether the `cpuid`
29-
/// instruction is available.
32+
/// The [CPUID Wikipedia page][wiki_cpuid] contains how to query which
33+
/// information using the `EAX` and `ECX` registers, and the interpretation of
34+
/// the results returned in `EAX`, `EBX`, `ECX`, and `EDX`.
3035
///
31-
/// The definitive references are:
36+
/// The references are:
3237
/// - [Intel 64 and IA-32 Architectures Software Developer's Manual Volume 2:
3338
/// Instruction Set Reference, A-Z][intel64_ref].
3439
/// - [AMD64 Architecture Programmer's Manual, Volume 3: General-Purpose and
@@ -39,22 +44,28 @@ pub struct CpuidResult {
3944
/// [amd64_ref]: http://support.amd.com/TechDocs/24594.pdf
4045
#[inline(always)]
4146
#[cfg_attr(test, assert_instr(cpuid))]
42-
pub unsafe fn __cpuid_count(eax: u32, ecx: u32) -> CpuidResult {
47+
pub unsafe fn __cpuid_count(leaf: u32, sub_leaf: u32) -> CpuidResult {
4348
let mut r = ::std::mem::uninitialized::<CpuidResult>();
44-
asm!("cpuid"
45-
: "={eax}"(r.eax), "={ebx}"(r.ebx), "={ecx}"(r.ecx), "={edx}"(r.edx)
46-
: "{eax}"(eax), "{ecx}"(ecx)
47-
: :);
49+
if cfg!(target_arch = "x86") {
50+
asm!("cpuid"
51+
: "={eax}"(r.eax), "={ebx}"(r.ebx), "={ecx}"(r.ecx), "={edx}"(r.edx)
52+
: "{eax}"(leaf), "{ecx}"(sub_leaf)
53+
: :);
54+
} else {
55+
// x86-64 uses %rbx as the base register, so preserve it.
56+
asm!("cpuid\n"
57+
: "={eax}"(r.eax), "={ebx}"(r.ebx), "={ecx}"(r.ecx), "={edx}"(r.edx)
58+
: "{eax}"(leaf), "{ecx}"(sub_leaf)
59+
: "rbx" :);
60+
}
4861
r
4962
}
5063

51-
/// `cpuid` instruction.
52-
///
53-
/// See `__cpuid_count`.
64+
/// See [`__cpuid_count`](fn.__cpuid_count.html).
5465
#[inline(always)]
5566
#[cfg_attr(test, assert_instr(cpuid))]
56-
pub unsafe fn __cpuid(eax: u32) -> CpuidResult {
57-
__cpuid_count(eax, 0)
67+
pub unsafe fn __cpuid(leaf: u32) -> CpuidResult {
68+
__cpuid_count(leaf, 0)
5869
}
5970

6071
/// Does the host support the `cpuid` instruction?
@@ -90,6 +101,22 @@ pub fn has_cpuid() -> bool {
90101
}
91102
}
92103

104+
/// Returns the highest-supported `leaf` (`EAX`) and sub-leaf (`ECX`) `cpuid`
105+
/// values.
106+
///
107+
/// If `cpuid` is supported, and `leaf` is zero, then the first tuple argument
108+
/// contains the highest `leaf` value that `cpuid` supports. For `leaf`s
109+
/// containing sub-leafs, the second tuple argument contains the
110+
/// highest-supported sub-leaf value.
111+
///
112+
/// See also [`__cpuid`](fn.__cpuid.html) and
113+
/// [`__cpuid_count`](fn.__cpuid_count.html).
114+
#[inline(always)]
115+
pub unsafe fn __get_cpuid_max(leaf: u32) -> (u32, u32) {
116+
let CpuidResult { eax, ebx, .. } = __cpuid(leaf);
117+
(eax, ebx)
118+
}
119+
93120
#[cfg(test)]
94121
mod tests {
95122
use super::*;
@@ -115,5 +142,4 @@ mod tests {
115142
}
116143
}
117144
}
118-
119145
}

0 commit comments

Comments
 (0)