vmbase: Move Trng internals to arch::aarch64
This commit moves trng implementation from common rand module to a
aarch64 arch module. This is at the moment purely cosmetic change,
however the purpose is move all aarch64 specific code away from common
modules to enable bringup of x86_64 support.
Bug: 362733888
Test: m pvmfw
Test: pVM boots with pvmfw
Change-Id: I5ac315ed38491de8b66f07a5df703cb50786c8bb
diff --git a/libs/libvmbase/src/arch.rs b/libs/libvmbase/src/arch.rs
index 49978d5..cc42939 100644
--- a/libs/libvmbase/src/arch.rs
+++ b/libs/libvmbase/src/arch.rs
@@ -30,6 +30,9 @@
pub use aarch64::dbm;
#[cfg(target_arch = "aarch64")]
+pub use aarch64::rand;
+
+#[cfg(target_arch = "aarch64")]
pub use aarch64::uart;
#[cfg(target_arch = "aarch64")]
diff --git a/libs/libvmbase/src/arch/aarch64.rs b/libs/libvmbase/src/arch/aarch64.rs
index 05b5566..9c4d256 100644
--- a/libs/libvmbase/src/arch/aarch64.rs
+++ b/libs/libvmbase/src/arch/aarch64.rs
@@ -21,6 +21,7 @@
pub mod linker;
pub mod page_table;
pub mod platform;
+pub mod rand;
pub mod uart;
/// Reads a value from a system register.
diff --git a/libs/libvmbase/src/arch/aarch64/rand.rs b/libs/libvmbase/src/arch/aarch64/rand.rs
new file mode 100644
index 0000000..4fd1905
--- /dev/null
+++ b/libs/libvmbase/src/arch/aarch64/rand.rs
@@ -0,0 +1,131 @@
+// Copyright 2025, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! Random number generator implementation for aarch64 platforms using TRNG
+
+use crate::arch::aarch64::hvc;
+use crate::rand::{Entropy, Error, Result};
+use core::fmt;
+use core::mem::size_of;
+use smccc::{self, Hvc};
+use zerocopy::IntoBytes as _;
+
+/// Error type for rand operations.
+pub enum PlatformError {
+ /// Error during architectural SMCCC call.
+ Smccc(smccc::arch::Error),
+ /// Error during SMCCC TRNG call.
+ Trng(hvc::trng::Error),
+ /// Unsupported SMCCC version.
+ UnsupportedSmcccVersion(smccc::arch::Version),
+ /// Unsupported SMCCC TRNG version.
+ UnsupportedTrngVersion(hvc::trng::Version),
+}
+
+impl From<smccc::arch::Error> for Error {
+ fn from(e: smccc::arch::Error) -> Self {
+ Self::Platform(PlatformError::Smccc(e))
+ }
+}
+
+impl From<hvc::trng::Error> for Error {
+ fn from(e: hvc::trng::Error) -> Self {
+ Self::Platform(PlatformError::Trng(e))
+ }
+}
+
+impl fmt::Display for PlatformError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ Self::Smccc(e) => write!(f, "Architectural SMCCC error: {e}"),
+ Self::Trng(e) => write!(f, "SMCCC TRNG error: {e}"),
+ Self::UnsupportedSmcccVersion(v) => write!(f, "Unsupported SMCCC version {v}"),
+ Self::UnsupportedTrngVersion(v) => write!(f, "Unsupported SMCCC TRNG version {v}"),
+ }
+ }
+}
+
+impl fmt::Debug for PlatformError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{self}")
+ }
+}
+
+pub(crate) const MAX_BYTES_PER_CALL: usize = size_of::<u64>() * 3;
+
+/// Configure the source of entropy.
+pub(crate) fn init() -> Result<()> {
+ // SMCCC TRNG requires SMCCC v1.1.
+ match smccc::arch::version::<Hvc>()? {
+ smccc::arch::Version { major: 1, minor } if minor >= 1 => (),
+ version => return Err(PlatformError::UnsupportedSmcccVersion(version).into()),
+ }
+
+ // TRNG_RND requires SMCCC TRNG v1.0.
+ match hvc::trng_version()? {
+ hvc::trng::Version { major: 1, minor: _ } => (),
+ version => return Err(PlatformError::UnsupportedTrngVersion(version).into()),
+ }
+
+ // TRNG_RND64 doesn't define any special capabilities so ignore the successful result.
+ let _ = hvc::trng_features(hvc::ARM_SMCCC_TRNG_RND64).map_err(|e| {
+ if e == hvc::trng::Error::NotSupported {
+ // SMCCC TRNG is currently our only source of entropy.
+ Error::NoEntropySource
+ } else {
+ e.into()
+ }
+ })?;
+
+ Ok(())
+}
+
+/// Returns an array where the first `n_bytes` bytes hold entropy.
+///
+/// The rest of the array should be ignored.
+pub(crate) fn platform_entropy(n_bytes: usize) -> Result<Entropy> {
+ loop {
+ if let Some(entropy) = rnd64(n_bytes)? {
+ return Ok(entropy);
+ }
+ }
+}
+
+/// Returns an array where the first `n_bytes` bytes hold entropy, if available.
+///
+/// The rest of the array should be ignored.
+fn rnd64(n_bytes: usize) -> Result<Option<Entropy>> {
+ let bits = usize::try_from(u8::BITS).unwrap();
+ let result = hvc::trng_rnd64((n_bytes * bits).try_into().unwrap());
+ let entropy = if matches!(result, Err(hvc::trng::Error::NoEntropy)) {
+ None
+ } else {
+ let r = result?;
+ // From the SMCCC TRNG:
+ //
+ // A MAX_BITS-bits wide value (Entropy) is returned across X1 to X3.
+ // The requested conditioned entropy is returned in Entropy[N-1:0].
+ //
+ // X1 Entropy[191:128]
+ // X2 Entropy[127:64]
+ // X3 Entropy[63:0]
+ //
+ // The bits in Entropy[MAX_BITS-1:N] are 0.
+ let reordered = [r[2].to_le(), r[1].to_le(), r[0].to_le()];
+
+ Some(reordered.as_bytes().try_into().unwrap())
+ };
+
+ Ok(entropy)
+}
diff --git a/libs/libvmbase/src/entry.rs b/libs/libvmbase/src/entry.rs
index 5db0f25..5c74753 100644
--- a/libs/libvmbase/src/entry.rs
+++ b/libs/libvmbase/src/entry.rs
@@ -38,7 +38,7 @@
// We keep a null byte at the top of the stack guard to act as a string terminator.
let random_guard = &mut stack_guard[..(SIZE_OF_STACK_GUARD - 1)];
- if let Err(e) = rand::init() {
+ if let Err(e) = crate::arch::rand::init() {
panic!("Failed to initialize a source of entropy: {e}");
}
diff --git a/libs/libvmbase/src/rand.rs b/libs/libvmbase/src/rand.rs
index e4623b7..e4b8c63 100644
--- a/libs/libvmbase/src/rand.rs
+++ b/libs/libvmbase/src/rand.rs
@@ -14,37 +14,23 @@
//! Functions and drivers for obtaining true entropy.
-use crate::arch::aarch64::hvc;
+use crate::arch::rand::{platform_entropy, PlatformError, MAX_BYTES_PER_CALL};
use core::fmt;
-use core::mem::size_of;
-use smccc::{self, Hvc};
-use zerocopy::IntoBytes as _;
-type Entropy = [u8; size_of::<u64>() * 3];
+pub(crate) type Entropy = [u8; MAX_BYTES_PER_CALL];
/// Error type for rand operations.
pub enum Error {
/// No source of entropy found.
NoEntropySource,
- /// Error during architectural SMCCC call.
- Smccc(smccc::arch::Error),
- /// Error during SMCCC TRNG call.
- Trng(hvc::trng::Error),
- /// Unsupported SMCCC version.
- UnsupportedSmcccVersion(smccc::arch::Version),
- /// Unsupported SMCCC TRNG version.
- UnsupportedTrngVersion(hvc::trng::Version),
+
+ /// Platform specific error
+ Platform(PlatformError),
}
-impl From<smccc::arch::Error> for Error {
- fn from(e: smccc::arch::Error) -> Self {
- Self::Smccc(e)
- }
-}
-
-impl From<hvc::trng::Error> for Error {
- fn from(e: hvc::trng::Error) -> Self {
- Self::Trng(e)
+impl From<PlatformError> for Error {
+ fn from(e: PlatformError) -> Self {
+ Error::Platform(e)
}
}
@@ -55,10 +41,7 @@
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::NoEntropySource => write!(f, "No source of entropy available"),
- Self::Smccc(e) => write!(f, "Architectural SMCCC error: {e}"),
- Self::Trng(e) => write!(f, "SMCCC TRNG error: {e}"),
- Self::UnsupportedSmcccVersion(v) => write!(f, "Unsupported SMCCC version {v}"),
- Self::UnsupportedTrngVersion(v) => write!(f, "Unsupported SMCCC TRNG version {v}"),
+ Self::Platform(e) => write!(f, "Platform error: {e}"),
}
}
}
@@ -69,84 +52,16 @@
}
}
-/// Configure the source of entropy.
-pub(crate) fn init() -> Result<()> {
- // SMCCC TRNG requires SMCCC v1.1.
- match smccc::arch::version::<Hvc>()? {
- smccc::arch::Version { major: 1, minor } if minor >= 1 => (),
- version => return Err(Error::UnsupportedSmcccVersion(version)),
- }
-
- // TRNG_RND requires SMCCC TRNG v1.0.
- match hvc::trng_version()? {
- hvc::trng::Version { major: 1, minor: _ } => (),
- version => return Err(Error::UnsupportedTrngVersion(version)),
- }
-
- // TRNG_RND64 doesn't define any special capabilities so ignore the successful result.
- let _ = hvc::trng_features(hvc::ARM_SMCCC_TRNG_RND64).map_err(|e| {
- if e == hvc::trng::Error::NotSupported {
- // SMCCC TRNG is currently our only source of entropy.
- Error::NoEntropySource
- } else {
- e.into()
- }
- })?;
-
- Ok(())
-}
-
/// Fills a slice of bytes with true entropy.
pub fn fill_with_entropy(s: &mut [u8]) -> Result<()> {
- const MAX_BYTES_PER_CALL: usize = size_of::<Entropy>();
-
for chunk in s.chunks_mut(MAX_BYTES_PER_CALL) {
- let entropy = repeat_trng_rnd(chunk.len())?;
+ let entropy = platform_entropy(chunk.len())?;
chunk.clone_from_slice(&entropy[..chunk.len()]);
}
Ok(())
}
-/// Returns an array where the first `n_bytes` bytes hold entropy.
-///
-/// The rest of the array should be ignored.
-fn repeat_trng_rnd(n_bytes: usize) -> Result<Entropy> {
- loop {
- if let Some(entropy) = rnd64(n_bytes)? {
- return Ok(entropy);
- }
- }
-}
-
-/// Returns an array where the first `n_bytes` bytes hold entropy, if available.
-///
-/// The rest of the array should be ignored.
-fn rnd64(n_bytes: usize) -> Result<Option<Entropy>> {
- let bits = usize::try_from(u8::BITS).unwrap();
- let result = hvc::trng_rnd64((n_bytes * bits).try_into().unwrap());
- let entropy = if matches!(result, Err(hvc::trng::Error::NoEntropy)) {
- None
- } else {
- let r = result?;
- // From the SMCCC TRNG:
- //
- // A MAX_BITS-bits wide value (Entropy) is returned across X1 to X3.
- // The requested conditioned entropy is returned in Entropy[N-1:0].
- //
- // X1 Entropy[191:128]
- // X2 Entropy[127:64]
- // X3 Entropy[63:0]
- //
- // The bits in Entropy[MAX_BITS-1:N] are 0.
- let reordered = [r[2].to_le(), r[1].to_le(), r[0].to_le()];
-
- Some(reordered.as_bytes().try_into().unwrap())
- };
-
- Ok(entropy)
-}
-
/// Generate an array of fixed-size initialized with true-random bytes.
pub fn random_array<const N: usize>() -> Result<[u8; N]> {
let mut arr = [0; N];