From efe9b53eb026d13c2be5bc2334a311babcc3be92 Mon Sep 17 00:00:00 2001 From: newpavlov Date: Tue, 20 Feb 2018 16:50:31 +0300 Subject: [PATCH 1/4] implemented rdrand and rdseed intrinsics --- coresimd/x86/i686/mod.rs | 3 ++ coresimd/x86/i686/rdrand.rs | 80 +++++++++++++++++++++++++++++++++++++ stdsimd/arch/detect/x86.rs | 16 ++++++++ 3 files changed, 99 insertions(+) create mode 100644 coresimd/x86/i686/rdrand.rs diff --git a/coresimd/x86/i686/mod.rs b/coresimd/x86/i686/mod.rs index 7dd55802e3..e46acc38cf 100644 --- a/coresimd/x86/i686/mod.rs +++ b/coresimd/x86/i686/mod.rs @@ -9,6 +9,9 @@ pub use self::mmx::*; mod pclmulqdq; pub use self::pclmulqdq::*; +mod rdrand; +pub use self::rdrand::*; + mod sse; pub use self::sse::*; diff --git a/coresimd/x86/i686/rdrand.rs b/coresimd/x86/i686/rdrand.rs new file mode 100644 index 0000000000..f8d335afee --- /dev/null +++ b/coresimd/x86/i686/rdrand.rs @@ -0,0 +1,80 @@ +//! 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_rdrand64_step() -> (u64, i32); + fn x86_rdseed16_step() -> (u16, i32); + fn x86_rdseed32_step() -> (u32, i32); + fn x86_rdseed64_step() -> (u64, 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 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 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 +} + +/// 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/stdsimd/arch/detect/x86.rs b/stdsimd/arch/detect/x86.rs index 83532f1168..793d3c0dff 100644 --- a/stdsimd/arch/detect/x86.rs +++ b/stdsimd/arch/detect/x86.rs @@ -33,6 +33,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) }; @@ -179,6 +185,10 @@ pub enum Feature { aes, /// CLMUL (Carry-less Multiplication) pclmulqdq, + /// RDRAND + rdrand, + /// RDSEED + rdseed, /// TSC (Time Stamp Counter) tsc, /// MMX @@ -351,6 +361,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); @@ -464,6 +476,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")); @@ -506,6 +520,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()); From 878b68dad09ac7cb04de7cd6f000f38eeaf9d529 Mon Sep 17 00:00:00 2001 From: newpavlov Date: Thu, 22 Feb 2018 17:45:19 +0300 Subject: [PATCH 2/4] added "unsigned short*" case --- crates/stdsimd-verify/tests/x86-intel.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/stdsimd-verify/tests/x86-intel.rs b/crates/stdsimd-verify/tests/x86-intel.rs index 2d4b5f1f85..f39571f2f2 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*") => {} From b1ec4cf8f942d62bd402faa32fc2a8fff7a81952 Mon Sep 17 00:00:00 2001 From: newpavlov Date: Tue, 27 Feb 2018 16:46:45 +0300 Subject: [PATCH 3/4] moved rdrand from i686 to x86_64 --- coresimd/x86/i686/mod.rs | 3 --- coresimd/x86/x86_64/mod.rs | 3 +++ coresimd/x86/{i686 => x86_64}/rdrand.rs | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename coresimd/x86/{i686 => x86_64}/rdrand.rs (100%) diff --git a/coresimd/x86/i686/mod.rs b/coresimd/x86/i686/mod.rs index e46acc38cf..7dd55802e3 100644 --- a/coresimd/x86/i686/mod.rs +++ b/coresimd/x86/i686/mod.rs @@ -9,9 +9,6 @@ pub use self::mmx::*; mod pclmulqdq; pub use self::pclmulqdq::*; -mod rdrand; -pub use self::rdrand::*; - mod sse; pub use self::sse::*; diff --git a/coresimd/x86/x86_64/mod.rs b/coresimd/x86/x86_64/mod.rs index 3b21197aa8..f258054c08 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/i686/rdrand.rs b/coresimd/x86/x86_64/rdrand.rs similarity index 100% rename from coresimd/x86/i686/rdrand.rs rename to coresimd/x86/x86_64/rdrand.rs From 71df48b4af183b0717ee55847d08747f3da2efd7 Mon Sep 17 00:00:00 2001 From: newpavlov Date: Tue, 27 Feb 2018 16:56:08 +0300 Subject: [PATCH 4/4] 64 bit rdrand functions in x86_64, 16 and 32 in i686 --- coresimd/x86/i686/mod.rs | 3 ++ coresimd/x86/i686/rdrand.rs | 57 +++++++++++++++++++++++++++++++++++ coresimd/x86/x86_64/rdrand.rs | 49 +----------------------------- 3 files changed, 61 insertions(+), 48 deletions(-) create mode 100644 coresimd/x86/i686/rdrand.rs diff --git a/coresimd/x86/i686/mod.rs b/coresimd/x86/i686/mod.rs index 7dd55802e3..fd2533d219 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 0000000000..e15da28e0e --- /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/rdrand.rs b/coresimd/x86/x86_64/rdrand.rs index f8d335afee..b3311c2b96 100644 --- a/coresimd/x86/x86_64/rdrand.rs +++ b/coresimd/x86/x86_64/rdrand.rs @@ -1,40 +1,15 @@ //! 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_rdrand64_step() -> (u64, i32); - fn x86_rdseed16_step() -> (u16, i32); - fn x86_rdseed32_step() -> (u32, i32); fn x86_rdseed64_step() -> (u64, 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 hardware generated 64-bit random value and store the result in val. /// Return 1 if a random value was generated, and 0 otherwise. #[inline] @@ -46,28 +21,6 @@ pub unsafe fn _rdrand64_step(val: &mut u64) -> i32 { 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 -} - /// 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]