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