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