Skip to content
This repository was archived by the owner on Nov 7, 2022. It is now read-only.

Commit

Permalink
Add support for using the Arm v8.5-RNG
Browse files Browse the repository at this point in the history
  • Loading branch information
AGSaidi authored and andre-richter committed May 20, 2022
1 parent fd76eb6 commit 95cfdb1
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
//! Wrappers around ARMv8-A instructions.
pub mod barrier;
pub mod random;

/// The classic no-op
#[inline(always)]
Expand Down
111 changes: 111 additions & 0 deletions src/asm/random.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Copyright (c) 2022 Amazon.com, Inc. or its affiliates.
//
// Author(s):
// - Ali Saidi <[email protected]>


/// Implement an interface for accessing Arm v8.5 RNG instructions.
/// An empty struct is used to confirm that the system has the
/// instructions available.
/// # Example:
/// ```no_run
/// use cortex_a::asm::random::ArmRng;
/// if let Some(rng) = ArmRng::new() {
/// let rand_num = rng.rndr();
/// }
/// ```
#[derive(Copy, Clone, Debug)]
pub struct ArmRng;

use crate::registers::ID_AA64ISAR0_EL1;
use core::arch::asm;
use tock_registers::interfaces::Readable;

impl ArmRng {
/// Return an empty object that is used to gate calling
/// rndr and rndrss on discovery of the feature so each
/// call doesn't need to confirm it.
#[inline]
pub fn new() -> Option<Self> {
#[cfg(not(target_arch = "aarch64"))]
return None;

#[cfg(target_arch = "aarch64")]
if ID_AA64ISAR0_EL1.is_set(ID_AA64ISAR0_EL1::RNDR) {
Some(ArmRng)
} else {
None
}
}

/// Return an random number from the Arm v8.5 RNG.
/// This returns an option because the instruction can fail
/// (e.g. the entropy is exhausted or the RNG has failed.)
#[inline]
pub fn rndr(&self) -> Option<u64> {
let mut flags: u64;
let mut data: u64;

#[cfg(target_arch = "aarch64")]
unsafe {
asm!(
"mrs {o}, s3_3_c2_c4_0",
"mrs {f}, nzcv",
o = out(reg) data,
f = out(reg) flags,
options(nomem, nostack));
}
if cfg!(not(target_arch = "aarch64")) || flags != 0 {
None
} else {
Some(data)
}
}

/// Return an random number from the Arm v8.5 RNG after reseeding it
/// This returns an option because the instruction can fail
/// (e.g. the entropy is exhausted or the RNG has failed.)
#[inline]
pub fn rndrss(&self) -> Option<u64> {
let mut flags: u64;
let mut data: u64;

#[cfg(target_arch = "aarch64")]
unsafe {
asm!(
"mrs {o}, s3_3_c2_c4_1",
"mrs {f}, nzcv",
o = out(reg) data,
f = out(reg) flags,
options(nomem, nostack));
}

if cfg!(not(target_arch = "aarch64")) || flags != 0 {
None
} else {
Some(data)
}
}


}


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

#[test]
pub fn test_rndr() {
// This works on Linux from userspace since Linux emulatates
// the Arm ID registers on the userspace undef.
if let Some(rand) = ArmRng::new() {
assert!(rand.rndr().unwrap() != 0);
assert!(rand.rndrss().unwrap() != 0);
}
}

}

2 changes: 2 additions & 0 deletions src/registers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ mod far_el2;
mod fp;
mod hcr_el2;
mod id_aa64mmfr0_el1;
mod id_aa64isar0_el1;
mod lr;
mod mair_el1;
mod mair_el2;
Expand Down Expand Up @@ -78,6 +79,7 @@ pub use far_el2::FAR_EL2;
pub use fp::FP;
pub use hcr_el2::HCR_EL2;
pub use id_aa64mmfr0_el1::ID_AA64MMFR0_EL1;
pub use id_aa64isar0_el1::ID_AA64ISAR0_EL1;
pub use lr::LR;
pub use mair_el1::MAIR_EL1;
pub use mair_el2::MAIR_EL2;
Expand Down
38 changes: 38 additions & 0 deletions src/registers/id_aa64isar0_el1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT
//
// Copyright (c) 2022 Amazon.com, Inc. or its affiliates.
//
// Author(s):
// - Ali Saidi <[email protected]>

//! AArch64 Instruction Set Architecture Feature Register 0 - EL1
//!
//! Provides information about the implemented instruction set.
use tock_registers::{interfaces::Readable, register_bitfields};

register_bitfields! {u64,
pub ID_AA64ISAR0_EL1 [
/// Support for Random Number instructions in AArch64.
///
/// 0000 No random number instructions are implemented
/// 0001 RNDR and RNDRSS are implemented
///
/// All other values are reserved.
RNDR OFFSET(60) NUMBITS(4) [
Supported = 0b0001,
NotSupported = 0b0000
],
]
}

pub struct Reg;

impl Readable for Reg {
type T = u64;
type R = ID_AA64ISAR0_EL1::Register;

sys_coproc_read_raw!(u64, "ID_AA64ISAR0_EL1", "x");
}

pub const ID_AA64ISAR0_EL1: Reg = Reg {};

0 comments on commit 95cfdb1

Please sign in to comment.