1757cc3e9SRijo Thomas // SPDX-License-Identifier: MIT
2757cc3e9SRijo Thomas /*
3757cc3e9SRijo Thomas * Copyright 2019 Advanced Micro Devices, Inc.
4757cc3e9SRijo Thomas */
5757cc3e9SRijo Thomas
6757cc3e9SRijo Thomas #include <linux/device.h>
7757cc3e9SRijo Thomas #include <linux/tee.h>
8757cc3e9SRijo Thomas #include <linux/tee_drv.h>
9757cc3e9SRijo Thomas #include <linux/psp-tee.h>
10757cc3e9SRijo Thomas #include <linux/slab.h>
11ae7d45fbSMario Limonciello #include <linux/psp.h>
12757cc3e9SRijo Thomas #include "amdtee_if.h"
13757cc3e9SRijo Thomas #include "amdtee_private.h"
14757cc3e9SRijo Thomas
tee_params_to_amd_params(struct tee_param * tee,u32 count,struct tee_operation * amd)15757cc3e9SRijo Thomas static int tee_params_to_amd_params(struct tee_param *tee, u32 count,
16757cc3e9SRijo Thomas struct tee_operation *amd)
17757cc3e9SRijo Thomas {
18757cc3e9SRijo Thomas int i, ret = 0;
19757cc3e9SRijo Thomas u32 type;
20757cc3e9SRijo Thomas
21757cc3e9SRijo Thomas if (!count)
22757cc3e9SRijo Thomas return 0;
23757cc3e9SRijo Thomas
24757cc3e9SRijo Thomas if (!tee || !amd || count > TEE_MAX_PARAMS)
25757cc3e9SRijo Thomas return -EINVAL;
26757cc3e9SRijo Thomas
27757cc3e9SRijo Thomas amd->param_types = 0;
28757cc3e9SRijo Thomas for (i = 0; i < count; i++) {
29757cc3e9SRijo Thomas /* AMD TEE does not support meta parameter */
30757cc3e9SRijo Thomas if (tee[i].attr > TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT)
31757cc3e9SRijo Thomas return -EINVAL;
32757cc3e9SRijo Thomas
33757cc3e9SRijo Thomas amd->param_types |= ((tee[i].attr & 0xF) << i * 4);
34757cc3e9SRijo Thomas }
35757cc3e9SRijo Thomas
36757cc3e9SRijo Thomas for (i = 0; i < count; i++) {
37757cc3e9SRijo Thomas type = TEE_PARAM_TYPE_GET(amd->param_types, i);
38757cc3e9SRijo Thomas pr_debug("%s: type[%d] = 0x%x\n", __func__, i, type);
39757cc3e9SRijo Thomas
40757cc3e9SRijo Thomas if (type == TEE_OP_PARAM_TYPE_INVALID)
41757cc3e9SRijo Thomas return -EINVAL;
42757cc3e9SRijo Thomas
43757cc3e9SRijo Thomas if (type == TEE_OP_PARAM_TYPE_NONE)
44757cc3e9SRijo Thomas continue;
45757cc3e9SRijo Thomas
46757cc3e9SRijo Thomas /* It is assumed that all values are within 2^32-1 */
47757cc3e9SRijo Thomas if (type > TEE_OP_PARAM_TYPE_VALUE_INOUT) {
48757cc3e9SRijo Thomas u32 buf_id = get_buffer_id(tee[i].u.memref.shm);
49757cc3e9SRijo Thomas
50757cc3e9SRijo Thomas amd->params[i].mref.buf_id = buf_id;
51757cc3e9SRijo Thomas amd->params[i].mref.offset = tee[i].u.memref.shm_offs;
52757cc3e9SRijo Thomas amd->params[i].mref.size = tee[i].u.memref.size;
53757cc3e9SRijo Thomas pr_debug("%s: bufid[%d] = 0x%x, offset[%d] = 0x%x, size[%d] = 0x%x\n",
54757cc3e9SRijo Thomas __func__,
55757cc3e9SRijo Thomas i, amd->params[i].mref.buf_id,
56757cc3e9SRijo Thomas i, amd->params[i].mref.offset,
57757cc3e9SRijo Thomas i, amd->params[i].mref.size);
58757cc3e9SRijo Thomas } else {
59757cc3e9SRijo Thomas if (tee[i].u.value.c)
60757cc3e9SRijo Thomas pr_warn("%s: Discarding value c", __func__);
61757cc3e9SRijo Thomas
62757cc3e9SRijo Thomas amd->params[i].val.a = tee[i].u.value.a;
63757cc3e9SRijo Thomas amd->params[i].val.b = tee[i].u.value.b;
64757cc3e9SRijo Thomas pr_debug("%s: a[%d] = 0x%x, b[%d] = 0x%x\n", __func__,
65757cc3e9SRijo Thomas i, amd->params[i].val.a,
66757cc3e9SRijo Thomas i, amd->params[i].val.b);
67757cc3e9SRijo Thomas }
68757cc3e9SRijo Thomas }
69757cc3e9SRijo Thomas return ret;
70757cc3e9SRijo Thomas }
71757cc3e9SRijo Thomas
amd_params_to_tee_params(struct tee_param * tee,u32 count,struct tee_operation * amd)72757cc3e9SRijo Thomas static int amd_params_to_tee_params(struct tee_param *tee, u32 count,
73757cc3e9SRijo Thomas struct tee_operation *amd)
74757cc3e9SRijo Thomas {
75757cc3e9SRijo Thomas int i, ret = 0;
76757cc3e9SRijo Thomas u32 type;
77757cc3e9SRijo Thomas
78757cc3e9SRijo Thomas if (!count)
79757cc3e9SRijo Thomas return 0;
80757cc3e9SRijo Thomas
81757cc3e9SRijo Thomas if (!tee || !amd || count > TEE_MAX_PARAMS)
82757cc3e9SRijo Thomas return -EINVAL;
83757cc3e9SRijo Thomas
84757cc3e9SRijo Thomas /* Assumes amd->param_types is valid */
85757cc3e9SRijo Thomas for (i = 0; i < count; i++) {
86757cc3e9SRijo Thomas type = TEE_PARAM_TYPE_GET(amd->param_types, i);
87757cc3e9SRijo Thomas pr_debug("%s: type[%d] = 0x%x\n", __func__, i, type);
88757cc3e9SRijo Thomas
89757cc3e9SRijo Thomas if (type == TEE_OP_PARAM_TYPE_INVALID ||
90757cc3e9SRijo Thomas type > TEE_OP_PARAM_TYPE_MEMREF_INOUT)
91757cc3e9SRijo Thomas return -EINVAL;
92757cc3e9SRijo Thomas
93757cc3e9SRijo Thomas if (type == TEE_OP_PARAM_TYPE_NONE ||
94757cc3e9SRijo Thomas type == TEE_OP_PARAM_TYPE_VALUE_INPUT ||
95757cc3e9SRijo Thomas type == TEE_OP_PARAM_TYPE_MEMREF_INPUT)
96757cc3e9SRijo Thomas continue;
97757cc3e9SRijo Thomas
98757cc3e9SRijo Thomas /*
99757cc3e9SRijo Thomas * It is assumed that buf_id remains unchanged for
100757cc3e9SRijo Thomas * both open_session and invoke_cmd call
101757cc3e9SRijo Thomas */
102757cc3e9SRijo Thomas if (type > TEE_OP_PARAM_TYPE_MEMREF_INPUT) {
103757cc3e9SRijo Thomas tee[i].u.memref.shm_offs = amd->params[i].mref.offset;
104757cc3e9SRijo Thomas tee[i].u.memref.size = amd->params[i].mref.size;
105757cc3e9SRijo Thomas pr_debug("%s: bufid[%d] = 0x%x, offset[%d] = 0x%x, size[%d] = 0x%x\n",
106757cc3e9SRijo Thomas __func__,
107757cc3e9SRijo Thomas i, amd->params[i].mref.buf_id,
108757cc3e9SRijo Thomas i, amd->params[i].mref.offset,
109757cc3e9SRijo Thomas i, amd->params[i].mref.size);
110757cc3e9SRijo Thomas } else {
111757cc3e9SRijo Thomas /* field 'c' not supported by AMD TEE */
112757cc3e9SRijo Thomas tee[i].u.value.a = amd->params[i].val.a;
113757cc3e9SRijo Thomas tee[i].u.value.b = amd->params[i].val.b;
114757cc3e9SRijo Thomas tee[i].u.value.c = 0;
115757cc3e9SRijo Thomas pr_debug("%s: a[%d] = 0x%x, b[%d] = 0x%x\n",
116757cc3e9SRijo Thomas __func__,
117757cc3e9SRijo Thomas i, amd->params[i].val.a,
118757cc3e9SRijo Thomas i, amd->params[i].val.b);
119757cc3e9SRijo Thomas }
120757cc3e9SRijo Thomas }
121757cc3e9SRijo Thomas return ret;
122757cc3e9SRijo Thomas }
123757cc3e9SRijo Thomas
1249f015b37SRijo Thomas static DEFINE_MUTEX(ta_refcount_mutex);
125f7b67642SCai Huoqing static LIST_HEAD(ta_list);
1269f015b37SRijo Thomas
get_ta_refcount(u32 ta_handle)1279f015b37SRijo Thomas static u32 get_ta_refcount(u32 ta_handle)
1289f015b37SRijo Thomas {
1299f015b37SRijo Thomas struct amdtee_ta_data *ta_data;
1309f015b37SRijo Thomas u32 count = 0;
1319f015b37SRijo Thomas
1329f015b37SRijo Thomas /* Caller must hold a mutex */
1339f015b37SRijo Thomas list_for_each_entry(ta_data, &ta_list, list_node)
1349f015b37SRijo Thomas if (ta_data->ta_handle == ta_handle)
1359f015b37SRijo Thomas return ++ta_data->refcount;
1369f015b37SRijo Thomas
1379f015b37SRijo Thomas ta_data = kzalloc(sizeof(*ta_data), GFP_KERNEL);
1389f015b37SRijo Thomas if (ta_data) {
1399f015b37SRijo Thomas ta_data->ta_handle = ta_handle;
1409f015b37SRijo Thomas ta_data->refcount = 1;
1419f015b37SRijo Thomas count = ta_data->refcount;
1429f015b37SRijo Thomas list_add(&ta_data->list_node, &ta_list);
1439f015b37SRijo Thomas }
1449f015b37SRijo Thomas
1459f015b37SRijo Thomas return count;
1469f015b37SRijo Thomas }
1479f015b37SRijo Thomas
put_ta_refcount(u32 ta_handle)1489f015b37SRijo Thomas static u32 put_ta_refcount(u32 ta_handle)
1499f015b37SRijo Thomas {
1509f015b37SRijo Thomas struct amdtee_ta_data *ta_data;
1519f015b37SRijo Thomas u32 count = 0;
1529f015b37SRijo Thomas
1539f015b37SRijo Thomas /* Caller must hold a mutex */
1549f015b37SRijo Thomas list_for_each_entry(ta_data, &ta_list, list_node)
1559f015b37SRijo Thomas if (ta_data->ta_handle == ta_handle) {
1569f015b37SRijo Thomas count = --ta_data->refcount;
1579f015b37SRijo Thomas if (count == 0) {
1589f015b37SRijo Thomas list_del(&ta_data->list_node);
1599f015b37SRijo Thomas kfree(ta_data);
1609f015b37SRijo Thomas break;
1619f015b37SRijo Thomas }
1629f015b37SRijo Thomas }
1639f015b37SRijo Thomas
1649f015b37SRijo Thomas return count;
1659f015b37SRijo Thomas }
1669f015b37SRijo Thomas
handle_unload_ta(u32 ta_handle)167757cc3e9SRijo Thomas int handle_unload_ta(u32 ta_handle)
168757cc3e9SRijo Thomas {
169757cc3e9SRijo Thomas struct tee_cmd_unload_ta cmd = {0};
1709f015b37SRijo Thomas u32 status, count;
1715ae63958SRijo Thomas int ret;
172757cc3e9SRijo Thomas
173757cc3e9SRijo Thomas if (!ta_handle)
174757cc3e9SRijo Thomas return -EINVAL;
175757cc3e9SRijo Thomas
1769f015b37SRijo Thomas mutex_lock(&ta_refcount_mutex);
1779f015b37SRijo Thomas
1789f015b37SRijo Thomas count = put_ta_refcount(ta_handle);
1799f015b37SRijo Thomas
1809f015b37SRijo Thomas if (count) {
1819f015b37SRijo Thomas pr_debug("unload ta: not unloading %u count %u\n",
1829f015b37SRijo Thomas ta_handle, count);
1839f015b37SRijo Thomas ret = -EBUSY;
1849f015b37SRijo Thomas goto unlock;
1859f015b37SRijo Thomas }
1869f015b37SRijo Thomas
187757cc3e9SRijo Thomas cmd.ta_handle = ta_handle;
188757cc3e9SRijo Thomas
189757cc3e9SRijo Thomas ret = psp_tee_process_cmd(TEE_CMD_ID_UNLOAD_TA, (void *)&cmd,
190757cc3e9SRijo Thomas sizeof(cmd), &status);
191757cc3e9SRijo Thomas if (!ret && status != 0) {
192757cc3e9SRijo Thomas pr_err("unload ta: status = 0x%x\n", status);
193757cc3e9SRijo Thomas ret = -EBUSY;
1949f015b37SRijo Thomas } else {
1959f015b37SRijo Thomas pr_debug("unloaded ta handle %u\n", ta_handle);
196757cc3e9SRijo Thomas }
197757cc3e9SRijo Thomas
1989f015b37SRijo Thomas unlock:
1999f015b37SRijo Thomas mutex_unlock(&ta_refcount_mutex);
200757cc3e9SRijo Thomas return ret;
201757cc3e9SRijo Thomas }
202757cc3e9SRijo Thomas
handle_close_session(u32 ta_handle,u32 info)203757cc3e9SRijo Thomas int handle_close_session(u32 ta_handle, u32 info)
204757cc3e9SRijo Thomas {
205757cc3e9SRijo Thomas struct tee_cmd_close_session cmd = {0};
206757cc3e9SRijo Thomas u32 status;
2075ae63958SRijo Thomas int ret;
208757cc3e9SRijo Thomas
209757cc3e9SRijo Thomas if (ta_handle == 0)
210757cc3e9SRijo Thomas return -EINVAL;
211757cc3e9SRijo Thomas
212757cc3e9SRijo Thomas cmd.ta_handle = ta_handle;
213757cc3e9SRijo Thomas cmd.session_info = info;
214757cc3e9SRijo Thomas
215757cc3e9SRijo Thomas ret = psp_tee_process_cmd(TEE_CMD_ID_CLOSE_SESSION, (void *)&cmd,
216757cc3e9SRijo Thomas sizeof(cmd), &status);
217757cc3e9SRijo Thomas if (!ret && status != 0) {
218757cc3e9SRijo Thomas pr_err("close session: status = 0x%x\n", status);
219757cc3e9SRijo Thomas ret = -EBUSY;
220757cc3e9SRijo Thomas }
221757cc3e9SRijo Thomas
222757cc3e9SRijo Thomas return ret;
223757cc3e9SRijo Thomas }
224757cc3e9SRijo Thomas
handle_unmap_shmem(u32 buf_id)225757cc3e9SRijo Thomas void handle_unmap_shmem(u32 buf_id)
226757cc3e9SRijo Thomas {
227757cc3e9SRijo Thomas struct tee_cmd_unmap_shared_mem cmd = {0};
228757cc3e9SRijo Thomas u32 status;
2295ae63958SRijo Thomas int ret;
230757cc3e9SRijo Thomas
231757cc3e9SRijo Thomas cmd.buf_id = buf_id;
232757cc3e9SRijo Thomas
233757cc3e9SRijo Thomas ret = psp_tee_process_cmd(TEE_CMD_ID_UNMAP_SHARED_MEM, (void *)&cmd,
234757cc3e9SRijo Thomas sizeof(cmd), &status);
235757cc3e9SRijo Thomas if (!ret)
236757cc3e9SRijo Thomas pr_debug("unmap shared memory: buf_id %u status = 0x%x\n",
237757cc3e9SRijo Thomas buf_id, status);
238757cc3e9SRijo Thomas }
239757cc3e9SRijo Thomas
handle_invoke_cmd(struct tee_ioctl_invoke_arg * arg,u32 sinfo,struct tee_param * p)240757cc3e9SRijo Thomas int handle_invoke_cmd(struct tee_ioctl_invoke_arg *arg, u32 sinfo,
241757cc3e9SRijo Thomas struct tee_param *p)
242757cc3e9SRijo Thomas {
243757cc3e9SRijo Thomas struct tee_cmd_invoke_cmd cmd = {0};
2445ae63958SRijo Thomas int ret;
245757cc3e9SRijo Thomas
246757cc3e9SRijo Thomas if (!arg || (!p && arg->num_params))
247757cc3e9SRijo Thomas return -EINVAL;
248757cc3e9SRijo Thomas
249757cc3e9SRijo Thomas arg->ret_origin = TEEC_ORIGIN_COMMS;
250757cc3e9SRijo Thomas
251757cc3e9SRijo Thomas if (arg->session == 0) {
252757cc3e9SRijo Thomas arg->ret = TEEC_ERROR_BAD_PARAMETERS;
253757cc3e9SRijo Thomas return -EINVAL;
254757cc3e9SRijo Thomas }
255757cc3e9SRijo Thomas
256757cc3e9SRijo Thomas ret = tee_params_to_amd_params(p, arg->num_params, &cmd.op);
257757cc3e9SRijo Thomas if (ret) {
258757cc3e9SRijo Thomas pr_err("invalid Params. Abort invoke command\n");
259757cc3e9SRijo Thomas arg->ret = TEEC_ERROR_BAD_PARAMETERS;
260757cc3e9SRijo Thomas return ret;
261757cc3e9SRijo Thomas }
262757cc3e9SRijo Thomas
263757cc3e9SRijo Thomas cmd.ta_handle = get_ta_handle(arg->session);
264757cc3e9SRijo Thomas cmd.cmd_id = arg->func;
265757cc3e9SRijo Thomas cmd.session_info = sinfo;
266757cc3e9SRijo Thomas
267757cc3e9SRijo Thomas ret = psp_tee_process_cmd(TEE_CMD_ID_INVOKE_CMD, (void *)&cmd,
268757cc3e9SRijo Thomas sizeof(cmd), &arg->ret);
269757cc3e9SRijo Thomas if (ret) {
270757cc3e9SRijo Thomas arg->ret = TEEC_ERROR_COMMUNICATION;
271757cc3e9SRijo Thomas } else {
272757cc3e9SRijo Thomas ret = amd_params_to_tee_params(p, arg->num_params, &cmd.op);
273757cc3e9SRijo Thomas if (unlikely(ret)) {
274757cc3e9SRijo Thomas pr_err("invoke command: failed to copy output\n");
275757cc3e9SRijo Thomas arg->ret = TEEC_ERROR_GENERIC;
276757cc3e9SRijo Thomas return ret;
277757cc3e9SRijo Thomas }
278757cc3e9SRijo Thomas arg->ret_origin = cmd.return_origin;
279757cc3e9SRijo Thomas pr_debug("invoke command: RO = 0x%x ret = 0x%x\n",
280757cc3e9SRijo Thomas arg->ret_origin, arg->ret);
281757cc3e9SRijo Thomas }
282757cc3e9SRijo Thomas
283757cc3e9SRijo Thomas return ret;
284757cc3e9SRijo Thomas }
285757cc3e9SRijo Thomas
handle_map_shmem(u32 count,struct shmem_desc * start,u32 * buf_id)286757cc3e9SRijo Thomas int handle_map_shmem(u32 count, struct shmem_desc *start, u32 *buf_id)
287757cc3e9SRijo Thomas {
288757cc3e9SRijo Thomas struct tee_cmd_map_shared_mem *cmd;
289757cc3e9SRijo Thomas phys_addr_t paddr;
2905ae63958SRijo Thomas int ret, i;
291757cc3e9SRijo Thomas u32 status;
292757cc3e9SRijo Thomas
293757cc3e9SRijo Thomas if (!count || !start || !buf_id)
294757cc3e9SRijo Thomas return -EINVAL;
295757cc3e9SRijo Thomas
296757cc3e9SRijo Thomas cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
297757cc3e9SRijo Thomas if (!cmd)
298757cc3e9SRijo Thomas return -ENOMEM;
299757cc3e9SRijo Thomas
300757cc3e9SRijo Thomas /* Size must be page aligned */
301757cc3e9SRijo Thomas for (i = 0; i < count ; i++) {
302757cc3e9SRijo Thomas if (!start[i].kaddr || (start[i].size & (PAGE_SIZE - 1))) {
303757cc3e9SRijo Thomas ret = -EINVAL;
304757cc3e9SRijo Thomas goto free_cmd;
305757cc3e9SRijo Thomas }
306757cc3e9SRijo Thomas
307757cc3e9SRijo Thomas if ((u64)start[i].kaddr & (PAGE_SIZE - 1)) {
308757cc3e9SRijo Thomas pr_err("map shared memory: page unaligned. addr 0x%llx",
309757cc3e9SRijo Thomas (u64)start[i].kaddr);
310757cc3e9SRijo Thomas ret = -EINVAL;
311757cc3e9SRijo Thomas goto free_cmd;
312757cc3e9SRijo Thomas }
313757cc3e9SRijo Thomas }
314757cc3e9SRijo Thomas
315757cc3e9SRijo Thomas cmd->sg_list.count = count;
316757cc3e9SRijo Thomas
317757cc3e9SRijo Thomas /* Create buffer list */
318757cc3e9SRijo Thomas for (i = 0; i < count ; i++) {
319757cc3e9SRijo Thomas paddr = __psp_pa(start[i].kaddr);
320757cc3e9SRijo Thomas cmd->sg_list.buf[i].hi_addr = upper_32_bits(paddr);
321757cc3e9SRijo Thomas cmd->sg_list.buf[i].low_addr = lower_32_bits(paddr);
322757cc3e9SRijo Thomas cmd->sg_list.buf[i].size = start[i].size;
323757cc3e9SRijo Thomas cmd->sg_list.size += cmd->sg_list.buf[i].size;
324757cc3e9SRijo Thomas
325757cc3e9SRijo Thomas pr_debug("buf[%d]:hi addr = 0x%x\n", i,
326757cc3e9SRijo Thomas cmd->sg_list.buf[i].hi_addr);
327757cc3e9SRijo Thomas pr_debug("buf[%d]:low addr = 0x%x\n", i,
328757cc3e9SRijo Thomas cmd->sg_list.buf[i].low_addr);
329757cc3e9SRijo Thomas pr_debug("buf[%d]:size = 0x%x\n", i, cmd->sg_list.buf[i].size);
330757cc3e9SRijo Thomas pr_debug("list size = 0x%x\n", cmd->sg_list.size);
331757cc3e9SRijo Thomas }
332757cc3e9SRijo Thomas
333757cc3e9SRijo Thomas *buf_id = 0;
334757cc3e9SRijo Thomas
335757cc3e9SRijo Thomas ret = psp_tee_process_cmd(TEE_CMD_ID_MAP_SHARED_MEM, (void *)cmd,
336757cc3e9SRijo Thomas sizeof(*cmd), &status);
337757cc3e9SRijo Thomas if (!ret && !status) {
338757cc3e9SRijo Thomas *buf_id = cmd->buf_id;
339757cc3e9SRijo Thomas pr_debug("mapped buffer ID = 0x%x\n", *buf_id);
340757cc3e9SRijo Thomas } else {
341757cc3e9SRijo Thomas pr_err("map shared memory: status = 0x%x\n", status);
342757cc3e9SRijo Thomas ret = -ENOMEM;
343757cc3e9SRijo Thomas }
344757cc3e9SRijo Thomas
345757cc3e9SRijo Thomas free_cmd:
346757cc3e9SRijo Thomas kfree(cmd);
347757cc3e9SRijo Thomas
348757cc3e9SRijo Thomas return ret;
349757cc3e9SRijo Thomas }
350757cc3e9SRijo Thomas
handle_open_session(struct tee_ioctl_open_session_arg * arg,u32 * info,struct tee_param * p)351757cc3e9SRijo Thomas int handle_open_session(struct tee_ioctl_open_session_arg *arg, u32 *info,
352757cc3e9SRijo Thomas struct tee_param *p)
353757cc3e9SRijo Thomas {
354757cc3e9SRijo Thomas struct tee_cmd_open_session cmd = {0};
3555ae63958SRijo Thomas int ret;
356757cc3e9SRijo Thomas
357757cc3e9SRijo Thomas if (!arg || !info || (!p && arg->num_params))
358757cc3e9SRijo Thomas return -EINVAL;
359757cc3e9SRijo Thomas
360757cc3e9SRijo Thomas arg->ret_origin = TEEC_ORIGIN_COMMS;
361757cc3e9SRijo Thomas
362757cc3e9SRijo Thomas if (arg->session == 0) {
363757cc3e9SRijo Thomas arg->ret = TEEC_ERROR_GENERIC;
364757cc3e9SRijo Thomas return -EINVAL;
365757cc3e9SRijo Thomas }
366757cc3e9SRijo Thomas
367757cc3e9SRijo Thomas ret = tee_params_to_amd_params(p, arg->num_params, &cmd.op);
368757cc3e9SRijo Thomas if (ret) {
369757cc3e9SRijo Thomas pr_err("invalid Params. Abort open session\n");
370757cc3e9SRijo Thomas arg->ret = TEEC_ERROR_BAD_PARAMETERS;
371757cc3e9SRijo Thomas return ret;
372757cc3e9SRijo Thomas }
373757cc3e9SRijo Thomas
374757cc3e9SRijo Thomas cmd.ta_handle = get_ta_handle(arg->session);
375757cc3e9SRijo Thomas *info = 0;
376757cc3e9SRijo Thomas
377757cc3e9SRijo Thomas ret = psp_tee_process_cmd(TEE_CMD_ID_OPEN_SESSION, (void *)&cmd,
378757cc3e9SRijo Thomas sizeof(cmd), &arg->ret);
379757cc3e9SRijo Thomas if (ret) {
380757cc3e9SRijo Thomas arg->ret = TEEC_ERROR_COMMUNICATION;
381757cc3e9SRijo Thomas } else {
382757cc3e9SRijo Thomas ret = amd_params_to_tee_params(p, arg->num_params, &cmd.op);
383757cc3e9SRijo Thomas if (unlikely(ret)) {
384757cc3e9SRijo Thomas pr_err("open session: failed to copy output\n");
385757cc3e9SRijo Thomas arg->ret = TEEC_ERROR_GENERIC;
386757cc3e9SRijo Thomas return ret;
387757cc3e9SRijo Thomas }
388757cc3e9SRijo Thomas arg->ret_origin = cmd.return_origin;
389757cc3e9SRijo Thomas *info = cmd.session_info;
390757cc3e9SRijo Thomas pr_debug("open session: session info = 0x%x\n", *info);
391757cc3e9SRijo Thomas }
392757cc3e9SRijo Thomas
393757cc3e9SRijo Thomas pr_debug("open session: ret = 0x%x RO = 0x%x\n", arg->ret,
394757cc3e9SRijo Thomas arg->ret_origin);
395757cc3e9SRijo Thomas
396757cc3e9SRijo Thomas return ret;
397757cc3e9SRijo Thomas }
398757cc3e9SRijo Thomas
handle_load_ta(void * data,u32 size,struct tee_ioctl_open_session_arg * arg)399757cc3e9SRijo Thomas int handle_load_ta(void *data, u32 size, struct tee_ioctl_open_session_arg *arg)
400757cc3e9SRijo Thomas {
4019f015b37SRijo Thomas struct tee_cmd_unload_ta unload_cmd = {};
4029f015b37SRijo Thomas struct tee_cmd_load_ta load_cmd = {};
403757cc3e9SRijo Thomas phys_addr_t blob;
4045ae63958SRijo Thomas int ret;
405757cc3e9SRijo Thomas
406757cc3e9SRijo Thomas if (size == 0 || !data || !arg)
407757cc3e9SRijo Thomas return -EINVAL;
408757cc3e9SRijo Thomas
409757cc3e9SRijo Thomas blob = __psp_pa(data);
410757cc3e9SRijo Thomas if (blob & (PAGE_SIZE - 1)) {
411757cc3e9SRijo Thomas pr_err("load TA: page unaligned. blob 0x%llx", blob);
412757cc3e9SRijo Thomas return -EINVAL;
413757cc3e9SRijo Thomas }
414757cc3e9SRijo Thomas
4159f015b37SRijo Thomas load_cmd.hi_addr = upper_32_bits(blob);
4169f015b37SRijo Thomas load_cmd.low_addr = lower_32_bits(blob);
4179f015b37SRijo Thomas load_cmd.size = size;
418757cc3e9SRijo Thomas
4199f015b37SRijo Thomas mutex_lock(&ta_refcount_mutex);
4209f015b37SRijo Thomas
4219f015b37SRijo Thomas ret = psp_tee_process_cmd(TEE_CMD_ID_LOAD_TA, (void *)&load_cmd,
4229f015b37SRijo Thomas sizeof(load_cmd), &arg->ret);
423757cc3e9SRijo Thomas if (ret) {
424757cc3e9SRijo Thomas arg->ret_origin = TEEC_ORIGIN_COMMS;
425757cc3e9SRijo Thomas arg->ret = TEEC_ERROR_COMMUNICATION;
426*436eeae0SRijo Thomas } else {
427*436eeae0SRijo Thomas arg->ret_origin = load_cmd.return_origin;
428*436eeae0SRijo Thomas
429*436eeae0SRijo Thomas if (arg->ret == TEEC_SUCCESS) {
4309f015b37SRijo Thomas ret = get_ta_refcount(load_cmd.ta_handle);
4319f015b37SRijo Thomas if (!ret) {
4329f015b37SRijo Thomas arg->ret_origin = TEEC_ORIGIN_COMMS;
4339f015b37SRijo Thomas arg->ret = TEEC_ERROR_OUT_OF_MEMORY;
4349f015b37SRijo Thomas
4359f015b37SRijo Thomas /* Unload the TA on error */
4369f015b37SRijo Thomas unload_cmd.ta_handle = load_cmd.ta_handle;
4379f015b37SRijo Thomas psp_tee_process_cmd(TEE_CMD_ID_UNLOAD_TA,
4389f015b37SRijo Thomas (void *)&unload_cmd,
4399f015b37SRijo Thomas sizeof(unload_cmd), &ret);
440757cc3e9SRijo Thomas } else {
4419f015b37SRijo Thomas set_session_id(load_cmd.ta_handle, 0, &arg->session);
442757cc3e9SRijo Thomas }
4439f015b37SRijo Thomas }
444*436eeae0SRijo Thomas }
4459f015b37SRijo Thomas mutex_unlock(&ta_refcount_mutex);
446757cc3e9SRijo Thomas
447757cc3e9SRijo Thomas pr_debug("load TA: TA handle = 0x%x, RO = 0x%x, ret = 0x%x\n",
4489f015b37SRijo Thomas load_cmd.ta_handle, arg->ret_origin, arg->ret);
449757cc3e9SRijo Thomas
450757cc3e9SRijo Thomas return 0;
451757cc3e9SRijo Thomas }
452