xref: /freebsd/sys/dev/psci/smccc_trng.c (revision b2f8b2dc87368d3f0a99865b2df13f5ad79f763a)
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