Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: MIT
0002 /*
0003  * Copyright 2019 Advanced Micro Devices, Inc.
0004  */
0005 
0006 #include <linux/device.h>
0007 #include <linux/tee.h>
0008 #include <linux/tee_drv.h>
0009 #include <linux/psp-tee.h>
0010 #include <linux/slab.h>
0011 #include <linux/psp-sev.h>
0012 #include "amdtee_if.h"
0013 #include "amdtee_private.h"
0014 
0015 static int tee_params_to_amd_params(struct tee_param *tee, u32 count,
0016                     struct tee_operation *amd)
0017 {
0018     int i, ret = 0;
0019     u32 type;
0020 
0021     if (!count)
0022         return 0;
0023 
0024     if (!tee || !amd || count > TEE_MAX_PARAMS)
0025         return -EINVAL;
0026 
0027     amd->param_types = 0;
0028     for (i = 0; i < count; i++) {
0029         /* AMD TEE does not support meta parameter */
0030         if (tee[i].attr > TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT)
0031             return -EINVAL;
0032 
0033         amd->param_types |= ((tee[i].attr & 0xF) << i * 4);
0034     }
0035 
0036     for (i = 0; i < count; i++) {
0037         type = TEE_PARAM_TYPE_GET(amd->param_types, i);
0038         pr_debug("%s: type[%d] = 0x%x\n", __func__, i, type);
0039 
0040         if (type == TEE_OP_PARAM_TYPE_INVALID)
0041             return -EINVAL;
0042 
0043         if (type == TEE_OP_PARAM_TYPE_NONE)
0044             continue;
0045 
0046         /* It is assumed that all values are within 2^32-1 */
0047         if (type > TEE_OP_PARAM_TYPE_VALUE_INOUT) {
0048             u32 buf_id = get_buffer_id(tee[i].u.memref.shm);
0049 
0050             amd->params[i].mref.buf_id = buf_id;
0051             amd->params[i].mref.offset = tee[i].u.memref.shm_offs;
0052             amd->params[i].mref.size = tee[i].u.memref.size;
0053             pr_debug("%s: bufid[%d] = 0x%x, offset[%d] = 0x%x, size[%d] = 0x%x\n",
0054                  __func__,
0055                  i, amd->params[i].mref.buf_id,
0056                  i, amd->params[i].mref.offset,
0057                  i, amd->params[i].mref.size);
0058         } else {
0059             if (tee[i].u.value.c)
0060                 pr_warn("%s: Discarding value c", __func__);
0061 
0062             amd->params[i].val.a = tee[i].u.value.a;
0063             amd->params[i].val.b = tee[i].u.value.b;
0064             pr_debug("%s: a[%d] = 0x%x, b[%d] = 0x%x\n", __func__,
0065                  i, amd->params[i].val.a,
0066                  i, amd->params[i].val.b);
0067         }
0068     }
0069     return ret;
0070 }
0071 
0072 static int amd_params_to_tee_params(struct tee_param *tee, u32 count,
0073                     struct tee_operation *amd)
0074 {
0075     int i, ret = 0;
0076     u32 type;
0077 
0078     if (!count)
0079         return 0;
0080 
0081     if (!tee || !amd || count > TEE_MAX_PARAMS)
0082         return -EINVAL;
0083 
0084     /* Assumes amd->param_types is valid */
0085     for (i = 0; i < count; i++) {
0086         type = TEE_PARAM_TYPE_GET(amd->param_types, i);
0087         pr_debug("%s: type[%d] = 0x%x\n", __func__, i, type);
0088 
0089         if (type == TEE_OP_PARAM_TYPE_INVALID ||
0090             type > TEE_OP_PARAM_TYPE_MEMREF_INOUT)
0091             return -EINVAL;
0092 
0093         if (type == TEE_OP_PARAM_TYPE_NONE ||
0094             type == TEE_OP_PARAM_TYPE_VALUE_INPUT ||
0095             type == TEE_OP_PARAM_TYPE_MEMREF_INPUT)
0096             continue;
0097 
0098         /*
0099          * It is assumed that buf_id remains unchanged for
0100          * both open_session and invoke_cmd call
0101          */
0102         if (type > TEE_OP_PARAM_TYPE_MEMREF_INPUT) {
0103             tee[i].u.memref.shm_offs = amd->params[i].mref.offset;
0104             tee[i].u.memref.size = amd->params[i].mref.size;
0105             pr_debug("%s: bufid[%d] = 0x%x, offset[%d] = 0x%x, size[%d] = 0x%x\n",
0106                  __func__,
0107                  i, amd->params[i].mref.buf_id,
0108                  i, amd->params[i].mref.offset,
0109                  i, amd->params[i].mref.size);
0110         } else {
0111             /* field 'c' not supported by AMD TEE */
0112             tee[i].u.value.a = amd->params[i].val.a;
0113             tee[i].u.value.b = amd->params[i].val.b;
0114             tee[i].u.value.c = 0;
0115             pr_debug("%s: a[%d] = 0x%x, b[%d] = 0x%x\n",
0116                  __func__,
0117                  i, amd->params[i].val.a,
0118                  i, amd->params[i].val.b);
0119         }
0120     }
0121     return ret;
0122 }
0123 
0124 static DEFINE_MUTEX(ta_refcount_mutex);
0125 static LIST_HEAD(ta_list);
0126 
0127 static u32 get_ta_refcount(u32 ta_handle)
0128 {
0129     struct amdtee_ta_data *ta_data;
0130     u32 count = 0;
0131 
0132     /* Caller must hold a mutex */
0133     list_for_each_entry(ta_data, &ta_list, list_node)
0134         if (ta_data->ta_handle == ta_handle)
0135             return ++ta_data->refcount;
0136 
0137     ta_data = kzalloc(sizeof(*ta_data), GFP_KERNEL);
0138     if (ta_data) {
0139         ta_data->ta_handle = ta_handle;
0140         ta_data->refcount = 1;
0141         count = ta_data->refcount;
0142         list_add(&ta_data->list_node, &ta_list);
0143     }
0144 
0145     return count;
0146 }
0147 
0148 static u32 put_ta_refcount(u32 ta_handle)
0149 {
0150     struct amdtee_ta_data *ta_data;
0151     u32 count = 0;
0152 
0153     /* Caller must hold a mutex */
0154     list_for_each_entry(ta_data, &ta_list, list_node)
0155         if (ta_data->ta_handle == ta_handle) {
0156             count = --ta_data->refcount;
0157             if (count == 0) {
0158                 list_del(&ta_data->list_node);
0159                 kfree(ta_data);
0160                 break;
0161             }
0162         }
0163 
0164     return count;
0165 }
0166 
0167 int handle_unload_ta(u32 ta_handle)
0168 {
0169     struct tee_cmd_unload_ta cmd = {0};
0170     u32 status, count;
0171     int ret;
0172 
0173     if (!ta_handle)
0174         return -EINVAL;
0175 
0176     mutex_lock(&ta_refcount_mutex);
0177 
0178     count = put_ta_refcount(ta_handle);
0179 
0180     if (count) {
0181         pr_debug("unload ta: not unloading %u count %u\n",
0182              ta_handle, count);
0183         ret = -EBUSY;
0184         goto unlock;
0185     }
0186 
0187     cmd.ta_handle = ta_handle;
0188 
0189     ret = psp_tee_process_cmd(TEE_CMD_ID_UNLOAD_TA, (void *)&cmd,
0190                   sizeof(cmd), &status);
0191     if (!ret && status != 0) {
0192         pr_err("unload ta: status = 0x%x\n", status);
0193         ret = -EBUSY;
0194     } else {
0195         pr_debug("unloaded ta handle %u\n", ta_handle);
0196     }
0197 
0198 unlock:
0199     mutex_unlock(&ta_refcount_mutex);
0200     return ret;
0201 }
0202 
0203 int handle_close_session(u32 ta_handle, u32 info)
0204 {
0205     struct tee_cmd_close_session cmd = {0};
0206     u32 status;
0207     int ret;
0208 
0209     if (ta_handle == 0)
0210         return -EINVAL;
0211 
0212     cmd.ta_handle = ta_handle;
0213     cmd.session_info = info;
0214 
0215     ret = psp_tee_process_cmd(TEE_CMD_ID_CLOSE_SESSION, (void *)&cmd,
0216                   sizeof(cmd), &status);
0217     if (!ret && status != 0) {
0218         pr_err("close session: status = 0x%x\n", status);
0219         ret = -EBUSY;
0220     }
0221 
0222     return ret;
0223 }
0224 
0225 void handle_unmap_shmem(u32 buf_id)
0226 {
0227     struct tee_cmd_unmap_shared_mem cmd = {0};
0228     u32 status;
0229     int ret;
0230 
0231     cmd.buf_id = buf_id;
0232 
0233     ret = psp_tee_process_cmd(TEE_CMD_ID_UNMAP_SHARED_MEM, (void *)&cmd,
0234                   sizeof(cmd), &status);
0235     if (!ret)
0236         pr_debug("unmap shared memory: buf_id %u status = 0x%x\n",
0237              buf_id, status);
0238 }
0239 
0240 int handle_invoke_cmd(struct tee_ioctl_invoke_arg *arg, u32 sinfo,
0241               struct tee_param *p)
0242 {
0243     struct tee_cmd_invoke_cmd cmd = {0};
0244     int ret;
0245 
0246     if (!arg || (!p && arg->num_params))
0247         return -EINVAL;
0248 
0249     arg->ret_origin = TEEC_ORIGIN_COMMS;
0250 
0251     if (arg->session == 0) {
0252         arg->ret = TEEC_ERROR_BAD_PARAMETERS;
0253         return -EINVAL;
0254     }
0255 
0256     ret = tee_params_to_amd_params(p, arg->num_params, &cmd.op);
0257     if (ret) {
0258         pr_err("invalid Params. Abort invoke command\n");
0259         arg->ret = TEEC_ERROR_BAD_PARAMETERS;
0260         return ret;
0261     }
0262 
0263     cmd.ta_handle = get_ta_handle(arg->session);
0264     cmd.cmd_id = arg->func;
0265     cmd.session_info = sinfo;
0266 
0267     ret = psp_tee_process_cmd(TEE_CMD_ID_INVOKE_CMD, (void *)&cmd,
0268                   sizeof(cmd), &arg->ret);
0269     if (ret) {
0270         arg->ret = TEEC_ERROR_COMMUNICATION;
0271     } else {
0272         ret = amd_params_to_tee_params(p, arg->num_params, &cmd.op);
0273         if (unlikely(ret)) {
0274             pr_err("invoke command: failed to copy output\n");
0275             arg->ret = TEEC_ERROR_GENERIC;
0276             return ret;
0277         }
0278         arg->ret_origin = cmd.return_origin;
0279         pr_debug("invoke command: RO = 0x%x ret = 0x%x\n",
0280              arg->ret_origin, arg->ret);
0281     }
0282 
0283     return ret;
0284 }
0285 
0286 int handle_map_shmem(u32 count, struct shmem_desc *start, u32 *buf_id)
0287 {
0288     struct tee_cmd_map_shared_mem *cmd;
0289     phys_addr_t paddr;
0290     int ret, i;
0291     u32 status;
0292 
0293     if (!count || !start || !buf_id)
0294         return -EINVAL;
0295 
0296     cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
0297     if (!cmd)
0298         return -ENOMEM;
0299 
0300     /* Size must be page aligned */
0301     for (i = 0; i < count ; i++) {
0302         if (!start[i].kaddr || (start[i].size & (PAGE_SIZE - 1))) {
0303             ret = -EINVAL;
0304             goto free_cmd;
0305         }
0306 
0307         if ((u64)start[i].kaddr & (PAGE_SIZE - 1)) {
0308             pr_err("map shared memory: page unaligned. addr 0x%llx",
0309                    (u64)start[i].kaddr);
0310             ret = -EINVAL;
0311             goto free_cmd;
0312         }
0313     }
0314 
0315     cmd->sg_list.count = count;
0316 
0317     /* Create buffer list */
0318     for (i = 0; i < count ; i++) {
0319         paddr = __psp_pa(start[i].kaddr);
0320         cmd->sg_list.buf[i].hi_addr = upper_32_bits(paddr);
0321         cmd->sg_list.buf[i].low_addr = lower_32_bits(paddr);
0322         cmd->sg_list.buf[i].size = start[i].size;
0323         cmd->sg_list.size += cmd->sg_list.buf[i].size;
0324 
0325         pr_debug("buf[%d]:hi addr = 0x%x\n", i,
0326              cmd->sg_list.buf[i].hi_addr);
0327         pr_debug("buf[%d]:low addr = 0x%x\n", i,
0328              cmd->sg_list.buf[i].low_addr);
0329         pr_debug("buf[%d]:size = 0x%x\n", i, cmd->sg_list.buf[i].size);
0330         pr_debug("list size = 0x%x\n", cmd->sg_list.size);
0331     }
0332 
0333     *buf_id = 0;
0334 
0335     ret = psp_tee_process_cmd(TEE_CMD_ID_MAP_SHARED_MEM, (void *)cmd,
0336                   sizeof(*cmd), &status);
0337     if (!ret && !status) {
0338         *buf_id = cmd->buf_id;
0339         pr_debug("mapped buffer ID = 0x%x\n", *buf_id);
0340     } else {
0341         pr_err("map shared memory: status = 0x%x\n", status);
0342         ret = -ENOMEM;
0343     }
0344 
0345 free_cmd:
0346     kfree(cmd);
0347 
0348     return ret;
0349 }
0350 
0351 int handle_open_session(struct tee_ioctl_open_session_arg *arg, u32 *info,
0352             struct tee_param *p)
0353 {
0354     struct tee_cmd_open_session cmd = {0};
0355     int ret;
0356 
0357     if (!arg || !info || (!p && arg->num_params))
0358         return -EINVAL;
0359 
0360     arg->ret_origin = TEEC_ORIGIN_COMMS;
0361 
0362     if (arg->session == 0) {
0363         arg->ret = TEEC_ERROR_GENERIC;
0364         return -EINVAL;
0365     }
0366 
0367     ret = tee_params_to_amd_params(p, arg->num_params, &cmd.op);
0368     if (ret) {
0369         pr_err("invalid Params. Abort open session\n");
0370         arg->ret = TEEC_ERROR_BAD_PARAMETERS;
0371         return ret;
0372     }
0373 
0374     cmd.ta_handle = get_ta_handle(arg->session);
0375     *info = 0;
0376 
0377     ret = psp_tee_process_cmd(TEE_CMD_ID_OPEN_SESSION, (void *)&cmd,
0378                   sizeof(cmd), &arg->ret);
0379     if (ret) {
0380         arg->ret = TEEC_ERROR_COMMUNICATION;
0381     } else {
0382         ret = amd_params_to_tee_params(p, arg->num_params, &cmd.op);
0383         if (unlikely(ret)) {
0384             pr_err("open session: failed to copy output\n");
0385             arg->ret = TEEC_ERROR_GENERIC;
0386             return ret;
0387         }
0388         arg->ret_origin = cmd.return_origin;
0389         *info = cmd.session_info;
0390         pr_debug("open session: session info = 0x%x\n", *info);
0391     }
0392 
0393     pr_debug("open session: ret = 0x%x RO = 0x%x\n", arg->ret,
0394          arg->ret_origin);
0395 
0396     return ret;
0397 }
0398 
0399 int handle_load_ta(void *data, u32 size, struct tee_ioctl_open_session_arg *arg)
0400 {
0401     struct tee_cmd_unload_ta unload_cmd = {};
0402     struct tee_cmd_load_ta load_cmd = {};
0403     phys_addr_t blob;
0404     int ret;
0405 
0406     if (size == 0 || !data || !arg)
0407         return -EINVAL;
0408 
0409     blob = __psp_pa(data);
0410     if (blob & (PAGE_SIZE - 1)) {
0411         pr_err("load TA: page unaligned. blob 0x%llx", blob);
0412         return -EINVAL;
0413     }
0414 
0415     load_cmd.hi_addr = upper_32_bits(blob);
0416     load_cmd.low_addr = lower_32_bits(blob);
0417     load_cmd.size = size;
0418 
0419     mutex_lock(&ta_refcount_mutex);
0420 
0421     ret = psp_tee_process_cmd(TEE_CMD_ID_LOAD_TA, (void *)&load_cmd,
0422                   sizeof(load_cmd), &arg->ret);
0423     if (ret) {
0424         arg->ret_origin = TEEC_ORIGIN_COMMS;
0425         arg->ret = TEEC_ERROR_COMMUNICATION;
0426     } else if (arg->ret == TEEC_SUCCESS) {
0427         ret = get_ta_refcount(load_cmd.ta_handle);
0428         if (!ret) {
0429             arg->ret_origin = TEEC_ORIGIN_COMMS;
0430             arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
0431 
0432             /* Unload the TA on error */
0433             unload_cmd.ta_handle = load_cmd.ta_handle;
0434             psp_tee_process_cmd(TEE_CMD_ID_UNLOAD_TA,
0435                         (void *)&unload_cmd,
0436                         sizeof(unload_cmd), &ret);
0437         } else {
0438             set_session_id(load_cmd.ta_handle, 0, &arg->session);
0439         }
0440     }
0441     mutex_unlock(&ta_refcount_mutex);
0442 
0443     pr_debug("load TA: TA handle = 0x%x, RO = 0x%x, ret = 0x%x\n",
0444          load_cmd.ta_handle, arg->ret_origin, arg->ret);
0445 
0446     return 0;
0447 }