1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright 2019 Advanced Micro Devices, Inc. 4 */ 5 6 #include <linux/device.h> 7 #include <linux/tee.h> 8 #include <linux/tee_drv.h> 9 #include <linux/psp-tee.h> 10 #include <linux/slab.h> 11 #include <linux/psp-sev.h> 12 #include "amdtee_if.h" 13 #include "amdtee_private.h" 14 15 static int tee_params_to_amd_params(struct tee_param *tee, u32 count, 16 struct tee_operation *amd) 17 { 18 int i, ret = 0; 19 u32 type; 20 21 if (!count) 22 return 0; 23 24 if (!tee || !amd || count > TEE_MAX_PARAMS) 25 return -EINVAL; 26 27 amd->param_types = 0; 28 for (i = 0; i < count; i++) { 29 /* AMD TEE does not support meta parameter */ 30 if (tee[i].attr > TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT) 31 return -EINVAL; 32 33 amd->param_types |= ((tee[i].attr & 0xF) << i * 4); 34 } 35 36 for (i = 0; i < count; i++) { 37 type = TEE_PARAM_TYPE_GET(amd->param_types, i); 38 pr_debug("%s: type[%d] = 0x%x\n", __func__, i, type); 39 40 if (type == TEE_OP_PARAM_TYPE_INVALID) 41 return -EINVAL; 42 43 if (type == TEE_OP_PARAM_TYPE_NONE) 44 continue; 45 46 /* It is assumed that all values are within 2^32-1 */ 47 if (type > TEE_OP_PARAM_TYPE_VALUE_INOUT) { 48 u32 buf_id = get_buffer_id(tee[i].u.memref.shm); 49 50 amd->params[i].mref.buf_id = buf_id; 51 amd->params[i].mref.offset = tee[i].u.memref.shm_offs; 52 amd->params[i].mref.size = tee[i].u.memref.size; 53 pr_debug("%s: bufid[%d] = 0x%x, offset[%d] = 0x%x, size[%d] = 0x%x\n", 54 __func__, 55 i, amd->params[i].mref.buf_id, 56 i, amd->params[i].mref.offset, 57 i, amd->params[i].mref.size); 58 } else { 59 if (tee[i].u.value.c) 60 pr_warn("%s: Discarding value c", __func__); 61 62 amd->params[i].val.a = tee[i].u.value.a; 63 amd->params[i].val.b = tee[i].u.value.b; 64 pr_debug("%s: a[%d] = 0x%x, b[%d] = 0x%x\n", __func__, 65 i, amd->params[i].val.a, 66 i, amd->params[i].val.b); 67 } 68 } 69 return ret; 70 } 71 72 static int amd_params_to_tee_params(struct tee_param *tee, u32 count, 73 struct tee_operation *amd) 74 { 75 int i, ret = 0; 76 u32 type; 77 78 if (!count) 79 return 0; 80 81 if (!tee || !amd || count > TEE_MAX_PARAMS) 82 return -EINVAL; 83 84 /* Assumes amd->param_types is valid */ 85 for (i = 0; i < count; i++) { 86 type = TEE_PARAM_TYPE_GET(amd->param_types, i); 87 pr_debug("%s: type[%d] = 0x%x\n", __func__, i, type); 88 89 if (type == TEE_OP_PARAM_TYPE_INVALID || 90 type > TEE_OP_PARAM_TYPE_MEMREF_INOUT) 91 return -EINVAL; 92 93 if (type == TEE_OP_PARAM_TYPE_NONE || 94 type == TEE_OP_PARAM_TYPE_VALUE_INPUT || 95 type == TEE_OP_PARAM_TYPE_MEMREF_INPUT) 96 continue; 97 98 /* 99 * It is assumed that buf_id remains unchanged for 100 * both open_session and invoke_cmd call 101 */ 102 if (type > TEE_OP_PARAM_TYPE_MEMREF_INPUT) { 103 tee[i].u.memref.shm_offs = amd->params[i].mref.offset; 104 tee[i].u.memref.size = amd->params[i].mref.size; 105 pr_debug("%s: bufid[%d] = 0x%x, offset[%d] = 0x%x, size[%d] = 0x%x\n", 106 __func__, 107 i, amd->params[i].mref.buf_id, 108 i, amd->params[i].mref.offset, 109 i, amd->params[i].mref.size); 110 } else { 111 /* field 'c' not supported by AMD TEE */ 112 tee[i].u.value.a = amd->params[i].val.a; 113 tee[i].u.value.b = amd->params[i].val.b; 114 tee[i].u.value.c = 0; 115 pr_debug("%s: a[%d] = 0x%x, b[%d] = 0x%x\n", 116 __func__, 117 i, amd->params[i].val.a, 118 i, amd->params[i].val.b); 119 } 120 } 121 return ret; 122 } 123 124 int handle_unload_ta(u32 ta_handle) 125 { 126 struct tee_cmd_unload_ta cmd = {0}; 127 u32 status; 128 int ret; 129 130 if (!ta_handle) 131 return -EINVAL; 132 133 cmd.ta_handle = ta_handle; 134 135 ret = psp_tee_process_cmd(TEE_CMD_ID_UNLOAD_TA, (void *)&cmd, 136 sizeof(cmd), &status); 137 if (!ret && status != 0) { 138 pr_err("unload ta: status = 0x%x\n", status); 139 ret = -EBUSY; 140 } 141 142 return ret; 143 } 144 145 int handle_close_session(u32 ta_handle, u32 info) 146 { 147 struct tee_cmd_close_session cmd = {0}; 148 u32 status; 149 int ret; 150 151 if (ta_handle == 0) 152 return -EINVAL; 153 154 cmd.ta_handle = ta_handle; 155 cmd.session_info = info; 156 157 ret = psp_tee_process_cmd(TEE_CMD_ID_CLOSE_SESSION, (void *)&cmd, 158 sizeof(cmd), &status); 159 if (!ret && status != 0) { 160 pr_err("close session: status = 0x%x\n", status); 161 ret = -EBUSY; 162 } 163 164 return ret; 165 } 166 167 void handle_unmap_shmem(u32 buf_id) 168 { 169 struct tee_cmd_unmap_shared_mem cmd = {0}; 170 u32 status; 171 int ret; 172 173 cmd.buf_id = buf_id; 174 175 ret = psp_tee_process_cmd(TEE_CMD_ID_UNMAP_SHARED_MEM, (void *)&cmd, 176 sizeof(cmd), &status); 177 if (!ret) 178 pr_debug("unmap shared memory: buf_id %u status = 0x%x\n", 179 buf_id, status); 180 } 181 182 int handle_invoke_cmd(struct tee_ioctl_invoke_arg *arg, u32 sinfo, 183 struct tee_param *p) 184 { 185 struct tee_cmd_invoke_cmd cmd = {0}; 186 int ret; 187 188 if (!arg || (!p && arg->num_params)) 189 return -EINVAL; 190 191 arg->ret_origin = TEEC_ORIGIN_COMMS; 192 193 if (arg->session == 0) { 194 arg->ret = TEEC_ERROR_BAD_PARAMETERS; 195 return -EINVAL; 196 } 197 198 ret = tee_params_to_amd_params(p, arg->num_params, &cmd.op); 199 if (ret) { 200 pr_err("invalid Params. Abort invoke command\n"); 201 arg->ret = TEEC_ERROR_BAD_PARAMETERS; 202 return ret; 203 } 204 205 cmd.ta_handle = get_ta_handle(arg->session); 206 cmd.cmd_id = arg->func; 207 cmd.session_info = sinfo; 208 209 ret = psp_tee_process_cmd(TEE_CMD_ID_INVOKE_CMD, (void *)&cmd, 210 sizeof(cmd), &arg->ret); 211 if (ret) { 212 arg->ret = TEEC_ERROR_COMMUNICATION; 213 } else { 214 ret = amd_params_to_tee_params(p, arg->num_params, &cmd.op); 215 if (unlikely(ret)) { 216 pr_err("invoke command: failed to copy output\n"); 217 arg->ret = TEEC_ERROR_GENERIC; 218 return ret; 219 } 220 arg->ret_origin = cmd.return_origin; 221 pr_debug("invoke command: RO = 0x%x ret = 0x%x\n", 222 arg->ret_origin, arg->ret); 223 } 224 225 return ret; 226 } 227 228 int handle_map_shmem(u32 count, struct shmem_desc *start, u32 *buf_id) 229 { 230 struct tee_cmd_map_shared_mem *cmd; 231 phys_addr_t paddr; 232 int ret, i; 233 u32 status; 234 235 if (!count || !start || !buf_id) 236 return -EINVAL; 237 238 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); 239 if (!cmd) 240 return -ENOMEM; 241 242 /* Size must be page aligned */ 243 for (i = 0; i < count ; i++) { 244 if (!start[i].kaddr || (start[i].size & (PAGE_SIZE - 1))) { 245 ret = -EINVAL; 246 goto free_cmd; 247 } 248 249 if ((u64)start[i].kaddr & (PAGE_SIZE - 1)) { 250 pr_err("map shared memory: page unaligned. addr 0x%llx", 251 (u64)start[i].kaddr); 252 ret = -EINVAL; 253 goto free_cmd; 254 } 255 } 256 257 cmd->sg_list.count = count; 258 259 /* Create buffer list */ 260 for (i = 0; i < count ; i++) { 261 paddr = __psp_pa(start[i].kaddr); 262 cmd->sg_list.buf[i].hi_addr = upper_32_bits(paddr); 263 cmd->sg_list.buf[i].low_addr = lower_32_bits(paddr); 264 cmd->sg_list.buf[i].size = start[i].size; 265 cmd->sg_list.size += cmd->sg_list.buf[i].size; 266 267 pr_debug("buf[%d]:hi addr = 0x%x\n", i, 268 cmd->sg_list.buf[i].hi_addr); 269 pr_debug("buf[%d]:low addr = 0x%x\n", i, 270 cmd->sg_list.buf[i].low_addr); 271 pr_debug("buf[%d]:size = 0x%x\n", i, cmd->sg_list.buf[i].size); 272 pr_debug("list size = 0x%x\n", cmd->sg_list.size); 273 } 274 275 *buf_id = 0; 276 277 ret = psp_tee_process_cmd(TEE_CMD_ID_MAP_SHARED_MEM, (void *)cmd, 278 sizeof(*cmd), &status); 279 if (!ret && !status) { 280 *buf_id = cmd->buf_id; 281 pr_debug("mapped buffer ID = 0x%x\n", *buf_id); 282 } else { 283 pr_err("map shared memory: status = 0x%x\n", status); 284 ret = -ENOMEM; 285 } 286 287 free_cmd: 288 kfree(cmd); 289 290 return ret; 291 } 292 293 int handle_open_session(struct tee_ioctl_open_session_arg *arg, u32 *info, 294 struct tee_param *p) 295 { 296 struct tee_cmd_open_session cmd = {0}; 297 int ret; 298 299 if (!arg || !info || (!p && arg->num_params)) 300 return -EINVAL; 301 302 arg->ret_origin = TEEC_ORIGIN_COMMS; 303 304 if (arg->session == 0) { 305 arg->ret = TEEC_ERROR_GENERIC; 306 return -EINVAL; 307 } 308 309 ret = tee_params_to_amd_params(p, arg->num_params, &cmd.op); 310 if (ret) { 311 pr_err("invalid Params. Abort open session\n"); 312 arg->ret = TEEC_ERROR_BAD_PARAMETERS; 313 return ret; 314 } 315 316 cmd.ta_handle = get_ta_handle(arg->session); 317 *info = 0; 318 319 ret = psp_tee_process_cmd(TEE_CMD_ID_OPEN_SESSION, (void *)&cmd, 320 sizeof(cmd), &arg->ret); 321 if (ret) { 322 arg->ret = TEEC_ERROR_COMMUNICATION; 323 } else { 324 ret = amd_params_to_tee_params(p, arg->num_params, &cmd.op); 325 if (unlikely(ret)) { 326 pr_err("open session: failed to copy output\n"); 327 arg->ret = TEEC_ERROR_GENERIC; 328 return ret; 329 } 330 arg->ret_origin = cmd.return_origin; 331 *info = cmd.session_info; 332 pr_debug("open session: session info = 0x%x\n", *info); 333 } 334 335 pr_debug("open session: ret = 0x%x RO = 0x%x\n", arg->ret, 336 arg->ret_origin); 337 338 return ret; 339 } 340 341 int handle_load_ta(void *data, u32 size, struct tee_ioctl_open_session_arg *arg) 342 { 343 struct tee_cmd_load_ta cmd = {0}; 344 phys_addr_t blob; 345 int ret; 346 347 if (size == 0 || !data || !arg) 348 return -EINVAL; 349 350 blob = __psp_pa(data); 351 if (blob & (PAGE_SIZE - 1)) { 352 pr_err("load TA: page unaligned. blob 0x%llx", blob); 353 return -EINVAL; 354 } 355 356 cmd.hi_addr = upper_32_bits(blob); 357 cmd.low_addr = lower_32_bits(blob); 358 cmd.size = size; 359 360 ret = psp_tee_process_cmd(TEE_CMD_ID_LOAD_TA, (void *)&cmd, 361 sizeof(cmd), &arg->ret); 362 if (ret) { 363 arg->ret_origin = TEEC_ORIGIN_COMMS; 364 arg->ret = TEEC_ERROR_COMMUNICATION; 365 } else { 366 set_session_id(cmd.ta_handle, 0, &arg->session); 367 } 368 369 pr_debug("load TA: TA handle = 0x%x, RO = 0x%x, ret = 0x%x\n", 370 cmd.ta_handle, arg->ret_origin, arg->ret); 371 372 return 0; 373 } 374