diff options
Diffstat (limited to 'drivers/tee/optee/optee_private.h')
| -rw-r--r-- | drivers/tee/optee/optee_private.h | 160 |
1 files changed, 131 insertions, 29 deletions
diff --git a/drivers/tee/optee/optee_private.h b/drivers/tee/optee/optee_private.h index 46f74ab07c7e..db9ea673fbca 100644 --- a/drivers/tee/optee/optee_private.h +++ b/drivers/tee/optee/optee_private.h @@ -1,15 +1,17 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2015-2021, Linaro Limited + * Copyright (c) 2015-2021, 2023 Linaro Limited */ #ifndef OPTEE_PRIVATE_H #define OPTEE_PRIVATE_H #include <linux/arm-smccc.h> +#include <linux/notifier.h> #include <linux/rhashtable.h> +#include <linux/rpmb.h> #include <linux/semaphore.h> -#include <linux/tee_drv.h> +#include <linux/tee_core.h> #include <linux/types.h> #include "optee_msg.h" @@ -20,12 +22,17 @@ /* Some Global Platform error codes used in this driver */ #define TEEC_SUCCESS 0x00000000 #define TEEC_ERROR_BAD_PARAMETERS 0xFFFF0006 +#define TEEC_ERROR_ITEM_NOT_FOUND 0xFFFF0008 #define TEEC_ERROR_NOT_SUPPORTED 0xFFFF000A #define TEEC_ERROR_COMMUNICATION 0xFFFF000E #define TEEC_ERROR_OUT_OF_MEMORY 0xFFFF000C #define TEEC_ERROR_BUSY 0xFFFF000D #define TEEC_ERROR_SHORT_BUFFER 0xFFFF0010 +/* API Return Codes are from the GP TEE Internal Core API Specification */ +#define TEE_ERROR_TIMEOUT 0xFFFF3001 +#define TEE_ERROR_STORAGE_NOT_AVAILABLE 0xF0100003 + #define TEEC_ORIGIN_COMMS 0x00000002 /* @@ -40,26 +47,53 @@ typedef void (optee_invoke_fn)(unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, struct arm_smccc_res *); +/* + * struct optee_call_waiter - TEE entry may need to wait for a free TEE thread + * @list_node Reference in waiters list + * @c Waiting completion reference + * @sys_thread True if waiter belongs to a system thread + */ struct optee_call_waiter { struct list_head list_node; struct completion c; + bool sys_thread; }; +/* + * struct optee_call_queue - OP-TEE call queue management + * @mutex Serializes access to this struct + * @waiters List of threads waiting to enter OP-TEE + * @total_thread_count Overall number of thread context in OP-TEE or 0 + * @free_thread_count Number of threads context free in OP-TEE + * @sys_thread_req_count Number of registered system thread sessions + */ struct optee_call_queue { /* Serializes access to this struct */ struct mutex mutex; struct list_head waiters; + int total_thread_count; + int free_thread_count; + int sys_thread_req_count; }; struct optee_notif { u_int max_key; - struct tee_context *ctx; /* Serializes access to the elements below in this struct */ spinlock_t lock; struct list_head db; u_long *bitmap; }; +#define OPTEE_SHM_ARG_ALLOC_PRIV BIT(0) +#define OPTEE_SHM_ARG_SHARED BIT(1) +struct optee_shm_arg_entry; +struct optee_shm_arg_cache { + u32 flags; + /* Serializes access to this struct */ + struct mutex mutex; + struct list_head shm_args; +}; + /** * struct optee_supp - supplicant synchronization struct * @ctx the context of current connected supplicant. @@ -85,27 +119,54 @@ struct optee_supp { struct completion reqs_c; }; +/* + * struct optee_pcpu - per cpu notif private struct passed to work functions + * @optee optee device reference + */ +struct optee_pcpu { + struct optee *optee; +}; + +/* + * struct optee_smc - optee smc communication struct + * @invoke_fn handler function to invoke secure monitor + * @memremaped_shm virtual address of memory in shared memory pool + * @sec_caps: secure world capabilities defined by + * OPTEE_SMC_SEC_CAP_* in optee_smc.h + * @notif_irq interrupt used as async notification by OP-TEE or 0 + * @optee_pcpu per_cpu optee instance for per cpu work or NULL + * @notif_pcpu_wq workqueue for per cpu asynchronous notification or NULL + * @notif_pcpu_work work for per cpu asynchronous notification + * @notif_cpuhp_state CPU hotplug state assigned for pcpu interrupt management + */ struct optee_smc { optee_invoke_fn *invoke_fn; void *memremaped_shm; u32 sec_caps; unsigned int notif_irq; + struct optee_pcpu __percpu *optee_pcpu; + struct workqueue_struct *notif_pcpu_wq; + struct work_struct notif_pcpu_work; + unsigned int notif_cpuhp_state; }; /** * struct optee_ffa_data - FFA communication struct * @ffa_dev FFA device, contains the destination id, the id of * OP-TEE in secure world - * @ffa_ops FFA operations + * @bottom_half_value Notification ID used for bottom half signalling or + * U32_MAX if unused * @mutex Serializes access to @global_ids * @global_ids FF-A shared memory global handle translation */ struct optee_ffa { struct ffa_device *ffa_dev; - const struct ffa_dev_ops *ffa_ops; + u32 bottom_half_value; /* Serializes access to @global_ids */ struct mutex mutex; struct rhashtable global_ids; + struct workqueue_struct *notif_wq; + struct work_struct notif_work; }; struct optee; @@ -115,60 +176,85 @@ struct optee; * @do_call_with_arg: enters OP-TEE in secure world * @to_msg_param: converts from struct tee_param to OPTEE_MSG parameters * @from_msg_param: converts from OPTEE_MSG parameters to struct tee_param + * @lend_protmem: lends physically contiguous memory as restricted + * memory, inaccessible by the kernel + * @reclaim_protmem: reclaims restricted memory previously lent with + * @lend_protmem() and makes it accessible by the + * kernel again * * These OPs are only supposed to be used internally in the OP-TEE driver - * as a way of abstracting the different methogs of entering OP-TEE in + * as a way of abstracting the different methods of entering OP-TEE in * secure world. */ struct optee_ops { int (*do_call_with_arg)(struct tee_context *ctx, - struct tee_shm *shm_arg); + struct tee_shm *shm_arg, u_int offs, + bool system_thread); int (*to_msg_param)(struct optee *optee, struct optee_msg_param *msg_params, size_t num_params, const struct tee_param *params); int (*from_msg_param)(struct optee *optee, struct tee_param *params, size_t num_params, const struct optee_msg_param *msg_params); + int (*lend_protmem)(struct optee *optee, struct tee_shm *protmem, + u32 *mem_attr, unsigned int ma_count, + u32 use_case); + int (*reclaim_protmem)(struct optee *optee, struct tee_shm *protmem); }; /** * struct optee - main service struct * @supp_teedev: supplicant device + * @teedev: client device * @ops: internal callbacks for different ways to reach secure * world - * @teedev: client device + * @ctx: driver internal TEE context * @smc: specific to SMC ABI * @ffa: specific to FF-A ABI * @call_queue: queue of threads waiting to call @invoke_fn * @notif: notification synchronization struct * @supp: supplicant synchronization struct for RPC to supplicant * @pool: shared memory pool - * @rpc_arg_count: If > 0 number of RPC parameters to make room for + * @mutex: mutex protecting @rpmb_dev + * @rpmb_dev: current RPMB device or NULL + * @rpmb_scan_bus_done flag if device registation of RPMB dependent devices + * was already done + * @rpmb_scan_bus_work workq to for an RPMB device and to scan optee bus + * and register RPMB dependent optee drivers + * @rpc_param_count: If > 0 number of RPC parameters to make room for * @scan_bus_done flag if device registation was already done. - * @scan_bus_wq workqueue to scan optee bus and register optee drivers * @scan_bus_work workq to scan optee bus and register optee drivers */ struct optee { struct tee_device *supp_teedev; struct tee_device *teedev; const struct optee_ops *ops; + struct tee_context *ctx; union { struct optee_smc smc; struct optee_ffa ffa; }; + struct optee_shm_arg_cache shm_arg_cache; struct optee_call_queue call_queue; struct optee_notif notif; struct optee_supp supp; struct tee_shm_pool *pool; - unsigned int rpc_arg_count; - bool scan_bus_done; - struct workqueue_struct *scan_bus_wq; + /* Protects rpmb_dev pointer */ + struct mutex rpmb_dev_mutex; + struct rpmb_dev *rpmb_dev; + struct notifier_block rpmb_intf; + unsigned int rpc_param_count; + bool scan_bus_done; + bool rpmb_scan_bus_done; + bool in_kernel_rpmb_routing; struct work_struct scan_bus_work; + struct work_struct rpmb_scan_bus_work; }; struct optee_session { struct list_head list_node; u32 session_id; + bool use_sys_thread; }; struct optee_context_data { @@ -195,19 +281,23 @@ struct optee_call_ctx { size_t num_entries; }; +extern struct blocking_notifier_head optee_rpmb_intf_added; + +int optee_set_dma_mask(struct optee *optee, u_int pa_width); + int optee_notif_init(struct optee *optee, u_int max_key); void optee_notif_uninit(struct optee *optee); -int optee_notif_wait(struct optee *optee, u_int key); +int optee_notif_wait(struct optee *optee, u_int key, u32 timeout); int optee_notif_send(struct optee *optee, u_int key); u32 optee_supp_thrd_req(struct tee_context *ctx, u32 func, size_t num_params, struct tee_param *param); -int optee_supp_read(struct tee_context *ctx, void __user *buf, size_t len); -int optee_supp_write(struct tee_context *ctx, void __user *buf, size_t len); void optee_supp_init(struct optee_supp *supp); void optee_supp_uninit(struct optee_supp *supp); void optee_supp_release(struct optee_supp *supp); +struct tee_protmem_pool *optee_protmem_alloc_dyn_pool(struct optee *optee, + enum tee_dma_heap_id id); int optee_supp_recv(struct tee_context *ctx, u32 *func, u32 *num_params, struct tee_param *param); @@ -217,7 +307,9 @@ int optee_supp_send(struct tee_context *ctx, u32 ret, u32 num_params, int optee_open_session(struct tee_context *ctx, struct tee_ioctl_open_session_arg *arg, struct tee_param *param); -int optee_close_session_helper(struct tee_context *ctx, u32 session); +int optee_system_session(struct tee_context *ctx, u32 session); +int optee_close_session_helper(struct tee_context *ctx, u32 session, + bool system_thread); int optee_close_session(struct tee_context *ctx, u32 session); int optee_invoke_func(struct tee_context *ctx, struct tee_ioctl_invoke_arg *arg, struct tee_param *param); @@ -225,18 +317,14 @@ int optee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session); #define PTA_CMD_GET_DEVICES 0x0 #define PTA_CMD_GET_DEVICES_SUPP 0x1 +#define PTA_CMD_GET_DEVICES_RPMB 0x2 int optee_enumerate_devices(u32 func); void optee_unregister_devices(void); +void optee_bus_scan_rpmb(struct work_struct *work); +int optee_rpmb_intf_rdev(struct notifier_block *intf, unsigned long action, + void *data); -int optee_pool_op_alloc_helper(struct tee_shm_pool_mgr *poolm, - struct tee_shm *shm, size_t size, - int (*shm_register)(struct tee_context *ctx, - struct tee_shm *shm, - struct page **pages, - size_t num_pages, - unsigned long start)); - - +void optee_set_dev_group(struct optee *optee); void optee_remove_common(struct optee *optee); int optee_open(struct tee_context *ctx, bool cap_memref_null); void optee_release(struct tee_context *ctx); @@ -262,21 +350,35 @@ static inline void optee_to_msg_param_value(struct optee_msg_param *mp, mp->u.value.c = p->u.value.c; } +void optee_cq_init(struct optee_call_queue *cq, int thread_count); void optee_cq_wait_init(struct optee_call_queue *cq, - struct optee_call_waiter *w); + struct optee_call_waiter *w, bool sys_thread); void optee_cq_wait_for_completion(struct optee_call_queue *cq, struct optee_call_waiter *w); void optee_cq_wait_final(struct optee_call_queue *cq, struct optee_call_waiter *w); int optee_check_mem_type(unsigned long start, size_t num_pages); -struct tee_shm *optee_get_msg_arg(struct tee_context *ctx, size_t num_params, - struct optee_msg_arg **msg_arg); + +void optee_shm_arg_cache_init(struct optee *optee, u32 flags); +void optee_shm_arg_cache_uninit(struct optee *optee); +struct optee_msg_arg *optee_get_msg_arg(struct tee_context *ctx, + size_t num_params, + struct optee_shm_arg_entry **entry, + struct tee_shm **shm_ret, + u_int *offs); +void optee_free_msg_arg(struct tee_context *ctx, + struct optee_shm_arg_entry *entry, u_int offs); +size_t optee_msg_arg_size(size_t rpc_param_count); + struct tee_shm *optee_rpc_cmd_alloc_suppl(struct tee_context *ctx, size_t sz); void optee_rpc_cmd_free_suppl(struct tee_context *ctx, struct tee_shm *shm); void optee_rpc_cmd(struct tee_context *ctx, struct optee *optee, struct optee_msg_arg *arg); +int optee_do_bottom_half(struct tee_context *ctx); +int optee_stop_async_notif(struct tee_context *ctx); + /* * Small helpers */ |
