Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/smccc_trng.rs
5392 views
1
// Copyright 2025 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
use std::ops::Range;
6
7
use anyhow::bail;
8
use base::fold_into_i32;
9
use base::warn;
10
use base::NegativeI32;
11
use base::U31;
12
use hypervisor::HypercallAbi;
13
use static_assertions::const_assert_ne;
14
use uuid::uuid;
15
use uuid::Uuid;
16
use vm_control::DeviceId;
17
use vm_control::PlatformDeviceId;
18
19
use crate::BusAccessInfo;
20
use crate::BusDevice;
21
use crate::BusDeviceSync;
22
use crate::Suspendable;
23
24
/// Error codes, as defined by the SMCCC TRNG (DEN0098).
25
///
26
/// Note that values are strictly positive but API return values are strictly negative.
27
#[repr(i32)]
28
#[derive(Clone, Copy, Debug)]
29
enum SmcccTrngError {
30
NotSupported = -1,
31
InvalidParameters = -2,
32
#[allow(unused)]
33
NoEntropy = -3,
34
}
35
36
impl SmcccTrngError {
37
const fn as_i32(&self) -> i32 {
38
*self as _
39
}
40
}
41
42
impl From<SmcccTrngError> for i32 {
43
fn from(e: SmcccTrngError) -> Self {
44
e.as_i32()
45
}
46
}
47
48
impl From<SmcccTrngError> for NegativeI32 {
49
fn from(e: SmcccTrngError) -> Self {
50
Self::new(e.as_i32()).unwrap()
51
}
52
}
53
54
/// A backend implementation of the SMCCC TRNG (DEN0098).
55
///
56
/// Might not be fully spec-compliant regarding the conditioned entropy.
57
pub struct SmcccTrng {}
58
59
impl Default for SmcccTrng {
60
fn default() -> Self {
61
Self::new()
62
}
63
}
64
65
impl SmcccTrng {
66
/// Standard function ID ranges for TRNG 32-bit calls, defined in SMCCC (DEN0028).
67
pub const HVC32_FID_RANGE: Range<u32> = 0x8400_0050..0x8400_0060;
68
/// Standard function ID ranges for TRNG 64-bit calls, defined in SMCCC (DEN0028).
69
pub const HVC64_FID_RANGE: Range<u32> = 0xC400_0050..0xC400_0060;
70
71
const FID_TRNG_VERSION: u32 = 0x8400_0050;
72
const FID_TRNG_FEATURES: u32 = 0x8400_0051;
73
const FID_TRNG_GET_UUID: u32 = 0x8400_0052;
74
const FID_TRNG_RND32: u32 = 0x8400_0053;
75
const FID_TRNG_RND64: u32 = 0xC400_0053;
76
77
const VERSION: (u16, u16) = (1, 0);
78
/// CrosVM SMCCC TRNG back-end UUID.
79
///
80
/// Equivalent to `Uuid::new_v8(*b"SMCCCTRNG-CrosVM")`.
81
const UUID: Uuid = uuid!("534d4343-4354-824e-872d-43726f73564d");
82
83
/// Creates a new instance of `SmcccTrng`.
84
pub fn new() -> Self {
85
Self {}
86
}
87
88
fn version(&self) -> Result<U31, SmcccTrngError> {
89
Ok(U31::new(((Self::VERSION.0 as u32) << 16) | (Self::VERSION.1 as u32)).unwrap())
90
}
91
92
fn features(&self, func_id: u32) -> Result<U31, SmcccTrngError> {
93
const AVAILABLE: U31 = U31::new(0).unwrap();
94
match func_id {
95
Self::FID_TRNG_VERSION => Ok(AVAILABLE),
96
Self::FID_TRNG_FEATURES => Ok(AVAILABLE),
97
Self::FID_TRNG_GET_UUID => Ok(AVAILABLE),
98
Self::FID_TRNG_RND32 => Ok(AVAILABLE),
99
Self::FID_TRNG_RND64 => Ok(AVAILABLE),
100
_ => Err(SmcccTrngError::NotSupported),
101
}
102
}
103
104
fn get_uuid(&self) -> Result<[u32; 4], SmcccTrngError> {
105
const UUID: u128 = SmcccTrng::UUID.to_u128_le();
106
const R3: u32 = (UUID >> (3 * u32::BITS)) as _;
107
const R2: u32 = (UUID >> (2 * u32::BITS)) as _;
108
const R1: u32 = (UUID >> u32::BITS) as _;
109
const R0: u32 = UUID as _;
110
// Otherwise return would be indistinguishable from SMCCC's NOT_SUPPORTED
111
const_assert_ne!(R0, u32::MAX);
112
113
Ok([R0, R1, R2, R3])
114
}
115
116
fn rnd32(&self, n_bits: u32) -> Result<[u32; 3], SmcccTrngError> {
117
match n_bits.div_ceil(u32::BITS) {
118
1 => Ok([rand::random(), 0, 0]),
119
2 => Ok([rand::random(), rand::random(), 0]),
120
3 => Ok([rand::random(), rand::random(), rand::random()]),
121
n => {
122
warn!("SMCCC TRNG: Invalid request for {n} u32 words");
123
Err(SmcccTrngError::InvalidParameters)
124
}
125
}
126
}
127
128
fn rnd64(&self, n_bits: u64) -> Result<[u64; 3], SmcccTrngError> {
129
match n_bits.div_ceil(u64::BITS.into()) {
130
1 => Ok([rand::random(), 0, 0]),
131
2 => Ok([rand::random(), rand::random(), 0]),
132
3 => Ok([rand::random(), rand::random(), rand::random()]),
133
n => {
134
warn!("SMCCC TRNG: Invalid request for {n} u64 words");
135
Err(SmcccTrngError::InvalidParameters)
136
}
137
}
138
}
139
}
140
141
fn as_signed_usize(i: i32) -> usize {
142
let sign_extended = i64::from(i);
143
(sign_extended as u64).try_into().unwrap()
144
}
145
146
impl BusDevice for SmcccTrng {
147
fn device_id(&self) -> DeviceId {
148
PlatformDeviceId::SmcccTrng.into()
149
}
150
151
fn debug_label(&self) -> String {
152
"SmcccTrng".to_owned()
153
}
154
155
fn handle_hypercall(&self, abi: &mut HypercallAbi) -> anyhow::Result<()> {
156
let regs = match abi.hypercall_id() as u32 {
157
Self::FID_TRNG_VERSION => {
158
let r0 = as_signed_usize(fold_into_i32(self.version()));
159
[r0, 0, 0, 0]
160
}
161
Self::FID_TRNG_FEATURES => {
162
let feat = (*abi.get_argument(0).unwrap()) as u32;
163
let r0 = as_signed_usize(fold_into_i32(self.features(feat)));
164
[r0, 0, 0, 0]
165
}
166
Self::FID_TRNG_GET_UUID => match self.get_uuid() {
167
Ok(uuid) => [
168
uuid[0].try_into().unwrap(),
169
uuid[1].try_into().unwrap(),
170
uuid[2].try_into().unwrap(),
171
uuid[3].try_into().unwrap(),
172
],
173
Err(e) => [as_signed_usize(e.into()), 0, 0, 0],
174
},
175
Self::FID_TRNG_RND32 => {
176
let n_bits = (*abi.get_argument(0).unwrap()) as u32;
177
match self.rnd32(n_bits) {
178
Ok(entropy) => [
179
0,
180
entropy[0].try_into().unwrap(),
181
entropy[1].try_into().unwrap(),
182
entropy[2].try_into().unwrap(),
183
],
184
Err(e) => [as_signed_usize(e.into()), 0, 0, 0],
185
}
186
}
187
Self::FID_TRNG_RND64 => {
188
let n_bits = (*abi.get_argument(0).unwrap()).try_into().unwrap();
189
match self.rnd64(n_bits) {
190
Ok(entropy) => [
191
0,
192
entropy[0].try_into().unwrap(),
193
entropy[1].try_into().unwrap(),
194
entropy[2].try_into().unwrap(),
195
],
196
Err(e) => [as_signed_usize(e.into()), 0, 0, 0],
197
}
198
}
199
fid => bail!("SmcccTrng: Call {fid:#x} is not implemented"),
200
};
201
abi.set_results(&regs);
202
Ok(())
203
}
204
205
fn read(&mut self, _info: BusAccessInfo, _data: &mut [u8]) {
206
unimplemented!("SmcccTrng: read not supported");
207
}
208
209
fn write(&mut self, _info: BusAccessInfo, _data: &[u8]) {
210
unimplemented!("SmcccTrng: write not supported");
211
}
212
}
213
214
impl BusDeviceSync for SmcccTrng {
215
fn read(&self, _info: BusAccessInfo, _data: &mut [u8]) {
216
unimplemented!("SmcccTrng: read not supported");
217
}
218
219
fn write(&self, _info: BusAccessInfo, _data: &[u8]) {
220
unimplemented!("SmcccTrng: write not supported");
221
}
222
}
223
224
impl Suspendable for SmcccTrng {}
225
226