1f97ae380SAleksandr Anisimov // SPDX-License-Identifier: BSD-2-Clause
2f97ae380SAleksandr Anisimov /*
3f97ae380SAleksandr Anisimov * Copyright (c) 2020, Open Mobile Platform LLC
4f97ae380SAleksandr Anisimov */
5f97ae380SAleksandr Anisimov
6f97ae380SAleksandr Anisimov #include <assert.h>
7f97ae380SAleksandr Anisimov #include <kernel/thread.h>
8*eb4a988aSJens Wiklander #include <kernel/user_access.h>
9f97ae380SAleksandr Anisimov #include <mm/mobj.h>
10f97ae380SAleksandr Anisimov #include <optee_rpc_cmd.h>
11f97ae380SAleksandr Anisimov #include <stddef.h>
12f97ae380SAleksandr Anisimov #include <stdint.h>
13f97ae380SAleksandr Anisimov #include <stdlib.h>
14f97ae380SAleksandr Anisimov #include <string.h>
15f97ae380SAleksandr Anisimov #include <tee/tee_supp_plugin_rpc.h>
16f97ae380SAleksandr Anisimov #include <tee/uuid.h>
17f97ae380SAleksandr Anisimov #include <trace.h>
18f97ae380SAleksandr Anisimov
tee_invoke_supp_plugin_rpc(const TEE_UUID * uuid,uint32_t cmd,uint32_t sub_cmd,void * buf_core,void * buf_user,size_t len,size_t * outlen)19f97ae380SAleksandr Anisimov TEE_Result tee_invoke_supp_plugin_rpc(const TEE_UUID *uuid, uint32_t cmd,
20*eb4a988aSJens Wiklander uint32_t sub_cmd, void *buf_core,
21*eb4a988aSJens Wiklander void *buf_user, size_t len,
22f97ae380SAleksandr Anisimov size_t *outlen)
23f97ae380SAleksandr Anisimov {
24f97ae380SAleksandr Anisimov TEE_Result res = TEE_ERROR_GENERIC;
25f97ae380SAleksandr Anisimov struct thread_param params[THREAD_RPC_MAX_NUM_PARAMS];
26f97ae380SAleksandr Anisimov uint32_t uuid_words[4] = { };
27f97ae380SAleksandr Anisimov void *va = NULL;
28f97ae380SAleksandr Anisimov struct mobj *mobj = NULL;
29f97ae380SAleksandr Anisimov
30f97ae380SAleksandr Anisimov /*
31f97ae380SAleksandr Anisimov * sizeof 'TEE_UUID' and array 'uuid_words' must be same size,
32f97ae380SAleksandr Anisimov * because 'tee_uuid_to_octets()' is used to copy variable
33f97ae380SAleksandr Anisimov * with one type to another.
34f97ae380SAleksandr Anisimov *
35f97ae380SAleksandr Anisimov * Array 'uuid_words' is used just for convenient work with
36f97ae380SAleksandr Anisimov * 'TEE_UUID' as with uint32_t values.
37f97ae380SAleksandr Anisimov */
38f97ae380SAleksandr Anisimov COMPILE_TIME_ASSERT(sizeof(TEE_UUID) == sizeof(uuid_words));
39f97ae380SAleksandr Anisimov
40*eb4a988aSJens Wiklander if (!uuid || (len && !buf_core && !buf_user) ||
41*eb4a988aSJens Wiklander (!len && (buf_core || buf_user)) || (buf_core && buf_user))
42f97ae380SAleksandr Anisimov return TEE_ERROR_BAD_PARAMETERS;
43f97ae380SAleksandr Anisimov
44f97ae380SAleksandr Anisimov if (len) {
45f97ae380SAleksandr Anisimov mobj = thread_rpc_alloc_payload(len);
46f97ae380SAleksandr Anisimov if (!mobj) {
47f97ae380SAleksandr Anisimov EMSG("can't create mobj for plugin data");
48f97ae380SAleksandr Anisimov return TEE_ERROR_OUT_OF_MEMORY;
49f97ae380SAleksandr Anisimov }
50f97ae380SAleksandr Anisimov
519c4aaf67SJens Wiklander va = mobj_get_va(mobj, 0, len);
52f97ae380SAleksandr Anisimov if (!va) {
53f97ae380SAleksandr Anisimov EMSG("can't get va from mobj");
54f97ae380SAleksandr Anisimov goto out;
55f97ae380SAleksandr Anisimov }
56f97ae380SAleksandr Anisimov
57*eb4a988aSJens Wiklander if (buf_core)
58*eb4a988aSJens Wiklander memcpy(va, buf_core, len);
59*eb4a988aSJens Wiklander if (buf_user) {
60*eb4a988aSJens Wiklander res = copy_from_user(va, buf_user, len);
61*eb4a988aSJens Wiklander if (res)
62*eb4a988aSJens Wiklander goto out;
63*eb4a988aSJens Wiklander }
64f97ae380SAleksandr Anisimov }
65f97ae380SAleksandr Anisimov
66f97ae380SAleksandr Anisimov tee_uuid_to_octets((uint8_t *)uuid_words, uuid);
67f97ae380SAleksandr Anisimov
68f97ae380SAleksandr Anisimov params[0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_SUPP_PLUGIN_INVOKE,
69f97ae380SAleksandr Anisimov uuid_words[0], uuid_words[1]);
70f97ae380SAleksandr Anisimov params[1] = THREAD_PARAM_VALUE(IN, uuid_words[2], uuid_words[3], cmd);
71f97ae380SAleksandr Anisimov params[2] = THREAD_PARAM_VALUE(INOUT, sub_cmd, 0, 0);
72f97ae380SAleksandr Anisimov params[3] = THREAD_PARAM_MEMREF(INOUT, mobj, 0, len);
73f97ae380SAleksandr Anisimov
74f97ae380SAleksandr Anisimov res = thread_rpc_cmd(OPTEE_RPC_CMD_SUPP_PLUGIN, 4, params);
75f97ae380SAleksandr Anisimov
76f97ae380SAleksandr Anisimov if (outlen)
77f97ae380SAleksandr Anisimov *outlen = params[2].u.value.b;
78f97ae380SAleksandr Anisimov
79*eb4a988aSJens Wiklander if (len && outlen && *outlen) {
80*eb4a988aSJens Wiklander if (buf_core)
81*eb4a988aSJens Wiklander memcpy(buf_core, va, *outlen <= len ? *outlen : len);
82*eb4a988aSJens Wiklander if (buf_user)
83*eb4a988aSJens Wiklander res = copy_to_user(buf_user, va, len);
84*eb4a988aSJens Wiklander }
85f97ae380SAleksandr Anisimov
86f97ae380SAleksandr Anisimov out:
87f97ae380SAleksandr Anisimov if (len)
88f97ae380SAleksandr Anisimov thread_rpc_free_payload(mobj);
89f97ae380SAleksandr Anisimov
90f97ae380SAleksandr Anisimov return res;
91f97ae380SAleksandr Anisimov }
92