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