18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: MIT 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2019 Advanced Micro Devices, Inc. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/errno.h> 78c2ecf20Sopenharmony_ci#include <linux/io.h> 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/slab.h> 108c2ecf20Sopenharmony_ci#include <linux/string.h> 118c2ecf20Sopenharmony_ci#include <linux/device.h> 128c2ecf20Sopenharmony_ci#include <linux/tee_drv.h> 138c2ecf20Sopenharmony_ci#include <linux/types.h> 148c2ecf20Sopenharmony_ci#include <linux/mm.h> 158c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 168c2ecf20Sopenharmony_ci#include <linux/firmware.h> 178c2ecf20Sopenharmony_ci#include "amdtee_private.h" 188c2ecf20Sopenharmony_ci#include "../tee_private.h" 198c2ecf20Sopenharmony_ci#include <linux/psp-tee.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic struct amdtee_driver_data *drv_data; 228c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(session_list_mutex); 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic void amdtee_get_version(struct tee_device *teedev, 258c2ecf20Sopenharmony_ci struct tee_ioctl_version_data *vers) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci struct tee_ioctl_version_data v = { 288c2ecf20Sopenharmony_ci .impl_id = TEE_IMPL_ID_AMDTEE, 298c2ecf20Sopenharmony_ci .impl_caps = 0, 308c2ecf20Sopenharmony_ci .gen_caps = TEE_GEN_CAP_GP, 318c2ecf20Sopenharmony_ci }; 328c2ecf20Sopenharmony_ci *vers = v; 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic int amdtee_open(struct tee_context *ctx) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci struct amdtee_context_data *ctxdata; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci ctxdata = kzalloc(sizeof(*ctxdata), GFP_KERNEL); 408c2ecf20Sopenharmony_ci if (!ctxdata) 418c2ecf20Sopenharmony_ci return -ENOMEM; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ctxdata->sess_list); 448c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ctxdata->shm_list); 458c2ecf20Sopenharmony_ci mutex_init(&ctxdata->shm_mutex); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci ctx->data = ctxdata; 488c2ecf20Sopenharmony_ci return 0; 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic void release_session(struct amdtee_session *sess) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci int i; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci /* Close any open session */ 568c2ecf20Sopenharmony_ci for (i = 0; i < TEE_NUM_SESSIONS; ++i) { 578c2ecf20Sopenharmony_ci /* Check if session entry 'i' is valid */ 588c2ecf20Sopenharmony_ci if (!test_bit(i, sess->sess_mask)) 598c2ecf20Sopenharmony_ci continue; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci handle_close_session(sess->ta_handle, sess->session_info[i]); 628c2ecf20Sopenharmony_ci handle_unload_ta(sess->ta_handle); 638c2ecf20Sopenharmony_ci } 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci kfree(sess); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic void amdtee_release(struct tee_context *ctx) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci struct amdtee_context_data *ctxdata = ctx->data; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (!ctxdata) 738c2ecf20Sopenharmony_ci return; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci while (true) { 768c2ecf20Sopenharmony_ci struct amdtee_session *sess; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci sess = list_first_entry_or_null(&ctxdata->sess_list, 798c2ecf20Sopenharmony_ci struct amdtee_session, 808c2ecf20Sopenharmony_ci list_node); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (!sess) 838c2ecf20Sopenharmony_ci break; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci list_del(&sess->list_node); 868c2ecf20Sopenharmony_ci release_session(sess); 878c2ecf20Sopenharmony_ci } 888c2ecf20Sopenharmony_ci mutex_destroy(&ctxdata->shm_mutex); 898c2ecf20Sopenharmony_ci kfree(ctxdata); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci ctx->data = NULL; 928c2ecf20Sopenharmony_ci} 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci/** 958c2ecf20Sopenharmony_ci * alloc_session() - Allocate a session structure 968c2ecf20Sopenharmony_ci * @ctxdata: TEE Context data structure 978c2ecf20Sopenharmony_ci * @session: Session ID for which 'struct amdtee_session' structure is to be 988c2ecf20Sopenharmony_ci * allocated. 998c2ecf20Sopenharmony_ci * 1008c2ecf20Sopenharmony_ci * Scans the TEE context's session list to check if TA is already loaded in to 1018c2ecf20Sopenharmony_ci * TEE. If yes, returns the 'session' structure for that TA. Else allocates, 1028c2ecf20Sopenharmony_ci * initializes a new 'session' structure and adds it to context's session list. 1038c2ecf20Sopenharmony_ci * 1048c2ecf20Sopenharmony_ci * The caller must hold a mutex. 1058c2ecf20Sopenharmony_ci * 1068c2ecf20Sopenharmony_ci * Returns: 1078c2ecf20Sopenharmony_ci * 'struct amdtee_session *' on success and NULL on failure. 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_cistatic struct amdtee_session *alloc_session(struct amdtee_context_data *ctxdata, 1108c2ecf20Sopenharmony_ci u32 session) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci struct amdtee_session *sess; 1138c2ecf20Sopenharmony_ci u32 ta_handle = get_ta_handle(session); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci /* Scan session list to check if TA is already loaded in to TEE */ 1168c2ecf20Sopenharmony_ci list_for_each_entry(sess, &ctxdata->sess_list, list_node) 1178c2ecf20Sopenharmony_ci if (sess->ta_handle == ta_handle) { 1188c2ecf20Sopenharmony_ci kref_get(&sess->refcount); 1198c2ecf20Sopenharmony_ci return sess; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* Allocate a new session and add to list */ 1238c2ecf20Sopenharmony_ci sess = kzalloc(sizeof(*sess), GFP_KERNEL); 1248c2ecf20Sopenharmony_ci if (sess) { 1258c2ecf20Sopenharmony_ci sess->ta_handle = ta_handle; 1268c2ecf20Sopenharmony_ci kref_init(&sess->refcount); 1278c2ecf20Sopenharmony_ci spin_lock_init(&sess->lock); 1288c2ecf20Sopenharmony_ci list_add(&sess->list_node, &ctxdata->sess_list); 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci return sess; 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci/* Requires mutex to be held */ 1358c2ecf20Sopenharmony_cistatic struct amdtee_session *find_session(struct amdtee_context_data *ctxdata, 1368c2ecf20Sopenharmony_ci u32 session) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci u32 ta_handle = get_ta_handle(session); 1398c2ecf20Sopenharmony_ci u32 index = get_session_index(session); 1408c2ecf20Sopenharmony_ci struct amdtee_session *sess; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci if (index >= TEE_NUM_SESSIONS) 1438c2ecf20Sopenharmony_ci return NULL; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci list_for_each_entry(sess, &ctxdata->sess_list, list_node) 1468c2ecf20Sopenharmony_ci if (ta_handle == sess->ta_handle && 1478c2ecf20Sopenharmony_ci test_bit(index, sess->sess_mask)) 1488c2ecf20Sopenharmony_ci return sess; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci return NULL; 1518c2ecf20Sopenharmony_ci} 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ciu32 get_buffer_id(struct tee_shm *shm) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci struct amdtee_context_data *ctxdata = shm->ctx->data; 1568c2ecf20Sopenharmony_ci struct amdtee_shm_data *shmdata; 1578c2ecf20Sopenharmony_ci u32 buf_id = 0; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci mutex_lock(&ctxdata->shm_mutex); 1608c2ecf20Sopenharmony_ci list_for_each_entry(shmdata, &ctxdata->shm_list, shm_node) 1618c2ecf20Sopenharmony_ci if (shmdata->kaddr == shm->kaddr) { 1628c2ecf20Sopenharmony_ci buf_id = shmdata->buf_id; 1638c2ecf20Sopenharmony_ci break; 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci mutex_unlock(&ctxdata->shm_mutex); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci return buf_id; 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(drv_mutex); 1718c2ecf20Sopenharmony_cistatic int copy_ta_binary(struct tee_context *ctx, void *ptr, void **ta, 1728c2ecf20Sopenharmony_ci size_t *ta_size) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci const struct firmware *fw; 1758c2ecf20Sopenharmony_ci char fw_name[TA_PATH_MAX]; 1768c2ecf20Sopenharmony_ci struct { 1778c2ecf20Sopenharmony_ci u32 lo; 1788c2ecf20Sopenharmony_ci u16 mid; 1798c2ecf20Sopenharmony_ci u16 hi_ver; 1808c2ecf20Sopenharmony_ci u8 seq_n[8]; 1818c2ecf20Sopenharmony_ci } *uuid = ptr; 1828c2ecf20Sopenharmony_ci int n, rc = 0; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci n = snprintf(fw_name, TA_PATH_MAX, 1858c2ecf20Sopenharmony_ci "%s/%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x.bin", 1868c2ecf20Sopenharmony_ci TA_LOAD_PATH, uuid->lo, uuid->mid, uuid->hi_ver, 1878c2ecf20Sopenharmony_ci uuid->seq_n[0], uuid->seq_n[1], 1888c2ecf20Sopenharmony_ci uuid->seq_n[2], uuid->seq_n[3], 1898c2ecf20Sopenharmony_ci uuid->seq_n[4], uuid->seq_n[5], 1908c2ecf20Sopenharmony_ci uuid->seq_n[6], uuid->seq_n[7]); 1918c2ecf20Sopenharmony_ci if (n < 0 || n >= TA_PATH_MAX) { 1928c2ecf20Sopenharmony_ci pr_err("failed to get firmware name\n"); 1938c2ecf20Sopenharmony_ci return -EINVAL; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci mutex_lock(&drv_mutex); 1978c2ecf20Sopenharmony_ci n = request_firmware(&fw, fw_name, &ctx->teedev->dev); 1988c2ecf20Sopenharmony_ci if (n) { 1998c2ecf20Sopenharmony_ci pr_err("failed to load firmware %s\n", fw_name); 2008c2ecf20Sopenharmony_ci rc = -ENOMEM; 2018c2ecf20Sopenharmony_ci goto unlock; 2028c2ecf20Sopenharmony_ci } 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci *ta_size = roundup(fw->size, PAGE_SIZE); 2058c2ecf20Sopenharmony_ci *ta = (void *)__get_free_pages(GFP_KERNEL, get_order(*ta_size)); 2068c2ecf20Sopenharmony_ci if (!*ta) { 2078c2ecf20Sopenharmony_ci pr_err("%s: get_free_pages failed\n", __func__); 2088c2ecf20Sopenharmony_ci rc = -ENOMEM; 2098c2ecf20Sopenharmony_ci goto rel_fw; 2108c2ecf20Sopenharmony_ci } 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci memcpy(*ta, fw->data, fw->size); 2138c2ecf20Sopenharmony_cirel_fw: 2148c2ecf20Sopenharmony_ci release_firmware(fw); 2158c2ecf20Sopenharmony_ciunlock: 2168c2ecf20Sopenharmony_ci mutex_unlock(&drv_mutex); 2178c2ecf20Sopenharmony_ci return rc; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci/* mutex must be held by caller */ 2218c2ecf20Sopenharmony_cistatic void destroy_session(struct kref *ref) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct amdtee_session *sess = container_of(ref, struct amdtee_session, 2248c2ecf20Sopenharmony_ci refcount); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci list_del(&sess->list_node); 2278c2ecf20Sopenharmony_ci mutex_unlock(&session_list_mutex); 2288c2ecf20Sopenharmony_ci kfree(sess); 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ciint amdtee_open_session(struct tee_context *ctx, 2328c2ecf20Sopenharmony_ci struct tee_ioctl_open_session_arg *arg, 2338c2ecf20Sopenharmony_ci struct tee_param *param) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci struct amdtee_context_data *ctxdata = ctx->data; 2368c2ecf20Sopenharmony_ci struct amdtee_session *sess = NULL; 2378c2ecf20Sopenharmony_ci u32 session_info, ta_handle; 2388c2ecf20Sopenharmony_ci size_t ta_size; 2398c2ecf20Sopenharmony_ci int rc, i; 2408c2ecf20Sopenharmony_ci void *ta; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (arg->clnt_login != TEE_IOCTL_LOGIN_PUBLIC) { 2438c2ecf20Sopenharmony_ci pr_err("unsupported client login method\n"); 2448c2ecf20Sopenharmony_ci return -EINVAL; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci rc = copy_ta_binary(ctx, &arg->uuid[0], &ta, &ta_size); 2488c2ecf20Sopenharmony_ci if (rc) { 2498c2ecf20Sopenharmony_ci pr_err("failed to copy TA binary\n"); 2508c2ecf20Sopenharmony_ci return rc; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* Load the TA binary into TEE environment */ 2548c2ecf20Sopenharmony_ci handle_load_ta(ta, ta_size, arg); 2558c2ecf20Sopenharmony_ci if (arg->ret != TEEC_SUCCESS) 2568c2ecf20Sopenharmony_ci goto out; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci ta_handle = get_ta_handle(arg->session); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci mutex_lock(&session_list_mutex); 2618c2ecf20Sopenharmony_ci sess = alloc_session(ctxdata, arg->session); 2628c2ecf20Sopenharmony_ci mutex_unlock(&session_list_mutex); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (!sess) { 2658c2ecf20Sopenharmony_ci handle_unload_ta(ta_handle); 2668c2ecf20Sopenharmony_ci rc = -ENOMEM; 2678c2ecf20Sopenharmony_ci goto out; 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci /* Open session with loaded TA */ 2718c2ecf20Sopenharmony_ci handle_open_session(arg, &session_info, param); 2728c2ecf20Sopenharmony_ci if (arg->ret != TEEC_SUCCESS) { 2738c2ecf20Sopenharmony_ci pr_err("open_session failed %d\n", arg->ret); 2748c2ecf20Sopenharmony_ci handle_unload_ta(ta_handle); 2758c2ecf20Sopenharmony_ci kref_put_mutex(&sess->refcount, destroy_session, 2768c2ecf20Sopenharmony_ci &session_list_mutex); 2778c2ecf20Sopenharmony_ci goto out; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci /* Find an empty session index for the given TA */ 2818c2ecf20Sopenharmony_ci spin_lock(&sess->lock); 2828c2ecf20Sopenharmony_ci i = find_first_zero_bit(sess->sess_mask, TEE_NUM_SESSIONS); 2838c2ecf20Sopenharmony_ci if (i < TEE_NUM_SESSIONS) { 2848c2ecf20Sopenharmony_ci sess->session_info[i] = session_info; 2858c2ecf20Sopenharmony_ci set_session_id(ta_handle, i, &arg->session); 2868c2ecf20Sopenharmony_ci set_bit(i, sess->sess_mask); 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci spin_unlock(&sess->lock); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (i >= TEE_NUM_SESSIONS) { 2918c2ecf20Sopenharmony_ci pr_err("reached maximum session count %d\n", TEE_NUM_SESSIONS); 2928c2ecf20Sopenharmony_ci handle_close_session(ta_handle, session_info); 2938c2ecf20Sopenharmony_ci handle_unload_ta(ta_handle); 2948c2ecf20Sopenharmony_ci kref_put_mutex(&sess->refcount, destroy_session, 2958c2ecf20Sopenharmony_ci &session_list_mutex); 2968c2ecf20Sopenharmony_ci rc = -ENOMEM; 2978c2ecf20Sopenharmony_ci goto out; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ciout: 3018c2ecf20Sopenharmony_ci free_pages((u64)ta, get_order(ta_size)); 3028c2ecf20Sopenharmony_ci return rc; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ciint amdtee_close_session(struct tee_context *ctx, u32 session) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci struct amdtee_context_data *ctxdata = ctx->data; 3088c2ecf20Sopenharmony_ci u32 i, ta_handle, session_info; 3098c2ecf20Sopenharmony_ci struct amdtee_session *sess; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci pr_debug("%s: sid = 0x%x\n", __func__, session); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* 3148c2ecf20Sopenharmony_ci * Check that the session is valid and clear the session 3158c2ecf20Sopenharmony_ci * usage bit 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_ci mutex_lock(&session_list_mutex); 3188c2ecf20Sopenharmony_ci sess = find_session(ctxdata, session); 3198c2ecf20Sopenharmony_ci if (sess) { 3208c2ecf20Sopenharmony_ci ta_handle = get_ta_handle(session); 3218c2ecf20Sopenharmony_ci i = get_session_index(session); 3228c2ecf20Sopenharmony_ci session_info = sess->session_info[i]; 3238c2ecf20Sopenharmony_ci spin_lock(&sess->lock); 3248c2ecf20Sopenharmony_ci clear_bit(i, sess->sess_mask); 3258c2ecf20Sopenharmony_ci spin_unlock(&sess->lock); 3268c2ecf20Sopenharmony_ci } 3278c2ecf20Sopenharmony_ci mutex_unlock(&session_list_mutex); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (!sess) 3308c2ecf20Sopenharmony_ci return -EINVAL; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* Close the session */ 3338c2ecf20Sopenharmony_ci handle_close_session(ta_handle, session_info); 3348c2ecf20Sopenharmony_ci handle_unload_ta(ta_handle); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci kref_put_mutex(&sess->refcount, destroy_session, &session_list_mutex); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci return 0; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ciint amdtee_map_shmem(struct tee_shm *shm) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci struct amdtee_context_data *ctxdata; 3448c2ecf20Sopenharmony_ci struct amdtee_shm_data *shmnode; 3458c2ecf20Sopenharmony_ci struct shmem_desc shmem; 3468c2ecf20Sopenharmony_ci int rc, count; 3478c2ecf20Sopenharmony_ci u32 buf_id; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (!shm) 3508c2ecf20Sopenharmony_ci return -EINVAL; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci shmnode = kmalloc(sizeof(*shmnode), GFP_KERNEL); 3538c2ecf20Sopenharmony_ci if (!shmnode) 3548c2ecf20Sopenharmony_ci return -ENOMEM; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci count = 1; 3578c2ecf20Sopenharmony_ci shmem.kaddr = shm->kaddr; 3588c2ecf20Sopenharmony_ci shmem.size = shm->size; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci /* 3618c2ecf20Sopenharmony_ci * Send a MAP command to TEE and get the corresponding 3628c2ecf20Sopenharmony_ci * buffer Id 3638c2ecf20Sopenharmony_ci */ 3648c2ecf20Sopenharmony_ci rc = handle_map_shmem(count, &shmem, &buf_id); 3658c2ecf20Sopenharmony_ci if (rc) { 3668c2ecf20Sopenharmony_ci pr_err("map_shmem failed: ret = %d\n", rc); 3678c2ecf20Sopenharmony_ci kfree(shmnode); 3688c2ecf20Sopenharmony_ci return rc; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci shmnode->kaddr = shm->kaddr; 3728c2ecf20Sopenharmony_ci shmnode->buf_id = buf_id; 3738c2ecf20Sopenharmony_ci ctxdata = shm->ctx->data; 3748c2ecf20Sopenharmony_ci mutex_lock(&ctxdata->shm_mutex); 3758c2ecf20Sopenharmony_ci list_add(&shmnode->shm_node, &ctxdata->shm_list); 3768c2ecf20Sopenharmony_ci mutex_unlock(&ctxdata->shm_mutex); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci pr_debug("buf_id :[%x] kaddr[%p]\n", shmnode->buf_id, shmnode->kaddr); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci return 0; 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_civoid amdtee_unmap_shmem(struct tee_shm *shm) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci struct amdtee_context_data *ctxdata; 3868c2ecf20Sopenharmony_ci struct amdtee_shm_data *shmnode; 3878c2ecf20Sopenharmony_ci u32 buf_id; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci if (!shm) 3908c2ecf20Sopenharmony_ci return; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci buf_id = get_buffer_id(shm); 3938c2ecf20Sopenharmony_ci /* Unmap the shared memory from TEE */ 3948c2ecf20Sopenharmony_ci handle_unmap_shmem(buf_id); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci ctxdata = shm->ctx->data; 3978c2ecf20Sopenharmony_ci mutex_lock(&ctxdata->shm_mutex); 3988c2ecf20Sopenharmony_ci list_for_each_entry(shmnode, &ctxdata->shm_list, shm_node) 3998c2ecf20Sopenharmony_ci if (buf_id == shmnode->buf_id) { 4008c2ecf20Sopenharmony_ci list_del(&shmnode->shm_node); 4018c2ecf20Sopenharmony_ci kfree(shmnode); 4028c2ecf20Sopenharmony_ci break; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci mutex_unlock(&ctxdata->shm_mutex); 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ciint amdtee_invoke_func(struct tee_context *ctx, 4088c2ecf20Sopenharmony_ci struct tee_ioctl_invoke_arg *arg, 4098c2ecf20Sopenharmony_ci struct tee_param *param) 4108c2ecf20Sopenharmony_ci{ 4118c2ecf20Sopenharmony_ci struct amdtee_context_data *ctxdata = ctx->data; 4128c2ecf20Sopenharmony_ci struct amdtee_session *sess; 4138c2ecf20Sopenharmony_ci u32 i, session_info; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci /* Check that the session is valid */ 4168c2ecf20Sopenharmony_ci mutex_lock(&session_list_mutex); 4178c2ecf20Sopenharmony_ci sess = find_session(ctxdata, arg->session); 4188c2ecf20Sopenharmony_ci if (sess) { 4198c2ecf20Sopenharmony_ci i = get_session_index(arg->session); 4208c2ecf20Sopenharmony_ci session_info = sess->session_info[i]; 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci mutex_unlock(&session_list_mutex); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci if (!sess) 4258c2ecf20Sopenharmony_ci return -EINVAL; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci handle_invoke_cmd(arg, session_info, param); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci return 0; 4308c2ecf20Sopenharmony_ci} 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ciint amdtee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci return -EINVAL; 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic const struct tee_driver_ops amdtee_ops = { 4388c2ecf20Sopenharmony_ci .get_version = amdtee_get_version, 4398c2ecf20Sopenharmony_ci .open = amdtee_open, 4408c2ecf20Sopenharmony_ci .release = amdtee_release, 4418c2ecf20Sopenharmony_ci .open_session = amdtee_open_session, 4428c2ecf20Sopenharmony_ci .close_session = amdtee_close_session, 4438c2ecf20Sopenharmony_ci .invoke_func = amdtee_invoke_func, 4448c2ecf20Sopenharmony_ci .cancel_req = amdtee_cancel_req, 4458c2ecf20Sopenharmony_ci}; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic const struct tee_desc amdtee_desc = { 4488c2ecf20Sopenharmony_ci .name = DRIVER_NAME "-clnt", 4498c2ecf20Sopenharmony_ci .ops = &amdtee_ops, 4508c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4518c2ecf20Sopenharmony_ci}; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic int __init amdtee_driver_init(void) 4548c2ecf20Sopenharmony_ci{ 4558c2ecf20Sopenharmony_ci struct tee_device *teedev; 4568c2ecf20Sopenharmony_ci struct tee_shm_pool *pool; 4578c2ecf20Sopenharmony_ci struct amdtee *amdtee; 4588c2ecf20Sopenharmony_ci int rc; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci rc = psp_check_tee_status(); 4618c2ecf20Sopenharmony_ci if (rc) { 4628c2ecf20Sopenharmony_ci pr_err("amd-tee driver: tee not present\n"); 4638c2ecf20Sopenharmony_ci return rc; 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL); 4678c2ecf20Sopenharmony_ci if (!drv_data) 4688c2ecf20Sopenharmony_ci return -ENOMEM; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci amdtee = kzalloc(sizeof(*amdtee), GFP_KERNEL); 4718c2ecf20Sopenharmony_ci if (!amdtee) { 4728c2ecf20Sopenharmony_ci rc = -ENOMEM; 4738c2ecf20Sopenharmony_ci goto err_kfree_drv_data; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci pool = amdtee_config_shm(); 4778c2ecf20Sopenharmony_ci if (IS_ERR(pool)) { 4788c2ecf20Sopenharmony_ci pr_err("shared pool configuration error\n"); 4798c2ecf20Sopenharmony_ci rc = PTR_ERR(pool); 4808c2ecf20Sopenharmony_ci goto err_kfree_amdtee; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci teedev = tee_device_alloc(&amdtee_desc, NULL, pool, amdtee); 4848c2ecf20Sopenharmony_ci if (IS_ERR(teedev)) { 4858c2ecf20Sopenharmony_ci rc = PTR_ERR(teedev); 4868c2ecf20Sopenharmony_ci goto err_free_pool; 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci amdtee->teedev = teedev; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci rc = tee_device_register(amdtee->teedev); 4918c2ecf20Sopenharmony_ci if (rc) 4928c2ecf20Sopenharmony_ci goto err_device_unregister; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci amdtee->pool = pool; 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci drv_data->amdtee = amdtee; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci pr_info("amd-tee driver initialization successful\n"); 4998c2ecf20Sopenharmony_ci return 0; 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_cierr_device_unregister: 5028c2ecf20Sopenharmony_ci tee_device_unregister(amdtee->teedev); 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_cierr_free_pool: 5058c2ecf20Sopenharmony_ci tee_shm_pool_free(pool); 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_cierr_kfree_amdtee: 5088c2ecf20Sopenharmony_ci kfree(amdtee); 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cierr_kfree_drv_data: 5118c2ecf20Sopenharmony_ci kfree(drv_data); 5128c2ecf20Sopenharmony_ci drv_data = NULL; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci pr_err("amd-tee driver initialization failed\n"); 5158c2ecf20Sopenharmony_ci return rc; 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_cimodule_init(amdtee_driver_init); 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_cistatic void __exit amdtee_driver_exit(void) 5208c2ecf20Sopenharmony_ci{ 5218c2ecf20Sopenharmony_ci struct amdtee *amdtee; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci if (!drv_data || !drv_data->amdtee) 5248c2ecf20Sopenharmony_ci return; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci amdtee = drv_data->amdtee; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci tee_device_unregister(amdtee->teedev); 5298c2ecf20Sopenharmony_ci tee_shm_pool_free(amdtee->pool); 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_cimodule_exit(amdtee_driver_exit); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR); 5348c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("AMD-TEE driver"); 5358c2ecf20Sopenharmony_ciMODULE_VERSION("1.0"); 5368c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual MIT/GPL"); 537