162306a36Sopenharmony_ci// SPDX-License-Identifier: MIT 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright 2019 Advanced Micro Devices, Inc. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/errno.h> 762306a36Sopenharmony_ci#include <linux/io.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/slab.h> 1062306a36Sopenharmony_ci#include <linux/string.h> 1162306a36Sopenharmony_ci#include <linux/device.h> 1262306a36Sopenharmony_ci#include <linux/tee_drv.h> 1362306a36Sopenharmony_ci#include <linux/types.h> 1462306a36Sopenharmony_ci#include <linux/mm.h> 1562306a36Sopenharmony_ci#include <linux/uaccess.h> 1662306a36Sopenharmony_ci#include <linux/firmware.h> 1762306a36Sopenharmony_ci#include "amdtee_private.h" 1862306a36Sopenharmony_ci#include "../tee_private.h" 1962306a36Sopenharmony_ci#include <linux/psp-tee.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_cistatic struct amdtee_driver_data *drv_data; 2262306a36Sopenharmony_cistatic DEFINE_MUTEX(session_list_mutex); 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistatic void amdtee_get_version(struct tee_device *teedev, 2562306a36Sopenharmony_ci struct tee_ioctl_version_data *vers) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci struct tee_ioctl_version_data v = { 2862306a36Sopenharmony_ci .impl_id = TEE_IMPL_ID_AMDTEE, 2962306a36Sopenharmony_ci .impl_caps = 0, 3062306a36Sopenharmony_ci .gen_caps = TEE_GEN_CAP_GP, 3162306a36Sopenharmony_ci }; 3262306a36Sopenharmony_ci *vers = v; 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic int amdtee_open(struct tee_context *ctx) 3662306a36Sopenharmony_ci{ 3762306a36Sopenharmony_ci struct amdtee_context_data *ctxdata; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci ctxdata = kzalloc(sizeof(*ctxdata), GFP_KERNEL); 4062306a36Sopenharmony_ci if (!ctxdata) 4162306a36Sopenharmony_ci return -ENOMEM; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci INIT_LIST_HEAD(&ctxdata->sess_list); 4462306a36Sopenharmony_ci INIT_LIST_HEAD(&ctxdata->shm_list); 4562306a36Sopenharmony_ci mutex_init(&ctxdata->shm_mutex); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci ctx->data = ctxdata; 4862306a36Sopenharmony_ci return 0; 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic void release_session(struct amdtee_session *sess) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci int i; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci /* Close any open session */ 5662306a36Sopenharmony_ci for (i = 0; i < TEE_NUM_SESSIONS; ++i) { 5762306a36Sopenharmony_ci /* Check if session entry 'i' is valid */ 5862306a36Sopenharmony_ci if (!test_bit(i, sess->sess_mask)) 5962306a36Sopenharmony_ci continue; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci handle_close_session(sess->ta_handle, sess->session_info[i]); 6262306a36Sopenharmony_ci handle_unload_ta(sess->ta_handle); 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci kfree(sess); 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic void amdtee_release(struct tee_context *ctx) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci struct amdtee_context_data *ctxdata = ctx->data; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (!ctxdata) 7362306a36Sopenharmony_ci return; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci while (true) { 7662306a36Sopenharmony_ci struct amdtee_session *sess; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci sess = list_first_entry_or_null(&ctxdata->sess_list, 7962306a36Sopenharmony_ci struct amdtee_session, 8062306a36Sopenharmony_ci list_node); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if (!sess) 8362306a36Sopenharmony_ci break; 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci list_del(&sess->list_node); 8662306a36Sopenharmony_ci release_session(sess); 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci mutex_destroy(&ctxdata->shm_mutex); 8962306a36Sopenharmony_ci kfree(ctxdata); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci ctx->data = NULL; 9262306a36Sopenharmony_ci} 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/** 9562306a36Sopenharmony_ci * alloc_session() - Allocate a session structure 9662306a36Sopenharmony_ci * @ctxdata: TEE Context data structure 9762306a36Sopenharmony_ci * @session: Session ID for which 'struct amdtee_session' structure is to be 9862306a36Sopenharmony_ci * allocated. 9962306a36Sopenharmony_ci * 10062306a36Sopenharmony_ci * Scans the TEE context's session list to check if TA is already loaded in to 10162306a36Sopenharmony_ci * TEE. If yes, returns the 'session' structure for that TA. Else allocates, 10262306a36Sopenharmony_ci * initializes a new 'session' structure and adds it to context's session list. 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * The caller must hold a mutex. 10562306a36Sopenharmony_ci * 10662306a36Sopenharmony_ci * Returns: 10762306a36Sopenharmony_ci * 'struct amdtee_session *' on success and NULL on failure. 10862306a36Sopenharmony_ci */ 10962306a36Sopenharmony_cistatic struct amdtee_session *alloc_session(struct amdtee_context_data *ctxdata, 11062306a36Sopenharmony_ci u32 session) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci struct amdtee_session *sess; 11362306a36Sopenharmony_ci u32 ta_handle = get_ta_handle(session); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci /* Scan session list to check if TA is already loaded in to TEE */ 11662306a36Sopenharmony_ci list_for_each_entry(sess, &ctxdata->sess_list, list_node) 11762306a36Sopenharmony_ci if (sess->ta_handle == ta_handle) { 11862306a36Sopenharmony_ci kref_get(&sess->refcount); 11962306a36Sopenharmony_ci return sess; 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci /* Allocate a new session and add to list */ 12362306a36Sopenharmony_ci sess = kzalloc(sizeof(*sess), GFP_KERNEL); 12462306a36Sopenharmony_ci if (sess) { 12562306a36Sopenharmony_ci sess->ta_handle = ta_handle; 12662306a36Sopenharmony_ci kref_init(&sess->refcount); 12762306a36Sopenharmony_ci spin_lock_init(&sess->lock); 12862306a36Sopenharmony_ci list_add(&sess->list_node, &ctxdata->sess_list); 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci return sess; 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci/* Requires mutex to be held */ 13562306a36Sopenharmony_cistatic struct amdtee_session *find_session(struct amdtee_context_data *ctxdata, 13662306a36Sopenharmony_ci u32 session) 13762306a36Sopenharmony_ci{ 13862306a36Sopenharmony_ci u32 ta_handle = get_ta_handle(session); 13962306a36Sopenharmony_ci u32 index = get_session_index(session); 14062306a36Sopenharmony_ci struct amdtee_session *sess; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci if (index >= TEE_NUM_SESSIONS) 14362306a36Sopenharmony_ci return NULL; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci list_for_each_entry(sess, &ctxdata->sess_list, list_node) 14662306a36Sopenharmony_ci if (ta_handle == sess->ta_handle && 14762306a36Sopenharmony_ci test_bit(index, sess->sess_mask)) 14862306a36Sopenharmony_ci return sess; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci return NULL; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ciu32 get_buffer_id(struct tee_shm *shm) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci struct amdtee_context_data *ctxdata = shm->ctx->data; 15662306a36Sopenharmony_ci struct amdtee_shm_data *shmdata; 15762306a36Sopenharmony_ci u32 buf_id = 0; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci mutex_lock(&ctxdata->shm_mutex); 16062306a36Sopenharmony_ci list_for_each_entry(shmdata, &ctxdata->shm_list, shm_node) 16162306a36Sopenharmony_ci if (shmdata->kaddr == shm->kaddr) { 16262306a36Sopenharmony_ci buf_id = shmdata->buf_id; 16362306a36Sopenharmony_ci break; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci mutex_unlock(&ctxdata->shm_mutex); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci return buf_id; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic DEFINE_MUTEX(drv_mutex); 17162306a36Sopenharmony_cistatic int copy_ta_binary(struct tee_context *ctx, void *ptr, void **ta, 17262306a36Sopenharmony_ci size_t *ta_size) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci const struct firmware *fw; 17562306a36Sopenharmony_ci char fw_name[TA_PATH_MAX]; 17662306a36Sopenharmony_ci struct { 17762306a36Sopenharmony_ci u32 lo; 17862306a36Sopenharmony_ci u16 mid; 17962306a36Sopenharmony_ci u16 hi_ver; 18062306a36Sopenharmony_ci u8 seq_n[8]; 18162306a36Sopenharmony_ci } *uuid = ptr; 18262306a36Sopenharmony_ci int n, rc = 0; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci n = snprintf(fw_name, TA_PATH_MAX, 18562306a36Sopenharmony_ci "%s/%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x.bin", 18662306a36Sopenharmony_ci TA_LOAD_PATH, uuid->lo, uuid->mid, uuid->hi_ver, 18762306a36Sopenharmony_ci uuid->seq_n[0], uuid->seq_n[1], 18862306a36Sopenharmony_ci uuid->seq_n[2], uuid->seq_n[3], 18962306a36Sopenharmony_ci uuid->seq_n[4], uuid->seq_n[5], 19062306a36Sopenharmony_ci uuid->seq_n[6], uuid->seq_n[7]); 19162306a36Sopenharmony_ci if (n < 0 || n >= TA_PATH_MAX) { 19262306a36Sopenharmony_ci pr_err("failed to get firmware name\n"); 19362306a36Sopenharmony_ci return -EINVAL; 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci mutex_lock(&drv_mutex); 19762306a36Sopenharmony_ci n = request_firmware(&fw, fw_name, &ctx->teedev->dev); 19862306a36Sopenharmony_ci if (n) { 19962306a36Sopenharmony_ci pr_err("failed to load firmware %s\n", fw_name); 20062306a36Sopenharmony_ci rc = -ENOMEM; 20162306a36Sopenharmony_ci goto unlock; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci *ta_size = roundup(fw->size, PAGE_SIZE); 20562306a36Sopenharmony_ci *ta = (void *)__get_free_pages(GFP_KERNEL, get_order(*ta_size)); 20662306a36Sopenharmony_ci if (!*ta) { 20762306a36Sopenharmony_ci pr_err("%s: get_free_pages failed\n", __func__); 20862306a36Sopenharmony_ci rc = -ENOMEM; 20962306a36Sopenharmony_ci goto rel_fw; 21062306a36Sopenharmony_ci } 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci memcpy(*ta, fw->data, fw->size); 21362306a36Sopenharmony_cirel_fw: 21462306a36Sopenharmony_ci release_firmware(fw); 21562306a36Sopenharmony_ciunlock: 21662306a36Sopenharmony_ci mutex_unlock(&drv_mutex); 21762306a36Sopenharmony_ci return rc; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci/* mutex must be held by caller */ 22162306a36Sopenharmony_cistatic void destroy_session(struct kref *ref) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci struct amdtee_session *sess = container_of(ref, struct amdtee_session, 22462306a36Sopenharmony_ci refcount); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci list_del(&sess->list_node); 22762306a36Sopenharmony_ci mutex_unlock(&session_list_mutex); 22862306a36Sopenharmony_ci kfree(sess); 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ciint amdtee_open_session(struct tee_context *ctx, 23262306a36Sopenharmony_ci struct tee_ioctl_open_session_arg *arg, 23362306a36Sopenharmony_ci struct tee_param *param) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci struct amdtee_context_data *ctxdata = ctx->data; 23662306a36Sopenharmony_ci struct amdtee_session *sess = NULL; 23762306a36Sopenharmony_ci u32 session_info, ta_handle; 23862306a36Sopenharmony_ci size_t ta_size; 23962306a36Sopenharmony_ci int rc, i; 24062306a36Sopenharmony_ci void *ta; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci if (arg->clnt_login != TEE_IOCTL_LOGIN_PUBLIC) { 24362306a36Sopenharmony_ci pr_err("unsupported client login method\n"); 24462306a36Sopenharmony_ci return -EINVAL; 24562306a36Sopenharmony_ci } 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci rc = copy_ta_binary(ctx, &arg->uuid[0], &ta, &ta_size); 24862306a36Sopenharmony_ci if (rc) { 24962306a36Sopenharmony_ci pr_err("failed to copy TA binary\n"); 25062306a36Sopenharmony_ci return rc; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* Load the TA binary into TEE environment */ 25462306a36Sopenharmony_ci handle_load_ta(ta, ta_size, arg); 25562306a36Sopenharmony_ci if (arg->ret != TEEC_SUCCESS) 25662306a36Sopenharmony_ci goto out; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci ta_handle = get_ta_handle(arg->session); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci mutex_lock(&session_list_mutex); 26162306a36Sopenharmony_ci sess = alloc_session(ctxdata, arg->session); 26262306a36Sopenharmony_ci mutex_unlock(&session_list_mutex); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (!sess) { 26562306a36Sopenharmony_ci handle_unload_ta(ta_handle); 26662306a36Sopenharmony_ci rc = -ENOMEM; 26762306a36Sopenharmony_ci goto out; 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* Open session with loaded TA */ 27162306a36Sopenharmony_ci handle_open_session(arg, &session_info, param); 27262306a36Sopenharmony_ci if (arg->ret != TEEC_SUCCESS) { 27362306a36Sopenharmony_ci pr_err("open_session failed %d\n", arg->ret); 27462306a36Sopenharmony_ci handle_unload_ta(ta_handle); 27562306a36Sopenharmony_ci kref_put_mutex(&sess->refcount, destroy_session, 27662306a36Sopenharmony_ci &session_list_mutex); 27762306a36Sopenharmony_ci goto out; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci /* Find an empty session index for the given TA */ 28162306a36Sopenharmony_ci spin_lock(&sess->lock); 28262306a36Sopenharmony_ci i = find_first_zero_bit(sess->sess_mask, TEE_NUM_SESSIONS); 28362306a36Sopenharmony_ci if (i < TEE_NUM_SESSIONS) { 28462306a36Sopenharmony_ci sess->session_info[i] = session_info; 28562306a36Sopenharmony_ci set_session_id(ta_handle, i, &arg->session); 28662306a36Sopenharmony_ci set_bit(i, sess->sess_mask); 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci spin_unlock(&sess->lock); 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if (i >= TEE_NUM_SESSIONS) { 29162306a36Sopenharmony_ci pr_err("reached maximum session count %d\n", TEE_NUM_SESSIONS); 29262306a36Sopenharmony_ci handle_close_session(ta_handle, session_info); 29362306a36Sopenharmony_ci handle_unload_ta(ta_handle); 29462306a36Sopenharmony_ci kref_put_mutex(&sess->refcount, destroy_session, 29562306a36Sopenharmony_ci &session_list_mutex); 29662306a36Sopenharmony_ci rc = -ENOMEM; 29762306a36Sopenharmony_ci goto out; 29862306a36Sopenharmony_ci } 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ciout: 30162306a36Sopenharmony_ci free_pages((u64)ta, get_order(ta_size)); 30262306a36Sopenharmony_ci return rc; 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ciint amdtee_close_session(struct tee_context *ctx, u32 session) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci struct amdtee_context_data *ctxdata = ctx->data; 30862306a36Sopenharmony_ci u32 i, ta_handle, session_info; 30962306a36Sopenharmony_ci struct amdtee_session *sess; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci pr_debug("%s: sid = 0x%x\n", __func__, session); 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci /* 31462306a36Sopenharmony_ci * Check that the session is valid and clear the session 31562306a36Sopenharmony_ci * usage bit 31662306a36Sopenharmony_ci */ 31762306a36Sopenharmony_ci mutex_lock(&session_list_mutex); 31862306a36Sopenharmony_ci sess = find_session(ctxdata, session); 31962306a36Sopenharmony_ci if (sess) { 32062306a36Sopenharmony_ci ta_handle = get_ta_handle(session); 32162306a36Sopenharmony_ci i = get_session_index(session); 32262306a36Sopenharmony_ci session_info = sess->session_info[i]; 32362306a36Sopenharmony_ci spin_lock(&sess->lock); 32462306a36Sopenharmony_ci clear_bit(i, sess->sess_mask); 32562306a36Sopenharmony_ci spin_unlock(&sess->lock); 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci mutex_unlock(&session_list_mutex); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if (!sess) 33062306a36Sopenharmony_ci return -EINVAL; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* Close the session */ 33362306a36Sopenharmony_ci handle_close_session(ta_handle, session_info); 33462306a36Sopenharmony_ci handle_unload_ta(ta_handle); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci kref_put_mutex(&sess->refcount, destroy_session, &session_list_mutex); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci return 0; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ciint amdtee_map_shmem(struct tee_shm *shm) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci struct amdtee_context_data *ctxdata; 34462306a36Sopenharmony_ci struct amdtee_shm_data *shmnode; 34562306a36Sopenharmony_ci struct shmem_desc shmem; 34662306a36Sopenharmony_ci int rc, count; 34762306a36Sopenharmony_ci u32 buf_id; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (!shm) 35062306a36Sopenharmony_ci return -EINVAL; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci shmnode = kmalloc(sizeof(*shmnode), GFP_KERNEL); 35362306a36Sopenharmony_ci if (!shmnode) 35462306a36Sopenharmony_ci return -ENOMEM; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci count = 1; 35762306a36Sopenharmony_ci shmem.kaddr = shm->kaddr; 35862306a36Sopenharmony_ci shmem.size = shm->size; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* 36162306a36Sopenharmony_ci * Send a MAP command to TEE and get the corresponding 36262306a36Sopenharmony_ci * buffer Id 36362306a36Sopenharmony_ci */ 36462306a36Sopenharmony_ci rc = handle_map_shmem(count, &shmem, &buf_id); 36562306a36Sopenharmony_ci if (rc) { 36662306a36Sopenharmony_ci pr_err("map_shmem failed: ret = %d\n", rc); 36762306a36Sopenharmony_ci kfree(shmnode); 36862306a36Sopenharmony_ci return rc; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci shmnode->kaddr = shm->kaddr; 37262306a36Sopenharmony_ci shmnode->buf_id = buf_id; 37362306a36Sopenharmony_ci ctxdata = shm->ctx->data; 37462306a36Sopenharmony_ci mutex_lock(&ctxdata->shm_mutex); 37562306a36Sopenharmony_ci list_add(&shmnode->shm_node, &ctxdata->shm_list); 37662306a36Sopenharmony_ci mutex_unlock(&ctxdata->shm_mutex); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci pr_debug("buf_id :[%x] kaddr[%p]\n", shmnode->buf_id, shmnode->kaddr); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci return 0; 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_civoid amdtee_unmap_shmem(struct tee_shm *shm) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci struct amdtee_context_data *ctxdata; 38662306a36Sopenharmony_ci struct amdtee_shm_data *shmnode; 38762306a36Sopenharmony_ci u32 buf_id; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci if (!shm) 39062306a36Sopenharmony_ci return; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci buf_id = get_buffer_id(shm); 39362306a36Sopenharmony_ci /* Unmap the shared memory from TEE */ 39462306a36Sopenharmony_ci handle_unmap_shmem(buf_id); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci ctxdata = shm->ctx->data; 39762306a36Sopenharmony_ci mutex_lock(&ctxdata->shm_mutex); 39862306a36Sopenharmony_ci list_for_each_entry(shmnode, &ctxdata->shm_list, shm_node) 39962306a36Sopenharmony_ci if (buf_id == shmnode->buf_id) { 40062306a36Sopenharmony_ci list_del(&shmnode->shm_node); 40162306a36Sopenharmony_ci kfree(shmnode); 40262306a36Sopenharmony_ci break; 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci mutex_unlock(&ctxdata->shm_mutex); 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ciint amdtee_invoke_func(struct tee_context *ctx, 40862306a36Sopenharmony_ci struct tee_ioctl_invoke_arg *arg, 40962306a36Sopenharmony_ci struct tee_param *param) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci struct amdtee_context_data *ctxdata = ctx->data; 41262306a36Sopenharmony_ci struct amdtee_session *sess; 41362306a36Sopenharmony_ci u32 i, session_info; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* Check that the session is valid */ 41662306a36Sopenharmony_ci mutex_lock(&session_list_mutex); 41762306a36Sopenharmony_ci sess = find_session(ctxdata, arg->session); 41862306a36Sopenharmony_ci if (sess) { 41962306a36Sopenharmony_ci i = get_session_index(arg->session); 42062306a36Sopenharmony_ci session_info = sess->session_info[i]; 42162306a36Sopenharmony_ci } 42262306a36Sopenharmony_ci mutex_unlock(&session_list_mutex); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci if (!sess) 42562306a36Sopenharmony_ci return -EINVAL; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci handle_invoke_cmd(arg, session_info, param); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci return 0; 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ciint amdtee_cancel_req(struct tee_context *ctx, u32 cancel_id, u32 session) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci return -EINVAL; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic const struct tee_driver_ops amdtee_ops = { 43862306a36Sopenharmony_ci .get_version = amdtee_get_version, 43962306a36Sopenharmony_ci .open = amdtee_open, 44062306a36Sopenharmony_ci .release = amdtee_release, 44162306a36Sopenharmony_ci .open_session = amdtee_open_session, 44262306a36Sopenharmony_ci .close_session = amdtee_close_session, 44362306a36Sopenharmony_ci .invoke_func = amdtee_invoke_func, 44462306a36Sopenharmony_ci .cancel_req = amdtee_cancel_req, 44562306a36Sopenharmony_ci}; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic const struct tee_desc amdtee_desc = { 44862306a36Sopenharmony_ci .name = DRIVER_NAME "-clnt", 44962306a36Sopenharmony_ci .ops = &amdtee_ops, 45062306a36Sopenharmony_ci .owner = THIS_MODULE, 45162306a36Sopenharmony_ci}; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistatic int __init amdtee_driver_init(void) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci struct tee_device *teedev; 45662306a36Sopenharmony_ci struct tee_shm_pool *pool; 45762306a36Sopenharmony_ci struct amdtee *amdtee; 45862306a36Sopenharmony_ci int rc; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci rc = psp_check_tee_status(); 46162306a36Sopenharmony_ci if (rc) { 46262306a36Sopenharmony_ci pr_err("amd-tee driver: tee not present\n"); 46362306a36Sopenharmony_ci return rc; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL); 46762306a36Sopenharmony_ci if (!drv_data) 46862306a36Sopenharmony_ci return -ENOMEM; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci amdtee = kzalloc(sizeof(*amdtee), GFP_KERNEL); 47162306a36Sopenharmony_ci if (!amdtee) { 47262306a36Sopenharmony_ci rc = -ENOMEM; 47362306a36Sopenharmony_ci goto err_kfree_drv_data; 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci pool = amdtee_config_shm(); 47762306a36Sopenharmony_ci if (IS_ERR(pool)) { 47862306a36Sopenharmony_ci pr_err("shared pool configuration error\n"); 47962306a36Sopenharmony_ci rc = PTR_ERR(pool); 48062306a36Sopenharmony_ci goto err_kfree_amdtee; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci teedev = tee_device_alloc(&amdtee_desc, NULL, pool, amdtee); 48462306a36Sopenharmony_ci if (IS_ERR(teedev)) { 48562306a36Sopenharmony_ci rc = PTR_ERR(teedev); 48662306a36Sopenharmony_ci goto err_free_pool; 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci amdtee->teedev = teedev; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci rc = tee_device_register(amdtee->teedev); 49162306a36Sopenharmony_ci if (rc) 49262306a36Sopenharmony_ci goto err_device_unregister; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci amdtee->pool = pool; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci drv_data->amdtee = amdtee; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci pr_info("amd-tee driver initialization successful\n"); 49962306a36Sopenharmony_ci return 0; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cierr_device_unregister: 50262306a36Sopenharmony_ci tee_device_unregister(amdtee->teedev); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cierr_free_pool: 50562306a36Sopenharmony_ci tee_shm_pool_free(pool); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_cierr_kfree_amdtee: 50862306a36Sopenharmony_ci kfree(amdtee); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_cierr_kfree_drv_data: 51162306a36Sopenharmony_ci kfree(drv_data); 51262306a36Sopenharmony_ci drv_data = NULL; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci pr_err("amd-tee driver initialization failed\n"); 51562306a36Sopenharmony_ci return rc; 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_cimodule_init(amdtee_driver_init); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cistatic void __exit amdtee_driver_exit(void) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci struct amdtee *amdtee; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci if (!drv_data || !drv_data->amdtee) 52462306a36Sopenharmony_ci return; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci amdtee = drv_data->amdtee; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci tee_device_unregister(amdtee->teedev); 52962306a36Sopenharmony_ci tee_shm_pool_free(amdtee->pool); 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_cimodule_exit(amdtee_driver_exit); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR); 53462306a36Sopenharmony_ciMODULE_DESCRIPTION("AMD-TEE driver"); 53562306a36Sopenharmony_ciMODULE_VERSION("1.0"); 53662306a36Sopenharmony_ciMODULE_LICENSE("Dual MIT/GPL"); 537