Skip to content

Commit

Permalink
Remove raw-cpuid dependency and use rdrand intrinsics
Browse files Browse the repository at this point in the history
  • Loading branch information
64 committed Jul 18, 2019
1 parent 1adc1dd commit d21458f
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 38 deletions.
3 changes: 0 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@ array-init = "0.0.4"
version = "0.2.2"
default-features = false

[target.'cfg(target_arch = "x86_64")'.dependencies]
raw-cpuid = "6.1.0"

[dependencies.ux]
default-features = false
version = "0.1.3"
Expand Down
83 changes: 48 additions & 35 deletions src/instructions/random.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,64 +8,77 @@ pub struct RdRand(());
impl RdRand {
/// Creates Some(RdRand) if RDRAND is supported, None otherwise
pub fn new() -> Option<Self> {
let cpuid = raw_cpuid::CpuId::new();
let has_rdrand = match cpuid.get_feature_info() {
Some(finfo) => finfo.has_rdrand(),
None => false,
};

match has_rdrand {
true => Some(RdRand(())),
false => None,
// RDRAND support indicated by CPUID page 01h, ecx bit 30
// https://en.wikipedia.org/wiki/RdRand#Overview
let cpuid = unsafe { core::arch::x86_64::__cpuid(0x1) };
if cpuid.ecx & (1 << 30) != 0 {
Some(RdRand(()))
} else {
None
}
}

/// Uniformly sampled u64.
/// May fail in rare circumstances or heavy load.
#[inline]
pub fn get_u64(&self) -> Option<u64> {
let res: u64;
let ok: u8;
let mut res: u64 = 0;
unsafe {
asm!("rdrand %rax; setc $1;"
: "={rax}"(res) "=r"(ok)
:: "flags" : "volatile");
}
match ok {
1 => Some(res),
_ => None,
match core::arch::x86_64::_rdrand64_step(&mut res) {
1 => Some(res),
x => {
debug_assert_eq!(x, 0, "rdrand64 returned non-binary value");
None
}
}
}
}
/// Uniformly sampled u32.
/// May fail in rare circumstances or heavy load.
#[inline]
pub fn get_u32(&self) -> Option<u32> {
let res: u32;
let ok: u8;
let mut res: u32 = 0;
unsafe {
asm!("rdrand %eax; setc $1;"
: "={eax}"(res) "=r"(ok)
:: "flags" : "volatile");
}
match ok {
1 => Some(res),
_ => None,
match core::arch::x86_64::_rdrand32_step(&mut res) {
1 => Some(res),
x => {
debug_assert_eq!(x, 0, "rdrand32 returned non-binary value");
None
}
}
}
}
/// Uniformly sampled u16.
/// May fail in rare circumstances or heavy load.
#[inline]
pub fn get_u16(&self) -> Option<u16> {
let res: u16;
let ok: u8;
let mut res: u16 = 0;
unsafe {
asm!("rdrand %ax; setc $1;"
: "={ax}"(res) "=r"(ok)
:: "flags" : "volatile");
match core::arch::x86_64::_rdrand16_step(&mut res) {
1 => Some(res),
x => {
debug_assert_eq!(x, 0, "rdrand16 returned non-binary value");
None
}
}
}
match ok {
1 => Some(res),
_ => None,
}
}

#[cfg(all(test, target_arch = "x86_64"))]
mod tests {
use super::*;

#[test]
pub fn test_rdrand() {
let rand = RdRand::new();
if is_x86_feature_detected!("rdrand") {
let rand = rand.unwrap();
assert!(rand.get_u16().is_some());
assert!(rand.get_u32().is_some());
assert!(rand.get_u64().is_some());
} else {
assert!(rand.is_none());
}
}
}

0 comments on commit d21458f

Please sign in to comment.