Giter Club home page Giter Club logo

rust-cpuid's Introduction

cpuid Crates.io Standard checks

A library to parse the x86 CPUID instruction, written in rust with no external dependencies. The implementation closely resembles the Intel CPUID manual description. The library works in no_std environments. Some additional cargo features require std (e.g., pretty printing, serialization).

  • For Intel platforms: The code should be in sync with the March 2018 revision of the Intel Architectures SDM.
  • For AMD platforms it should be in sync with the AMD64 systems manual no. 24594, Revision 3.32 (March 2021).

Library usage

use raw_cpuid::CpuId;
let cpuid = CpuId::new();

if let Some(vf) = cpuid.get_vendor_info() {
    assert!(vf.as_str() == "GenuineIntel" || vf.as_str() == "AuthenticAMD");
}

let has_sse = cpuid.get_feature_info().map_or(false, |finfo| finfo.has_sse());
if has_sse {
    println!("CPU supports SSE!");
}

if let Some(cparams) = cpuid.get_cache_parameters() {
    for cache in cparams {
        let size = cache.associativity() * cache.physical_line_partitions() * cache.coherency_line_size() * cache.sets();
        println!("L{}-Cache size is {}", cache.level(), size);
    }
} else {
    println!("No cache parameter information available")
}

cpuid binary

raw-cpuid ships with a cpuid binary that can be installed to inspect the output of the CPUID instruction on a host system.

To install, use:

cargo install raw-cpuid --features cli

The cli feature is currently required to build the binary version due to cargo limitations.

Documentation

rust-cpuid's People

Contributors

a1phyr avatar alex-mckenna avatar colinfinck avatar dependabot[bot] avatar ericson2314 avatar g2p avatar gabrielmajeri avatar gnociyeh avatar gz avatar hiraokatakuya avatar isaacdynamo avatar johnbartholomew avatar khuey avatar kisaragieffective avatar mkeeter avatar mssun avatar niklasf avatar npmccallum avatar olivierlemasle avatar phip1611 avatar pireax avatar rafalmiel avatar spaceeraser avatar stlankes avatar tones111 avatar tylerwhall avatar umio-yasuno avatar waywardmonkeys avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

rust-cpuid's Issues

raw-cpuid 4.0.0 depends on heavyweight serde crate

raw-cpuid is advertised as "A library to parse the x86 CPUID instruction, written in rust with no external dependencies" and until 3.1.0, this was the case.

However, the recent 4.0.0 release added a dependency to the heavyweight "serde" crate.
While that was an optional feature when introduced by @alex-mckenna in ef3a6f5, it quietly became a hard dependency in 686a7c5 by @gz

Please make "serde" optional again in a subsequent release to keep raw-cpuid a small and universal crate.

Incorrect (and probably unsound) transmutes

The code contains several transmutes similar to this:

#[derive(Debug, Default)]
#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
pub struct VendorInfo {
    ebx: u32,
    edx: u32,
    ecx: u32,
}

impl VendorInfo {
    /// Return vendor identification as human readable string.
    pub fn as_string<'a>(&'a self) -> &'a str {
        unsafe {
            let brand_string_start = self as *const VendorInfo as *const u8;
            let slice = slice::from_raw_parts(brand_string_start, 3 * 4);
            let byte_array: &'a [u8] = transmute(slice);
            str::from_utf8_unchecked(byte_array)
        }
    }
}

Reading about transmutes in the nomicon, this is not correct, because the Rust compiler is free to reorder the fields of the struct.

It is also probably unsound, because I believe the Rust compiler is technically even free to add padding.

Adding #[repr(C)] may be a fix. However I am not sure what role endianness plays here (same question as #39). is a fix. I'll submit a pull request.

Serialization issue

I don't use the serialize feature my self but the following use-case seems broken:

  • Serialization on machine A
  • Deserialization on machine B

Structs with a CpuIdReader member will return a mix of machine A and B features.

For example a RdtMonitoringInfo serialized on machine A and deserialized on machine B will return a mix of info. RdtMonitoringInfo::rmid_range() will return machine A info while RdtMonitoringInfo::l3_monitoring() will return machine B info.

Use of CpuId::new() on non-SSE x86 targets?

I was attempting to use this crate on an x86 target (intended for bare-metal code w/o XMM/SSE register usage).

However, it seems this crate depends on the Rust target having sse support. However, just because a processor hardware implements SSE instructions, it seems like the CpuId functionality in this crate should still be available even if the code is being compiled without SSE instruction usage.

Or is there something I'm missing?

path to use on stable Rust?

I think it would be great if this crate could be made to work on stable Rust. As far as I can see, there are two nightly-only features being used: prelude_import and asm. I don't think prelude_import is being used. Indeed, if I remove it, the crate still compiles and passes tests.

Getting rid of the asm feature is trickier. But, there's not that much Assembly, and it seems like it should be possible to write the Assembly in their own .S files and then link them in using build.rs. You can see an example of that working here: https://github.com/alexcrichton/stacker

Would you be open to such a strategy? If so, I'd be happy to try and do the leg work on this!

Combination of Deserialize and from_str_unchecked() is unsound

While writing the safety comments for #40, I noticed that

            // Safety: The field is specified to be ASCII, and the only safe
            // way to construct VendorInfo is from real CPUID data or the
            // Default implementation.
            str::from_utf8_unchecked(slice)

is not actually true. Using Deserialize, types like VendorInfo can be constructed with arbitrary content in safe code, but calling str::from_utf8_unchecked() with invalid UTF-8 is undefined behavior.

Possible fixes are removing Deserialize, or validating at construction or right when constructing the str.

Backport `into_iter` -> `iter` fix to 7.0.x?

Hi there!

Do you think you could backport this fix to version 7 and release it as 7.0.4? At least judging by the downloads on crates.io, most crates seem to depend on raw-cpuid = "7" still. It would help a lot with https://github.com/rust-lang/rust/pull/65819 if the fix could be released for 7. Thanks for your consideration :)

Relicense under dual MIT/Apache-2.0

This issue was automatically generated. Feel free to close without ceremony if
you do not agree with re-licensing or if it is not possible for other reasons.
Respond to @cmr with any questions or concerns, or pop over to
#rust-offtopic on IRC to discuss.

You're receiving this because someone (perhaps the project maintainer)
published a crates.io package with the license as "MIT" xor "Apache-2.0" and
the repository field pointing here.

TL;DR the Rust ecosystem is largely Apache-2.0. Being available under that
license is good for interoperation. The MIT license as an add-on can be nice
for GPLv2 projects to use your code.

Why?

The MIT license requires reproducing countless copies of the same copyright
header with different names in the copyright field, for every MIT library in
use. The Apache license does not have this drawback. However, this is not the
primary motivation for me creating these issues. The Apache license also has
protections from patent trolls and an explicit contribution licensing clause.
However, the Apache license is incompatible with GPLv2. This is why Rust is
dual-licensed as MIT/Apache (the "primary" license being Apache, MIT only for
GPLv2 compat), and doing so would be wise for this project. This also makes
this crate suitable for inclusion and unrestricted sharing in the Rust
standard distribution and other projects using dual MIT/Apache, such as my
personal ulterior motive, the Robigalia project.

Some ask, "Does this really apply to binary redistributions? Does MIT really
require reproducing the whole thing?" I'm not a lawyer, and I can't give legal
advice, but some Google Android apps include open source attributions using
this interpretation. Others also agree with
it
.
But, again, the copyright notice redistribution is not the primary motivation
for the dual-licensing. It's stronger protections to licensees and better
interoperation with the wider Rust ecosystem.

How?

To do this, get explicit approval from each contributor of copyrightable work
(as not all contributions qualify for copyright, due to not being a "creative
work", e.g. a typo fix) and then add the following to your README:

## License

Licensed under either of

 * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
 * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)

at your option.

### Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any
additional terms or conditions.

and in your license headers, if you have them, use the following boilerplate
(based on that used in Rust):

// Copyright 2016 rust-cpuid developers
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

It's commonly asked whether license headers are required. I'm not comfortable
making an official recommendation either way, but the Apache license
recommends it in their appendix on how to use the license.

Be sure to add the relevant LICENSE-{MIT,APACHE} files. You can copy these
from the Rust repo for a plain-text
version.

And don't forget to update the license metadata in your Cargo.toml to:

license = "MIT/Apache-2.0"

I'll be going through projects which agree to be relicensed and have approval
by the necessary contributors and doing this changes, so feel free to leave
the heavy lifting to me!

Contributor checkoff

To agree to relicensing, comment with :

I license past and future contributions under the dual MIT/Apache-2.0 license, allowing licensees to chose either at their option.

Or, if you're a contributor, you can check the box in this repo next to your
name. My scripts will pick this exact phrase up and check your checkbox, but
I'll come through and manually review this issue later as well.

Maybe wrong result of Hypervisor Info?

Hi! I'm having a x86_64 UEFI machine with an Intel i5-10600k as CPU that runs the latest Windows 10. The HYPERVISOR-flag in the CPU features is - as expected - not set but .hypervisor_info() still returns something. Do you know why this happens? Is there a bug in this library or is the operating system doing strange things?

The value I receive is (4800, 100, 0) (ebx, ecx, edx).

On another machine of mine (notebook running Ubuntu) CpuId::get_hypervisor_info() doesn't return anything as expected, because I'm not in a virtualized environment.

Issuses on offset and size in extended state region

Hi, I want to get the specific size and offset of a state component n (2 <= n <= 31) in the extended state by using the functions rust-cpuid lib provides. But it seems the library always returns the information (size and offset) of the first valid state component.

Here is the sample code:

pub fn extended_state_size_and_offset(level: u32) -> (u32, u32) {
    let cpuid = CpuId::new();
    let mut offset  = 0;
    let mut size = 0;
    if let Some(info) = cpuid.get_extended_state_info() {
        let extended_state_iter = info.iter();
        if let Some(extend_state) = extended_state_iter.next() {
            offset = extend_state.offset();
            size = extend_state.size();
        }
    }
    (offset, size)
}

The code above can only returns the size and offset of the first valid state component, and cannot returns the specific state component indexed by level.

Could you please help me to confirm whether such issue exists indeed? If so, I'm pleased to submit PR to fix the issue.

Add function to check for ABM

Hi Gerd!

(I'm not sure whether it makes sense to have this bug exist separately to #26, but I think this issue has a way smaller scope and may be fixable without needing to solve #26.)

According to https://en.wikipedia.org/wiki/Bit_Manipulation_Instruction_Sets, availability of the lzcount instruction is indicated by the ABM flag:

Intel uses AMD's ABM flag to indicate LZCNT support (since LZCNT completes the ABM)

It would be really useful to have a function available to check for ABM, even if the details differ slightly (there are Intel CPUs that support popcnt instructions, but not lzcnt instructions; while AMD added support for both at the same time).

As there seems no requirement to add a distinction between Intel and AMD for this, maybe this check could be added independently of what's decided in #26?

Please let me know if I can help!

Cheers,

Simon

Fails to build (windows x64, msvc 2017)

This crate fails to compile for me. Here is the error text that I get:

error: failed to run custom build command for `raw-cpuid v3.0.0`
process didn't exit successfully: `D:\Workspace\cretonne\target\debug\build\raw-cpuid-ae4125d19227d10f\build-script-build` (exit code: 101)
--- stdout
TARGET = Some("x86_64-pc-windows-msvc")
OPT_LEVEL = Some("0")
TARGET = Some("x86_64-pc-windows-msvc")
HOST = Some("x86_64-pc-windows-msvc")
TARGET = Some("x86_64-pc-windows-msvc")
TARGET = Some("x86_64-pc-windows-msvc")
HOST = Some("x86_64-pc-windows-msvc")
CC_x86_64-pc-windows-msvc = None
CC_x86_64_pc_windows_msvc = None
HOST_CC = None
CC = None
TARGET = Some("x86_64-pc-windows-msvc")
HOST = Some("x86_64-pc-windows-msvc")
CFLAGS_x86_64-pc-windows-msvc = None
CFLAGS_x86_64_pc_windows_msvc = None
HOST_CFLAGS = None
CFLAGS = None
DEBUG = Some("true")
running: "C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\Community\\VC\\Tools\\MSVC\\14.11.25503\\bin\\HostX64\\x64\\cl.exe" "/nologo" "/MD" "/Z7" "/W4" "/FoD:\\Workspace\\cretonne\\target\\debug\\build\\raw-cpuid-e8bd9ff618fd74c1\\out\\src\\cpuid.o" "/c" "src/cpuid.c"
cpuid.c
src/cpuid.c(4): error C2065: 'asm': undeclared identifier
src/cpuid.c(4): error C2143: syntax error: missing ';' before 'volatile'
exit code: 2

Public safe fn native_cpuid::cpuid_count() technically unsafe

Reviewing unsafe code in this crate, here's one more issue (but much less important, more pedantic - sorry about that).

All intrinsics in std::arch are unsafe, if only because the instruction may not be available on the current CPU. Even CPUID does not exist in all x86 and x86_64 instruction sets, so exposing the unsafe function as a safe function is technically unsound.

pub mod native_cpuid {
    pub fn cpuid_count(a: u32, c: u32) -> CpuIdResult {
        let result = unsafe { self::arch::__cpuid_count(a, c) };

        CpuIdResult {
            eax: result.eax,
            ebx: result.ebx,
            ecx: result.ecx,
            edx: result.edx,
        }
    }
}

A possible solution may be to do something equivalent to assert!(has_cpuid()) (the implementation is very interesting), or to just make the function unsafe.

A third approach would be an API to do the check only once:

struct CpuId(_priv: ());

impl CpuId {
    /// Panics if CPUID not supported.
    pub fn new() -> CpuId {
        assert!(has_cpuid());
        Self::assume_supported()
    }

    /// Safety: It is the callers responsibility to ensure that CPUID is supported.
    pub unsafe fn assume_supported() -> CpuId {
        Cpuid { _priv: () }
    }

    pub fn cpuid(&self, a: u32, c: u32) -> CpuIdResult {
        unsafe {
            // ...
        }
    }
}

has_rdseed typoed as has_rdseet

Not sure when this was added and if you want to keep compatibility.
I guess the recommended course would be to add the correct name and deprecate the other.

Compile Problems with Mac OS

Hello Guys,

We are actually developing a small own OS in rust.
https://github.com/beschaef/rtos

Currently we are testing ist under Mac OS. But we get the following error when we try to compile it.

= note: lld: error: undefined symbol: cpuid

      >>> referenced by lib.rs:32 (/Users/philippschultheiss/.cargo/registry/src/github.com-1ecc6299db9ec823/raw-cpuid-5.0.0/src/lib.rs:32)

      >>>               raw_cpuid-e9487655fe8e7103.raw_cpuid5.rcgu.o:(raw_cpuid::native_cpuid::cpuid_count::heb590b374d42c7b3) in archive /Users/philippschultheiss/Desktop/rtos/target/x86_64-rtos/debug/deps/libraw_cpuid-e9487655fe8e7103.rlib

The Error messages show the raw_cpuid Crate, but we are not shure if this really is a raw_cpuid problem, because it's running in your travis.
Have you an idea what we are doing wrong or how to fix it? It seems only to be a mac problem

best regards,

Benny

cpuid dies on overflow on AMD 7713P

Thanks for this useful crate! Running the cpuid binary on an AMD 7713P with overflow detection enabled (either via the debug profile or explicitly enabled) results in a panic:

...
Processor Brand String = "AMD EPYC 7713P 64-Core Processor"
L1 TLB 2/4 MiB entries (0x8000_0005/eax):
┌──────────────────┬─────────────────┐
│     iTLB #entries│               64│
│iTLB associativity│Fully associative│
│     dTLB #entries│               64│
│dTLB associativity│Fully associative│
└──────────────────┴─────────────────┘
L1 TLB 4 KiB entries (0x8000_0005/ebx):
┌──────────────────┬─────────────────┐
│     iTLB #entries│               64│
│iTLB associativity│Fully associative│
│     dTLB #entries│               64│
│dTLB associativity│Fully associative│
└──────────────────┴─────────────────┘
L1 dCache (0x8000_0005/ecx):
┌─────────────────┬───────┐
│line size [Bytes]│     64│
│    lines per tag│      1│
│    associativity│NWay(8)│
│       size [KiB]│     32│
└─────────────────┴───────┘
L1 iCache (0x8000_0005/edx):
┌─────────────────┬───────┐
│line size [Bytes]│     64│
│    lines per tag│      1│
│    associativity│NWay(8)│
│       size [KiB]│     32│
└─────────────────┴───────┘
L2 TLB 2/4 MiB entries (0x8000_0006/eax):
┌──────────────────┬───────┐
│     iTLB #entries│    512│
│iTLB associativity│NWay(2)│
│     dTLB #entries│   2048│
│dTLB associativity│NWay(4)│
└──────────────────┴───────┘
L2 TLB 4 KiB entries (0x8000_0006/ebx):
┌──────────────────┬───────┐
│     iTLB #entries│    512│
│iTLB associativity│NWay(4)│
│     dTLB #entries│   2048│
│dTLB associativity│NWay(8)│
└──────────────────┴───────┘
L2 Cache (0x8000_0006/ecx):
┌─────────────────┬───────┐
│line size [Bytes]│     64│
│    lines per tag│      1│
│    associativity│NWay(8)│
│       size [KiB]│    512│
└─────────────────┴───────┘
L3 Cache (0x8000_0006/edx):
thread 'main' panicked at 'attempt to multiply with overflow', src/bin/cpuid.rs:1300:45
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

The problem is that l3cache_size() returns a u16 -- and the cache size here (512) times 512 exceeds a 16-bit quantity; it should be promoted to a u32 before being multiplied:

diff --git a/src/bin/cpuid.rs b/src/bin/cpuid.rs
index e58ce16..f27d11f 100644
--- a/src/bin/cpuid.rs
+++ b/src/bin/cpuid.rs
@@ -1297,7 +1297,7 @@ fn markdown(_opts: Opts) {
                 RowGen::tuple("line size [Bytes]", info.l3cache_line_size()),
                 RowGen::tuple("lines per tag", info.l3cache_lines_per_tag()),
                 RowGen::tuple("associativity", info.l3cache_associativity()),
-                RowGen::tuple("size [KiB]", info.l3cache_size() * 512),
+                RowGen::tuple("size [KiB]", info.l3cache_size() as u32 * 512),
             ],
         );
     }

Thanks again for the crate!

Micro-architecture categorisation

I have written, (during my PhD) a piece of code that categorise micro-architectures from the CPUID Vendor, Family, Model and stepping, (e.g. detect Skylake, Coffee Lake, Ice Lake, etc), currently only supporting Intel architectures (but that I mean to extend to support AMD micro-arch too). It is based of Intel SDM / Optimization Manual (and cross checked on WikiChip)

Do you think such a feature would belong in this crate ? (I could obviously make my own crate too).

If so, I'll probably start working on a PR to integrate it here.

"raw::Slice does not name a structure"

I updated my nightly compiler and libcore to 2016-06-03 and am now being met with this error.

/home/thomas/.cargo/registry/src/github.com-1ecc6299db9ec823/raw-cpuid-2.0.0/src/lib.rs:435:25: 435:35 error: `raw::Slice` does not name a structure [E0422]
/home/thomas/.cargo/registry/src/github.com-1ecc6299db9ec823/raw-cpuid-2.0.0/src/lib.rs:435             let slice = raw::Slice { data: brand_string_start, len: 3*4 };
                                                                                                                    ^~~~~~~~~~
/home/thomas/.cargo/registry/src/github.com-1ecc6299db9ec823/raw-cpuid-2.0.0/src/lib.rs:435:25: 435:35 help: run `rustc --explain E0422` to see a detailed explanation
/home/thomas/.cargo/registry/src/github.com-1ecc6299db9ec823/raw-cpuid-2.0.0/src/lib.rs:2097:29: 2097:39 error: `raw::Slice` does not name a structure [E0422]
/home/thomas/.cargo/registry/src/github.com-1ecc6299db9ec823/raw-cpuid-2.0.0/src/lib.rs:2097                 let slice = raw::Slice { data: brand_string_start, len: 3*4*4 };
                                                                                                                         ^~~~~~~~~~
/home/thomas/.cargo/registry/src/github.com-1ecc6299db9ec823/raw-cpuid-2.0.0/src/lib.rs:2097:29: 2097:39 help: run `rustc --explain E0422` to see a detailed explanation

Edit: Okay, now I've had a chance to look at this in more detail I see the problem was solved in a commit two days ago, but hasn't made it onto crates.io yet. Could you push a point release so those of us using raw-cpuid only as a dependency (of the x86 crate, in this case) can take advantage of it?

panic at `res.eax == 0`

Hi, Nice to meet you. Our project met a panic error at the below line. I'm not professional at cpu. May I know in which kind of situation would cause the failure of the following error? Any help would be appreciated.

assert!(res.eax == 0);

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.