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

Commit 95cfdb1

Browse files
AGSaidiandre-richter
authored andcommitted
Add support for using the Arm v8.5-RNG
1 parent fd76eb6 commit 95cfdb1

File tree

4 files changed

+152
-0
lines changed

4 files changed

+152
-0
lines changed

src/asm.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
//! Wrappers around ARMv8-A instructions.
1010
1111
pub mod barrier;
12+
pub mod random;
1213

1314
/// The classic no-op
1415
#[inline(always)]

src/asm/random.rs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// SPDX-License-Identifier: Apache-2.0 OR MIT
2+
//
3+
// Copyright (c) 2022 Amazon.com, Inc. or its affiliates.
4+
//
5+
// Author(s):
6+
// - Ali Saidi <alisaidi@amazon.com>
7+
8+
9+
/// Implement an interface for accessing Arm v8.5 RNG instructions.
10+
/// An empty struct is used to confirm that the system has the
11+
/// instructions available.
12+
/// # Example:
13+
/// ```no_run
14+
/// use cortex_a::asm::random::ArmRng;
15+
/// if let Some(rng) = ArmRng::new() {
16+
/// let rand_num = rng.rndr();
17+
/// }
18+
/// ```
19+
#[derive(Copy, Clone, Debug)]
20+
pub struct ArmRng;
21+
22+
use crate::registers::ID_AA64ISAR0_EL1;
23+
use core::arch::asm;
24+
use tock_registers::interfaces::Readable;
25+
26+
impl ArmRng {
27+
/// Return an empty object that is used to gate calling
28+
/// rndr and rndrss on discovery of the feature so each
29+
/// call doesn't need to confirm it.
30+
#[inline]
31+
pub fn new() -> Option<Self> {
32+
#[cfg(not(target_arch = "aarch64"))]
33+
return None;
34+
35+
#[cfg(target_arch = "aarch64")]
36+
if ID_AA64ISAR0_EL1.is_set(ID_AA64ISAR0_EL1::RNDR) {
37+
Some(ArmRng)
38+
} else {
39+
None
40+
}
41+
}
42+
43+
/// Return an random number from the Arm v8.5 RNG.
44+
/// This returns an option because the instruction can fail
45+
/// (e.g. the entropy is exhausted or the RNG has failed.)
46+
#[inline]
47+
pub fn rndr(&self) -> Option<u64> {
48+
let mut flags: u64;
49+
let mut data: u64;
50+
51+
#[cfg(target_arch = "aarch64")]
52+
unsafe {
53+
asm!(
54+
"mrs {o}, s3_3_c2_c4_0",
55+
"mrs {f}, nzcv",
56+
o = out(reg) data,
57+
f = out(reg) flags,
58+
options(nomem, nostack));
59+
}
60+
if cfg!(not(target_arch = "aarch64")) || flags != 0 {
61+
None
62+
} else {
63+
Some(data)
64+
}
65+
}
66+
67+
/// Return an random number from the Arm v8.5 RNG after reseeding it
68+
/// This returns an option because the instruction can fail
69+
/// (e.g. the entropy is exhausted or the RNG has failed.)
70+
#[inline]
71+
pub fn rndrss(&self) -> Option<u64> {
72+
let mut flags: u64;
73+
let mut data: u64;
74+
75+
#[cfg(target_arch = "aarch64")]
76+
unsafe {
77+
asm!(
78+
"mrs {o}, s3_3_c2_c4_1",
79+
"mrs {f}, nzcv",
80+
o = out(reg) data,
81+
f = out(reg) flags,
82+
options(nomem, nostack));
83+
}
84+
85+
if cfg!(not(target_arch = "aarch64")) || flags != 0 {
86+
None
87+
} else {
88+
Some(data)
89+
}
90+
}
91+
92+
93+
}
94+
95+
96+
#[cfg(all(test, target_os = "linux"))]
97+
mod tests {
98+
use super::*;
99+
100+
#[test]
101+
pub fn test_rndr() {
102+
// This works on Linux from userspace since Linux emulatates
103+
// the Arm ID registers on the userspace undef.
104+
if let Some(rand) = ArmRng::new() {
105+
assert!(rand.rndr().unwrap() != 0);
106+
assert!(rand.rndrss().unwrap() != 0);
107+
}
108+
}
109+
110+
}
111+

src/registers.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ mod far_el2;
2828
mod fp;
2929
mod hcr_el2;
3030
mod id_aa64mmfr0_el1;
31+
mod id_aa64isar0_el1;
3132
mod lr;
3233
mod mair_el1;
3334
mod mair_el2;
@@ -78,6 +79,7 @@ pub use far_el2::FAR_EL2;
7879
pub use fp::FP;
7980
pub use hcr_el2::HCR_EL2;
8081
pub use id_aa64mmfr0_el1::ID_AA64MMFR0_EL1;
82+
pub use id_aa64isar0_el1::ID_AA64ISAR0_EL1;
8183
pub use lr::LR;
8284
pub use mair_el1::MAIR_EL1;
8385
pub use mair_el2::MAIR_EL2;

src/registers/id_aa64isar0_el1.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// SPDX-License-Identifier: Apache-2.0 OR MIT
2+
//
3+
// Copyright (c) 2022 Amazon.com, Inc. or its affiliates.
4+
//
5+
// Author(s):
6+
// - Ali Saidi <alisaidi@amazon.com>
7+
8+
//! AArch64 Instruction Set Architecture Feature Register 0 - EL1
9+
//!
10+
//! Provides information about the implemented instruction set.
11+
12+
use tock_registers::{interfaces::Readable, register_bitfields};
13+
14+
register_bitfields! {u64,
15+
pub ID_AA64ISAR0_EL1 [
16+
/// Support for Random Number instructions in AArch64.
17+
///
18+
/// 0000 No random number instructions are implemented
19+
/// 0001 RNDR and RNDRSS are implemented
20+
///
21+
/// All other values are reserved.
22+
RNDR OFFSET(60) NUMBITS(4) [
23+
Supported = 0b0001,
24+
NotSupported = 0b0000
25+
],
26+
]
27+
}
28+
29+
pub struct Reg;
30+
31+
impl Readable for Reg {
32+
type T = u64;
33+
type R = ID_AA64ISAR0_EL1::Register;
34+
35+
sys_coproc_read_raw!(u64, "ID_AA64ISAR0_EL1", "x");
36+
}
37+
38+
pub const ID_AA64ISAR0_EL1: Reg = Reg {};

0 commit comments

Comments
 (0)