Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'tee-prot-dma-buf-for-v6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/jenswi/linux-tee into soc/drivers

TEE protected DMA-bufs for v6.18

- Allocates protected DMA-bufs from a DMA-heap instantiated from the TEE
subsystem.
- The DMA-heap uses a protected memory pool provided by the backend TEE
driver, allowing it to choose how to allocate the protected physical
memory.
- Three use-cases (Secure Video Playback, Trusted UI, and Secure Video
Recording) have been identified so far to serve as examples of what
can be expected.
- The use-cases have predefined DMA-heap names,
"protected,secure-video", "protected,trusted-ui", and
"protected,secure-video-record". The backend driver registers protected
memory pools for the use-cases it supports.

* tag 'tee-prot-dma-buf-for-v6.18' of git://git.kernel.org/pub/scm/linux/kernel/git/jenswi/linux-tee:
optee: smc abi: dynamic protected memory allocation
optee: FF-A: dynamic protected memory allocation
optee: support protected memory allocation
tee: add tee_shm_alloc_dma_mem()
tee: new ioctl to a register tee_shm from a dmabuf file descriptor
tee: refactor params_from_user()
tee: implement protected DMA-heap
dma-buf: dma-heap: export declared functions
optee: sync secure world ABI headers

Link: https://lore.kernel.org/r/20250912101752.GA1453408@rayden
Signed-off-by: Arnd Bergmann <arnd@arndb.de>

+1671 -68
+4
drivers/dma-buf/dma-heap.c
··· 11 11 #include <linux/dma-buf.h> 12 12 #include <linux/dma-heap.h> 13 13 #include <linux/err.h> 14 + #include <linux/export.h> 14 15 #include <linux/list.h> 15 16 #include <linux/nospec.h> 16 17 #include <linux/syscalls.h> ··· 203 202 { 204 203 return heap->priv; 205 204 } 205 + EXPORT_SYMBOL_NS_GPL(dma_heap_get_drvdata, "DMA_BUF_HEAP"); 206 206 207 207 /** 208 208 * dma_heap_get_name - get heap name ··· 216 214 { 217 215 return heap->name; 218 216 } 217 + EXPORT_SYMBOL_NS_GPL(dma_heap_get_name, "DMA_BUF_HEAP"); 219 218 220 219 /** 221 220 * dma_heap_add - adds a heap to dmabuf heaps ··· 306 303 kfree(heap); 307 304 return err_ret; 308 305 } 306 + EXPORT_SYMBOL_NS_GPL(dma_heap_add, "DMA_BUF_HEAP"); 309 307 310 308 static char *dma_heap_devnode(const struct device *dev, umode_t *mode) 311 309 {
+5
drivers/tee/Kconfig
··· 12 12 13 13 if TEE 14 14 15 + config TEE_DMABUF_HEAPS 16 + bool 17 + depends on HAS_DMA && DMABUF_HEAPS 18 + default y 19 + 15 20 source "drivers/tee/optee/Kconfig" 16 21 source "drivers/tee/amdtee/Kconfig" 17 22 source "drivers/tee/tstee/Kconfig"
+1
drivers/tee/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 obj-$(CONFIG_TEE) += tee.o 3 3 tee-objs += tee_core.o 4 + tee-objs += tee_heap.o 4 5 tee-objs += tee_shm.o 5 6 tee-objs += tee_shm_pool.o 6 7 obj-$(CONFIG_OPTEE) += optee/
+5
drivers/tee/optee/Kconfig
··· 25 25 26 26 Additional documentation on kernel security risks are at 27 27 Documentation/tee/op-tee.rst. 28 + 29 + config OPTEE_STATIC_PROTMEM_POOL 30 + bool 31 + depends on HAS_IOMEM && TEE_DMABUF_HEAPS 32 + default y
+1
drivers/tee/optee/Makefile
··· 4 4 optee-objs += call.o 5 5 optee-objs += notif.o 6 6 optee-objs += rpc.o 7 + optee-objs += protmem.o 7 8 optee-objs += supp.o 8 9 optee-objs += device.o 9 10 optee-objs += smc_abi.o
+7
drivers/tee/optee/core.c
··· 56 56 return 0; 57 57 } 58 58 59 + int optee_set_dma_mask(struct optee *optee, u_int pa_width) 60 + { 61 + u64 mask = DMA_BIT_MASK(min(64, pa_width)); 62 + 63 + return dma_coerce_mask_and_coherent(&optee->teedev->dev, mask); 64 + } 65 + 59 66 static void optee_bus_scan(struct work_struct *work) 60 67 { 61 68 WARN_ON(optee_enumerate_devices(PTA_CMD_GET_DEVICES_SUPP));
+144 -2
drivers/tee/optee/ffa_abi.c
··· 649 649 return optee_ffa_yielding_call(ctx, &data, rpc_arg, system_thread); 650 650 } 651 651 652 + static int do_call_lend_protmem(struct optee *optee, u64 cookie, u32 use_case) 653 + { 654 + struct optee_shm_arg_entry *entry; 655 + struct optee_msg_arg *msg_arg; 656 + struct tee_shm *shm; 657 + u_int offs; 658 + int rc; 659 + 660 + msg_arg = optee_get_msg_arg(optee->ctx, 1, &entry, &shm, &offs); 661 + if (IS_ERR(msg_arg)) 662 + return PTR_ERR(msg_arg); 663 + 664 + msg_arg->cmd = OPTEE_MSG_CMD_ASSIGN_PROTMEM; 665 + msg_arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 666 + msg_arg->params[0].u.value.a = cookie; 667 + msg_arg->params[0].u.value.b = use_case; 668 + 669 + rc = optee->ops->do_call_with_arg(optee->ctx, shm, offs, false); 670 + if (rc) 671 + goto out; 672 + if (msg_arg->ret != TEEC_SUCCESS) { 673 + rc = -EINVAL; 674 + goto out; 675 + } 676 + 677 + out: 678 + optee_free_msg_arg(optee->ctx, entry, offs); 679 + return rc; 680 + } 681 + 682 + static int optee_ffa_lend_protmem(struct optee *optee, struct tee_shm *protmem, 683 + u32 *mem_attrs, unsigned int ma_count, 684 + u32 use_case) 685 + { 686 + struct ffa_device *ffa_dev = optee->ffa.ffa_dev; 687 + const struct ffa_mem_ops *mem_ops = ffa_dev->ops->mem_ops; 688 + const struct ffa_msg_ops *msg_ops = ffa_dev->ops->msg_ops; 689 + struct ffa_send_direct_data data; 690 + struct ffa_mem_region_attributes *mem_attr; 691 + struct ffa_mem_ops_args args = { 692 + .use_txbuf = true, 693 + .tag = use_case, 694 + }; 695 + struct page *page; 696 + struct scatterlist sgl; 697 + unsigned int n; 698 + int rc; 699 + 700 + mem_attr = kcalloc(ma_count, sizeof(*mem_attr), GFP_KERNEL); 701 + for (n = 0; n < ma_count; n++) { 702 + mem_attr[n].receiver = mem_attrs[n] & U16_MAX; 703 + mem_attr[n].attrs = mem_attrs[n] >> 16; 704 + } 705 + args.attrs = mem_attr; 706 + args.nattrs = ma_count; 707 + 708 + page = phys_to_page(protmem->paddr); 709 + sg_init_table(&sgl, 1); 710 + sg_set_page(&sgl, page, protmem->size, 0); 711 + 712 + args.sg = &sgl; 713 + rc = mem_ops->memory_lend(&args); 714 + kfree(mem_attr); 715 + if (rc) 716 + return rc; 717 + 718 + rc = do_call_lend_protmem(optee, args.g_handle, use_case); 719 + if (rc) 720 + goto err_reclaim; 721 + 722 + rc = optee_shm_add_ffa_handle(optee, protmem, args.g_handle); 723 + if (rc) 724 + goto err_unreg; 725 + 726 + protmem->sec_world_id = args.g_handle; 727 + 728 + return 0; 729 + 730 + err_unreg: 731 + data = (struct ffa_send_direct_data){ 732 + .data0 = OPTEE_FFA_RELEASE_PROTMEM, 733 + .data1 = (u32)args.g_handle, 734 + .data2 = (u32)(args.g_handle >> 32), 735 + }; 736 + msg_ops->sync_send_receive(ffa_dev, &data); 737 + err_reclaim: 738 + mem_ops->memory_reclaim(args.g_handle, 0); 739 + return rc; 740 + } 741 + 742 + static int optee_ffa_reclaim_protmem(struct optee *optee, 743 + struct tee_shm *protmem) 744 + { 745 + struct ffa_device *ffa_dev = optee->ffa.ffa_dev; 746 + const struct ffa_msg_ops *msg_ops = ffa_dev->ops->msg_ops; 747 + const struct ffa_mem_ops *mem_ops = ffa_dev->ops->mem_ops; 748 + u64 global_handle = protmem->sec_world_id; 749 + struct ffa_send_direct_data data = { 750 + .data0 = OPTEE_FFA_RELEASE_PROTMEM, 751 + .data1 = (u32)global_handle, 752 + .data2 = (u32)(global_handle >> 32) 753 + }; 754 + int rc; 755 + 756 + optee_shm_rem_ffa_handle(optee, global_handle); 757 + protmem->sec_world_id = 0; 758 + 759 + rc = msg_ops->sync_send_receive(ffa_dev, &data); 760 + if (rc) 761 + pr_err("Release SHM id 0x%llx rc %d\n", global_handle, rc); 762 + 763 + rc = mem_ops->memory_reclaim(global_handle, 0); 764 + if (rc) 765 + pr_err("mem_reclaim: 0x%llx %d", global_handle, rc); 766 + 767 + return rc; 768 + } 769 + 652 770 /* 653 771 * 6. Driver initialization 654 772 * ··· 937 819 .do_call_with_arg = optee_ffa_do_call_with_arg, 938 820 .to_msg_param = optee_ffa_to_msg_param, 939 821 .from_msg_param = optee_ffa_from_msg_param, 822 + .lend_protmem = optee_ffa_lend_protmem, 823 + .reclaim_protmem = optee_ffa_reclaim_protmem, 940 824 }; 941 825 942 826 static void optee_ffa_remove(struct ffa_device *ffa_dev) ··· 1011 891 return rc; 1012 892 } 1013 893 894 + static int optee_ffa_protmem_pool_init(struct optee *optee, u32 sec_caps) 895 + { 896 + enum tee_dma_heap_id id = TEE_DMA_HEAP_SECURE_VIDEO_PLAY; 897 + struct tee_protmem_pool *pool; 898 + int rc = 0; 899 + 900 + if (sec_caps & OPTEE_FFA_SEC_CAP_PROTMEM) { 901 + pool = optee_protmem_alloc_dyn_pool(optee, id); 902 + if (IS_ERR(pool)) 903 + return PTR_ERR(pool); 904 + 905 + rc = tee_device_register_dma_heap(optee->teedev, id, pool); 906 + if (rc) 907 + pool->ops->destroy_pool(pool); 908 + } 909 + 910 + return rc; 911 + } 912 + 1014 913 static int optee_ffa_probe(struct ffa_device *ffa_dev) 1015 914 { 1016 915 const struct ffa_notifier_ops *notif_ops; ··· 1080 941 optee); 1081 942 if (IS_ERR(teedev)) { 1082 943 rc = PTR_ERR(teedev); 1083 - goto err_free_pool; 944 + goto err_free_shm_pool; 1084 945 } 1085 946 optee->teedev = teedev; 1086 947 ··· 1127 988 rc); 1128 989 } 1129 990 991 + if (optee_ffa_protmem_pool_init(optee, sec_caps)) 992 + pr_info("Protected memory service not available\n"); 993 + 1130 994 rc = optee_enumerate_devices(PTA_CMD_GET_DEVICES); 1131 995 if (rc) 1132 996 goto err_unregister_devices; ··· 1160 1018 tee_device_unregister(optee->supp_teedev); 1161 1019 err_unreg_teedev: 1162 1020 tee_device_unregister(optee->teedev); 1163 - err_free_pool: 1021 + err_free_shm_pool: 1164 1022 tee_shm_pool_free(pool); 1165 1023 err_free_optee: 1166 1024 kfree(optee);
+23 -6
drivers/tee/optee/optee_ffa.h
··· 81 81 * as the second MSG arg struct for 82 82 * OPTEE_FFA_YIELDING_CALL_WITH_ARG. 83 83 * Bit[31:8]: Reserved (MBZ) 84 - * w5: Bitfield of secure world capabilities OPTEE_FFA_SEC_CAP_* below, 84 + * w5: Bitfield of OP-TEE capabilities OPTEE_FFA_SEC_CAP_* 85 85 * w6: The maximum secure world notification number 86 86 * w7: Not used (MBZ) 87 87 */ ··· 94 94 #define OPTEE_FFA_SEC_CAP_ASYNC_NOTIF BIT(1) 95 95 /* OP-TEE supports probing for RPMB device if needed */ 96 96 #define OPTEE_FFA_SEC_CAP_RPMB_PROBE BIT(2) 97 + /* OP-TEE supports Protected Memory for secure data path */ 98 + #define OPTEE_FFA_SEC_CAP_PROTMEM BIT(3) 97 99 98 100 #define OPTEE_FFA_EXCHANGE_CAPABILITIES OPTEE_FFA_BLOCKING_CALL(2) 99 101 ··· 110 108 * 111 109 * Return register usage: 112 110 * w3: Error code, 0 on success 113 - * w4-w7: Note used (MBZ) 111 + * w4-w7: Not used (MBZ) 114 112 */ 115 113 #define OPTEE_FFA_UNREGISTER_SHM OPTEE_FFA_BLOCKING_CALL(3) 116 114 ··· 121 119 * Call register usage: 122 120 * w3: Service ID, OPTEE_FFA_ENABLE_ASYNC_NOTIF 123 121 * w4: Notification value to request bottom half processing, should be 124 - * less than OPTEE_FFA_MAX_ASYNC_NOTIF_VALUE. 122 + * less than OPTEE_FFA_MAX_ASYNC_NOTIF_VALUE 125 123 * w5-w7: Not used (MBZ) 124 + * 125 + * Return register usage: 126 + * w3: Error code, 0 on success 127 + * w4-w7: Not used (MBZ) 128 + */ 129 + #define OPTEE_FFA_ENABLE_ASYNC_NOTIF OPTEE_FFA_BLOCKING_CALL(5) 130 + 131 + #define OPTEE_FFA_MAX_ASYNC_NOTIF_VALUE 64 132 + 133 + /* 134 + * Release Protected memory 135 + * 136 + * Call register usage: 137 + * w3: Service ID, OPTEE_FFA_RECLAIM_PROTMEM 138 + * w4: Shared memory handle, lower bits 139 + * w5: Shared memory handle, higher bits 140 + * w6-w7: Not used (MBZ) 126 141 * 127 142 * Return register usage: 128 143 * w3: Error code, 0 on success 129 144 * w4-w7: Note used (MBZ) 130 145 */ 131 - #define OPTEE_FFA_ENABLE_ASYNC_NOTIF OPTEE_FFA_BLOCKING_CALL(5) 132 - 133 - #define OPTEE_FFA_MAX_ASYNC_NOTIF_VALUE 64 146 + #define OPTEE_FFA_RELEASE_PROTMEM OPTEE_FFA_BLOCKING_CALL(8) 134 147 135 148 /* 136 149 * Call with struct optee_msg_arg as argument in the supplied shared memory
+72 -12
drivers/tee/optee/optee_msg.h
··· 133 133 }; 134 134 135 135 /** 136 - * struct optee_msg_param_fmem - ffa memory reference parameter 136 + * struct optee_msg_param_fmem - FF-A memory reference parameter 137 137 * @offs_lower: Lower bits of offset into shared memory reference 138 138 * @offs_upper: Upper bits of offset into shared memory reference 139 139 * @internal_offs: Internal offset into the first page of shared memory 140 140 * reference 141 141 * @size: Size of the buffer 142 - * @global_id: Global identifier of Shared memory 142 + * @global_id: Global identifier of the shared memory 143 143 */ 144 144 struct optee_msg_param_fmem { 145 145 u32 offs_low; ··· 165 165 * @attr: attributes 166 166 * @tmem: parameter by temporary memory reference 167 167 * @rmem: parameter by registered memory reference 168 - * @fmem: parameter by ffa registered memory reference 168 + * @fmem: parameter by FF-A registered memory reference 169 169 * @value: parameter by opaque value 170 170 * @octets: parameter by octet string 171 171 * ··· 297 297 #define OPTEE_MSG_FUNCID_GET_OS_REVISION 0x0001 298 298 299 299 /* 300 + * Values used in OPTEE_MSG_CMD_LEND_PROTMEM below 301 + * OPTEE_MSG_PROTMEM_RESERVED Reserved 302 + * OPTEE_MSG_PROTMEM_SECURE_VIDEO_PLAY Secure Video Playback 303 + * OPTEE_MSG_PROTMEM_TRUSTED_UI Trused UI 304 + * OPTEE_MSG_PROTMEM_SECURE_VIDEO_RECORD Secure Video Recording 305 + */ 306 + #define OPTEE_MSG_PROTMEM_RESERVED 0 307 + #define OPTEE_MSG_PROTMEM_SECURE_VIDEO_PLAY 1 308 + #define OPTEE_MSG_PROTMEM_TRUSTED_UI 2 309 + #define OPTEE_MSG_PROTMEM_SECURE_VIDEO_RECORD 3 310 + 311 + /* 300 312 * Do a secure call with struct optee_msg_arg as argument 301 313 * The OPTEE_MSG_CMD_* below defines what goes in struct optee_msg_arg::cmd 302 314 * ··· 349 337 * OPTEE_MSG_CMD_STOP_ASYNC_NOTIF informs secure world that from now is 350 338 * normal world unable to process asynchronous notifications. Typically 351 339 * used when the driver is shut down. 340 + * 341 + * OPTEE_MSG_CMD_LEND_PROTMEM lends protected memory. The passed normal 342 + * physical memory is protected from normal world access. The memory 343 + * should be unmapped prior to this call since it becomes inaccessible 344 + * during the request. 345 + * Parameters are passed as: 346 + * [in] param[0].attr OPTEE_MSG_ATTR_TYPE_VALUE_INPUT 347 + * [in] param[0].u.value.a OPTEE_MSG_PROTMEM_* defined above 348 + * [in] param[1].attr OPTEE_MSG_ATTR_TYPE_TMEM_INPUT 349 + * [in] param[1].u.tmem.buf_ptr physical address 350 + * [in] param[1].u.tmem.size size 351 + * [in] param[1].u.tmem.shm_ref holds protected memory reference 352 + * 353 + * OPTEE_MSG_CMD_RECLAIM_PROTMEM reclaims a previously lent protected 354 + * memory reference. The physical memory is accessible by the normal world 355 + * after this function has return and can be mapped again. The information 356 + * is passed as: 357 + * [in] param[0].attr OPTEE_MSG_ATTR_TYPE_VALUE_INPUT 358 + * [in] param[0].u.value.a holds protected memory cookie 359 + * 360 + * OPTEE_MSG_CMD_GET_PROTMEM_CONFIG get configuration for a specific 361 + * protected memory use case. Parameters are passed as: 362 + * [in] param[0].attr OPTEE_MSG_ATTR_TYPE_VALUE_INOUT 363 + * [in] param[0].value.a OPTEE_MSG_PROTMEM_* 364 + * [in] param[1].attr OPTEE_MSG_ATTR_TYPE_{R,F}MEM_OUTPUT 365 + * [in] param[1].u.{r,f}mem Buffer or NULL 366 + * [in] param[1].u.{r,f}mem.size Provided size of buffer or 0 for query 367 + * output for the protected use case: 368 + * [out] param[0].value.a Minimal size of protected memory 369 + * [out] param[0].value.b Required alignment of size and start of 370 + * protected memory 371 + * [out] param[0].value.c PA width, max 64 372 + * [out] param[1].{r,f}mem.size Size of output data 373 + * [out] param[1].{r,f}mem If non-NULL, contains an array of 374 + * uint32_t memory attributes that must be 375 + * included when lending memory for this 376 + * use case 377 + * 378 + * OPTEE_MSG_CMD_ASSIGN_PROTMEM assigns use-case to protected memory 379 + * previously lent using the FFA_LEND framework ABI. Parameters are passed 380 + * as: 381 + * [in] param[0].attr OPTEE_MSG_ATTR_TYPE_VALUE_INPUT 382 + * [in] param[0].u.value.a holds protected memory cookie 383 + * [in] param[0].u.value.b OPTEE_MSG_PROTMEM_* defined above 352 384 */ 353 - #define OPTEE_MSG_CMD_OPEN_SESSION 0 354 - #define OPTEE_MSG_CMD_INVOKE_COMMAND 1 355 - #define OPTEE_MSG_CMD_CLOSE_SESSION 2 356 - #define OPTEE_MSG_CMD_CANCEL 3 357 - #define OPTEE_MSG_CMD_REGISTER_SHM 4 358 - #define OPTEE_MSG_CMD_UNREGISTER_SHM 5 359 - #define OPTEE_MSG_CMD_DO_BOTTOM_HALF 6 360 - #define OPTEE_MSG_CMD_STOP_ASYNC_NOTIF 7 361 - #define OPTEE_MSG_FUNCID_CALL_WITH_ARG 0x0004 385 + #define OPTEE_MSG_CMD_OPEN_SESSION 0 386 + #define OPTEE_MSG_CMD_INVOKE_COMMAND 1 387 + #define OPTEE_MSG_CMD_CLOSE_SESSION 2 388 + #define OPTEE_MSG_CMD_CANCEL 3 389 + #define OPTEE_MSG_CMD_REGISTER_SHM 4 390 + #define OPTEE_MSG_CMD_UNREGISTER_SHM 5 391 + #define OPTEE_MSG_CMD_DO_BOTTOM_HALF 6 392 + #define OPTEE_MSG_CMD_STOP_ASYNC_NOTIF 7 393 + #define OPTEE_MSG_CMD_LEND_PROTMEM 8 394 + #define OPTEE_MSG_CMD_RECLAIM_PROTMEM 9 395 + #define OPTEE_MSG_CMD_GET_PROTMEM_CONFIG 10 396 + #define OPTEE_MSG_CMD_ASSIGN_PROTMEM 11 397 + #define OPTEE_MSG_FUNCID_CALL_WITH_ARG 0x0004 362 398 363 399 #endif /* _OPTEE_MSG_H */
+14 -1
drivers/tee/optee/optee_private.h
··· 176 176 * @do_call_with_arg: enters OP-TEE in secure world 177 177 * @to_msg_param: converts from struct tee_param to OPTEE_MSG parameters 178 178 * @from_msg_param: converts from OPTEE_MSG parameters to struct tee_param 179 + * @lend_protmem: lends physically contiguous memory as restricted 180 + * memory, inaccessible by the kernel 181 + * @reclaim_protmem: reclaims restricted memory previously lent with 182 + * @lend_protmem() and makes it accessible by the 183 + * kernel again 179 184 * 180 185 * These OPs are only supposed to be used internally in the OP-TEE driver 181 - * as a way of abstracting the different methogs of entering OP-TEE in 186 + * as a way of abstracting the different methods of entering OP-TEE in 182 187 * secure world. 183 188 */ 184 189 struct optee_ops { ··· 196 191 int (*from_msg_param)(struct optee *optee, struct tee_param *params, 197 192 size_t num_params, 198 193 const struct optee_msg_param *msg_params); 194 + int (*lend_protmem)(struct optee *optee, struct tee_shm *protmem, 195 + u32 *mem_attr, unsigned int ma_count, 196 + u32 use_case); 197 + int (*reclaim_protmem)(struct optee *optee, struct tee_shm *protmem); 199 198 }; 200 199 201 200 /** ··· 283 274 284 275 extern struct blocking_notifier_head optee_rpmb_intf_added; 285 276 277 + int optee_set_dma_mask(struct optee *optee, u_int pa_width); 278 + 286 279 int optee_notif_init(struct optee *optee, u_int max_key); 287 280 void optee_notif_uninit(struct optee *optee); 288 281 int optee_notif_wait(struct optee *optee, u_int key, u32 timeout); ··· 296 285 void optee_supp_init(struct optee_supp *supp); 297 286 void optee_supp_uninit(struct optee_supp *supp); 298 287 void optee_supp_release(struct optee_supp *supp); 288 + struct tee_protmem_pool *optee_protmem_alloc_dyn_pool(struct optee *optee, 289 + enum tee_dma_heap_id id); 299 290 300 291 int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, 301 292 struct tee_param *param);
+36 -1
drivers/tee/optee/optee_smc.h
··· 264 264 #define OPTEE_SMC_SEC_CAP_HAVE_RESERVED_SHM BIT(0) 265 265 /* Secure world can communicate via previously unregistered shared memory */ 266 266 #define OPTEE_SMC_SEC_CAP_UNREGISTERED_SHM BIT(1) 267 - 268 267 /* 269 268 * Secure world supports commands "register/unregister shared memory", 270 269 * secure world accepts command buffers located in any parts of non-secure RAM ··· 279 280 #define OPTEE_SMC_SEC_CAP_RPC_ARG BIT(6) 280 281 /* Secure world supports probing for RPMB device if needed */ 281 282 #define OPTEE_SMC_SEC_CAP_RPMB_PROBE BIT(7) 283 + /* Secure world supports protected memory */ 284 + #define OPTEE_SMC_SEC_CAP_PROTMEM BIT(8) 285 + /* Secure world supports dynamic protected memory */ 286 + #define OPTEE_SMC_SEC_CAP_DYNAMIC_PROTMEM BIT(9) 282 287 283 288 #define OPTEE_SMC_FUNCID_EXCHANGE_CAPABILITIES 9 284 289 #define OPTEE_SMC_EXCHANGE_CAPABILITIES \ ··· 454 451 455 452 /* See OPTEE_SMC_CALL_WITH_REGD_ARG above */ 456 453 #define OPTEE_SMC_FUNCID_CALL_WITH_REGD_ARG 19 454 + /* 455 + * Get protected memory config 456 + * 457 + * Returns the protected memory config. 458 + * 459 + * Call register usage: 460 + * a0 SMC Function ID, OPTEE_SMC_GET_PROTMEM_CONFIG 461 + * a2-6 Not used, must be zero 462 + * a7 Hypervisor Client ID register 463 + * 464 + * Have config return register usage: 465 + * a0 OPTEE_SMC_RETURN_OK 466 + * a1 Physical address of start of protected memory 467 + * a2 Size of protected memory 468 + * a3 PA width, max 64 469 + * a4-7 Preserved 470 + * 471 + * Not available register usage: 472 + * a0 OPTEE_SMC_RETURN_ENOTAVAIL 473 + * a1-3 Not used 474 + * a4-7 Preserved 475 + */ 476 + #define OPTEE_SMC_FUNCID_GET_PROTMEM_CONFIG 20 477 + #define OPTEE_SMC_GET_PROTMEM_CONFIG \ 478 + OPTEE_SMC_FAST_CALL_VAL(OPTEE_SMC_FUNCID_GET_PROTMEM_CONFIG) 479 + 480 + struct optee_smc_get_protmem_config_result { 481 + unsigned long status; 482 + unsigned long start; 483 + unsigned long size; 484 + unsigned long pa_width; 485 + }; 457 486 458 487 /* 459 488 * Resume from RPC (for example after processing a foreign interrupt)
+335
drivers/tee/optee/protmem.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (c) 2025, Linaro Limited 4 + */ 5 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 6 + 7 + #include <linux/errno.h> 8 + #include <linux/genalloc.h> 9 + #include <linux/slab.h> 10 + #include <linux/string.h> 11 + #include <linux/tee_core.h> 12 + #include <linux/types.h> 13 + #include "optee_private.h" 14 + 15 + struct optee_protmem_dyn_pool { 16 + struct tee_protmem_pool pool; 17 + struct gen_pool *gen_pool; 18 + struct optee *optee; 19 + size_t page_count; 20 + u32 *mem_attrs; 21 + u_int mem_attr_count; 22 + refcount_t refcount; 23 + u32 use_case; 24 + struct tee_shm *protmem; 25 + /* Protects when initializing and tearing down this struct */ 26 + struct mutex mutex; 27 + }; 28 + 29 + static struct optee_protmem_dyn_pool * 30 + to_protmem_dyn_pool(struct tee_protmem_pool *pool) 31 + { 32 + return container_of(pool, struct optee_protmem_dyn_pool, pool); 33 + } 34 + 35 + static int init_dyn_protmem(struct optee_protmem_dyn_pool *rp) 36 + { 37 + int rc; 38 + 39 + rp->protmem = tee_shm_alloc_dma_mem(rp->optee->ctx, rp->page_count); 40 + if (IS_ERR(rp->protmem)) { 41 + rc = PTR_ERR(rp->protmem); 42 + goto err_null_protmem; 43 + } 44 + 45 + /* 46 + * TODO unmap the memory range since the physical memory will 47 + * become inaccesible after the lend_protmem() call. 48 + * 49 + * If the platform supports a hypervisor at EL2, it will unmap the 50 + * intermediate physical memory for us and stop cache pre-fetch of 51 + * the memory. 52 + */ 53 + rc = rp->optee->ops->lend_protmem(rp->optee, rp->protmem, 54 + rp->mem_attrs, 55 + rp->mem_attr_count, rp->use_case); 56 + if (rc) 57 + goto err_put_shm; 58 + rp->protmem->flags |= TEE_SHM_DYNAMIC; 59 + 60 + rp->gen_pool = gen_pool_create(PAGE_SHIFT, -1); 61 + if (!rp->gen_pool) { 62 + rc = -ENOMEM; 63 + goto err_reclaim; 64 + } 65 + 66 + rc = gen_pool_add(rp->gen_pool, rp->protmem->paddr, 67 + rp->protmem->size, -1); 68 + if (rc) 69 + goto err_free_pool; 70 + 71 + refcount_set(&rp->refcount, 1); 72 + return 0; 73 + 74 + err_free_pool: 75 + gen_pool_destroy(rp->gen_pool); 76 + rp->gen_pool = NULL; 77 + err_reclaim: 78 + rp->optee->ops->reclaim_protmem(rp->optee, rp->protmem); 79 + err_put_shm: 80 + tee_shm_put(rp->protmem); 81 + err_null_protmem: 82 + rp->protmem = NULL; 83 + return rc; 84 + } 85 + 86 + static int get_dyn_protmem(struct optee_protmem_dyn_pool *rp) 87 + { 88 + int rc = 0; 89 + 90 + if (!refcount_inc_not_zero(&rp->refcount)) { 91 + mutex_lock(&rp->mutex); 92 + if (rp->gen_pool) { 93 + /* 94 + * Another thread has already initialized the pool 95 + * before us, or the pool was just about to be torn 96 + * down. Either way we only need to increase the 97 + * refcount and we're done. 98 + */ 99 + refcount_inc(&rp->refcount); 100 + } else { 101 + rc = init_dyn_protmem(rp); 102 + } 103 + mutex_unlock(&rp->mutex); 104 + } 105 + 106 + return rc; 107 + } 108 + 109 + static void release_dyn_protmem(struct optee_protmem_dyn_pool *rp) 110 + { 111 + gen_pool_destroy(rp->gen_pool); 112 + rp->gen_pool = NULL; 113 + 114 + rp->optee->ops->reclaim_protmem(rp->optee, rp->protmem); 115 + rp->protmem->flags &= ~TEE_SHM_DYNAMIC; 116 + 117 + WARN(refcount_read(&rp->protmem->refcount) != 1, "Unexpected refcount"); 118 + tee_shm_put(rp->protmem); 119 + rp->protmem = NULL; 120 + } 121 + 122 + static void put_dyn_protmem(struct optee_protmem_dyn_pool *rp) 123 + { 124 + if (refcount_dec_and_test(&rp->refcount)) { 125 + mutex_lock(&rp->mutex); 126 + if (rp->gen_pool) 127 + release_dyn_protmem(rp); 128 + mutex_unlock(&rp->mutex); 129 + } 130 + } 131 + 132 + static int protmem_pool_op_dyn_alloc(struct tee_protmem_pool *pool, 133 + struct sg_table *sgt, size_t size, 134 + size_t *offs) 135 + { 136 + struct optee_protmem_dyn_pool *rp = to_protmem_dyn_pool(pool); 137 + size_t sz = ALIGN(size, PAGE_SIZE); 138 + phys_addr_t pa; 139 + int rc; 140 + 141 + rc = get_dyn_protmem(rp); 142 + if (rc) 143 + return rc; 144 + 145 + pa = gen_pool_alloc(rp->gen_pool, sz); 146 + if (!pa) { 147 + rc = -ENOMEM; 148 + goto err_put; 149 + } 150 + 151 + rc = sg_alloc_table(sgt, 1, GFP_KERNEL); 152 + if (rc) 153 + goto err_free; 154 + 155 + sg_set_page(sgt->sgl, phys_to_page(pa), size, 0); 156 + *offs = pa - rp->protmem->paddr; 157 + 158 + return 0; 159 + err_free: 160 + gen_pool_free(rp->gen_pool, pa, size); 161 + err_put: 162 + put_dyn_protmem(rp); 163 + 164 + return rc; 165 + } 166 + 167 + static void protmem_pool_op_dyn_free(struct tee_protmem_pool *pool, 168 + struct sg_table *sgt) 169 + { 170 + struct optee_protmem_dyn_pool *rp = to_protmem_dyn_pool(pool); 171 + struct scatterlist *sg; 172 + int i; 173 + 174 + for_each_sgtable_sg(sgt, sg, i) 175 + gen_pool_free(rp->gen_pool, sg_phys(sg), sg->length); 176 + sg_free_table(sgt); 177 + put_dyn_protmem(rp); 178 + } 179 + 180 + static int protmem_pool_op_dyn_update_shm(struct tee_protmem_pool *pool, 181 + struct sg_table *sgt, size_t offs, 182 + struct tee_shm *shm, 183 + struct tee_shm **parent_shm) 184 + { 185 + struct optee_protmem_dyn_pool *rp = to_protmem_dyn_pool(pool); 186 + 187 + *parent_shm = rp->protmem; 188 + 189 + return 0; 190 + } 191 + 192 + static void pool_op_dyn_destroy_pool(struct tee_protmem_pool *pool) 193 + { 194 + struct optee_protmem_dyn_pool *rp = to_protmem_dyn_pool(pool); 195 + 196 + mutex_destroy(&rp->mutex); 197 + kfree(rp); 198 + } 199 + 200 + static struct tee_protmem_pool_ops protmem_pool_ops_dyn = { 201 + .alloc = protmem_pool_op_dyn_alloc, 202 + .free = protmem_pool_op_dyn_free, 203 + .update_shm = protmem_pool_op_dyn_update_shm, 204 + .destroy_pool = pool_op_dyn_destroy_pool, 205 + }; 206 + 207 + static int get_protmem_config(struct optee *optee, u32 use_case, 208 + size_t *min_size, u_int *pa_width, 209 + u32 *mem_attrs, u_int *ma_count) 210 + { 211 + struct tee_param params[2] = { 212 + [0] = { 213 + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT, 214 + .u.value.a = use_case, 215 + }, 216 + [1] = { 217 + .attr = TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT, 218 + }, 219 + }; 220 + struct optee_shm_arg_entry *entry; 221 + struct tee_shm *shm_param = NULL; 222 + struct optee_msg_arg *msg_arg; 223 + struct tee_shm *shm; 224 + u_int offs; 225 + int rc; 226 + 227 + if (mem_attrs && *ma_count) { 228 + params[1].u.memref.size = *ma_count * sizeof(*mem_attrs); 229 + shm_param = tee_shm_alloc_priv_buf(optee->ctx, 230 + params[1].u.memref.size); 231 + if (IS_ERR(shm_param)) 232 + return PTR_ERR(shm_param); 233 + params[1].u.memref.shm = shm_param; 234 + } 235 + 236 + msg_arg = optee_get_msg_arg(optee->ctx, ARRAY_SIZE(params), &entry, 237 + &shm, &offs); 238 + if (IS_ERR(msg_arg)) { 239 + rc = PTR_ERR(msg_arg); 240 + goto out_free_shm; 241 + } 242 + msg_arg->cmd = OPTEE_MSG_CMD_GET_PROTMEM_CONFIG; 243 + 244 + rc = optee->ops->to_msg_param(optee, msg_arg->params, 245 + ARRAY_SIZE(params), params); 246 + if (rc) 247 + goto out_free_msg; 248 + 249 + rc = optee->ops->do_call_with_arg(optee->ctx, shm, offs, false); 250 + if (rc) 251 + goto out_free_msg; 252 + if (msg_arg->ret && msg_arg->ret != TEEC_ERROR_SHORT_BUFFER) { 253 + rc = -EINVAL; 254 + goto out_free_msg; 255 + } 256 + 257 + rc = optee->ops->from_msg_param(optee, params, ARRAY_SIZE(params), 258 + msg_arg->params); 259 + if (rc) 260 + goto out_free_msg; 261 + 262 + if (!msg_arg->ret && mem_attrs && 263 + *ma_count < params[1].u.memref.size / sizeof(*mem_attrs)) { 264 + rc = -EINVAL; 265 + goto out_free_msg; 266 + } 267 + 268 + *min_size = params[0].u.value.a; 269 + *pa_width = params[0].u.value.c; 270 + *ma_count = params[1].u.memref.size / sizeof(*mem_attrs); 271 + 272 + if (msg_arg->ret == TEEC_ERROR_SHORT_BUFFER) { 273 + rc = -ENOSPC; 274 + goto out_free_msg; 275 + } 276 + 277 + if (mem_attrs) 278 + memcpy(mem_attrs, tee_shm_get_va(shm_param, 0), 279 + params[1].u.memref.size); 280 + 281 + out_free_msg: 282 + optee_free_msg_arg(optee->ctx, entry, offs); 283 + out_free_shm: 284 + if (shm_param) 285 + tee_shm_free(shm_param); 286 + return rc; 287 + } 288 + 289 + struct tee_protmem_pool *optee_protmem_alloc_dyn_pool(struct optee *optee, 290 + enum tee_dma_heap_id id) 291 + { 292 + struct optee_protmem_dyn_pool *rp; 293 + size_t min_size; 294 + u_int pa_width; 295 + int rc; 296 + 297 + rp = kzalloc(sizeof(*rp), GFP_KERNEL); 298 + if (!rp) 299 + return ERR_PTR(-ENOMEM); 300 + rp->use_case = id; 301 + 302 + rc = get_protmem_config(optee, id, &min_size, &pa_width, NULL, 303 + &rp->mem_attr_count); 304 + if (rc) { 305 + if (rc != -ENOSPC) 306 + goto err; 307 + rp->mem_attrs = kcalloc(rp->mem_attr_count, 308 + sizeof(*rp->mem_attrs), GFP_KERNEL); 309 + if (!rp->mem_attrs) { 310 + rc = -ENOMEM; 311 + goto err; 312 + } 313 + rc = get_protmem_config(optee, id, &min_size, &pa_width, 314 + rp->mem_attrs, &rp->mem_attr_count); 315 + if (rc) 316 + goto err_kfree_eps; 317 + } 318 + 319 + rc = optee_set_dma_mask(optee, pa_width); 320 + if (rc) 321 + goto err_kfree_eps; 322 + 323 + rp->pool.ops = &protmem_pool_ops_dyn; 324 + rp->optee = optee; 325 + rp->page_count = min_size / PAGE_SIZE; 326 + mutex_init(&rp->mutex); 327 + 328 + return &rp->pool; 329 + 330 + err_kfree_eps: 331 + kfree(rp->mem_attrs); 332 + err: 333 + kfree(rp); 334 + return ERR_PTR(rc); 335 + }
+139 -2
drivers/tee/optee/smc_abi.c
··· 965 965 return rc; 966 966 } 967 967 968 + static int optee_smc_lend_protmem(struct optee *optee, struct tee_shm *protmem, 969 + u32 *mem_attrs, unsigned int ma_count, 970 + u32 use_case) 971 + { 972 + struct optee_shm_arg_entry *entry; 973 + struct optee_msg_arg *msg_arg; 974 + struct tee_shm *shm; 975 + u_int offs; 976 + int rc; 977 + 978 + msg_arg = optee_get_msg_arg(optee->ctx, 2, &entry, &shm, &offs); 979 + if (IS_ERR(msg_arg)) 980 + return PTR_ERR(msg_arg); 981 + 982 + msg_arg->cmd = OPTEE_MSG_CMD_LEND_PROTMEM; 983 + msg_arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_VALUE_INPUT; 984 + msg_arg->params[0].u.value.a = use_case; 985 + msg_arg->params[1].attr = OPTEE_MSG_ATTR_TYPE_TMEM_INPUT; 986 + msg_arg->params[1].u.tmem.buf_ptr = protmem->paddr; 987 + msg_arg->params[1].u.tmem.size = protmem->size; 988 + msg_arg->params[1].u.tmem.shm_ref = (u_long)protmem; 989 + 990 + rc = optee->ops->do_call_with_arg(optee->ctx, shm, offs, false); 991 + if (rc) 992 + goto out; 993 + if (msg_arg->ret != TEEC_SUCCESS) { 994 + rc = -EINVAL; 995 + goto out; 996 + } 997 + protmem->sec_world_id = (u_long)protmem; 998 + 999 + out: 1000 + optee_free_msg_arg(optee->ctx, entry, offs); 1001 + return rc; 1002 + } 1003 + 1004 + static int optee_smc_reclaim_protmem(struct optee *optee, 1005 + struct tee_shm *protmem) 1006 + { 1007 + struct optee_shm_arg_entry *entry; 1008 + struct optee_msg_arg *msg_arg; 1009 + struct tee_shm *shm; 1010 + u_int offs; 1011 + int rc; 1012 + 1013 + msg_arg = optee_get_msg_arg(optee->ctx, 1, &entry, &shm, &offs); 1014 + if (IS_ERR(msg_arg)) 1015 + return PTR_ERR(msg_arg); 1016 + 1017 + msg_arg->cmd = OPTEE_MSG_CMD_RECLAIM_PROTMEM; 1018 + msg_arg->params[0].attr = OPTEE_MSG_ATTR_TYPE_RMEM_INPUT; 1019 + msg_arg->params[0].u.rmem.shm_ref = (u_long)protmem; 1020 + 1021 + rc = optee->ops->do_call_with_arg(optee->ctx, shm, offs, false); 1022 + if (rc) 1023 + goto out; 1024 + if (msg_arg->ret != TEEC_SUCCESS) 1025 + rc = -EINVAL; 1026 + 1027 + out: 1028 + optee_free_msg_arg(optee->ctx, entry, offs); 1029 + return rc; 1030 + } 1031 + 968 1032 /* 969 1033 * 5. Asynchronous notification 970 1034 */ ··· 1280 1216 .do_call_with_arg = optee_smc_do_call_with_arg, 1281 1217 .to_msg_param = optee_to_msg_param, 1282 1218 .from_msg_param = optee_from_msg_param, 1219 + .lend_protmem = optee_smc_lend_protmem, 1220 + .reclaim_protmem = optee_smc_reclaim_protmem, 1283 1221 }; 1284 1222 1285 1223 static int enable_async_notif(optee_invoke_fn *invoke_fn) ··· 1649 1583 } 1650 1584 #endif 1651 1585 1586 + static struct tee_protmem_pool *static_protmem_pool_init(struct optee *optee) 1587 + { 1588 + #if IS_ENABLED(CONFIG_OPTEE_STATIC_PROTMEM_POOL) 1589 + union { 1590 + struct arm_smccc_res smccc; 1591 + struct optee_smc_get_protmem_config_result result; 1592 + } res; 1593 + struct tee_protmem_pool *pool; 1594 + void *p; 1595 + int rc; 1596 + 1597 + optee->smc.invoke_fn(OPTEE_SMC_GET_PROTMEM_CONFIG, 0, 0, 0, 0, 1598 + 0, 0, 0, &res.smccc); 1599 + if (res.result.status != OPTEE_SMC_RETURN_OK) 1600 + return ERR_PTR(-EINVAL); 1601 + 1602 + rc = optee_set_dma_mask(optee, res.result.pa_width); 1603 + if (rc) 1604 + return ERR_PTR(rc); 1605 + 1606 + /* 1607 + * Map the memory as uncached to make sure the kernel can work with 1608 + * __pfn_to_page() and friends since that's needed when passing the 1609 + * protected DMA-buf to a device. The memory should otherwise not 1610 + * be touched by the kernel since it's likely to cause an external 1611 + * abort due to the protection status. 1612 + */ 1613 + p = devm_memremap(&optee->teedev->dev, res.result.start, 1614 + res.result.size, MEMREMAP_WC); 1615 + if (IS_ERR(p)) 1616 + return p; 1617 + 1618 + pool = tee_protmem_static_pool_alloc(res.result.start, res.result.size); 1619 + if (IS_ERR(pool)) 1620 + devm_memunmap(&optee->teedev->dev, p); 1621 + 1622 + return pool; 1623 + #else 1624 + return ERR_PTR(-EINVAL); 1625 + #endif 1626 + } 1627 + 1628 + static int optee_protmem_pool_init(struct optee *optee) 1629 + { 1630 + bool protm = optee->smc.sec_caps & OPTEE_SMC_SEC_CAP_PROTMEM; 1631 + bool dyn_protm = optee->smc.sec_caps & 1632 + OPTEE_SMC_SEC_CAP_DYNAMIC_PROTMEM; 1633 + enum tee_dma_heap_id heap_id = TEE_DMA_HEAP_SECURE_VIDEO_PLAY; 1634 + struct tee_protmem_pool *pool = ERR_PTR(-EINVAL); 1635 + int rc = -EINVAL; 1636 + 1637 + if (!protm && !dyn_protm) 1638 + return 0; 1639 + 1640 + if (protm) 1641 + pool = static_protmem_pool_init(optee); 1642 + if (dyn_protm && IS_ERR(pool)) 1643 + pool = optee_protmem_alloc_dyn_pool(optee, heap_id); 1644 + if (IS_ERR(pool)) 1645 + return PTR_ERR(pool); 1646 + 1647 + rc = tee_device_register_dma_heap(optee->teedev, heap_id, pool); 1648 + if (rc) 1649 + pool->ops->destroy_pool(pool); 1650 + 1651 + return rc; 1652 + } 1653 + 1652 1654 static int optee_probe(struct platform_device *pdev) 1653 1655 { 1654 1656 optee_invoke_fn *invoke_fn; ··· 1812 1678 optee = kzalloc(sizeof(*optee), GFP_KERNEL); 1813 1679 if (!optee) { 1814 1680 rc = -ENOMEM; 1815 - goto err_free_pool; 1681 + goto err_free_shm_pool; 1816 1682 } 1817 1683 1818 1684 optee->ops = &optee_ops; ··· 1885 1751 pr_info("Asynchronous notifications enabled\n"); 1886 1752 } 1887 1753 1754 + if (optee_protmem_pool_init(optee)) 1755 + pr_info("Protected memory service not available\n"); 1756 + 1888 1757 /* 1889 1758 * Ensure that there are no pre-existing shm objects before enabling 1890 1759 * the shm cache so that there's no chance of receiving an invalid ··· 1939 1802 tee_device_unregister(optee->teedev); 1940 1803 err_free_optee: 1941 1804 kfree(optee); 1942 - err_free_pool: 1805 + err_free_shm_pool: 1943 1806 tee_shm_pool_free(pool); 1944 1807 if (memremaped_shm) 1945 1808 memunmap(memremaped_shm);
+118 -40
drivers/tee/tee_core.c
··· 317 317 return ret; 318 318 } 319 319 320 + static int 321 + tee_ioctl_shm_register_fd(struct tee_context *ctx, 322 + struct tee_ioctl_shm_register_fd_data __user *udata) 323 + { 324 + struct tee_ioctl_shm_register_fd_data data; 325 + struct tee_shm *shm; 326 + long ret; 327 + 328 + if (copy_from_user(&data, udata, sizeof(data))) 329 + return -EFAULT; 330 + 331 + /* Currently no input flags are supported */ 332 + if (data.flags) 333 + return -EINVAL; 334 + 335 + shm = tee_shm_register_fd(ctx, data.fd); 336 + if (IS_ERR(shm)) 337 + return -EINVAL; 338 + 339 + data.id = shm->id; 340 + data.flags = shm->flags; 341 + data.size = shm->size; 342 + 343 + if (copy_to_user(udata, &data, sizeof(data))) 344 + ret = -EFAULT; 345 + else 346 + ret = tee_shm_get_fd(shm); 347 + 348 + /* 349 + * When user space closes the file descriptor the shared memory 350 + * should be freed or if tee_shm_get_fd() failed then it will 351 + * be freed immediately. 352 + */ 353 + tee_shm_put(shm); 354 + return ret; 355 + } 356 + 357 + static int param_from_user_memref(struct tee_context *ctx, 358 + struct tee_param_memref *memref, 359 + struct tee_ioctl_param *ip) 360 + { 361 + struct tee_shm *shm; 362 + size_t offs = 0; 363 + 364 + /* 365 + * If a NULL pointer is passed to a TA in the TEE, 366 + * the ip.c IOCTL parameters is set to TEE_MEMREF_NULL 367 + * indicating a NULL memory reference. 368 + */ 369 + if (ip->c != TEE_MEMREF_NULL) { 370 + /* 371 + * If we fail to get a pointer to a shared 372 + * memory object (and increase the ref count) 373 + * from an identifier we return an error. All 374 + * pointers that has been added in params have 375 + * an increased ref count. It's the callers 376 + * responibility to do tee_shm_put() on all 377 + * resolved pointers. 378 + */ 379 + shm = tee_shm_get_from_id(ctx, ip->c); 380 + if (IS_ERR(shm)) 381 + return PTR_ERR(shm); 382 + 383 + /* 384 + * Ensure offset + size does not overflow 385 + * offset and does not overflow the size of 386 + * the referred shared memory object. 387 + */ 388 + if ((ip->a + ip->b) < ip->a || 389 + (ip->a + ip->b) > shm->size) { 390 + tee_shm_put(shm); 391 + return -EINVAL; 392 + } 393 + 394 + if (shm->flags & TEE_SHM_DMA_BUF) { 395 + struct tee_shm_dmabuf_ref *ref; 396 + 397 + ref = container_of(shm, struct tee_shm_dmabuf_ref, shm); 398 + if (ref->parent_shm) { 399 + /* 400 + * The shm already has one reference to 401 + * ref->parent_shm so we are clear of 0. 402 + * We're getting another reference since 403 + * this shm will be used in the parameter 404 + * list instead of the shm we got with 405 + * tee_shm_get_from_id() above. 406 + */ 407 + refcount_inc(&ref->parent_shm->refcount); 408 + tee_shm_put(shm); 409 + shm = ref->parent_shm; 410 + offs = ref->offset; 411 + } 412 + } 413 + } else if (ctx->cap_memref_null) { 414 + /* Pass NULL pointer to OP-TEE */ 415 + shm = NULL; 416 + } else { 417 + return -EINVAL; 418 + } 419 + 420 + memref->shm_offs = ip->a + offs; 421 + memref->size = ip->b; 422 + memref->shm = shm; 423 + 424 + return 0; 425 + } 426 + 320 427 static int params_from_user(struct tee_context *ctx, struct tee_param *params, 321 428 size_t num_params, 322 429 struct tee_ioctl_param __user *uparams) ··· 431 324 size_t n; 432 325 433 326 for (n = 0; n < num_params; n++) { 434 - struct tee_shm *shm; 435 327 struct tee_ioctl_param ip; 328 + int rc; 436 329 437 330 if (copy_from_user(&ip, uparams + n, sizeof(ip))) 438 331 return -EFAULT; ··· 455 348 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INPUT: 456 349 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_OUTPUT: 457 350 case TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT: 458 - /* 459 - * If a NULL pointer is passed to a TA in the TEE, 460 - * the ip.c IOCTL parameters is set to TEE_MEMREF_NULL 461 - * indicating a NULL memory reference. 462 - */ 463 - if (ip.c != TEE_MEMREF_NULL) { 464 - /* 465 - * If we fail to get a pointer to a shared 466 - * memory object (and increase the ref count) 467 - * from an identifier we return an error. All 468 - * pointers that has been added in params have 469 - * an increased ref count. It's the callers 470 - * responibility to do tee_shm_put() on all 471 - * resolved pointers. 472 - */ 473 - shm = tee_shm_get_from_id(ctx, ip.c); 474 - if (IS_ERR(shm)) 475 - return PTR_ERR(shm); 476 - 477 - /* 478 - * Ensure offset + size does not overflow 479 - * offset and does not overflow the size of 480 - * the referred shared memory object. 481 - */ 482 - if ((ip.a + ip.b) < ip.a || 483 - (ip.a + ip.b) > shm->size) { 484 - tee_shm_put(shm); 485 - return -EINVAL; 486 - } 487 - } else if (ctx->cap_memref_null) { 488 - /* Pass NULL pointer to OP-TEE */ 489 - shm = NULL; 490 - } else { 491 - return -EINVAL; 492 - } 493 - 494 - params[n].u.memref.shm_offs = ip.a; 495 - params[n].u.memref.size = ip.b; 496 - params[n].u.memref.shm = shm; 351 + rc = param_from_user_memref(ctx, &params[n].u.memref, 352 + &ip); 353 + if (rc) 354 + return rc; 497 355 break; 498 356 default: 499 357 /* Unknown attribute */ ··· 863 791 return tee_ioctl_shm_alloc(ctx, uarg); 864 792 case TEE_IOC_SHM_REGISTER: 865 793 return tee_ioctl_shm_register(ctx, uarg); 794 + case TEE_IOC_SHM_REGISTER_FD: 795 + return tee_ioctl_shm_register_fd(ctx, uarg); 866 796 case TEE_IOC_OPEN_SESSION: 867 797 return tee_ioctl_open_session(ctx, uarg); 868 798 case TEE_IOC_INVOKE: ··· 1101 1027 if (!teedev) 1102 1028 return; 1103 1029 1030 + tee_device_put_all_dma_heaps(teedev); 1031 + 1104 1032 if (teedev->flags & TEE_DEVICE_FLAG_REGISTERED) 1105 1033 cdev_device_del(&teedev->cdev, &teedev->dev); 1106 1034 ··· 1326 1250 MODULE_DESCRIPTION("TEE Driver"); 1327 1251 MODULE_VERSION("1.0"); 1328 1252 MODULE_LICENSE("GPL v2"); 1253 + MODULE_IMPORT_NS("DMA_BUF"); 1254 + MODULE_IMPORT_NS("DMA_BUF_HEAP");
+500
drivers/tee/tee_heap.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (c) 2025, Linaro Limited 4 + */ 5 + 6 + #include <linux/dma-buf.h> 7 + #include <linux/dma-heap.h> 8 + #include <linux/genalloc.h> 9 + #include <linux/module.h> 10 + #include <linux/scatterlist.h> 11 + #include <linux/slab.h> 12 + #include <linux/tee_core.h> 13 + #include <linux/xarray.h> 14 + 15 + #include "tee_private.h" 16 + 17 + struct tee_dma_heap { 18 + struct dma_heap *heap; 19 + enum tee_dma_heap_id id; 20 + struct kref kref; 21 + struct tee_protmem_pool *pool; 22 + struct tee_device *teedev; 23 + bool shutting_down; 24 + /* Protects pool, teedev, and shutting_down above */ 25 + struct mutex mu; 26 + }; 27 + 28 + struct tee_heap_buffer { 29 + struct tee_dma_heap *heap; 30 + size_t size; 31 + size_t offs; 32 + struct sg_table table; 33 + }; 34 + 35 + struct tee_heap_attachment { 36 + struct sg_table table; 37 + struct device *dev; 38 + }; 39 + 40 + struct tee_protmem_static_pool { 41 + struct tee_protmem_pool pool; 42 + struct gen_pool *gen_pool; 43 + phys_addr_t pa_base; 44 + }; 45 + 46 + #if IS_ENABLED(CONFIG_TEE_DMABUF_HEAPS) 47 + static DEFINE_XARRAY_ALLOC(tee_dma_heap); 48 + 49 + static void tee_heap_release(struct kref *kref) 50 + { 51 + struct tee_dma_heap *h = container_of(kref, struct tee_dma_heap, kref); 52 + 53 + h->pool->ops->destroy_pool(h->pool); 54 + tee_device_put(h->teedev); 55 + h->pool = NULL; 56 + h->teedev = NULL; 57 + } 58 + 59 + static void put_tee_heap(struct tee_dma_heap *h) 60 + { 61 + kref_put(&h->kref, tee_heap_release); 62 + } 63 + 64 + static void get_tee_heap(struct tee_dma_heap *h) 65 + { 66 + kref_get(&h->kref); 67 + } 68 + 69 + static int copy_sg_table(struct sg_table *dst, struct sg_table *src) 70 + { 71 + struct scatterlist *dst_sg; 72 + struct scatterlist *src_sg; 73 + int ret; 74 + int i; 75 + 76 + ret = sg_alloc_table(dst, src->orig_nents, GFP_KERNEL); 77 + if (ret) 78 + return ret; 79 + 80 + dst_sg = dst->sgl; 81 + for_each_sgtable_sg(src, src_sg, i) { 82 + sg_set_page(dst_sg, sg_page(src_sg), src_sg->length, 83 + src_sg->offset); 84 + dst_sg = sg_next(dst_sg); 85 + } 86 + 87 + return 0; 88 + } 89 + 90 + static int tee_heap_attach(struct dma_buf *dmabuf, 91 + struct dma_buf_attachment *attachment) 92 + { 93 + struct tee_heap_buffer *buf = dmabuf->priv; 94 + struct tee_heap_attachment *a; 95 + int ret; 96 + 97 + a = kzalloc(sizeof(*a), GFP_KERNEL); 98 + if (!a) 99 + return -ENOMEM; 100 + 101 + ret = copy_sg_table(&a->table, &buf->table); 102 + if (ret) { 103 + kfree(a); 104 + return ret; 105 + } 106 + 107 + a->dev = attachment->dev; 108 + attachment->priv = a; 109 + 110 + return 0; 111 + } 112 + 113 + static void tee_heap_detach(struct dma_buf *dmabuf, 114 + struct dma_buf_attachment *attachment) 115 + { 116 + struct tee_heap_attachment *a = attachment->priv; 117 + 118 + sg_free_table(&a->table); 119 + kfree(a); 120 + } 121 + 122 + static struct sg_table * 123 + tee_heap_map_dma_buf(struct dma_buf_attachment *attachment, 124 + enum dma_data_direction direction) 125 + { 126 + struct tee_heap_attachment *a = attachment->priv; 127 + int ret; 128 + 129 + ret = dma_map_sgtable(attachment->dev, &a->table, direction, 130 + DMA_ATTR_SKIP_CPU_SYNC); 131 + if (ret) 132 + return ERR_PTR(ret); 133 + 134 + return &a->table; 135 + } 136 + 137 + static void tee_heap_unmap_dma_buf(struct dma_buf_attachment *attachment, 138 + struct sg_table *table, 139 + enum dma_data_direction direction) 140 + { 141 + struct tee_heap_attachment *a = attachment->priv; 142 + 143 + WARN_ON(&a->table != table); 144 + 145 + dma_unmap_sgtable(attachment->dev, table, direction, 146 + DMA_ATTR_SKIP_CPU_SYNC); 147 + } 148 + 149 + static void tee_heap_buf_free(struct dma_buf *dmabuf) 150 + { 151 + struct tee_heap_buffer *buf = dmabuf->priv; 152 + 153 + buf->heap->pool->ops->free(buf->heap->pool, &buf->table); 154 + mutex_lock(&buf->heap->mu); 155 + put_tee_heap(buf->heap); 156 + mutex_unlock(&buf->heap->mu); 157 + kfree(buf); 158 + } 159 + 160 + static const struct dma_buf_ops tee_heap_buf_ops = { 161 + .attach = tee_heap_attach, 162 + .detach = tee_heap_detach, 163 + .map_dma_buf = tee_heap_map_dma_buf, 164 + .unmap_dma_buf = tee_heap_unmap_dma_buf, 165 + .release = tee_heap_buf_free, 166 + }; 167 + 168 + static struct dma_buf *tee_dma_heap_alloc(struct dma_heap *heap, 169 + unsigned long len, u32 fd_flags, 170 + u64 heap_flags) 171 + { 172 + struct tee_dma_heap *h = dma_heap_get_drvdata(heap); 173 + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); 174 + struct tee_device *teedev = NULL; 175 + struct tee_heap_buffer *buf; 176 + struct tee_protmem_pool *pool; 177 + struct dma_buf *dmabuf; 178 + int rc; 179 + 180 + mutex_lock(&h->mu); 181 + if (h->teedev) { 182 + teedev = h->teedev; 183 + pool = h->pool; 184 + get_tee_heap(h); 185 + } 186 + mutex_unlock(&h->mu); 187 + 188 + if (!teedev) 189 + return ERR_PTR(-EINVAL); 190 + 191 + buf = kzalloc(sizeof(*buf), GFP_KERNEL); 192 + if (!buf) { 193 + dmabuf = ERR_PTR(-ENOMEM); 194 + goto err; 195 + } 196 + buf->size = len; 197 + buf->heap = h; 198 + 199 + rc = pool->ops->alloc(pool, &buf->table, len, &buf->offs); 200 + if (rc) { 201 + dmabuf = ERR_PTR(rc); 202 + goto err_kfree; 203 + } 204 + 205 + exp_info.ops = &tee_heap_buf_ops; 206 + exp_info.size = len; 207 + exp_info.priv = buf; 208 + exp_info.flags = fd_flags; 209 + dmabuf = dma_buf_export(&exp_info); 210 + if (IS_ERR(dmabuf)) 211 + goto err_protmem_free; 212 + 213 + return dmabuf; 214 + 215 + err_protmem_free: 216 + pool->ops->free(pool, &buf->table); 217 + err_kfree: 218 + kfree(buf); 219 + err: 220 + mutex_lock(&h->mu); 221 + put_tee_heap(h); 222 + mutex_unlock(&h->mu); 223 + return dmabuf; 224 + } 225 + 226 + static const struct dma_heap_ops tee_dma_heap_ops = { 227 + .allocate = tee_dma_heap_alloc, 228 + }; 229 + 230 + static const char *heap_id_2_name(enum tee_dma_heap_id id) 231 + { 232 + switch (id) { 233 + case TEE_DMA_HEAP_SECURE_VIDEO_PLAY: 234 + return "protected,secure-video"; 235 + case TEE_DMA_HEAP_TRUSTED_UI: 236 + return "protected,trusted-ui"; 237 + case TEE_DMA_HEAP_SECURE_VIDEO_RECORD: 238 + return "protected,secure-video-record"; 239 + default: 240 + return NULL; 241 + } 242 + } 243 + 244 + static int alloc_dma_heap(struct tee_device *teedev, enum tee_dma_heap_id id, 245 + struct tee_protmem_pool *pool) 246 + { 247 + struct dma_heap_export_info exp_info = { 248 + .ops = &tee_dma_heap_ops, 249 + .name = heap_id_2_name(id), 250 + }; 251 + struct tee_dma_heap *h; 252 + int rc; 253 + 254 + if (!exp_info.name) 255 + return -EINVAL; 256 + 257 + if (xa_reserve(&tee_dma_heap, id, GFP_KERNEL)) { 258 + if (!xa_load(&tee_dma_heap, id)) 259 + return -EEXIST; 260 + return -ENOMEM; 261 + } 262 + 263 + h = kzalloc(sizeof(*h), GFP_KERNEL); 264 + if (!h) 265 + return -ENOMEM; 266 + h->id = id; 267 + kref_init(&h->kref); 268 + h->teedev = teedev; 269 + h->pool = pool; 270 + mutex_init(&h->mu); 271 + 272 + exp_info.priv = h; 273 + h->heap = dma_heap_add(&exp_info); 274 + if (IS_ERR(h->heap)) { 275 + rc = PTR_ERR(h->heap); 276 + kfree(h); 277 + 278 + return rc; 279 + } 280 + 281 + /* "can't fail" due to the call to xa_reserve() above */ 282 + return WARN_ON(xa_is_err(xa_store(&tee_dma_heap, id, h, GFP_KERNEL))); 283 + } 284 + 285 + int tee_device_register_dma_heap(struct tee_device *teedev, 286 + enum tee_dma_heap_id id, 287 + struct tee_protmem_pool *pool) 288 + { 289 + struct tee_dma_heap *h; 290 + int rc; 291 + 292 + if (!tee_device_get(teedev)) 293 + return -EINVAL; 294 + 295 + h = xa_load(&tee_dma_heap, id); 296 + if (h) { 297 + mutex_lock(&h->mu); 298 + if (h->teedev) { 299 + rc = -EBUSY; 300 + } else { 301 + kref_init(&h->kref); 302 + h->shutting_down = false; 303 + h->teedev = teedev; 304 + h->pool = pool; 305 + rc = 0; 306 + } 307 + mutex_unlock(&h->mu); 308 + } else { 309 + rc = alloc_dma_heap(teedev, id, pool); 310 + } 311 + 312 + if (rc) { 313 + tee_device_put(teedev); 314 + dev_err(&teedev->dev, "can't register DMA heap id %d (%s)\n", 315 + id, heap_id_2_name(id)); 316 + } 317 + 318 + return rc; 319 + } 320 + EXPORT_SYMBOL_GPL(tee_device_register_dma_heap); 321 + 322 + void tee_device_put_all_dma_heaps(struct tee_device *teedev) 323 + { 324 + struct tee_dma_heap *h; 325 + u_long i; 326 + 327 + xa_for_each(&tee_dma_heap, i, h) { 328 + if (h) { 329 + mutex_lock(&h->mu); 330 + if (h->teedev == teedev && !h->shutting_down) { 331 + h->shutting_down = true; 332 + put_tee_heap(h); 333 + } 334 + mutex_unlock(&h->mu); 335 + } 336 + } 337 + } 338 + EXPORT_SYMBOL_GPL(tee_device_put_all_dma_heaps); 339 + 340 + int tee_heap_update_from_dma_buf(struct tee_device *teedev, 341 + struct dma_buf *dmabuf, size_t *offset, 342 + struct tee_shm *shm, 343 + struct tee_shm **parent_shm) 344 + { 345 + struct tee_heap_buffer *buf; 346 + int rc; 347 + 348 + /* The DMA-buf must be from our heap */ 349 + if (dmabuf->ops != &tee_heap_buf_ops) 350 + return -EINVAL; 351 + 352 + buf = dmabuf->priv; 353 + /* The buffer must be from the same teedev */ 354 + if (buf->heap->teedev != teedev) 355 + return -EINVAL; 356 + 357 + shm->size = buf->size; 358 + 359 + rc = buf->heap->pool->ops->update_shm(buf->heap->pool, &buf->table, 360 + buf->offs, shm, parent_shm); 361 + if (!rc && *parent_shm) 362 + *offset = buf->offs; 363 + 364 + return rc; 365 + } 366 + #else 367 + int tee_device_register_dma_heap(struct tee_device *teedev __always_unused, 368 + enum tee_dma_heap_id id __always_unused, 369 + struct tee_protmem_pool *pool __always_unused) 370 + { 371 + return -EINVAL; 372 + } 373 + EXPORT_SYMBOL_GPL(tee_device_register_dma_heap); 374 + 375 + void 376 + tee_device_put_all_dma_heaps(struct tee_device *teedev __always_unused) 377 + { 378 + } 379 + EXPORT_SYMBOL_GPL(tee_device_put_all_dma_heaps); 380 + 381 + int tee_heap_update_from_dma_buf(struct tee_device *teedev __always_unused, 382 + struct dma_buf *dmabuf __always_unused, 383 + size_t *offset __always_unused, 384 + struct tee_shm *shm __always_unused, 385 + struct tee_shm **parent_shm __always_unused) 386 + { 387 + return -EINVAL; 388 + } 389 + #endif 390 + 391 + static struct tee_protmem_static_pool * 392 + to_protmem_static_pool(struct tee_protmem_pool *pool) 393 + { 394 + return container_of(pool, struct tee_protmem_static_pool, pool); 395 + } 396 + 397 + static int protmem_pool_op_static_alloc(struct tee_protmem_pool *pool, 398 + struct sg_table *sgt, size_t size, 399 + size_t *offs) 400 + { 401 + struct tee_protmem_static_pool *stp = to_protmem_static_pool(pool); 402 + phys_addr_t pa; 403 + int ret; 404 + 405 + pa = gen_pool_alloc(stp->gen_pool, size); 406 + if (!pa) 407 + return -ENOMEM; 408 + 409 + ret = sg_alloc_table(sgt, 1, GFP_KERNEL); 410 + if (ret) { 411 + gen_pool_free(stp->gen_pool, pa, size); 412 + return ret; 413 + } 414 + 415 + sg_set_page(sgt->sgl, phys_to_page(pa), size, 0); 416 + *offs = pa - stp->pa_base; 417 + 418 + return 0; 419 + } 420 + 421 + static void protmem_pool_op_static_free(struct tee_protmem_pool *pool, 422 + struct sg_table *sgt) 423 + { 424 + struct tee_protmem_static_pool *stp = to_protmem_static_pool(pool); 425 + struct scatterlist *sg; 426 + int i; 427 + 428 + for_each_sgtable_sg(sgt, sg, i) 429 + gen_pool_free(stp->gen_pool, sg_phys(sg), sg->length); 430 + sg_free_table(sgt); 431 + } 432 + 433 + static int protmem_pool_op_static_update_shm(struct tee_protmem_pool *pool, 434 + struct sg_table *sgt, size_t offs, 435 + struct tee_shm *shm, 436 + struct tee_shm **parent_shm) 437 + { 438 + struct tee_protmem_static_pool *stp = to_protmem_static_pool(pool); 439 + 440 + shm->paddr = stp->pa_base + offs; 441 + *parent_shm = NULL; 442 + 443 + return 0; 444 + } 445 + 446 + static void protmem_pool_op_static_destroy_pool(struct tee_protmem_pool *pool) 447 + { 448 + struct tee_protmem_static_pool *stp = to_protmem_static_pool(pool); 449 + 450 + gen_pool_destroy(stp->gen_pool); 451 + kfree(stp); 452 + } 453 + 454 + static struct tee_protmem_pool_ops protmem_pool_ops_static = { 455 + .alloc = protmem_pool_op_static_alloc, 456 + .free = protmem_pool_op_static_free, 457 + .update_shm = protmem_pool_op_static_update_shm, 458 + .destroy_pool = protmem_pool_op_static_destroy_pool, 459 + }; 460 + 461 + struct tee_protmem_pool *tee_protmem_static_pool_alloc(phys_addr_t paddr, 462 + size_t size) 463 + { 464 + const size_t page_mask = PAGE_SIZE - 1; 465 + struct tee_protmem_static_pool *stp; 466 + int rc; 467 + 468 + /* Check it's page aligned */ 469 + if ((paddr | size) & page_mask) 470 + return ERR_PTR(-EINVAL); 471 + 472 + if (!pfn_valid(PHYS_PFN(paddr))) 473 + return ERR_PTR(-EINVAL); 474 + 475 + stp = kzalloc(sizeof(*stp), GFP_KERNEL); 476 + if (!stp) 477 + return ERR_PTR(-ENOMEM); 478 + 479 + stp->gen_pool = gen_pool_create(PAGE_SHIFT, -1); 480 + if (!stp->gen_pool) { 481 + rc = -ENOMEM; 482 + goto err_free; 483 + } 484 + 485 + rc = gen_pool_add(stp->gen_pool, paddr, size, -1); 486 + if (rc) 487 + goto err_free_pool; 488 + 489 + stp->pool.ops = &protmem_pool_ops_static; 490 + stp->pa_base = paddr; 491 + return &stp->pool; 492 + 493 + err_free_pool: 494 + gen_pool_destroy(stp->gen_pool); 495 + err_free: 496 + kfree(stp); 497 + 498 + return ERR_PTR(rc); 499 + } 500 + EXPORT_SYMBOL_GPL(tee_protmem_static_pool_alloc);
+14
drivers/tee/tee_private.h
··· 8 8 #include <linux/cdev.h> 9 9 #include <linux/completion.h> 10 10 #include <linux/device.h> 11 + #include <linux/dma-buf.h> 11 12 #include <linux/kref.h> 12 13 #include <linux/mutex.h> 13 14 #include <linux/types.h> 15 + 16 + /* extra references appended to shm object for registered shared memory */ 17 + struct tee_shm_dmabuf_ref { 18 + struct tee_shm shm; 19 + size_t offset; 20 + struct dma_buf *dmabuf; 21 + struct tee_shm *parent_shm; 22 + }; 14 23 15 24 int tee_shm_get_fd(struct tee_shm *shm); 16 25 ··· 32 23 struct tee_shm *tee_shm_alloc_user_buf(struct tee_context *ctx, size_t size); 33 24 struct tee_shm *tee_shm_register_user_buf(struct tee_context *ctx, 34 25 unsigned long addr, size_t length); 26 + 27 + int tee_heap_update_from_dma_buf(struct tee_device *teedev, 28 + struct dma_buf *dmabuf, size_t *offset, 29 + struct tee_shm *shm, 30 + struct tee_shm **parent_shm); 35 31 36 32 #endif /*TEE_PRIVATE_H*/
+153 -4
drivers/tee/tee_shm.c
··· 4 4 */ 5 5 #include <linux/anon_inodes.h> 6 6 #include <linux/device.h> 7 + #include <linux/dma-buf.h> 8 + #include <linux/dma-mapping.h> 9 + #include <linux/highmem.h> 7 10 #include <linux/idr.h> 8 11 #include <linux/io.h> 9 12 #include <linux/mm.h> ··· 15 12 #include <linux/tee_core.h> 16 13 #include <linux/uaccess.h> 17 14 #include <linux/uio.h> 18 - #include <linux/highmem.h> 19 15 #include "tee_private.h" 16 + 17 + struct tee_shm_dma_mem { 18 + struct tee_shm shm; 19 + dma_addr_t dma_addr; 20 + struct page *page; 21 + }; 20 22 21 23 static void shm_put_kernel_pages(struct page **pages, size_t page_count) 22 24 { ··· 53 45 54 46 static void tee_shm_release(struct tee_device *teedev, struct tee_shm *shm) 55 47 { 56 - if (shm->flags & TEE_SHM_POOL) { 48 + void *p = shm; 49 + 50 + if (shm->flags & TEE_SHM_DMA_MEM) { 51 + #if IS_ENABLED(CONFIG_TEE_DMABUF_HEAPS) 52 + struct tee_shm_dma_mem *dma_mem; 53 + 54 + dma_mem = container_of(shm, struct tee_shm_dma_mem, shm); 55 + p = dma_mem; 56 + dma_free_pages(&teedev->dev, shm->size, dma_mem->page, 57 + dma_mem->dma_addr, DMA_BIDIRECTIONAL); 58 + #endif 59 + } else if (shm->flags & TEE_SHM_DMA_BUF) { 60 + struct tee_shm_dmabuf_ref *ref; 61 + 62 + ref = container_of(shm, struct tee_shm_dmabuf_ref, shm); 63 + p = ref; 64 + dma_buf_put(ref->dmabuf); 65 + } else if (shm->flags & TEE_SHM_POOL) { 57 66 teedev->pool->ops->free(teedev->pool, shm); 58 67 } else if (shm->flags & TEE_SHM_DYNAMIC) { 59 68 int rc = teedev->desc->ops->shm_unregister(shm->ctx, shm); ··· 84 59 85 60 teedev_ctx_put(shm->ctx); 86 61 87 - kfree(shm); 62 + kfree(p); 88 63 89 64 tee_device_put(teedev); 90 65 } ··· 194 169 * tee_client_invoke_func(). The memory allocated is later freed with a 195 170 * call to tee_shm_free(). 196 171 * 197 - * @returns a pointer to 'struct tee_shm' 172 + * @returns a pointer to 'struct tee_shm' on success, and ERR_PTR on failure 198 173 */ 199 174 struct tee_shm *tee_shm_alloc_kernel_buf(struct tee_context *ctx, size_t size) 200 175 { ··· 203 178 return shm_alloc_helper(ctx, size, PAGE_SIZE, flags, -1); 204 179 } 205 180 EXPORT_SYMBOL_GPL(tee_shm_alloc_kernel_buf); 181 + 182 + struct tee_shm *tee_shm_register_fd(struct tee_context *ctx, int fd) 183 + { 184 + struct tee_shm_dmabuf_ref *ref; 185 + int rc; 186 + 187 + if (!tee_device_get(ctx->teedev)) 188 + return ERR_PTR(-EINVAL); 189 + 190 + teedev_ctx_get(ctx); 191 + 192 + ref = kzalloc(sizeof(*ref), GFP_KERNEL); 193 + if (!ref) { 194 + rc = -ENOMEM; 195 + goto err_put_tee; 196 + } 197 + 198 + refcount_set(&ref->shm.refcount, 1); 199 + ref->shm.ctx = ctx; 200 + ref->shm.id = -1; 201 + ref->shm.flags = TEE_SHM_DMA_BUF; 202 + 203 + ref->dmabuf = dma_buf_get(fd); 204 + if (IS_ERR(ref->dmabuf)) { 205 + rc = PTR_ERR(ref->dmabuf); 206 + goto err_kfree_ref; 207 + } 208 + 209 + rc = tee_heap_update_from_dma_buf(ctx->teedev, ref->dmabuf, 210 + &ref->offset, &ref->shm, 211 + &ref->parent_shm); 212 + if (rc) 213 + goto err_put_dmabuf; 214 + 215 + mutex_lock(&ref->shm.ctx->teedev->mutex); 216 + ref->shm.id = idr_alloc(&ref->shm.ctx->teedev->idr, &ref->shm, 217 + 1, 0, GFP_KERNEL); 218 + mutex_unlock(&ref->shm.ctx->teedev->mutex); 219 + if (ref->shm.id < 0) { 220 + rc = ref->shm.id; 221 + goto err_put_dmabuf; 222 + } 223 + 224 + return &ref->shm; 225 + 226 + err_put_dmabuf: 227 + dma_buf_put(ref->dmabuf); 228 + err_kfree_ref: 229 + kfree(ref); 230 + err_put_tee: 231 + teedev_ctx_put(ctx); 232 + tee_device_put(ctx->teedev); 233 + 234 + return ERR_PTR(rc); 235 + } 236 + EXPORT_SYMBOL_GPL(tee_shm_register_fd); 206 237 207 238 /** 208 239 * tee_shm_alloc_priv_buf() - Allocate shared memory for a privately shared ··· 283 202 return shm_alloc_helper(ctx, size, sizeof(long) * 2, flags, -1); 284 203 } 285 204 EXPORT_SYMBOL_GPL(tee_shm_alloc_priv_buf); 205 + 206 + #if IS_ENABLED(CONFIG_TEE_DMABUF_HEAPS) 207 + /** 208 + * tee_shm_alloc_dma_mem() - Allocate DMA memory as shared memory object 209 + * @ctx: Context that allocates the shared memory 210 + * @page_count: Number of pages 211 + * 212 + * The allocated memory is expected to be lent (made inaccessible to the 213 + * kernel) to the TEE while it's used and returned (accessible to the 214 + * kernel again) before it's freed. 215 + * 216 + * This function should normally only be used internally in the TEE 217 + * drivers. 218 + * 219 + * @returns a pointer to 'struct tee_shm' 220 + */ 221 + struct tee_shm *tee_shm_alloc_dma_mem(struct tee_context *ctx, 222 + size_t page_count) 223 + { 224 + struct tee_device *teedev = ctx->teedev; 225 + struct tee_shm_dma_mem *dma_mem; 226 + dma_addr_t dma_addr; 227 + struct page *page; 228 + 229 + if (!tee_device_get(teedev)) 230 + return ERR_PTR(-EINVAL); 231 + 232 + page = dma_alloc_pages(&teedev->dev, page_count * PAGE_SIZE, 233 + &dma_addr, DMA_BIDIRECTIONAL, GFP_KERNEL); 234 + if (!page) 235 + goto err_put_teedev; 236 + 237 + dma_mem = kzalloc(sizeof(*dma_mem), GFP_KERNEL); 238 + if (!dma_mem) 239 + goto err_free_pages; 240 + 241 + refcount_set(&dma_mem->shm.refcount, 1); 242 + dma_mem->shm.ctx = ctx; 243 + dma_mem->shm.paddr = page_to_phys(page); 244 + dma_mem->dma_addr = dma_addr; 245 + dma_mem->page = page; 246 + dma_mem->shm.size = page_count * PAGE_SIZE; 247 + dma_mem->shm.flags = TEE_SHM_DMA_MEM; 248 + 249 + teedev_ctx_get(ctx); 250 + 251 + return &dma_mem->shm; 252 + 253 + err_free_pages: 254 + dma_free_pages(&teedev->dev, page_count * PAGE_SIZE, page, dma_addr, 255 + DMA_BIDIRECTIONAL); 256 + err_put_teedev: 257 + tee_device_put(teedev); 258 + 259 + return ERR_PTR(-ENOMEM); 260 + } 261 + EXPORT_SYMBOL_GPL(tee_shm_alloc_dma_mem); 262 + #else 263 + struct tee_shm *tee_shm_alloc_dma_mem(struct tee_context *ctx, 264 + size_t page_count) 265 + { 266 + return ERR_PTR(-EINVAL); 267 + } 268 + EXPORT_SYMBOL_GPL(tee_shm_alloc_dma_mem); 269 + #endif 286 270 287 271 int tee_dyn_shm_alloc_helper(struct tee_shm *shm, size_t size, size_t align, 288 272 int (*shm_register)(struct tee_context *ctx, ··· 587 441 588 442 /* Refuse sharing shared memory provided by application */ 589 443 if (shm->flags & TEE_SHM_USER_MAPPED) 444 + return -EINVAL; 445 + /* Refuse sharing registered DMA_bufs with the application */ 446 + if (shm->flags & TEE_SHM_DMA_BUF) 590 447 return -EINVAL; 591 448 592 449 /* check for overflowing the buffer's size */
+59
include/linux/tee_core.h
··· 8 8 9 9 #include <linux/cdev.h> 10 10 #include <linux/device.h> 11 + #include <linux/dma-buf.h> 11 12 #include <linux/idr.h> 12 13 #include <linux/kref.h> 13 14 #include <linux/list.h> 15 + #include <linux/scatterlist.h> 14 16 #include <linux/tee.h> 15 17 #include <linux/tee_drv.h> 16 18 #include <linux/types.h> ··· 28 26 #define TEE_SHM_USER_MAPPED BIT(1) /* Memory mapped in user space */ 29 27 #define TEE_SHM_POOL BIT(2) /* Memory allocated from pool */ 30 28 #define TEE_SHM_PRIV BIT(3) /* Memory private to TEE driver */ 29 + #define TEE_SHM_DMA_BUF BIT(4) /* Memory with dma-buf handle */ 30 + #define TEE_SHM_DMA_MEM BIT(5) /* Memory allocated with */ 31 + /* dma_alloc_pages() */ 31 32 32 33 #define TEE_DEVICE_FLAG_REGISTERED 0x1 33 34 #define TEE_MAX_DEV_NAME_LEN 32 35 + 36 + enum tee_dma_heap_id { 37 + TEE_DMA_HEAP_SECURE_VIDEO_PLAY = 1, 38 + TEE_DMA_HEAP_TRUSTED_UI, 39 + TEE_DMA_HEAP_SECURE_VIDEO_RECORD, 40 + }; 34 41 35 42 /** 36 43 * struct tee_device - TEE Device representation ··· 128 117 }; 129 118 130 119 /** 120 + * struct tee_protmem_pool - protected memory pool 121 + * @ops: operations 122 + * 123 + * This is an abstract interface where this struct is expected to be 124 + * embedded in another struct specific to the implementation. 125 + */ 126 + struct tee_protmem_pool { 127 + const struct tee_protmem_pool_ops *ops; 128 + }; 129 + 130 + /** 131 + * struct tee_protmem_pool_ops - protected memory pool operations 132 + * @alloc: called when allocating protected memory 133 + * @free: called when freeing protected memory 134 + * @update_shm: called when registering a dma-buf to update the @shm 135 + * with physical address of the buffer or to return the 136 + * @parent_shm of the memory pool 137 + * @destroy_pool: called when destroying the pool 138 + */ 139 + struct tee_protmem_pool_ops { 140 + int (*alloc)(struct tee_protmem_pool *pool, struct sg_table *sgt, 141 + size_t size, size_t *offs); 142 + void (*free)(struct tee_protmem_pool *pool, struct sg_table *sgt); 143 + int (*update_shm)(struct tee_protmem_pool *pool, struct sg_table *sgt, 144 + size_t offs, struct tee_shm *shm, 145 + struct tee_shm **parent_shm); 146 + void (*destroy_pool)(struct tee_protmem_pool *pool); 147 + }; 148 + 149 + /** 131 150 * tee_device_alloc() - Allocate a new struct tee_device instance 132 151 * @teedesc: Descriptor for this driver 133 152 * @dev: Parent device for this device ··· 194 153 * @teedev is NULL. 195 154 */ 196 155 void tee_device_unregister(struct tee_device *teedev); 156 + 157 + int tee_device_register_dma_heap(struct tee_device *teedev, 158 + enum tee_dma_heap_id id, 159 + struct tee_protmem_pool *pool); 160 + void tee_device_put_all_dma_heaps(struct tee_device *teedev); 197 161 198 162 /** 199 163 * tee_device_set_dev_groups() - Set device attribute groups ··· 276 230 } 277 231 278 232 /** 233 + * tee_protmem_static_pool_alloc() - Create a protected memory manager 234 + * @paddr: Physical address of start of pool 235 + * @size: Size in bytes of the pool 236 + * 237 + * @returns pointer to a 'struct tee_protmem_pool' or an ERR_PTR on failure. 238 + */ 239 + struct tee_protmem_pool *tee_protmem_static_pool_alloc(phys_addr_t paddr, 240 + size_t size); 241 + 242 + /** 279 243 * tee_get_drvdata() - Return driver_data pointer 280 244 * @returns the driver_data pointer supplied to tee_register(). 281 245 */ ··· 299 243 * @returns a pointer to 'struct tee_shm' on success or an ERR_PTR on failure 300 244 */ 301 245 struct tee_shm *tee_shm_alloc_priv_buf(struct tee_context *ctx, size_t size); 246 + 247 + struct tee_shm *tee_shm_alloc_dma_mem(struct tee_context *ctx, 248 + size_t page_count); 302 249 303 250 int tee_dyn_shm_alloc_helper(struct tee_shm *shm, size_t size, size_t align, 304 251 int (*shm_register)(struct tee_context *ctx,
+10
include/linux/tee_drv.h
··· 117 117 void *addr, size_t length); 118 118 119 119 /** 120 + * tee_shm_register_fd() - Register shared memory from file descriptor 121 + * 122 + * @ctx: Context that allocates the shared memory 123 + * @fd: Shared memory file descriptor reference 124 + * 125 + * @returns a pointer to 'struct tee_shm' on success, and ERR_PTR on failure 126 + */ 127 + struct tee_shm *tee_shm_register_fd(struct tee_context *ctx, int fd); 128 + 129 + /** 120 130 * tee_shm_free() - Free shared memory 121 131 * @shm: Handle to shared memory to free 122 132 */
+31
include/uapi/linux/tee.h
··· 379 379 }; 380 380 381 381 /** 382 + * struct tee_ioctl_shm_register_fd_data - Shared memory registering argument 383 + * @fd: [in] File descriptor identifying dmabuf reference 384 + * @size: [out] Size of referenced memory 385 + * @flags: [in] Flags to/from allocation. 386 + * @id: [out] Identifier of the shared memory 387 + * 388 + * The flags field should currently be zero as input. Updated by the call 389 + * with actual flags as defined by TEE_IOCTL_SHM_* above. 390 + * This structure is used as argument for TEE_IOC_SHM_REGISTER_FD below. 391 + */ 392 + struct tee_ioctl_shm_register_fd_data { 393 + __s64 fd; 394 + __u64 size; 395 + __u32 flags; 396 + __s32 id; 397 + }; 398 + 399 + /** 400 + * TEE_IOC_SHM_REGISTER_FD - register a shared memory from a file descriptor 401 + * 402 + * Returns a file descriptor on success or < 0 on failure 403 + * 404 + * The returned file descriptor refers to the shared memory object in the 405 + * kernel. The supplied file deccriptor can be closed if it's not needed 406 + * for other purposes. The shared memory is freed when the descriptor is 407 + * closed. 408 + */ 409 + #define TEE_IOC_SHM_REGISTER_FD _IOWR(TEE_IOC_MAGIC, TEE_IOC_BASE + 8, \ 410 + struct tee_ioctl_shm_register_fd_data) 411 + 412 + /** 382 413 * TEE_IOC_SHM_REGISTER - Register shared memory argument 383 414 * 384 415 * Registers shared memory between the user space process and secure OS.