optee-rng.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2018-2019 Linaro Ltd.
  4. */
  5. #include <linux/delay.h>
  6. #include <linux/of.h>
  7. #include <linux/hw_random.h>
  8. #include <linux/kernel.h>
  9. #include <linux/module.h>
  10. #include <linux/slab.h>
  11. #include <linux/tee_drv.h>
  12. #include <linux/uuid.h>
  13. #define DRIVER_NAME "optee-rng"
  14. #define TEE_ERROR_HEALTH_TEST_FAIL 0x00000001
  15. /*
  16. * TA_CMD_GET_ENTROPY - Get Entropy from RNG
  17. *
  18. * param[0] (inout memref) - Entropy buffer memory reference
  19. * param[1] unused
  20. * param[2] unused
  21. * param[3] unused
  22. *
  23. * Result:
  24. * TEE_SUCCESS - Invoke command success
  25. * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
  26. * TEE_ERROR_NOT_SUPPORTED - Requested entropy size greater than size of pool
  27. * TEE_ERROR_HEALTH_TEST_FAIL - Continuous health testing failed
  28. */
  29. #define TA_CMD_GET_ENTROPY 0x0
  30. /*
  31. * TA_CMD_GET_RNG_INFO - Get RNG information
  32. *
  33. * param[0] (out value) - value.a: RNG data-rate in bytes per second
  34. * value.b: Quality/Entropy per 1024 bit of data
  35. * param[1] unused
  36. * param[2] unused
  37. * param[3] unused
  38. *
  39. * Result:
  40. * TEE_SUCCESS - Invoke command success
  41. * TEE_ERROR_BAD_PARAMETERS - Incorrect input param
  42. */
  43. #define TA_CMD_GET_RNG_INFO 0x1
  44. #define MAX_ENTROPY_REQ_SZ (4 * 1024)
  45. /**
  46. * struct optee_rng_private - OP-TEE Random Number Generator private data
  47. * @dev: OP-TEE based RNG device.
  48. * @ctx: OP-TEE context handler.
  49. * @session_id: RNG TA session identifier.
  50. * @data_rate: RNG data rate.
  51. * @entropy_shm_pool: Memory pool shared with RNG device.
  52. * @optee_rng: OP-TEE RNG driver structure.
  53. */
  54. struct optee_rng_private {
  55. struct device *dev;
  56. struct tee_context *ctx;
  57. u32 session_id;
  58. u32 data_rate;
  59. struct tee_shm *entropy_shm_pool;
  60. struct hwrng optee_rng;
  61. };
  62. #define to_optee_rng_private(r) \
  63. container_of(r, struct optee_rng_private, optee_rng)
  64. static size_t get_optee_rng_data(struct optee_rng_private *pvt_data,
  65. void *buf, size_t req_size)
  66. {
  67. int ret = 0;
  68. u8 *rng_data = NULL;
  69. size_t rng_size = 0;
  70. struct tee_ioctl_invoke_arg inv_arg;
  71. struct tee_param param[4];
  72. memset(&inv_arg, 0, sizeof(inv_arg));
  73. memset(&param, 0, sizeof(param));
  74. /* Invoke TA_CMD_GET_ENTROPY function of Trusted App */
  75. inv_arg.func = TA_CMD_GET_ENTROPY;
  76. inv_arg.session = pvt_data->session_id;
  77. inv_arg.num_params = 4;
  78. /* Fill invoke cmd params */
  79. param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT;
  80. param[0].u.memref.shm = pvt_data->entropy_shm_pool;
  81. param[0].u.memref.size = req_size;
  82. param[0].u.memref.shm_offs = 0;
  83. ret = tee_client_invoke_func(pvt_data->ctx, &inv_arg, param);
  84. if ((ret < 0) || (inv_arg.ret != 0)) {
  85. dev_err(pvt_data->dev, "TA_CMD_GET_ENTROPY invoke err: %x\n",
  86. inv_arg.ret);
  87. return 0;
  88. }
  89. rng_data = tee_shm_get_va(pvt_data->entropy_shm_pool, 0);
  90. if (IS_ERR(rng_data)) {
  91. dev_err(pvt_data->dev, "tee_shm_get_va failed\n");
  92. return 0;
  93. }
  94. rng_size = param[0].u.memref.size;
  95. memcpy(buf, rng_data, rng_size);
  96. return rng_size;
  97. }
  98. static int optee_rng_read(struct hwrng *rng, void *buf, size_t max, bool wait)
  99. {
  100. struct optee_rng_private *pvt_data = to_optee_rng_private(rng);
  101. size_t read = 0, rng_size;
  102. int timeout = 1;
  103. u8 *data = buf;
  104. if (max > MAX_ENTROPY_REQ_SZ)
  105. max = MAX_ENTROPY_REQ_SZ;
  106. while (read < max) {
  107. rng_size = get_optee_rng_data(pvt_data, data, (max - read));
  108. data += rng_size;
  109. read += rng_size;
  110. if (wait && pvt_data->data_rate) {
  111. if ((timeout-- == 0) || (read == max))
  112. return read;
  113. msleep((1000 * (max - read)) / pvt_data->data_rate);
  114. } else {
  115. return read;
  116. }
  117. }
  118. return read;
  119. }
  120. static int optee_rng_init(struct hwrng *rng)
  121. {
  122. struct optee_rng_private *pvt_data = to_optee_rng_private(rng);
  123. struct tee_shm *entropy_shm_pool = NULL;
  124. entropy_shm_pool = tee_shm_alloc_kernel_buf(pvt_data->ctx,
  125. MAX_ENTROPY_REQ_SZ);
  126. if (IS_ERR(entropy_shm_pool)) {
  127. dev_err(pvt_data->dev, "tee_shm_alloc_kernel_buf failed\n");
  128. return PTR_ERR(entropy_shm_pool);
  129. }
  130. pvt_data->entropy_shm_pool = entropy_shm_pool;
  131. return 0;
  132. }
  133. static void optee_rng_cleanup(struct hwrng *rng)
  134. {
  135. struct optee_rng_private *pvt_data = to_optee_rng_private(rng);
  136. tee_shm_free(pvt_data->entropy_shm_pool);
  137. }
  138. static struct optee_rng_private pvt_data = {
  139. .optee_rng = {
  140. .name = DRIVER_NAME,
  141. .init = optee_rng_init,
  142. .cleanup = optee_rng_cleanup,
  143. .read = optee_rng_read,
  144. }
  145. };
  146. static int get_optee_rng_info(struct device *dev)
  147. {
  148. int ret = 0;
  149. struct tee_ioctl_invoke_arg inv_arg;
  150. struct tee_param param[4];
  151. memset(&inv_arg, 0, sizeof(inv_arg));
  152. memset(&param, 0, sizeof(param));
  153. /* Invoke TA_CMD_GET_RNG_INFO function of Trusted App */
  154. inv_arg.func = TA_CMD_GET_RNG_INFO;
  155. inv_arg.session = pvt_data.session_id;
  156. inv_arg.num_params = 4;
  157. /* Fill invoke cmd params */
  158. param[0].attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT;
  159. ret = tee_client_invoke_func(pvt_data.ctx, &inv_arg, param);
  160. if ((ret < 0) || (inv_arg.ret != 0)) {
  161. dev_err(dev, "TA_CMD_GET_RNG_INFO invoke err: %x\n",
  162. inv_arg.ret);
  163. return -EINVAL;
  164. }
  165. pvt_data.data_rate = param[0].u.value.a;
  166. pvt_data.optee_rng.quality = param[0].u.value.b;
  167. return 0;
  168. }
  169. static int optee_ctx_match(struct tee_ioctl_version_data *ver, const void *data)
  170. {
  171. if (ver->impl_id == TEE_IMPL_ID_OPTEE)
  172. return 1;
  173. else
  174. return 0;
  175. }
  176. static int optee_rng_probe(struct device *dev)
  177. {
  178. struct tee_client_device *rng_device = to_tee_client_device(dev);
  179. int ret = 0, err = -ENODEV;
  180. struct tee_ioctl_open_session_arg sess_arg;
  181. memset(&sess_arg, 0, sizeof(sess_arg));
  182. /* Open context with TEE driver */
  183. pvt_data.ctx = tee_client_open_context(NULL, optee_ctx_match, NULL,
  184. NULL);
  185. if (IS_ERR(pvt_data.ctx))
  186. return -ENODEV;
  187. /* Open session with hwrng Trusted App */
  188. export_uuid(sess_arg.uuid, &rng_device->id.uuid);
  189. sess_arg.clnt_login = TEE_IOCTL_LOGIN_PUBLIC;
  190. sess_arg.num_params = 0;
  191. ret = tee_client_open_session(pvt_data.ctx, &sess_arg, NULL);
  192. if ((ret < 0) || (sess_arg.ret != 0)) {
  193. dev_err(dev, "tee_client_open_session failed, err: %x\n",
  194. sess_arg.ret);
  195. err = -EINVAL;
  196. goto out_ctx;
  197. }
  198. pvt_data.session_id = sess_arg.session;
  199. err = get_optee_rng_info(dev);
  200. if (err)
  201. goto out_sess;
  202. err = devm_hwrng_register(dev, &pvt_data.optee_rng);
  203. if (err) {
  204. dev_err(dev, "hwrng registration failed (%d)\n", err);
  205. goto out_sess;
  206. }
  207. pvt_data.dev = dev;
  208. return 0;
  209. out_sess:
  210. tee_client_close_session(pvt_data.ctx, pvt_data.session_id);
  211. out_ctx:
  212. tee_client_close_context(pvt_data.ctx);
  213. return err;
  214. }
  215. static int optee_rng_remove(struct device *dev)
  216. {
  217. tee_client_close_session(pvt_data.ctx, pvt_data.session_id);
  218. tee_client_close_context(pvt_data.ctx);
  219. return 0;
  220. }
  221. static const struct tee_client_device_id optee_rng_id_table[] = {
  222. {UUID_INIT(0xab7a617c, 0xb8e7, 0x4d8f,
  223. 0x83, 0x01, 0xd0, 0x9b, 0x61, 0x03, 0x6b, 0x64)},
  224. {}
  225. };
  226. MODULE_DEVICE_TABLE(tee, optee_rng_id_table);
  227. static struct tee_client_driver optee_rng_driver = {
  228. .id_table = optee_rng_id_table,
  229. .driver = {
  230. .name = DRIVER_NAME,
  231. .bus = &tee_bus_type,
  232. .probe = optee_rng_probe,
  233. .remove = optee_rng_remove,
  234. },
  235. };
  236. static int __init optee_rng_mod_init(void)
  237. {
  238. return driver_register(&optee_rng_driver.driver);
  239. }
  240. static void __exit optee_rng_mod_exit(void)
  241. {
  242. driver_unregister(&optee_rng_driver.driver);
  243. }
  244. module_init(optee_rng_mod_init);
  245. module_exit(optee_rng_mod_exit);
  246. MODULE_LICENSE("GPL v2");
  247. MODULE_AUTHOR("Sumit Garg <[email protected]>");
  248. MODULE_DESCRIPTION("OP-TEE based random number generator driver");