1*b2f8b2dcSAndrew Turner /*-
2*b2f8b2dcSAndrew Turner * SPDX-License-Identifier: BSD-2-Clause
3*b2f8b2dcSAndrew Turner *
4*b2f8b2dcSAndrew Turner * Copyright (c) 2024 Arm Ltd
5*b2f8b2dcSAndrew Turner *
6*b2f8b2dcSAndrew Turner * Redistribution and use in source and binary forms, with or without
7*b2f8b2dcSAndrew Turner * modification, are permitted provided that the following conditions
8*b2f8b2dcSAndrew Turner * are met:
9*b2f8b2dcSAndrew Turner * 1. Redistributions of source code must retain the above copyright
10*b2f8b2dcSAndrew Turner * notice, this list of conditions and the following disclaimer.
11*b2f8b2dcSAndrew Turner * 2. Redistributions in binary form must reproduce the above copyright
12*b2f8b2dcSAndrew Turner * notice, this list of conditions and the following disclaimer in the
13*b2f8b2dcSAndrew Turner * documentation and/or other materials provided with the distribution.
14*b2f8b2dcSAndrew Turner *
15*b2f8b2dcSAndrew Turner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*b2f8b2dcSAndrew Turner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*b2f8b2dcSAndrew Turner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*b2f8b2dcSAndrew Turner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*b2f8b2dcSAndrew Turner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*b2f8b2dcSAndrew Turner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*b2f8b2dcSAndrew Turner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*b2f8b2dcSAndrew Turner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*b2f8b2dcSAndrew Turner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*b2f8b2dcSAndrew Turner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*b2f8b2dcSAndrew Turner * SUCH DAMAGE.
26*b2f8b2dcSAndrew Turner */
27*b2f8b2dcSAndrew Turner
28*b2f8b2dcSAndrew Turner /*
29*b2f8b2dcSAndrew Turner * A driver for the Arm True Random Number Generator Firmware Interface.
30*b2f8b2dcSAndrew Turner * This queries into the SMCCC firmware for random numbers using the
31*b2f8b2dcSAndrew Turner * interface documented in den0098 [1].
32*b2f8b2dcSAndrew Turner *
33*b2f8b2dcSAndrew Turner * [1] https://developer.arm.com/documentation/den0098/latest
34*b2f8b2dcSAndrew Turner */
35*b2f8b2dcSAndrew Turner
36*b2f8b2dcSAndrew Turner #include <sys/param.h>
37*b2f8b2dcSAndrew Turner #include <sys/systm.h>
38*b2f8b2dcSAndrew Turner #include <sys/bus.h>
39*b2f8b2dcSAndrew Turner #include <sys/kernel.h>
40*b2f8b2dcSAndrew Turner #include <sys/malloc.h>
41*b2f8b2dcSAndrew Turner #include <sys/module.h>
42*b2f8b2dcSAndrew Turner #include <sys/random.h>
43*b2f8b2dcSAndrew Turner
44*b2f8b2dcSAndrew Turner #include <dev/psci/psci.h>
45*b2f8b2dcSAndrew Turner #include <dev/psci/smccc.h>
46*b2f8b2dcSAndrew Turner
47*b2f8b2dcSAndrew Turner #include <dev/random/randomdev.h>
48*b2f8b2dcSAndrew Turner
49*b2f8b2dcSAndrew Turner #define TRNG_VERSION SMCCC_FUNC_ID(SMCCC_FAST_CALL, \
50*b2f8b2dcSAndrew Turner SMCCC_32BIT_CALL, SMCCC_STD_SECURE_SERVICE_CALLS, 0x50)
51*b2f8b2dcSAndrew Turner #define TRNG_VERSION_MIN 0x10000L
52*b2f8b2dcSAndrew Turner #define TRNG_RND64 SMCCC_FUNC_ID(SMCCC_FAST_CALL, \
53*b2f8b2dcSAndrew Turner SMCCC_64BIT_CALL, SMCCC_STD_SECURE_SERVICE_CALLS, 0x53)
54*b2f8b2dcSAndrew Turner
55*b2f8b2dcSAndrew Turner static device_identify_t trng_identify;
56*b2f8b2dcSAndrew Turner static device_probe_t trng_probe;
57*b2f8b2dcSAndrew Turner static device_attach_t trng_attach;
58*b2f8b2dcSAndrew Turner
59*b2f8b2dcSAndrew Turner static unsigned trng_read(void *, unsigned);
60*b2f8b2dcSAndrew Turner
61*b2f8b2dcSAndrew Turner static struct random_source random_trng = {
62*b2f8b2dcSAndrew Turner .rs_ident = "Arm SMCCC TRNG",
63*b2f8b2dcSAndrew Turner .rs_source = RANDOM_PURE_ARM_TRNG,
64*b2f8b2dcSAndrew Turner .rs_read = trng_read,
65*b2f8b2dcSAndrew Turner };
66*b2f8b2dcSAndrew Turner
67*b2f8b2dcSAndrew Turner static void
trng_identify(driver_t * driver,device_t parent)68*b2f8b2dcSAndrew Turner trng_identify(driver_t *driver, device_t parent)
69*b2f8b2dcSAndrew Turner {
70*b2f8b2dcSAndrew Turner int32_t version;
71*b2f8b2dcSAndrew Turner
72*b2f8b2dcSAndrew Turner /* TRNG depends on SMCCC 1.1 (per the spec) */
73*b2f8b2dcSAndrew Turner if (smccc_get_version() < SMCCC_MAKE_VERSION(1, 1))
74*b2f8b2dcSAndrew Turner return;
75*b2f8b2dcSAndrew Turner
76*b2f8b2dcSAndrew Turner /* Check we have TRNG 1.0 or later */
77*b2f8b2dcSAndrew Turner version = psci_call(TRNG_VERSION, 0, 0, 0);
78*b2f8b2dcSAndrew Turner if (version < TRNG_VERSION_MIN)
79*b2f8b2dcSAndrew Turner return;
80*b2f8b2dcSAndrew Turner
81*b2f8b2dcSAndrew Turner if (BUS_ADD_CHILD(parent, 0, "trng", -1) == NULL)
82*b2f8b2dcSAndrew Turner device_printf(parent, "add TRNG child failed\n");
83*b2f8b2dcSAndrew Turner }
84*b2f8b2dcSAndrew Turner
85*b2f8b2dcSAndrew Turner static int
trng_probe(device_t dev)86*b2f8b2dcSAndrew Turner trng_probe(device_t dev)
87*b2f8b2dcSAndrew Turner {
88*b2f8b2dcSAndrew Turner device_set_desc(dev, "Arm SMCCC TRNG");
89*b2f8b2dcSAndrew Turner return (BUS_PROBE_NOWILDCARD);
90*b2f8b2dcSAndrew Turner }
91*b2f8b2dcSAndrew Turner
92*b2f8b2dcSAndrew Turner static int
trng_attach(device_t dev)93*b2f8b2dcSAndrew Turner trng_attach(device_t dev)
94*b2f8b2dcSAndrew Turner {
95*b2f8b2dcSAndrew Turner struct arm_smccc_res res;
96*b2f8b2dcSAndrew Turner int32_t ret;
97*b2f8b2dcSAndrew Turner
98*b2f8b2dcSAndrew Turner ret = arm_smccc_invoke(TRNG_RND64, 192, &res);
99*b2f8b2dcSAndrew Turner if (ret < 0) {
100*b2f8b2dcSAndrew Turner device_printf(dev, "Failed to read fron TRNG\n");
101*b2f8b2dcSAndrew Turner } else {
102*b2f8b2dcSAndrew Turner random_source_register(&random_trng);
103*b2f8b2dcSAndrew Turner }
104*b2f8b2dcSAndrew Turner
105*b2f8b2dcSAndrew Turner return (0);
106*b2f8b2dcSAndrew Turner }
107*b2f8b2dcSAndrew Turner
108*b2f8b2dcSAndrew Turner static unsigned
trng_read(void * buf,unsigned usz)109*b2f8b2dcSAndrew Turner trng_read(void *buf, unsigned usz)
110*b2f8b2dcSAndrew Turner {
111*b2f8b2dcSAndrew Turner struct arm_smccc_res res;
112*b2f8b2dcSAndrew Turner register_t len;
113*b2f8b2dcSAndrew Turner int32_t ret;
114*b2f8b2dcSAndrew Turner
115*b2f8b2dcSAndrew Turner len = usz;
116*b2f8b2dcSAndrew Turner if (len > sizeof(uint64_t))
117*b2f8b2dcSAndrew Turner len = sizeof(uint64_t);
118*b2f8b2dcSAndrew Turner if (len == 0)
119*b2f8b2dcSAndrew Turner return (0);
120*b2f8b2dcSAndrew Turner
121*b2f8b2dcSAndrew Turner ret = arm_smccc_invoke(TRNG_RND64, len * 8, &res);
122*b2f8b2dcSAndrew Turner if (ret < 0)
123*b2f8b2dcSAndrew Turner return (0);
124*b2f8b2dcSAndrew Turner
125*b2f8b2dcSAndrew Turner memcpy(buf, &res.a0, len);
126*b2f8b2dcSAndrew Turner return (len);
127*b2f8b2dcSAndrew Turner }
128*b2f8b2dcSAndrew Turner
129*b2f8b2dcSAndrew Turner static device_method_t trng_methods[] = {
130*b2f8b2dcSAndrew Turner DEVMETHOD(device_identify, trng_identify),
131*b2f8b2dcSAndrew Turner DEVMETHOD(device_probe, trng_probe),
132*b2f8b2dcSAndrew Turner DEVMETHOD(device_attach, trng_attach),
133*b2f8b2dcSAndrew Turner
134*b2f8b2dcSAndrew Turner DEVMETHOD_END
135*b2f8b2dcSAndrew Turner };
136*b2f8b2dcSAndrew Turner
137*b2f8b2dcSAndrew Turner static driver_t trng_driver = {
138*b2f8b2dcSAndrew Turner "trng",
139*b2f8b2dcSAndrew Turner trng_methods,
140*b2f8b2dcSAndrew Turner 0
141*b2f8b2dcSAndrew Turner };
142*b2f8b2dcSAndrew Turner
143*b2f8b2dcSAndrew Turner DRIVER_MODULE(trng, smccc, trng_driver, 0, 0);
144