Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rdrand: Add 32-bit x86 support #134

Merged
merged 1 commit into from
Feb 20, 2020
Merged
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
16 changes: 15 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
language: rust
os: linux

# Targets that we just build (rather than run and test)
env:
global:
# All of the supported x86 Linux targets
- LINUX_TARGETS="x86_64-unknown-linux-gnu x86_64-unknown-linux-musl i686-unknown-linux-gnu i686-unknown-linux-musl"
# Targets that we just build (rather than run and test)
- STD_TARGETS="x86_64-sun-solaris x86_64-unknown-cloudabi x86_64-unknown-freebsd x86_64-fuchsia x86_64-unknown-netbsd x86_64-unknown-redox x86_64-fortanix-unknown-sgx"
- NO_STD_TARGETS="x86_64-unknown-uefi x86_64-unknown-hermit x86_64-unknown-l4re-uclibc x86_64-uwp-windows-gnu x86_64-wrs-vxworks"

Expand Down Expand Up @@ -112,6 +114,18 @@ jobs:
name: "OSX, nightly, docs"
os: osx

- name: "cross-platform tests"
rust: nightly
addons:
apt:
packages:
- gcc-multilib
install:
- echo $LINUX_TARGETS | xargs -n1 rustup target add
script:
# We run tests for all supported x86 Linux targets
- echo $LINUX_TARGETS | xargs -t -n1 cargo test --target

- name: "cross-platform build only"
rust: nightly
install:
Expand Down
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,8 @@ cfg_if! {
#[path = "rdrand.rs"] mod imp;
} else if #[cfg(feature = "custom")] {
use custom as imp;
} else if #[cfg(all(feature = "cpu", target_arch = "x86_64"))] {
} else if #[cfg(all(feature = "cpu",
any(target_arch = "x86_64", target_arch = "x86")))] {
#[path = "rdrand.rs"] mod imp;
} else {
compile_error!("\
Expand Down
25 changes: 17 additions & 8 deletions src/rdrand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,30 @@
// except according to those terms.

//! Implementation for SGX using RDRAND instruction
#[cfg(not(target_feature = "rdrand"))]
use crate::util::LazyBool;
use crate::Error;
use core::arch::x86_64::_rdrand64_step;
use core::mem;

cfg_if! {
if #[cfg(target_arch = "x86_64")] {
use core::arch::x86_64 as arch;
use arch::_rdrand64_step as rdrand_step;
} else if #[cfg(target_arch = "x86")] {
use core::arch::x86 as arch;
use arch::_rdrand32_step as rdrand_step;
}
}

// Recommendation from "Intel® Digital Random Number Generator (DRNG) Software
// Implementation Guide" - Section 5.2.1 and "Intel® 64 and IA-32 Architectures
// Software Developer’s Manual" - Volume 1 - Section 7.3.17.1.
const RETRY_LIMIT: usize = 10;
const WORD_SIZE: usize = mem::size_of::<u64>();
const WORD_SIZE: usize = mem::size_of::<usize>();

#[target_feature(enable = "rdrand")]
unsafe fn rdrand() -> Result<[u8; WORD_SIZE], Error> {
for _ in 0..RETRY_LIMIT {
let mut el = mem::zeroed();
if _rdrand64_step(&mut el) == 1 {
if rdrand_step(&mut el) == 1 {
// AMD CPUs from families 14h to 16h (pre Ryzen) sometimes fail to
// set CF on bogus random data, so we check these values explicitly.
// See https://github.com/systemd/systemd/issues/11810#issuecomment-489727505
Expand Down Expand Up @@ -53,11 +60,13 @@ fn is_rdrand_supported() -> bool {
// https://github.com/rust-lang-nursery/stdsimd/issues/464
#[cfg(not(target_feature = "rdrand"))]
fn is_rdrand_supported() -> bool {
use core::arch::x86_64::__cpuid;
// SAFETY: All x86_64 CPUs support CPUID leaf 1
use crate::util::LazyBool;

// SAFETY: All Rust x86 targets are new enough to have CPUID, and if CPUID
// is supported, CPUID leaf 1 is always supported.
const FLAG: u32 = 1 << 30;
static HAS_RDRAND: LazyBool = LazyBool::new();
HAS_RDRAND.unsync_init(|| unsafe { (__cpuid(1).ecx & FLAG) != 0 })
HAS_RDRAND.unsync_init(|| unsafe { (arch::__cpuid(1).ecx & FLAG) != 0 })
}

pub fn getrandom_inner(dest: &mut [u8]) -> Result<(), Error> {
Expand Down
2 changes: 1 addition & 1 deletion src/test_cpu.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// We only test the CPU-based RNG source on supported architectures.
#![cfg(target_arch = "x86_64")]
#![cfg(any(target_arch = "x86_64", target_arch = "x86"))]

#[path = "rdrand.rs"]
mod rdrand;
Expand Down