1 // SPDX-License-Identifier: MIT
3 * Copyright 2019 Advanced Micro Devices, Inc.
6 #include <linux/device.h>
8 #include <linux/tee_core.h>
9 #include <linux/psp-tee.h>
10 #include <linux/slab.h>
11 #include <linux/psp.h>
12 #include "amdtee_if.h"
13 #include "amdtee_private.h"
15 static int tee_params_to_amd_params(struct tee_param
*tee
, u32 count
,
16 struct tee_operation
*amd
)
24 if (!tee
|| !amd
|| count
> TEE_MAX_PARAMS
)
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
)
33 amd
->param_types
|= ((tee
[i
].attr
& 0xF) << i
* 4);
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
);
40 if (type
== TEE_OP_PARAM_TYPE_INVALID
)
43 if (type
== TEE_OP_PARAM_TYPE_NONE
)
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
);
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",
55 i
, amd
->params
[i
].mref
.buf_id
,
56 i
, amd
->params
[i
].mref
.offset
,
57 i
, amd
->params
[i
].mref
.size
);
60 pr_warn("%s: Discarding value c", __func__
);
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
);
72 static int amd_params_to_tee_params(struct tee_param
*tee
, u32 count
,
73 struct tee_operation
*amd
)
81 if (!tee
|| !amd
|| count
> TEE_MAX_PARAMS
)
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
);
89 if (type
== TEE_OP_PARAM_TYPE_INVALID
||
90 type
> TEE_OP_PARAM_TYPE_MEMREF_INOUT
)
93 if (type
== TEE_OP_PARAM_TYPE_NONE
||
94 type
== TEE_OP_PARAM_TYPE_VALUE_INPUT
||
95 type
== TEE_OP_PARAM_TYPE_MEMREF_INPUT
)
99 * It is assumed that buf_id remains unchanged for
100 * both open_session and invoke_cmd call
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",
107 i
, amd
->params
[i
].mref
.buf_id
,
108 i
, amd
->params
[i
].mref
.offset
,
109 i
, amd
->params
[i
].mref
.size
);
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",
117 i
, amd
->params
[i
].val
.a
,
118 i
, amd
->params
[i
].val
.b
);
124 static DEFINE_MUTEX(ta_refcount_mutex
);
125 static LIST_HEAD(ta_list
);
127 static u32
get_ta_refcount(u32 ta_handle
)
129 struct amdtee_ta_data
*ta_data
;
132 /* Caller must hold a mutex */
133 list_for_each_entry(ta_data
, &ta_list
, list_node
)
134 if (ta_data
->ta_handle
== ta_handle
)
135 return ++ta_data
->refcount
;
137 ta_data
= kzalloc(sizeof(*ta_data
), GFP_KERNEL
);
139 ta_data
->ta_handle
= ta_handle
;
140 ta_data
->refcount
= 1;
141 count
= ta_data
->refcount
;
142 list_add(&ta_data
->list_node
, &ta_list
);
148 static u32
put_ta_refcount(u32 ta_handle
)
150 struct amdtee_ta_data
*ta_data
;
153 /* Caller must hold a mutex */
154 list_for_each_entry(ta_data
, &ta_list
, list_node
)
155 if (ta_data
->ta_handle
== ta_handle
) {
156 count
= --ta_data
->refcount
;
158 list_del(&ta_data
->list_node
);
167 int handle_unload_ta(u32 ta_handle
)
169 struct tee_cmd_unload_ta cmd
= {0};
176 mutex_lock(&ta_refcount_mutex
);
178 count
= put_ta_refcount(ta_handle
);
181 pr_debug("unload ta: not unloading %u count %u\n",
187 cmd
.ta_handle
= ta_handle
;
189 ret
= psp_tee_process_cmd(TEE_CMD_ID_UNLOAD_TA
, (void *)&cmd
,
190 sizeof(cmd
), &status
);
191 if (!ret
&& status
!= 0) {
192 pr_err("unload ta: status = 0x%x\n", status
);
195 pr_debug("unloaded ta handle %u\n", ta_handle
);
199 mutex_unlock(&ta_refcount_mutex
);
203 int handle_close_session(u32 ta_handle
, u32 info
)
205 struct tee_cmd_close_session cmd
= {0};
212 cmd
.ta_handle
= ta_handle
;
213 cmd
.session_info
= info
;
215 ret
= psp_tee_process_cmd(TEE_CMD_ID_CLOSE_SESSION
, (void *)&cmd
,
216 sizeof(cmd
), &status
);
217 if (!ret
&& status
!= 0) {
218 pr_err("close session: status = 0x%x\n", status
);
225 void handle_unmap_shmem(u32 buf_id
)
227 struct tee_cmd_unmap_shared_mem cmd
= {0};
233 ret
= psp_tee_process_cmd(TEE_CMD_ID_UNMAP_SHARED_MEM
, (void *)&cmd
,
234 sizeof(cmd
), &status
);
236 pr_debug("unmap shared memory: buf_id %u status = 0x%x\n",
240 int handle_invoke_cmd(struct tee_ioctl_invoke_arg
*arg
, u32 sinfo
,
243 struct tee_cmd_invoke_cmd cmd
= {0};
246 if (!arg
|| (!p
&& arg
->num_params
))
249 arg
->ret_origin
= TEEC_ORIGIN_COMMS
;
251 if (arg
->session
== 0) {
252 arg
->ret
= TEEC_ERROR_BAD_PARAMETERS
;
256 ret
= tee_params_to_amd_params(p
, arg
->num_params
, &cmd
.op
);
258 pr_err("invalid Params. Abort invoke command\n");
259 arg
->ret
= TEEC_ERROR_BAD_PARAMETERS
;
263 cmd
.ta_handle
= get_ta_handle(arg
->session
);
264 cmd
.cmd_id
= arg
->func
;
265 cmd
.session_info
= sinfo
;
267 ret
= psp_tee_process_cmd(TEE_CMD_ID_INVOKE_CMD
, (void *)&cmd
,
268 sizeof(cmd
), &arg
->ret
);
270 arg
->ret
= TEEC_ERROR_COMMUNICATION
;
272 ret
= amd_params_to_tee_params(p
, arg
->num_params
, &cmd
.op
);
274 pr_err("invoke command: failed to copy output\n");
275 arg
->ret
= TEEC_ERROR_GENERIC
;
278 arg
->ret_origin
= cmd
.return_origin
;
279 pr_debug("invoke command: RO = 0x%x ret = 0x%x\n",
280 arg
->ret_origin
, arg
->ret
);
286 int handle_map_shmem(u32 count
, struct shmem_desc
*start
, u32
*buf_id
)
288 struct tee_cmd_map_shared_mem
*cmd
;
293 if (!count
|| !start
|| !buf_id
)
296 cmd
= kzalloc(sizeof(*cmd
), GFP_KERNEL
);
300 /* Size must be page aligned */
301 for (i
= 0; i
< count
; i
++) {
302 if (!start
[i
].kaddr
|| (start
[i
].size
& (PAGE_SIZE
- 1))) {
307 if ((u64
)start
[i
].kaddr
& (PAGE_SIZE
- 1)) {
308 pr_err("map shared memory: page unaligned. addr 0x%llx",
309 (u64
)start
[i
].kaddr
);
315 cmd
->sg_list
.count
= count
;
317 /* Create buffer list */
318 for (i
= 0; i
< count
; i
++) {
319 paddr
= __psp_pa(start
[i
].kaddr
);
320 cmd
->sg_list
.buf
[i
].hi_addr
= upper_32_bits(paddr
);
321 cmd
->sg_list
.buf
[i
].low_addr
= lower_32_bits(paddr
);
322 cmd
->sg_list
.buf
[i
].size
= start
[i
].size
;
323 cmd
->sg_list
.size
+= cmd
->sg_list
.buf
[i
].size
;
325 pr_debug("buf[%d]:hi addr = 0x%x\n", i
,
326 cmd
->sg_list
.buf
[i
].hi_addr
);
327 pr_debug("buf[%d]:low addr = 0x%x\n", i
,
328 cmd
->sg_list
.buf
[i
].low_addr
);
329 pr_debug("buf[%d]:size = 0x%x\n", i
, cmd
->sg_list
.buf
[i
].size
);
330 pr_debug("list size = 0x%x\n", cmd
->sg_list
.size
);
335 ret
= psp_tee_process_cmd(TEE_CMD_ID_MAP_SHARED_MEM
, (void *)cmd
,
336 sizeof(*cmd
), &status
);
337 if (!ret
&& !status
) {
338 *buf_id
= cmd
->buf_id
;
339 pr_debug("mapped buffer ID = 0x%x\n", *buf_id
);
341 pr_err("map shared memory: status = 0x%x\n", status
);
351 int handle_open_session(struct tee_ioctl_open_session_arg
*arg
, u32
*info
,
354 struct tee_cmd_open_session cmd
= {0};
357 if (!arg
|| !info
|| (!p
&& arg
->num_params
))
360 arg
->ret_origin
= TEEC_ORIGIN_COMMS
;
362 if (arg
->session
== 0) {
363 arg
->ret
= TEEC_ERROR_GENERIC
;
367 ret
= tee_params_to_amd_params(p
, arg
->num_params
, &cmd
.op
);
369 pr_err("invalid Params. Abort open session\n");
370 arg
->ret
= TEEC_ERROR_BAD_PARAMETERS
;
374 cmd
.ta_handle
= get_ta_handle(arg
->session
);
377 ret
= psp_tee_process_cmd(TEE_CMD_ID_OPEN_SESSION
, (void *)&cmd
,
378 sizeof(cmd
), &arg
->ret
);
380 arg
->ret
= TEEC_ERROR_COMMUNICATION
;
382 ret
= amd_params_to_tee_params(p
, arg
->num_params
, &cmd
.op
);
384 pr_err("open session: failed to copy output\n");
385 arg
->ret
= TEEC_ERROR_GENERIC
;
388 arg
->ret_origin
= cmd
.return_origin
;
389 *info
= cmd
.session_info
;
390 pr_debug("open session: session info = 0x%x\n", *info
);
393 pr_debug("open session: ret = 0x%x RO = 0x%x\n", arg
->ret
,
399 int handle_load_ta(void *data
, u32 size
, struct tee_ioctl_open_session_arg
*arg
)
401 struct tee_cmd_unload_ta unload_cmd
= {};
402 struct tee_cmd_load_ta load_cmd
= {};
406 if (size
== 0 || !data
|| !arg
)
409 blob
= __psp_pa(data
);
410 if (blob
& (PAGE_SIZE
- 1)) {
411 pr_err("load TA: page unaligned. blob 0x%llx", blob
);
415 load_cmd
.hi_addr
= upper_32_bits(blob
);
416 load_cmd
.low_addr
= lower_32_bits(blob
);
417 load_cmd
.size
= size
;
419 mutex_lock(&ta_refcount_mutex
);
421 ret
= psp_tee_process_cmd(TEE_CMD_ID_LOAD_TA
, (void *)&load_cmd
,
422 sizeof(load_cmd
), &arg
->ret
);
424 arg
->ret_origin
= TEEC_ORIGIN_COMMS
;
425 arg
->ret
= TEEC_ERROR_COMMUNICATION
;
427 arg
->ret_origin
= load_cmd
.return_origin
;
429 if (arg
->ret
== TEEC_SUCCESS
) {
430 ret
= get_ta_refcount(load_cmd
.ta_handle
);
432 arg
->ret_origin
= TEEC_ORIGIN_COMMS
;
433 arg
->ret
= TEEC_ERROR_OUT_OF_MEMORY
;
435 /* Unload the TA on error */
436 unload_cmd
.ta_handle
= load_cmd
.ta_handle
;
437 psp_tee_process_cmd(TEE_CMD_ID_UNLOAD_TA
,
439 sizeof(unload_cmd
), &ret
);
441 set_session_id(load_cmd
.ta_handle
, 0, &arg
->session
);
445 mutex_unlock(&ta_refcount_mutex
);
447 pr_debug("load TA: TA handle = 0x%x, RO = 0x%x, ret = 0x%x\n",
448 load_cmd
.ta_handle
, arg
->ret_origin
, arg
->ret
);