root/drivers/char/hw_random/optee-rng.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_optee_rng_data
  2. optee_rng_read
  3. optee_rng_init
  4. optee_rng_cleanup
  5. get_optee_rng_info
  6. optee_ctx_match
  7. optee_rng_probe
  8. optee_rng_remove
  9. optee_rng_mod_init
  10. optee_rng_mod_exit

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (C) 2018-2019 Linaro Ltd.
   4  */
   5 
   6 #include <linux/delay.h>
   7 #include <linux/of.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>
  14 
  15 #define DRIVER_NAME "optee-rng"
  16 
  17 #define TEE_ERROR_HEALTH_TEST_FAIL      0x00000001
  18 
  19 /*
  20  * TA_CMD_GET_ENTROPY - Get Entropy from RNG
  21  *
  22  * param[0] (inout memref) - Entropy buffer memory reference
  23  * param[1] unused
  24  * param[2] unused
  25  * param[3] unused
  26  *
  27  * Result:
  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
  32  */
  33 #define TA_CMD_GET_ENTROPY              0x0
  34 
  35 /*
  36  * TA_CMD_GET_RNG_INFO - Get RNG information
  37  *
  38  * param[0] (out value) - value.a: RNG data-rate in bytes per second
  39  *                        value.b: Quality/Entropy per 1024 bit of data
  40  * param[1] unused
  41  * param[2] unused
  42  * param[3] unused
  43  *
  44  * Result:
  45  * TEE_SUCCESS - Invoke command success
  46  * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
  47  */
  48 #define TA_CMD_GET_RNG_INFO             0x1
  49 
  50 #define MAX_ENTROPY_REQ_SZ              (4 * 1024)
  51 
  52 /**
  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.
  60  */
  61 struct optee_rng_private {
  62         struct device *dev;
  63         struct tee_context *ctx;
  64         u32 session_id;
  65         u32 data_rate;
  66         struct tee_shm *entropy_shm_pool;
  67         struct hwrng optee_rng;
  68 };
  69 
  70 #define to_optee_rng_private(r) \
  71                 container_of(r, struct optee_rng_private, optee_rng)
  72 
  73 static size_t get_optee_rng_data(struct optee_rng_private *pvt_data,
  74                                  void *buf, size_t req_size)
  75 {
  76         int ret = 0;
  77         u8 *rng_data = NULL;
  78         size_t rng_size = 0;
  79         struct tee_ioctl_invoke_arg inv_arg;
  80         struct tee_param param[4];
  81 
  82         memset(&inv_arg, 0, sizeof(inv_arg));
  83         memset(&param, 0, sizeof(param));
  84 
  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;
  89 
  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;
  95 
  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",
  99                         inv_arg.ret);
 100                 return 0;
 101         }
 102 
 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");
 106                 return 0;
 107         }
 108 
 109         rng_size = param[0].u.memref.size;
 110         memcpy(buf, rng_data, rng_size);
 111 
 112         return rng_size;
 113 }
 114 
 115 static int optee_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
 116 {
 117         struct optee_rng_private *pvt_data = to_optee_rng_private(rng);
 118         size_t read = 0, rng_size = 0;
 119         int timeout = 1;
 120         u8 *data = buf;
 121 
 122         if (max > MAX_ENTROPY_REQ_SZ)
 123                 max = MAX_ENTROPY_REQ_SZ;
 124 
 125         while (read == 0) {
 126                 rng_size = get_optee_rng_data(pvt_data, data, (max - read));
 127 
 128                 data += rng_size;
 129                 read += rng_size;
 130 
 131                 if (wait) {
 132                         if (timeout-- == 0)
 133                                 return read;
 134                         msleep((1000 * (max - read)) / pvt_data->data_rate);
 135                 } else {
 136                         return read;
 137                 }
 138         }
 139 
 140         return read;
 141 }
 142 
 143 static int optee_rng_init(struct hwrng *rng)
 144 {
 145         struct optee_rng_private *pvt_data = to_optee_rng_private(rng);
 146         struct tee_shm *entropy_shm_pool = NULL;
 147 
 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);
 153         }
 154 
 155         pvt_data->entropy_shm_pool = entropy_shm_pool;
 156 
 157         return 0;
 158 }
 159 
 160 static void optee_rng_cleanup(struct hwrng *rng)
 161 {
 162         struct optee_rng_private *pvt_data = to_optee_rng_private(rng);
 163 
 164         tee_shm_free(pvt_data->entropy_shm_pool);
 165 }
 166 
 167 static struct optee_rng_private pvt_data = {
 168         .optee_rng = {
 169                 .name           = DRIVER_NAME,
 170                 .init           = optee_rng_init,
 171                 .cleanup        = optee_rng_cleanup,
 172                 .read           = optee_rng_read,
 173         }
 174 };
 175 
 176 static int get_optee_rng_info(struct device *dev)
 177 {
 178         int ret = 0;
 179         struct tee_ioctl_invoke_arg inv_arg;
 180         struct tee_param param[4];
 181 
 182         memset(&inv_arg, 0, sizeof(inv_arg));
 183         memset(&param, 0, sizeof(param));
 184 
 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;
 189 
 190         /* Fill invoke cmd params */
 191         param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
 192 
 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",
 196                         inv_arg.ret);
 197                 return -EINVAL;
 198         }
 199 
 200         pvt_data.data_rate = param[0].u.value.a;
 201         pvt_data.optee_rng.quality = param[0].u.value.b;
 202 
 203         return 0;
 204 }
 205 
 206 static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
 207 {
 208         if (ver->impl_id == TEE_IMPL_ID_OPTEE)
 209                 return 1;
 210         else
 211                 return 0;
 212 }
 213 
 214 static int optee_rng_probe(struct device *dev)
 215 {
 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;
 219 
 220         memset(&sess_arg, 0, sizeof(sess_arg));
 221 
 222         /* Open context with TEE driver */
 223         pvt_data.ctx = tee_client_open_context(NULL, optee_ctx_match, NULL,
 224                                                NULL);
 225         if (IS_ERR(pvt_data.ctx))
 226                 return -ENODEV;
 227 
 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;
 232 
 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",
 236                         sess_arg.ret);
 237                 err = -EINVAL;
 238                 goto out_ctx;
 239         }
 240         pvt_data.session_id = sess_arg.session;
 241 
 242         err = get_optee_rng_info(dev);
 243         if (err)
 244                 goto out_sess;
 245 
 246         err = hwrng_register(&pvt_data.optee_rng);
 247         if (err) {
 248                 dev_err(dev, "hwrng registration failed (%d)\n", err);
 249                 goto out_sess;
 250         }
 251 
 252         pvt_data.dev = dev;
 253 
 254         return 0;
 255 
 256 out_sess:
 257         tee_client_close_session(pvt_data.ctx, pvt_data.session_id);
 258 out_ctx:
 259         tee_client_close_context(pvt_data.ctx);
 260 
 261         return err;
 262 }
 263 
 264 static int optee_rng_remove(struct device *dev)
 265 {
 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);
 269 
 270         return 0;
 271 }
 272 
 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)},
 276         {}
 277 };
 278 
 279 MODULE_DEVICE_TABLE(tee, optee_rng_id_table);
 280 
 281 static struct tee_client_driver optee_rng_driver = {
 282         .id_table       = optee_rng_id_table,
 283         .driver         = {
 284                 .name           = DRIVER_NAME,
 285                 .bus            = &tee_bus_type,
 286                 .probe          = optee_rng_probe,
 287                 .remove         = optee_rng_remove,
 288         },
 289 };
 290 
 291 static int __init optee_rng_mod_init(void)
 292 {
 293         return driver_register(&optee_rng_driver.driver);
 294 }
 295 
 296 static void __exit optee_rng_mod_exit(void)
 297 {
 298         driver_unregister(&optee_rng_driver.driver);
 299 }
 300 
 301 module_init(optee_rng_mod_init);
 302 module_exit(optee_rng_mod_exit);
 303 
 304 MODULE_LICENSE("GPL v2");
 305 MODULE_AUTHOR("Sumit Garg <sumit.garg@linaro.org>");
 306 MODULE_DESCRIPTION("OP-TEE based random number generator driver");

/* [<][>][^][v][top][bottom][index][help] */