@@ -19,16 +19,21 @@ pub struct CpuidResult {
19
19
pub edx : u32 ,
20
20
}
21
21
22
- /// `cpuid` instruction.
22
+ /// Returns the result of the `cpuid` instruction for a given `leaf` (`EAX`)
23
+ /// and
24
+ /// `sub_leaf` (`ECX`).
23
25
///
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.
27
31
///
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`.
30
35
///
31
- /// The definitive references are:
36
+ /// The references are:
32
37
/// - [Intel 64 and IA-32 Architectures Software Developer's Manual Volume 2:
33
38
/// Instruction Set Reference, A-Z][intel64_ref].
34
39
/// - [AMD64 Architecture Programmer's Manual, Volume 3: General-Purpose and
@@ -39,22 +44,28 @@ pub struct CpuidResult {
39
44
/// [amd64_ref]: http://support.amd.com/TechDocs/24594.pdf
40
45
#[ inline( always) ]
41
46
#[ 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 {
43
48
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
+ }
48
61
r
49
62
}
50
63
51
- /// `cpuid` instruction.
52
- ///
53
- /// See `__cpuid_count`.
64
+ /// See [`__cpuid_count`](fn.__cpuid_count.html).
54
65
#[ inline( always) ]
55
66
#[ 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 )
58
69
}
59
70
60
71
/// Does the host support the `cpuid` instruction?
@@ -90,6 +101,22 @@ pub fn has_cpuid() -> bool {
90
101
}
91
102
}
92
103
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
+
93
120
#[ cfg( test) ]
94
121
mod tests {
95
122
use super :: * ;
@@ -115,5 +142,4 @@ mod tests {
115
142
}
116
143
}
117
144
}
118
-
119
145
}
0 commit comments