Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 24 additions & 16 deletions crates/core_arch/src/x86/cpuid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,21 @@ pub struct CpuidResult {
/// Returns the result of the `cpuid` instruction for a given `leaf` (`EAX`)
/// and `sub_leaf` (`ECX`).
///
/// The highest-supported leaf value is returned by the first tuple argument of
/// [`__get_cpuid_max(0)`](fn.__get_cpuid_max.html). For leaves containing
/// sub-leaves, the second tuple argument returns the highest-supported
/// sub-leaf value.
/// There are 2 types of information leaves - basic leaves (with `leaf < 0x8000000`)
/// and extended leaves (with `leaf >= 0x80000000`). The highest supported basic and
/// extended leaves can be obtained by calling CPUID with `0` and `0x80000000`,
/// respectively, and reading the value in the `EAX` register. If the leaf supports
/// more than one sub-leaf, then the procedure of obtaining the highest supported
/// sub-leaf, as well as the behavior if a invalid sub-leaf value is passed, depends
/// on the specific leaf.
///
/// The [CPUID Wikipedia page][wiki_cpuid] contains how to query which
/// If the `leaf` value is higher than the maximum supported basic or extended leaf
/// for the processor, this returns the information for the highest supported basic
/// information leaf (with the passed `sub_leaf` value). If the `leaf` value is less
/// than or equal to the highest basic or extended leaf value, but the leaf is not
/// supported on the processor, all zeros are returned.
///
/// The [CPUID Wikipedia page][wiki_cpuid] contains information on how to query which
/// information using the `EAX` and `ECX` registers, and the interpretation of
/// the results returned in `EAX`, `EBX`, `ECX`, and `EDX`.
///
Expand All @@ -49,7 +58,7 @@ pub struct CpuidResult {
#[inline]
#[cfg_attr(test, assert_instr(cpuid))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn __cpuid_count(leaf: u32, sub_leaf: u32) -> CpuidResult {
pub fn __cpuid_count(leaf: u32, sub_leaf: u32) -> CpuidResult {
let eax;
let ebx;
let ecx;
Expand All @@ -58,7 +67,7 @@ pub unsafe fn __cpuid_count(leaf: u32, sub_leaf: u32) -> CpuidResult {
// LLVM sometimes reserves `ebx` for its internal use, we so we need to use
// a scratch register for it instead.
#[cfg(target_arch = "x86")]
{
unsafe {
asm!(
"mov {0}, ebx",
"cpuid",
Expand All @@ -71,7 +80,7 @@ pub unsafe fn __cpuid_count(leaf: u32, sub_leaf: u32) -> CpuidResult {
);
}
#[cfg(target_arch = "x86_64")]
{
unsafe {
asm!(
"mov {0:r}, rbx",
"cpuid",
Expand All @@ -86,27 +95,26 @@ pub unsafe fn __cpuid_count(leaf: u32, sub_leaf: u32) -> CpuidResult {
CpuidResult { eax, ebx, ecx, edx }
}

/// Calls CPUID with the provided `leaf` value, with `sub_leaf` set to 0.
/// See [`__cpuid_count`](fn.__cpuid_count.html).
#[inline]
#[cfg_attr(test, assert_instr(cpuid))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn __cpuid(leaf: u32) -> CpuidResult {
pub fn __cpuid(leaf: u32) -> CpuidResult {
__cpuid_count(leaf, 0)
}

/// Returns the highest-supported `leaf` (`EAX`) and sub-leaf (`ECX`) `cpuid`
/// values.
/// Returns the EAX and EBX register after calling CPUID with the provided `leaf`,
/// with `sub_leaf` set to 0.
///
/// If `cpuid` is supported, and `leaf` is zero, then the first tuple argument
/// contains the highest `leaf` value that `cpuid` supports. For `leaf`s
/// containing sub-leafs, the second tuple argument contains the
/// highest-supported sub-leaf value.
/// If `leaf` if 0 or `0x80000000`, the first tuple argument contains the maximum
/// supported basic or extended leaf, respectively.
///
/// See also [`__cpuid`](fn.__cpuid.html) and
/// [`__cpuid_count`](fn.__cpuid_count.html).
#[inline]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn __get_cpuid_max(leaf: u32) -> (u32, u32) {
pub fn __get_cpuid_max(leaf: u32) -> (u32, u32) {
let CpuidResult { eax, ebx, .. } = __cpuid(leaf);
(eax, ebx)
}
2 changes: 1 addition & 1 deletion crates/core_arch/src/x86/xsave.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ mod tests {
// `CPUID.(EAX=0DH,ECX=0):ECX` contains the size required to hold all supported xsave
// components. `EBX` contains the size required to hold all xsave components currently
// enabled in `XCR0`. We are using `ECX` to ensure enough space in all scenarios
let CpuidResult { ecx, .. } = unsafe { __cpuid(0x0d) };
let CpuidResult { ecx, .. } = __cpuid(0x0d);

XsaveArea {
data: vec![AlignedArray([0; 64]); ecx.div_ceil(64) as usize].into_boxed_slice(),
Expand Down