diff --git a/coresimd/x86/i686/mod.rs b/coresimd/x86/i686/mod.rs index 7dd55802e3eaf..fd2533d219440 100644 --- a/coresimd/x86/i686/mod.rs +++ b/coresimd/x86/i686/mod.rs @@ -3,6 +3,9 @@ mod aes; pub use self::aes::*; +mod rdrand; +pub use self::rdrand::*; + mod mmx; pub use self::mmx::*; diff --git a/coresimd/x86/i686/rdrand.rs b/coresimd/x86/i686/rdrand.rs new file mode 100644 index 0000000000000..e15da28e0e495 --- /dev/null +++ b/coresimd/x86/i686/rdrand.rs @@ -0,0 +1,57 @@ +//! RDRAND and RDSEED instructions for returning random numbers from an Intel +//! on-chip hardware random number generator which has been seeded by an on-chip +//! entropy source. + +extern "platform-intrinsic" { + fn x86_rdrand16_step() -> (u16, i32); + fn x86_rdrand32_step() -> (u32, i32); + fn x86_rdseed16_step() -> (u16, i32); + fn x86_rdseed32_step() -> (u32, i32); +} + +#[cfg(test)] +use stdsimd_test::assert_instr; + +/// Read a hardware generated 16-bit random value and store the result in val. +/// Return 1 if a random value was generated, and 0 otherwise. +#[inline] +#[target_feature(enable = "rdrand")] +#[cfg_attr(test, assert_instr(rdrand))] +pub unsafe fn _rdrand16_step(val: &mut u16) -> i32 { + let (v, flag) = x86_rdrand16_step(); + *val = v; + flag +} + +/// Read a hardware generated 32-bit random value and store the result in val. +/// Return 1 if a random value was generated, and 0 otherwise. +#[inline] +#[target_feature(enable = "rdrand")] +#[cfg_attr(test, assert_instr(rdrand))] +pub unsafe fn _rdrand32_step(val: &mut u32) -> i32 { + let (v, flag) = x86_rdrand32_step(); + *val = v; + flag +} + +/// Read a 16-bit NIST SP800-90B and SP800-90C compliant random value and store +/// in val. Return 1 if a random value was generated, and 0 otherwise. +#[inline] +#[target_feature(enable = "rdseed")] +#[cfg_attr(test, assert_instr(rdseed))] +pub unsafe fn _rdseed16_step(val: &mut u16) -> i32 { + let (v, flag) = x86_rdseed16_step(); + *val = v; + flag +} + +/// Read a 32-bit NIST SP800-90B and SP800-90C compliant random value and store +/// in val. Return 1 if a random value was generated, and 0 otherwise. +#[inline] +#[target_feature(enable = "rdseed")] +#[cfg_attr(test, assert_instr(rdseed))] +pub unsafe fn _rdseed32_step(val: &mut u32) -> i32 { + let (v, flag) = x86_rdseed32_step(); + *val = v; + flag +} diff --git a/coresimd/x86/x86_64/mod.rs b/coresimd/x86/x86_64/mod.rs index 3b21197aa88e1..f258054c08cef 100644 --- a/coresimd/x86/x86_64/mod.rs +++ b/coresimd/x86/x86_64/mod.rs @@ -37,3 +37,6 @@ pub use self::avx2::*; mod bswap; pub use self::bswap::*; + +mod rdrand; +pub use self::rdrand::*; diff --git a/coresimd/x86/x86_64/rdrand.rs b/coresimd/x86/x86_64/rdrand.rs new file mode 100644 index 0000000000000..b3311c2b96373 --- /dev/null +++ b/coresimd/x86/x86_64/rdrand.rs @@ -0,0 +1,33 @@ +//! RDRAND and RDSEED instructions for returning random numbers from an Intel +//! on-chip hardware random number generator which has been seeded by an on-chip +//! entropy source. + +extern "platform-intrinsic" { + fn x86_rdrand64_step() -> (u64, i32); + fn x86_rdseed64_step() -> (u64, i32); +} + +#[cfg(test)] +use stdsimd_test::assert_instr; + +/// Read a hardware generated 64-bit random value and store the result in val. +/// Return 1 if a random value was generated, and 0 otherwise. +#[inline] +#[target_feature(enable = "rdrand")] +#[cfg_attr(test, assert_instr(rdrand))] +pub unsafe fn _rdrand64_step(val: &mut u64) -> i32 { + let (v, flag) = x86_rdrand64_step(); + *val = v; + flag +} + +/// Read a 64-bit NIST SP800-90B and SP800-90C compliant random value and store +/// in val. Return 1 if a random value was generated, and 0 otherwise. +#[inline] +#[target_feature(enable = "rdseed")] +#[cfg_attr(test, assert_instr(rdseed))] +pub unsafe fn _rdseed64_step(val: &mut u64) -> i32 { + let (v, flag) = x86_rdseed64_step(); + *val = v; + flag +} diff --git a/crates/stdsimd-verify/tests/x86-intel.rs b/crates/stdsimd-verify/tests/x86-intel.rs index 2d4b5f1f85542..f39571f2f257c 100644 --- a/crates/stdsimd-verify/tests/x86-intel.rs +++ b/crates/stdsimd-verify/tests/x86-intel.rs @@ -395,6 +395,7 @@ fn equate(t: &Type, (&Type::Ptr(&Type::PrimSigned(32)), "int*") => {} (&Type::Ptr(&Type::PrimSigned(64)), "__int64*") => {} (&Type::Ptr(&Type::PrimSigned(8)), "char*") => {} + (&Type::Ptr(&Type::PrimUnsigned(16)), "unsigned short*") => {} (&Type::Ptr(&Type::PrimUnsigned(32)), "unsigned int*") => {} (&Type::Ptr(&Type::PrimUnsigned(64)), "unsigned __int64*") => {} (&Type::Ptr(&Type::PrimUnsigned(8)), "const void*") => {} diff --git a/stdsimd/arch/detect/x86.rs b/stdsimd/arch/detect/x86.rs index 6fe0924230f73..7a0681f60fc94 100644 --- a/stdsimd/arch/detect/x86.rs +++ b/stdsimd/arch/detect/x86.rs @@ -34,6 +34,12 @@ macro_rules! is_target_feature_detected { ("pclmulqdq") => { $crate::arch::detect::check_for( $crate::arch::detect::Feature::pclmulqdq) }; + ("rdrand") => { + $crate::arch::detect::check_for( + $crate::arch::detect::Feature::rdrand) }; + ("rdseed") => { + $crate::arch::detect::check_for( + $crate::arch::detect::Feature::rdseed) }; ("tsc") => { $crate::arch::detect::check_for( $crate::arch::detect::Feature::tsc) }; @@ -180,6 +186,10 @@ pub enum Feature { aes, /// CLMUL (Carry-less Multiplication) pclmulqdq, + /// RDRAND + rdrand, + /// RDSEED + rdseed, /// TSC (Time Stamp Counter) tsc, /// MMX @@ -352,6 +362,8 @@ pub fn detect_features() -> cache::Initializer { enable(proc_info_ecx, 23, Feature::popcnt); enable(proc_info_ecx, 25, Feature::aes); enable(proc_info_ecx, 1, Feature::pclmulqdq); + enable(proc_info_ecx, 30, Feature::rdrand); + enable(extended_features_ebx, 18, Feature::rdseed); enable(proc_info_edx, 4, Feature::tsc); enable(proc_info_edx, 23, Feature::mmx); enable(proc_info_edx, 24, Feature::fxsr); @@ -465,6 +477,8 @@ mod tests { fn dump() { println!("aes: {:?}", is_target_feature_detected!("aes")); println!("pclmulqdq: {:?}", is_target_feature_detected!("pclmulqdq")); + println!("rdrand: {:?}", is_target_feature_detected!("rdrand")); + println!("rdseed: {:?}", is_target_feature_detected!("rdseed")); println!("tsc: {:?}", is_target_feature_detected!("tsc")); println!("sse: {:?}", is_target_feature_detected!("sse")); println!("sse2: {:?}", is_target_feature_detected!("sse2")); @@ -507,6 +521,8 @@ mod tests { let information = cupid::master().unwrap(); assert_eq!(is_target_feature_detected!("aes"), information.aesni()); assert_eq!(is_target_feature_detected!("pclmulqdq"), information.pclmulqdq()); + assert_eq!(is_target_feature_detected!("rdrand"), information.rdrand()); + assert_eq!(is_target_feature_detected!("rdseed"), information.rdseed()); assert_eq!(is_target_feature_detected!("tsc"), information.tsc()); assert_eq!(is_target_feature_detected!("sse"), information.sse()); assert_eq!(is_target_feature_detected!("sse2"), information.sse2());