Merge pull request #1935 from sayantn/safe-cpuid
Make `cpuid` safe and update docs
This commit is contained in:
commit
46efc1b356
2 changed files with 25 additions and 17 deletions
|
|
@ -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 two 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`.
|
||||
///
|
||||
|
|
@ -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;
|
||||
|
|
@ -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",
|
||||
|
|
@ -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",
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue