blob: 410dfc053f1e98c4da0044cecfd38873ad32e064 [file] [log] [blame]
Patrick Delaunayfd52e7f2022-03-29 14:21:23 +02001// SPDX-License-Identifier: GPL-2.0-or-later OR BSD-3-Clause
2/*
3 * Copyright (C) 2022, STMicroelectronics - All Rights Reserved
4 */
5#define LOG_CATEGORY UCLASS_RNG
6
7#include <common.h>
8
9#include <rng.h>
10#include <tee.h>
11#include <dm/device.h>
12#include <dm/device_compat.h>
13#include <linux/sizes.h>
Etienne Carriere57fb86a2022-07-26 16:21:43 +020014#include <tee/optee_service.h>
15
16#define DRIVER_NAME "optee-rng"
Patrick Delaunayfd52e7f2022-03-29 14:21:23 +020017
18#define TEE_ERROR_HEALTH_TEST_FAIL 0x00000001
19
20/*
21 * TA_CMD_GET_ENTROPY - Get Entropy from RNG
22 *
23 * param[0] (inout memref) - Entropy buffer memory reference
24 * param[1] unused
25 * param[2] unused
26 * param[3] unused
27 *
28 * Result:
29 * TEE_SUCCESS - Invoke command success
30 * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
31 * TEE_ERROR_NOT_SUPPORTED - Requested entropy size greater than size of pool
32 * TEE_ERROR_HEALTH_TEST_FAIL - Continuous health testing failed
33 */
34#define TA_CMD_GET_ENTROPY 0x0
35
36#define MAX_ENTROPY_REQ_SZ SZ_4K
37
38#define TA_HWRNG_UUID { 0xab7a617c, 0xb8e7, 0x4d8f, \
39 { 0x83, 0x01, 0xd0, 0x9b, 0x61, 0x03, 0x6b, 0x64 } }
40
Etienne Carriere57fb86a2022-07-26 16:21:43 +020041OPTEE_SERVICE_DRIVER(optee_rng, TA_HWRNG_UUID, DRIVER_NAME);
42
Patrick Delaunayfd52e7f2022-03-29 14:21:23 +020043/** open_session_ta_hwrng() - Open session with hwrng Trusted App
44 *
45 * @dev: device
46 * @session_id: return the RNG TA session identifier
47 * Return: 0 if ok
48 */
49static int open_session_ta_hwrng(struct udevice *dev, u32 *session_id)
50{
51 const struct tee_optee_ta_uuid uuid = TA_HWRNG_UUID;
52 struct tee_open_session_arg sess_arg = {0};
53 int ret;
54
55 /* Open session with hwrng Trusted App */
56 tee_optee_ta_uuid_to_octets(sess_arg.uuid, &uuid);
57 sess_arg.clnt_login = TEE_LOGIN_PUBLIC;
58
59 ret = tee_open_session(dev->parent, &sess_arg, 0, NULL);
60 if (ret || sess_arg.ret) {
61 if (!ret)
62 ret = -EIO;
63 return ret;
64 }
65
66 *session_id = sess_arg.session;
67 return 0;
68}
69
70/**
71 * get_optee_rng_data() - read RNG data from OP-TEE TA
72 *
73 * @dev: device
74 * @session_id: the RNG TA session identifier
75 * @entropy_shm_pool: shared memory pool used for TEE message
76 * @buf: buffer to receive data
77 * @size: size of buffer, limited by entropy_shm_pool size
78 * Return: 0 if ok
79 */
80static int get_optee_rng_data(struct udevice *dev, u32 session_id,
81 struct tee_shm *entropy_shm_pool,
82 void *buf, size_t *size)
83{
84 int ret = 0;
85 struct tee_invoke_arg arg = {0};
86 struct tee_param param = {0};
87
88 /* Invoke TA_CMD_GET_ENTROPY function of Trusted App */
89 arg.func = TA_CMD_GET_ENTROPY;
90 arg.session = session_id;
91
92 /* Fill invoke cmd params */
93 param.attr = TEE_PARAM_ATTR_TYPE_MEMREF_INOUT;
94 param.u.memref.shm = entropy_shm_pool;
95 param.u.memref.size = *size;
96
97 ret = tee_invoke_func(dev->parent, &arg, 1, &param);
98 if (ret || arg.ret) {
99 if (!ret)
100 ret = -EPROTO;
101 dev_err(dev, "TA_CMD_GET_ENTROPY invoke err: %d 0x%x\n", ret, arg.ret);
102 *size = 0;
103
104 return ret;
105 }
106
107 memcpy(buf, param.u.memref.shm->addr, param.u.memref.size);
108 *size = param.u.memref.size;
109
110 return 0;
111}
112
113/**
114 * optee_rng_read() - rng read ops for OP-TEE RNG device
115 *
116 * @dev: device
117 * @buf: buffer to receive data
118 * @len: size of buffer
119 * Return: 0 if ok
120 */
121static int optee_rng_read(struct udevice *dev, void *buf, size_t len)
122{
123 size_t read = 0, rng_size = 0;
124 struct tee_shm *entropy_shm_pool;
125 u8 *data = buf;
126 int ret;
127 u32 session_id = 0;
128
129 ret = open_session_ta_hwrng(dev, &session_id);
130 if (ret) {
131 dev_err(dev, "can't open session: %d\n", ret);
132 return ret;
133 }
134
135 ret = tee_shm_alloc(dev->parent, MAX_ENTROPY_REQ_SZ, 0, &entropy_shm_pool);
136 if (ret) {
137 dev_err(dev, "tee_shm_alloc failed: %d\n", ret);
138 goto session_close;
139 }
140
141 while (read < len) {
142 rng_size = min(len - read, (size_t)MAX_ENTROPY_REQ_SZ);
143 ret = get_optee_rng_data(dev, session_id, entropy_shm_pool, data, &rng_size);
144 if (ret)
145 goto shm_free;
146 data += rng_size;
147 read += rng_size;
148 }
149
150shm_free:
151 tee_shm_free(entropy_shm_pool);
152
153session_close:
154 tee_close_session(dev->parent, session_id);
155
156 return ret;
157}
158
159/**
160 * optee_rng_probe() - probe function for OP-TEE RNG device
161 *
162 * @dev: device
163 * Return: 0 if ok
164 */
165static int optee_rng_probe(struct udevice *dev)
166{
167 int ret;
168 u32 session_id;
169
170 ret = open_session_ta_hwrng(dev, &session_id);
171 if (ret) {
172 dev_err(dev, "can't open session: %d\n", ret);
173 return ret;
174 }
175 tee_close_session(dev->parent, session_id);
176
177 return 0;
178}
179
180static const struct dm_rng_ops optee_rng_ops = {
181 .read = optee_rng_read,
182};
183
184U_BOOT_DRIVER(optee_rng) = {
Etienne Carriere57fb86a2022-07-26 16:21:43 +0200185 .name = DRIVER_NAME,
Patrick Delaunayfd52e7f2022-03-29 14:21:23 +0200186 .id = UCLASS_RNG,
187 .ops = &optee_rng_ops,
188 .probe = optee_rng_probe,
189};