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
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ repository = "https://github.com/zsiciarz/rust-cpuid"
readme = "README.md"
keywords = ["cpuid", "cpu", "hardware"]
license = "MIT"
edition = "2021"

[lib]
name = "cpuid"
Expand All @@ -18,8 +19,11 @@ name = "cpuid"
name = "cpuid"
doc = false

[build-dependencies]
bindgen = "0.65.1"

[dependencies]
libc = "~0.2"
libc = "0.2"

[features]
unstable = []
16 changes: 16 additions & 0 deletions build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use std::env;
use std::path::PathBuf;

fn main() {
println!("cargo:rustc-link-lib=cpuid");
let bindings = bindgen::Builder::default()
.header("wrapper.h")
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.generate()
.expect("Unable to generate bindings");
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
// println!("bindings:{:#?}", bindings);
bindings
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}
61 changes: 5 additions & 56 deletions src/ffi.rs
Original file line number Diff line number Diff line change
@@ -1,57 +1,6 @@
use libc::{c_int, c_char, uint8_t, uint32_t, int32_t};
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(dead_code)]

pub const MAX_CPUID_LEVEL: usize = 32;
pub const MAX_EXT_CPUID_LEVEL: usize = 32;
pub const MAX_INTELFN4_LEVEL: usize = 4;
pub const MAX_INTELFN11_LEVEL: usize = 4;
pub const VENDOR_STR_MAX: usize = 16;
pub const BRAND_STR_MAX: usize = 64;
pub const CPU_FLAGS_MAX: usize = 128;
pub const CPU_HINTS_MAX: usize = 16;

#[repr(C)]
pub struct cpu_raw_data_t {
pub basic_cpuid: [[uint32_t; 4]; MAX_CPUID_LEVEL],
pub ext_cpuid: [[uint32_t; 4]; MAX_EXT_CPUID_LEVEL],
pub intel_fn4: [[uint32_t; 4]; MAX_INTELFN4_LEVEL],
pub intel_fn11: [[uint32_t; 4]; MAX_INTELFN11_LEVEL],
}

#[repr(C)]
pub struct cpu_id_t {
pub vendor_str: [c_char; VENDOR_STR_MAX],
pub brand_str: [c_char; BRAND_STR_MAX],
pub vendor: int32_t,
pub flags: [uint8_t; CPU_FLAGS_MAX],
pub family: int32_t,
pub model: int32_t,
pub stepping: int32_t,
pub ext_family: int32_t,
pub ext_model: int32_t,
pub num_cores: int32_t,
pub num_logical_cpus: int32_t,
pub total_logical_cpus: int32_t,
pub l1_data_cache: int32_t,
pub l1_instruction_cache: int32_t,
pub l2_cache: int32_t,
pub l3_cache: int32_t,
pub l1_assoc: int32_t,
pub l2_assoc: int32_t,
pub l3_assoc: int32_t,
pub l1_cacheline: int32_t,
pub l2_cacheline: int32_t,
pub l3_cacheline: int32_t,
pub cpu_codename: [c_char; 64],
pub sse_size: int32_t,
pub detection_hints: [uint8_t; CPU_HINTS_MAX],
}

#[link(name = "cpuid")]
extern {
pub fn cpuid_present() -> c_int;
pub fn cpuid_lib_version() -> *const c_char;
pub fn cpuid_error() -> *const c_char;
pub fn cpuid_get_raw_data(raw: *mut cpu_raw_data_t) -> c_int;
pub fn cpu_identify(raw: *mut cpu_raw_data_t, data: *mut cpu_id_t) -> c_int;
pub fn cpu_clock() -> c_int;
}
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
33 changes: 19 additions & 14 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
extern crate libc;

use std::ffi::CStr;
use std::mem;
use std::str;

mod ffi;
Expand Down Expand Up @@ -81,7 +80,7 @@ pub struct CpuInfo {
pub l2_cache: Option<i32>,
/// L3 cache size in kB. `Some(0)` if the CPU lacks L3 cache, `None` if it couldn't be determined.
pub l3_cache: Option<i32>,
flags: [u8; ffi::CPU_FLAGS_MAX],
flags: [u8; ffi::CPU_FLAGS_MAX as usize],
}

/// CPU feature identifiers.
Expand Down Expand Up @@ -195,15 +194,18 @@ impl CpuInfo {

/// Checks if the CPUID instruction is present.
pub fn is_present() -> bool {
unsafe { ffi::cpuid_present() == 1 }
let result = unsafe { ffi::cpuid_present() };
result != 0
}

/// Returns libcpuid version string.
pub fn version() -> String {
unsafe {
let ptr = ffi::cpuid_lib_version();
let bytes = CStr::from_ptr(ptr).to_bytes();
str::from_utf8(bytes).ok().expect("Invalid UTF8 string").to_string()
CStr::from_ptr(ptr)
.to_str()
.expect("Invalid UTF8 string")
.to_string()
}
}

Expand All @@ -212,7 +214,10 @@ pub fn error() -> String {
unsafe {
let ptr = ffi::cpuid_error();
let bytes = CStr::from_ptr(ptr).to_bytes();
str::from_utf8(bytes).ok().expect("Invalid UTF8 string").to_string()
str::from_utf8(bytes)
.ok()
.expect("Invalid UTF8 string")
.to_string()
}
}

Expand All @@ -223,26 +228,26 @@ pub fn error() -> String {
/// If libcpuid encounters an error, `identify` returns an `Err` with
/// the error message inside.
pub fn identify() -> Result<CpuInfo, String> {
let mut raw: ffi::cpu_raw_data_t = unsafe { mem::uninitialized() };
let mut raw: ffi::cpu_raw_data_t = unsafe { std::mem::zeroed() };
let raw_result = unsafe { ffi::cpuid_get_raw_data(&mut raw) };
if raw_result != 0 {
return Err(error());
}
let mut data: ffi::cpu_id_t = unsafe { mem::uninitialized() };
let mut data: ffi::cpu_id_t = unsafe { std::mem::zeroed() };
let identify_result = unsafe { ffi::cpu_identify(&mut raw, &mut data) };
if identify_result != 0 {
Err(error())
} else {
Ok(CpuInfo {
vendor: String::from_utf8(data.vendor_str.iter().map(|&x| x as u8).collect())
.ok()
.expect("Invalid vendor string"),
.ok()
.expect("Invalid vendor string"),
brand: String::from_utf8(data.brand_str.iter().map(|&x| x as u8).collect())
.ok()
.expect("Invalid brand string"),
.ok()
.expect("Invalid brand string"),
codename: String::from_utf8(data.cpu_codename.iter().map(|&x| x as u8).collect())
.ok()
.expect("Invalid codename string"),
.ok()
.expect("Invalid codename string"),
num_cores: data.num_cores,
num_logical_cpus: data.num_logical_cpus,
total_logical_cpus: data.total_logical_cpus,
Expand Down
22 changes: 12 additions & 10 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
extern crate cpuid;

#[cfg(not(test))]
fn main() {
println!("cpuid is present: {}", cpuid::is_present());
println!("cpuid version: {}", cpuid::version());
match cpuid::identify() {
Ok(info) => {
println!("Found: {} CPU, model: {}", info.vendor, info.codename);
println!("The full brand string is: {}", info.brand);
println!("The processor has {} cores and {} logical processors",
info.num_cores,
info.num_logical_cpus);
println!("Hardware AES support: {}",
if info.has_feature(cpuid::CpuFeature::AES) {
"yes"
} else {
"no"
});
println!(
"The processor has {} cores and {} logical processors",
info.num_cores, info.num_logical_cpus
);
println!(
"Hardware AES support: {}",
if info.has_feature(cpuid::CpuFeature::AES) {
"yes"
} else {
"no"
}
);
}
Err(err) => println!("cpuid error: {}", err),
}
Expand Down
3 changes: 3 additions & 0 deletions wrapper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include <libcpuid/libcpuid.h>
#include <libcpuid/libcpuid_constants.h>
#include <libcpuid/libcpuid_types.h>