18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: MIT 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2019 Advanced Micro Devices, Inc. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/device.h> 78c2ecf20Sopenharmony_ci#include <linux/tee.h> 88c2ecf20Sopenharmony_ci#include <linux/tee_drv.h> 98c2ecf20Sopenharmony_ci#include <linux/psp-tee.h> 108c2ecf20Sopenharmony_ci#include <linux/slab.h> 118c2ecf20Sopenharmony_ci#include <linux/psp-sev.h> 128c2ecf20Sopenharmony_ci#include "amdtee_if.h" 138c2ecf20Sopenharmony_ci#include "amdtee_private.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistatic int tee_params_to_amd_params(struct tee_param *tee, u32 count, 168c2ecf20Sopenharmony_ci struct tee_operation *amd) 178c2ecf20Sopenharmony_ci{ 188c2ecf20Sopenharmony_ci int i, ret = 0; 198c2ecf20Sopenharmony_ci u32 type; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci if (!count) 228c2ecf20Sopenharmony_ci return 0; 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci if (!tee || !amd || count > TEE_MAX_PARAMS) 258c2ecf20Sopenharmony_ci return -EINVAL; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci amd->param_types = 0; 288c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 298c2ecf20Sopenharmony_ci /* AMD TEE does not support meta parameter */ 308c2ecf20Sopenharmony_ci if (tee[i].attr > TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT) 318c2ecf20Sopenharmony_ci return -EINVAL; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci amd->param_types |= ((tee[i].attr & 0xF) << i * 4); 348c2ecf20Sopenharmony_ci } 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 378c2ecf20Sopenharmony_ci type = TEE_PARAM_TYPE_GET(amd->param_types, i); 388c2ecf20Sopenharmony_ci pr_debug("%s: type[%d] = 0x%x\n", __func__, i, type); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci if (type == TEE_OP_PARAM_TYPE_INVALID) 418c2ecf20Sopenharmony_ci return -EINVAL; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (type == TEE_OP_PARAM_TYPE_NONE) 448c2ecf20Sopenharmony_ci continue; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci /* It is assumed that all values are within 2^32-1 */ 478c2ecf20Sopenharmony_ci if (type > TEE_OP_PARAM_TYPE_VALUE_INOUT) { 488c2ecf20Sopenharmony_ci u32 buf_id = get_buffer_id(tee[i].u.memref.shm); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci amd->params[i].mref.buf_id = buf_id; 518c2ecf20Sopenharmony_ci amd->params[i].mref.offset = tee[i].u.memref.shm_offs; 528c2ecf20Sopenharmony_ci amd->params[i].mref.size = tee[i].u.memref.size; 538c2ecf20Sopenharmony_ci pr_debug("%s: bufid[%d] = 0x%x, offset[%d] = 0x%x, size[%d] = 0x%x\n", 548c2ecf20Sopenharmony_ci __func__, 558c2ecf20Sopenharmony_ci i, amd->params[i].mref.buf_id, 568c2ecf20Sopenharmony_ci i, amd->params[i].mref.offset, 578c2ecf20Sopenharmony_ci i, amd->params[i].mref.size); 588c2ecf20Sopenharmony_ci } else { 598c2ecf20Sopenharmony_ci if (tee[i].u.value.c) 608c2ecf20Sopenharmony_ci pr_warn("%s: Discarding value c", __func__); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci amd->params[i].val.a = tee[i].u.value.a; 638c2ecf20Sopenharmony_ci amd->params[i].val.b = tee[i].u.value.b; 648c2ecf20Sopenharmony_ci pr_debug("%s: a[%d] = 0x%x, b[%d] = 0x%x\n", __func__, 658c2ecf20Sopenharmony_ci i, amd->params[i].val.a, 668c2ecf20Sopenharmony_ci i, amd->params[i].val.b); 678c2ecf20Sopenharmony_ci } 688c2ecf20Sopenharmony_ci } 698c2ecf20Sopenharmony_ci return ret; 708c2ecf20Sopenharmony_ci} 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic int amd_params_to_tee_params(struct tee_param *tee, u32 count, 738c2ecf20Sopenharmony_ci struct tee_operation *amd) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci int i, ret = 0; 768c2ecf20Sopenharmony_ci u32 type; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci if (!count) 798c2ecf20Sopenharmony_ci return 0; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (!tee || !amd || count > TEE_MAX_PARAMS) 828c2ecf20Sopenharmony_ci return -EINVAL; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci /* Assumes amd->param_types is valid */ 858c2ecf20Sopenharmony_ci for (i = 0; i < count; i++) { 868c2ecf20Sopenharmony_ci type = TEE_PARAM_TYPE_GET(amd->param_types, i); 878c2ecf20Sopenharmony_ci pr_debug("%s: type[%d] = 0x%x\n", __func__, i, type); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (type == TEE_OP_PARAM_TYPE_INVALID || 908c2ecf20Sopenharmony_ci type > TEE_OP_PARAM_TYPE_MEMREF_INOUT) 918c2ecf20Sopenharmony_ci return -EINVAL; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (type == TEE_OP_PARAM_TYPE_NONE || 948c2ecf20Sopenharmony_ci type == TEE_OP_PARAM_TYPE_VALUE_INPUT || 958c2ecf20Sopenharmony_ci type == TEE_OP_PARAM_TYPE_MEMREF_INPUT) 968c2ecf20Sopenharmony_ci continue; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci /* 998c2ecf20Sopenharmony_ci * It is assumed that buf_id remains unchanged for 1008c2ecf20Sopenharmony_ci * both open_session and invoke_cmd call 1018c2ecf20Sopenharmony_ci */ 1028c2ecf20Sopenharmony_ci if (type > TEE_OP_PARAM_TYPE_MEMREF_INPUT) { 1038c2ecf20Sopenharmony_ci tee[i].u.memref.shm_offs = amd->params[i].mref.offset; 1048c2ecf20Sopenharmony_ci tee[i].u.memref.size = amd->params[i].mref.size; 1058c2ecf20Sopenharmony_ci pr_debug("%s: bufid[%d] = 0x%x, offset[%d] = 0x%x, size[%d] = 0x%x\n", 1068c2ecf20Sopenharmony_ci __func__, 1078c2ecf20Sopenharmony_ci i, amd->params[i].mref.buf_id, 1088c2ecf20Sopenharmony_ci i, amd->params[i].mref.offset, 1098c2ecf20Sopenharmony_ci i, amd->params[i].mref.size); 1108c2ecf20Sopenharmony_ci } else { 1118c2ecf20Sopenharmony_ci /* field 'c' not supported by AMD TEE */ 1128c2ecf20Sopenharmony_ci tee[i].u.value.a = amd->params[i].val.a; 1138c2ecf20Sopenharmony_ci tee[i].u.value.b = amd->params[i].val.b; 1148c2ecf20Sopenharmony_ci tee[i].u.value.c = 0; 1158c2ecf20Sopenharmony_ci pr_debug("%s: a[%d] = 0x%x, b[%d] = 0x%x\n", 1168c2ecf20Sopenharmony_ci __func__, 1178c2ecf20Sopenharmony_ci i, amd->params[i].val.a, 1188c2ecf20Sopenharmony_ci i, amd->params[i].val.b); 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci return ret; 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(ta_refcount_mutex); 1258c2ecf20Sopenharmony_cistatic struct list_head ta_list = LIST_HEAD_INIT(ta_list); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_cistatic u32 get_ta_refcount(u32 ta_handle) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci struct amdtee_ta_data *ta_data; 1308c2ecf20Sopenharmony_ci u32 count = 0; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci /* Caller must hold a mutex */ 1338c2ecf20Sopenharmony_ci list_for_each_entry(ta_data, &ta_list, list_node) 1348c2ecf20Sopenharmony_ci if (ta_data->ta_handle == ta_handle) 1358c2ecf20Sopenharmony_ci return ++ta_data->refcount; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci ta_data = kzalloc(sizeof(*ta_data), GFP_KERNEL); 1388c2ecf20Sopenharmony_ci if (ta_data) { 1398c2ecf20Sopenharmony_ci ta_data->ta_handle = ta_handle; 1408c2ecf20Sopenharmony_ci ta_data->refcount = 1; 1418c2ecf20Sopenharmony_ci count = ta_data->refcount; 1428c2ecf20Sopenharmony_ci list_add(&ta_data->list_node, &ta_list); 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci return count; 1468c2ecf20Sopenharmony_ci} 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic u32 put_ta_refcount(u32 ta_handle) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct amdtee_ta_data *ta_data; 1518c2ecf20Sopenharmony_ci u32 count = 0; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci /* Caller must hold a mutex */ 1548c2ecf20Sopenharmony_ci list_for_each_entry(ta_data, &ta_list, list_node) 1558c2ecf20Sopenharmony_ci if (ta_data->ta_handle == ta_handle) { 1568c2ecf20Sopenharmony_ci count = --ta_data->refcount; 1578c2ecf20Sopenharmony_ci if (count == 0) { 1588c2ecf20Sopenharmony_ci list_del(&ta_data->list_node); 1598c2ecf20Sopenharmony_ci kfree(ta_data); 1608c2ecf20Sopenharmony_ci break; 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci return count; 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ciint handle_unload_ta(u32 ta_handle) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct tee_cmd_unload_ta cmd = {0}; 1708c2ecf20Sopenharmony_ci u32 status, count; 1718c2ecf20Sopenharmony_ci int ret; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci if (!ta_handle) 1748c2ecf20Sopenharmony_ci return -EINVAL; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci mutex_lock(&ta_refcount_mutex); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci count = put_ta_refcount(ta_handle); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (count) { 1818c2ecf20Sopenharmony_ci pr_debug("unload ta: not unloading %u count %u\n", 1828c2ecf20Sopenharmony_ci ta_handle, count); 1838c2ecf20Sopenharmony_ci ret = -EBUSY; 1848c2ecf20Sopenharmony_ci goto unlock; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci cmd.ta_handle = ta_handle; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci ret = psp_tee_process_cmd(TEE_CMD_ID_UNLOAD_TA, (void *)&cmd, 1908c2ecf20Sopenharmony_ci sizeof(cmd), &status); 1918c2ecf20Sopenharmony_ci if (!ret && status != 0) { 1928c2ecf20Sopenharmony_ci pr_err("unload ta: status = 0x%x\n", status); 1938c2ecf20Sopenharmony_ci ret = -EBUSY; 1948c2ecf20Sopenharmony_ci } else { 1958c2ecf20Sopenharmony_ci pr_debug("unloaded ta handle %u\n", ta_handle); 1968c2ecf20Sopenharmony_ci } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ciunlock: 1998c2ecf20Sopenharmony_ci mutex_unlock(&ta_refcount_mutex); 2008c2ecf20Sopenharmony_ci return ret; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ciint handle_close_session(u32 ta_handle, u32 info) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci struct tee_cmd_close_session cmd = {0}; 2068c2ecf20Sopenharmony_ci u32 status; 2078c2ecf20Sopenharmony_ci int ret; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (ta_handle == 0) 2108c2ecf20Sopenharmony_ci return -EINVAL; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci cmd.ta_handle = ta_handle; 2138c2ecf20Sopenharmony_ci cmd.session_info = info; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci ret = psp_tee_process_cmd(TEE_CMD_ID_CLOSE_SESSION, (void *)&cmd, 2168c2ecf20Sopenharmony_ci sizeof(cmd), &status); 2178c2ecf20Sopenharmony_ci if (!ret && status != 0) { 2188c2ecf20Sopenharmony_ci pr_err("close session: status = 0x%x\n", status); 2198c2ecf20Sopenharmony_ci ret = -EBUSY; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci return ret; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_civoid handle_unmap_shmem(u32 buf_id) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci struct tee_cmd_unmap_shared_mem cmd = {0}; 2288c2ecf20Sopenharmony_ci u32 status; 2298c2ecf20Sopenharmony_ci int ret; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci cmd.buf_id = buf_id; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci ret = psp_tee_process_cmd(TEE_CMD_ID_UNMAP_SHARED_MEM, (void *)&cmd, 2348c2ecf20Sopenharmony_ci sizeof(cmd), &status); 2358c2ecf20Sopenharmony_ci if (!ret) 2368c2ecf20Sopenharmony_ci pr_debug("unmap shared memory: buf_id %u status = 0x%x\n", 2378c2ecf20Sopenharmony_ci buf_id, status); 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ciint handle_invoke_cmd(struct tee_ioctl_invoke_arg *arg, u32 sinfo, 2418c2ecf20Sopenharmony_ci struct tee_param *p) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct tee_cmd_invoke_cmd cmd = {0}; 2448c2ecf20Sopenharmony_ci int ret; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (!arg || (!p && arg->num_params)) 2478c2ecf20Sopenharmony_ci return -EINVAL; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci arg->ret_origin = TEEC_ORIGIN_COMMS; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci if (arg->session == 0) { 2528c2ecf20Sopenharmony_ci arg->ret = TEEC_ERROR_BAD_PARAMETERS; 2538c2ecf20Sopenharmony_ci return -EINVAL; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci ret = tee_params_to_amd_params(p, arg->num_params, &cmd.op); 2578c2ecf20Sopenharmony_ci if (ret) { 2588c2ecf20Sopenharmony_ci pr_err("invalid Params. Abort invoke command\n"); 2598c2ecf20Sopenharmony_ci arg->ret = TEEC_ERROR_BAD_PARAMETERS; 2608c2ecf20Sopenharmony_ci return ret; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci cmd.ta_handle = get_ta_handle(arg->session); 2648c2ecf20Sopenharmony_ci cmd.cmd_id = arg->func; 2658c2ecf20Sopenharmony_ci cmd.session_info = sinfo; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci ret = psp_tee_process_cmd(TEE_CMD_ID_INVOKE_CMD, (void *)&cmd, 2688c2ecf20Sopenharmony_ci sizeof(cmd), &arg->ret); 2698c2ecf20Sopenharmony_ci if (ret) { 2708c2ecf20Sopenharmony_ci arg->ret = TEEC_ERROR_COMMUNICATION; 2718c2ecf20Sopenharmony_ci } else { 2728c2ecf20Sopenharmony_ci ret = amd_params_to_tee_params(p, arg->num_params, &cmd.op); 2738c2ecf20Sopenharmony_ci if (unlikely(ret)) { 2748c2ecf20Sopenharmony_ci pr_err("invoke command: failed to copy output\n"); 2758c2ecf20Sopenharmony_ci arg->ret = TEEC_ERROR_GENERIC; 2768c2ecf20Sopenharmony_ci return ret; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci arg->ret_origin = cmd.return_origin; 2798c2ecf20Sopenharmony_ci pr_debug("invoke command: RO = 0x%x ret = 0x%x\n", 2808c2ecf20Sopenharmony_ci arg->ret_origin, arg->ret); 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci return ret; 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ciint handle_map_shmem(u32 count, struct shmem_desc *start, u32 *buf_id) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct tee_cmd_map_shared_mem *cmd; 2898c2ecf20Sopenharmony_ci phys_addr_t paddr; 2908c2ecf20Sopenharmony_ci int ret, i; 2918c2ecf20Sopenharmony_ci u32 status; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (!count || !start || !buf_id) 2948c2ecf20Sopenharmony_ci return -EINVAL; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 2978c2ecf20Sopenharmony_ci if (!cmd) 2988c2ecf20Sopenharmony_ci return -ENOMEM; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci /* Size must be page aligned */ 3018c2ecf20Sopenharmony_ci for (i = 0; i < count ; i++) { 3028c2ecf20Sopenharmony_ci if (!start[i].kaddr || (start[i].size & (PAGE_SIZE - 1))) { 3038c2ecf20Sopenharmony_ci ret = -EINVAL; 3048c2ecf20Sopenharmony_ci goto free_cmd; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci if ((u64)start[i].kaddr & (PAGE_SIZE - 1)) { 3088c2ecf20Sopenharmony_ci pr_err("map shared memory: page unaligned. addr 0x%llx", 3098c2ecf20Sopenharmony_ci (u64)start[i].kaddr); 3108c2ecf20Sopenharmony_ci ret = -EINVAL; 3118c2ecf20Sopenharmony_ci goto free_cmd; 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci cmd->sg_list.count = count; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci /* Create buffer list */ 3188c2ecf20Sopenharmony_ci for (i = 0; i < count ; i++) { 3198c2ecf20Sopenharmony_ci paddr = __psp_pa(start[i].kaddr); 3208c2ecf20Sopenharmony_ci cmd->sg_list.buf[i].hi_addr = upper_32_bits(paddr); 3218c2ecf20Sopenharmony_ci cmd->sg_list.buf[i].low_addr = lower_32_bits(paddr); 3228c2ecf20Sopenharmony_ci cmd->sg_list.buf[i].size = start[i].size; 3238c2ecf20Sopenharmony_ci cmd->sg_list.size += cmd->sg_list.buf[i].size; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci pr_debug("buf[%d]:hi addr = 0x%x\n", i, 3268c2ecf20Sopenharmony_ci cmd->sg_list.buf[i].hi_addr); 3278c2ecf20Sopenharmony_ci pr_debug("buf[%d]:low addr = 0x%x\n", i, 3288c2ecf20Sopenharmony_ci cmd->sg_list.buf[i].low_addr); 3298c2ecf20Sopenharmony_ci pr_debug("buf[%d]:size = 0x%x\n", i, cmd->sg_list.buf[i].size); 3308c2ecf20Sopenharmony_ci pr_debug("list size = 0x%x\n", cmd->sg_list.size); 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci *buf_id = 0; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci ret = psp_tee_process_cmd(TEE_CMD_ID_MAP_SHARED_MEM, (void *)cmd, 3368c2ecf20Sopenharmony_ci sizeof(*cmd), &status); 3378c2ecf20Sopenharmony_ci if (!ret && !status) { 3388c2ecf20Sopenharmony_ci *buf_id = cmd->buf_id; 3398c2ecf20Sopenharmony_ci pr_debug("mapped buffer ID = 0x%x\n", *buf_id); 3408c2ecf20Sopenharmony_ci } else { 3418c2ecf20Sopenharmony_ci pr_err("map shared memory: status = 0x%x\n", status); 3428c2ecf20Sopenharmony_ci ret = -ENOMEM; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cifree_cmd: 3468c2ecf20Sopenharmony_ci kfree(cmd); 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci return ret; 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ciint handle_open_session(struct tee_ioctl_open_session_arg *arg, u32 *info, 3528c2ecf20Sopenharmony_ci struct tee_param *p) 3538c2ecf20Sopenharmony_ci{ 3548c2ecf20Sopenharmony_ci struct tee_cmd_open_session cmd = {0}; 3558c2ecf20Sopenharmony_ci int ret; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (!arg || !info || (!p && arg->num_params)) 3588c2ecf20Sopenharmony_ci return -EINVAL; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci arg->ret_origin = TEEC_ORIGIN_COMMS; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (arg->session == 0) { 3638c2ecf20Sopenharmony_ci arg->ret = TEEC_ERROR_GENERIC; 3648c2ecf20Sopenharmony_ci return -EINVAL; 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci ret = tee_params_to_amd_params(p, arg->num_params, &cmd.op); 3688c2ecf20Sopenharmony_ci if (ret) { 3698c2ecf20Sopenharmony_ci pr_err("invalid Params. Abort open session\n"); 3708c2ecf20Sopenharmony_ci arg->ret = TEEC_ERROR_BAD_PARAMETERS; 3718c2ecf20Sopenharmony_ci return ret; 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci cmd.ta_handle = get_ta_handle(arg->session); 3758c2ecf20Sopenharmony_ci *info = 0; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci ret = psp_tee_process_cmd(TEE_CMD_ID_OPEN_SESSION, (void *)&cmd, 3788c2ecf20Sopenharmony_ci sizeof(cmd), &arg->ret); 3798c2ecf20Sopenharmony_ci if (ret) { 3808c2ecf20Sopenharmony_ci arg->ret = TEEC_ERROR_COMMUNICATION; 3818c2ecf20Sopenharmony_ci } else { 3828c2ecf20Sopenharmony_ci ret = amd_params_to_tee_params(p, arg->num_params, &cmd.op); 3838c2ecf20Sopenharmony_ci if (unlikely(ret)) { 3848c2ecf20Sopenharmony_ci pr_err("open session: failed to copy output\n"); 3858c2ecf20Sopenharmony_ci arg->ret = TEEC_ERROR_GENERIC; 3868c2ecf20Sopenharmony_ci return ret; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci arg->ret_origin = cmd.return_origin; 3898c2ecf20Sopenharmony_ci *info = cmd.session_info; 3908c2ecf20Sopenharmony_ci pr_debug("open session: session info = 0x%x\n", *info); 3918c2ecf20Sopenharmony_ci } 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci pr_debug("open session: ret = 0x%x RO = 0x%x\n", arg->ret, 3948c2ecf20Sopenharmony_ci arg->ret_origin); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci return ret; 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ciint handle_load_ta(void *data, u32 size, struct tee_ioctl_open_session_arg *arg) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci struct tee_cmd_unload_ta unload_cmd = {}; 4028c2ecf20Sopenharmony_ci struct tee_cmd_load_ta load_cmd = {}; 4038c2ecf20Sopenharmony_ci phys_addr_t blob; 4048c2ecf20Sopenharmony_ci int ret; 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci if (size == 0 || !data || !arg) 4078c2ecf20Sopenharmony_ci return -EINVAL; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci blob = __psp_pa(data); 4108c2ecf20Sopenharmony_ci if (blob & (PAGE_SIZE - 1)) { 4118c2ecf20Sopenharmony_ci pr_err("load TA: page unaligned. blob 0x%llx", blob); 4128c2ecf20Sopenharmony_ci return -EINVAL; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci load_cmd.hi_addr = upper_32_bits(blob); 4168c2ecf20Sopenharmony_ci load_cmd.low_addr = lower_32_bits(blob); 4178c2ecf20Sopenharmony_ci load_cmd.size = size; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci mutex_lock(&ta_refcount_mutex); 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci ret = psp_tee_process_cmd(TEE_CMD_ID_LOAD_TA, (void *)&load_cmd, 4228c2ecf20Sopenharmony_ci sizeof(load_cmd), &arg->ret); 4238c2ecf20Sopenharmony_ci if (ret) { 4248c2ecf20Sopenharmony_ci arg->ret_origin = TEEC_ORIGIN_COMMS; 4258c2ecf20Sopenharmony_ci arg->ret = TEEC_ERROR_COMMUNICATION; 4268c2ecf20Sopenharmony_ci } else { 4278c2ecf20Sopenharmony_ci arg->ret_origin = load_cmd.return_origin; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (arg->ret == TEEC_SUCCESS) { 4308c2ecf20Sopenharmony_ci ret = get_ta_refcount(load_cmd.ta_handle); 4318c2ecf20Sopenharmony_ci if (!ret) { 4328c2ecf20Sopenharmony_ci arg->ret_origin = TEEC_ORIGIN_COMMS; 4338c2ecf20Sopenharmony_ci arg->ret = TEEC_ERROR_OUT_OF_MEMORY; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci /* Unload the TA on error */ 4368c2ecf20Sopenharmony_ci unload_cmd.ta_handle = load_cmd.ta_handle; 4378c2ecf20Sopenharmony_ci psp_tee_process_cmd(TEE_CMD_ID_UNLOAD_TA, 4388c2ecf20Sopenharmony_ci (void *)&unload_cmd, 4398c2ecf20Sopenharmony_ci sizeof(unload_cmd), &ret); 4408c2ecf20Sopenharmony_ci } else { 4418c2ecf20Sopenharmony_ci set_session_id(load_cmd.ta_handle, 0, &arg->session); 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci mutex_unlock(&ta_refcount_mutex); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci pr_debug("load TA: TA handle = 0x%x, RO = 0x%x, ret = 0x%x\n", 4488c2ecf20Sopenharmony_ci load_cmd.ta_handle, arg->ret_origin, arg->ret); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci return 0; 4518c2ecf20Sopenharmony_ci} 452