1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2018-2019 Linaro Ltd.
6 #include <linux/delay.h>
8 #include <linux/hw_random.h>
9 #include <linux/kernel.h>
10 #include <linux/module.h>
11 #include <linux/slab.h>
12 #include <linux/tee_drv.h>
13 #include <linux/uuid.h>
15 #define DRIVER_NAME "optee-rng"
17 #define TEE_ERROR_HEALTH_TEST_FAIL 0x00000001
20 * TA_CMD_GET_ENTROPY - Get Entropy from RNG
22 * param[0] (inout memref) - Entropy buffer memory reference
28 * TEE_SUCCESS - Invoke command success
29 * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
30 * TEE_ERROR_NOT_SUPPORTED - Requested entropy size greater than size of pool
31 * TEE_ERROR_HEALTH_TEST_FAIL - Continuous health testing failed
33 #define TA_CMD_GET_ENTROPY 0x0
36 * TA_CMD_GET_RNG_INFO - Get RNG information
38 * param[0] (out value) - value.a: RNG data-rate in bytes per second
39 * value.b: Quality/Entropy per 1024 bit of data
45 * TEE_SUCCESS - Invoke command success
46 * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
48 #define TA_CMD_GET_RNG_INFO 0x1
50 #define MAX_ENTROPY_REQ_SZ (4 * 1024)
53 * struct optee_rng_private - OP-TEE Random Number Generator private data
54 * @dev: OP-TEE based RNG device.
55 * @ctx: OP-TEE context handler.
56 * @session_id: RNG TA session identifier.
57 * @data_rate: RNG data rate.
58 * @entropy_shm_pool: Memory pool shared with RNG device.
59 * @optee_rng: OP-TEE RNG driver structure.
61 struct optee_rng_private
{
63 struct tee_context
*ctx
;
66 struct tee_shm
*entropy_shm_pool
;
67 struct hwrng optee_rng
;
70 #define to_optee_rng_private(r) \
71 container_of(r, struct optee_rng_private, optee_rng)
73 static size_t get_optee_rng_data(struct optee_rng_private
*pvt_data
,
74 void *buf
, size_t req_size
)
79 struct tee_ioctl_invoke_arg inv_arg
;
80 struct tee_param param
[4];
82 memset(&inv_arg
, 0, sizeof(inv_arg
));
83 memset(¶m
, 0, sizeof(param
));
85 /* Invoke TA_CMD_GET_ENTROPY function of Trusted App */
86 inv_arg
.func
= TA_CMD_GET_ENTROPY
;
87 inv_arg
.session
= pvt_data
->session_id
;
88 inv_arg
.num_params
= 4;
90 /* Fill invoke cmd params */
91 param
[0].attr
= TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT
;
92 param
[0].u
.memref
.shm
= pvt_data
->entropy_shm_pool
;
93 param
[0].u
.memref
.size
= req_size
;
94 param
[0].u
.memref
.shm_offs
= 0;
96 ret
= tee_client_invoke_func(pvt_data
->ctx
, &inv_arg
, param
);
97 if ((ret
< 0) || (inv_arg
.ret
!= 0)) {
98 dev_err(pvt_data
->dev
, "TA_CMD_GET_ENTROPY invoke err: %x\n",
103 rng_data
= tee_shm_get_va(pvt_data
->entropy_shm_pool
, 0);
104 if (IS_ERR(rng_data
)) {
105 dev_err(pvt_data
->dev
, "tee_shm_get_va failed\n");
109 rng_size
= param
[0].u
.memref
.size
;
110 memcpy(buf
, rng_data
, rng_size
);
115 static int optee_rng_read(struct hwrng
*rng
, void *buf
, size_t max
, bool wait
)
117 struct optee_rng_private
*pvt_data
= to_optee_rng_private(rng
);
118 size_t read
= 0, rng_size
= 0;
122 if (max
> MAX_ENTROPY_REQ_SZ
)
123 max
= MAX_ENTROPY_REQ_SZ
;
126 rng_size
= get_optee_rng_data(pvt_data
, data
, (max
- read
));
134 msleep((1000 * (max
- read
)) / pvt_data
->data_rate
);
143 static int optee_rng_init(struct hwrng
*rng
)
145 struct optee_rng_private
*pvt_data
= to_optee_rng_private(rng
);
146 struct tee_shm
*entropy_shm_pool
= NULL
;
148 entropy_shm_pool
= tee_shm_alloc(pvt_data
->ctx
, MAX_ENTROPY_REQ_SZ
,
149 TEE_SHM_MAPPED
| TEE_SHM_DMA_BUF
);
150 if (IS_ERR(entropy_shm_pool
)) {
151 dev_err(pvt_data
->dev
, "tee_shm_alloc failed\n");
152 return PTR_ERR(entropy_shm_pool
);
155 pvt_data
->entropy_shm_pool
= entropy_shm_pool
;
160 static void optee_rng_cleanup(struct hwrng
*rng
)
162 struct optee_rng_private
*pvt_data
= to_optee_rng_private(rng
);
164 tee_shm_free(pvt_data
->entropy_shm_pool
);
167 static struct optee_rng_private pvt_data
= {
170 .init
= optee_rng_init
,
171 .cleanup
= optee_rng_cleanup
,
172 .read
= optee_rng_read
,
176 static int get_optee_rng_info(struct device
*dev
)
179 struct tee_ioctl_invoke_arg inv_arg
;
180 struct tee_param param
[4];
182 memset(&inv_arg
, 0, sizeof(inv_arg
));
183 memset(¶m
, 0, sizeof(param
));
185 /* Invoke TA_CMD_GET_RNG_INFO function of Trusted App */
186 inv_arg
.func
= TA_CMD_GET_RNG_INFO
;
187 inv_arg
.session
= pvt_data
.session_id
;
188 inv_arg
.num_params
= 4;
190 /* Fill invoke cmd params */
191 param
[0].attr
= TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT
;
193 ret
= tee_client_invoke_func(pvt_data
.ctx
, &inv_arg
, param
);
194 if ((ret
< 0) || (inv_arg
.ret
!= 0)) {
195 dev_err(dev
, "TA_CMD_GET_RNG_INFO invoke err: %x\n",
200 pvt_data
.data_rate
= param
[0].u
.value
.a
;
201 pvt_data
.optee_rng
.quality
= param
[0].u
.value
.b
;
206 static int optee_ctx_match(struct tee_ioctl_version_data
*ver
, const void *data
)
208 if (ver
->impl_id
== TEE_IMPL_ID_OPTEE
)
214 static int optee_rng_probe(struct device
*dev
)
216 struct tee_client_device
*rng_device
= to_tee_client_device(dev
);
217 int ret
= 0, err
= -ENODEV
;
218 struct tee_ioctl_open_session_arg sess_arg
;
220 memset(&sess_arg
, 0, sizeof(sess_arg
));
222 /* Open context with TEE driver */
223 pvt_data
.ctx
= tee_client_open_context(NULL
, optee_ctx_match
, NULL
,
225 if (IS_ERR(pvt_data
.ctx
))
228 /* Open session with hwrng Trusted App */
229 memcpy(sess_arg
.uuid
, rng_device
->id
.uuid
.b
, TEE_IOCTL_UUID_LEN
);
230 sess_arg
.clnt_login
= TEE_IOCTL_LOGIN_PUBLIC
;
231 sess_arg
.num_params
= 0;
233 ret
= tee_client_open_session(pvt_data
.ctx
, &sess_arg
, NULL
);
234 if ((ret
< 0) || (sess_arg
.ret
!= 0)) {
235 dev_err(dev
, "tee_client_open_session failed, err: %x\n",
240 pvt_data
.session_id
= sess_arg
.session
;
242 err
= get_optee_rng_info(dev
);
246 err
= hwrng_register(&pvt_data
.optee_rng
);
248 dev_err(dev
, "hwrng registration failed (%d)\n", err
);
257 tee_client_close_session(pvt_data
.ctx
, pvt_data
.session_id
);
259 tee_client_close_context(pvt_data
.ctx
);
264 static int optee_rng_remove(struct device
*dev
)
266 hwrng_unregister(&pvt_data
.optee_rng
);
267 tee_client_close_session(pvt_data
.ctx
, pvt_data
.session_id
);
268 tee_client_close_context(pvt_data
.ctx
);
273 static const struct tee_client_device_id optee_rng_id_table
[] = {
274 {UUID_INIT(0xab7a617c, 0xb8e7, 0x4d8f,
275 0x83, 0x01, 0xd0, 0x9b, 0x61, 0x03, 0x6b, 0x64)},
279 MODULE_DEVICE_TABLE(tee
, optee_rng_id_table
);
281 static struct tee_client_driver optee_rng_driver
= {
282 .id_table
= optee_rng_id_table
,
285 .bus
= &tee_bus_type
,
286 .probe
= optee_rng_probe
,
287 .remove
= optee_rng_remove
,
291 static int __init
optee_rng_mod_init(void)
293 return driver_register(&optee_rng_driver
.driver
);
296 static void __exit
optee_rng_mod_exit(void)
298 driver_unregister(&optee_rng_driver
.driver
);
301 module_init(optee_rng_mod_init
);
302 module_exit(optee_rng_mod_exit
);
304 MODULE_LICENSE("GPL v2");
305 MODULE_AUTHOR("Sumit Garg <sumit.garg@linaro.org>");
306 MODULE_DESCRIPTION("OP-TEE based random number generator driver");