1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (c) 2015-2021, Linaro Limited |
4 | */ |
5 | |
6 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
7 | |
8 | #include <linux/delay.h> |
9 | #include <linux/i2c.h> |
10 | #include <linux/slab.h> |
11 | #include <linux/tee_drv.h> |
12 | #include "optee_private.h" |
13 | #include "optee_rpc_cmd.h" |
14 | |
15 | static void handle_rpc_func_cmd_get_time(struct optee_msg_arg *arg) |
16 | { |
17 | struct timespec64 ts; |
18 | |
19 | if (arg->num_params != 1) |
20 | goto bad; |
21 | if ((arg->params[0].attr & OPTEE_MSG_ATTR_TYPE_MASK) != |
22 | OPTEE_MSG_ATTR_TYPE_VALUE_OUTPUT) |
23 | goto bad; |
24 | |
25 | ktime_get_real_ts64(tv: &ts); |
26 | arg->params[0].u.value.a = ts.tv_sec; |
27 | arg->params[0].u.value.b = ts.tv_nsec; |
28 | |
29 | arg->ret = TEEC_SUCCESS; |
30 | return; |
31 | bad: |
32 | arg->ret = TEEC_ERROR_BAD_PARAMETERS; |
33 | } |
34 | |
35 | #if IS_REACHABLE(CONFIG_I2C) |
36 | static void handle_rpc_func_cmd_i2c_transfer(struct tee_context *ctx, |
37 | struct optee_msg_arg *arg) |
38 | { |
39 | struct optee *optee = tee_get_drvdata(teedev: ctx->teedev); |
40 | struct tee_param *params; |
41 | struct i2c_adapter *adapter; |
42 | struct i2c_msg msg = { }; |
43 | size_t i; |
44 | int ret = -EOPNOTSUPP; |
45 | u8 attr[] = { |
46 | TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, |
47 | TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INPUT, |
48 | TEE_IOCTL_PARAM_ATTR_TYPE_MEMREF_INOUT, |
49 | TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_OUTPUT, |
50 | }; |
51 | |
52 | if (arg->num_params != ARRAY_SIZE(attr)) { |
53 | arg->ret = TEEC_ERROR_BAD_PARAMETERS; |
54 | return; |
55 | } |
56 | |
57 | params = kmalloc_array(n: arg->num_params, size: sizeof(struct tee_param), |
58 | GFP_KERNEL); |
59 | if (!params) { |
60 | arg->ret = TEEC_ERROR_OUT_OF_MEMORY; |
61 | return; |
62 | } |
63 | |
64 | if (optee->ops->from_msg_param(optee, params, arg->num_params, |
65 | arg->params)) |
66 | goto bad; |
67 | |
68 | for (i = 0; i < arg->num_params; i++) { |
69 | if (params[i].attr != attr[i]) |
70 | goto bad; |
71 | } |
72 | |
73 | adapter = i2c_get_adapter(nr: params[0].u.value.b); |
74 | if (!adapter) |
75 | goto bad; |
76 | |
77 | if (params[1].u.value.a & OPTEE_RPC_I2C_FLAGS_TEN_BIT) { |
78 | if (!i2c_check_functionality(adap: adapter, |
79 | I2C_FUNC_10BIT_ADDR)) { |
80 | i2c_put_adapter(adap: adapter); |
81 | goto bad; |
82 | } |
83 | |
84 | msg.flags = I2C_M_TEN; |
85 | } |
86 | |
87 | msg.addr = params[0].u.value.c; |
88 | msg.buf = params[2].u.memref.shm->kaddr; |
89 | msg.len = params[2].u.memref.size; |
90 | |
91 | switch (params[0].u.value.a) { |
92 | case OPTEE_RPC_I2C_TRANSFER_RD: |
93 | msg.flags |= I2C_M_RD; |
94 | break; |
95 | case OPTEE_RPC_I2C_TRANSFER_WR: |
96 | break; |
97 | default: |
98 | i2c_put_adapter(adap: adapter); |
99 | goto bad; |
100 | } |
101 | |
102 | ret = i2c_transfer(adap: adapter, msgs: &msg, num: 1); |
103 | |
104 | if (ret < 0) { |
105 | arg->ret = TEEC_ERROR_COMMUNICATION; |
106 | } else { |
107 | params[3].u.value.a = msg.len; |
108 | if (optee->ops->to_msg_param(optee, arg->params, |
109 | arg->num_params, params)) |
110 | arg->ret = TEEC_ERROR_BAD_PARAMETERS; |
111 | else |
112 | arg->ret = TEEC_SUCCESS; |
113 | } |
114 | |
115 | i2c_put_adapter(adap: adapter); |
116 | kfree(objp: params); |
117 | return; |
118 | bad: |
119 | kfree(objp: params); |
120 | arg->ret = TEEC_ERROR_BAD_PARAMETERS; |
121 | } |
122 | #else |
123 | static void handle_rpc_func_cmd_i2c_transfer(struct tee_context *ctx, |
124 | struct optee_msg_arg *arg) |
125 | { |
126 | arg->ret = TEEC_ERROR_NOT_SUPPORTED; |
127 | } |
128 | #endif |
129 | |
130 | static void handle_rpc_func_cmd_wq(struct optee *optee, |
131 | struct optee_msg_arg *arg) |
132 | { |
133 | if (arg->num_params != 1) |
134 | goto bad; |
135 | |
136 | if ((arg->params[0].attr & OPTEE_MSG_ATTR_TYPE_MASK) != |
137 | OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) |
138 | goto bad; |
139 | |
140 | switch (arg->params[0].u.value.a) { |
141 | case OPTEE_RPC_NOTIFICATION_WAIT: |
142 | if (optee_notif_wait(optee, key: arg->params[0].u.value.b)) |
143 | goto bad; |
144 | break; |
145 | case OPTEE_RPC_NOTIFICATION_SEND: |
146 | if (optee_notif_send(optee, key: arg->params[0].u.value.b)) |
147 | goto bad; |
148 | break; |
149 | default: |
150 | goto bad; |
151 | } |
152 | |
153 | arg->ret = TEEC_SUCCESS; |
154 | return; |
155 | bad: |
156 | arg->ret = TEEC_ERROR_BAD_PARAMETERS; |
157 | } |
158 | |
159 | static void handle_rpc_func_cmd_wait(struct optee_msg_arg *arg) |
160 | { |
161 | u32 msec_to_wait; |
162 | |
163 | if (arg->num_params != 1) |
164 | goto bad; |
165 | |
166 | if ((arg->params[0].attr & OPTEE_MSG_ATTR_TYPE_MASK) != |
167 | OPTEE_MSG_ATTR_TYPE_VALUE_INPUT) |
168 | goto bad; |
169 | |
170 | msec_to_wait = arg->params[0].u.value.a; |
171 | |
172 | /* Go to interruptible sleep */ |
173 | msleep_interruptible(msecs: msec_to_wait); |
174 | |
175 | arg->ret = TEEC_SUCCESS; |
176 | return; |
177 | bad: |
178 | arg->ret = TEEC_ERROR_BAD_PARAMETERS; |
179 | } |
180 | |
181 | static void handle_rpc_supp_cmd(struct tee_context *ctx, struct optee *optee, |
182 | struct optee_msg_arg *arg) |
183 | { |
184 | struct tee_param *params; |
185 | |
186 | arg->ret_origin = TEEC_ORIGIN_COMMS; |
187 | |
188 | params = kmalloc_array(n: arg->num_params, size: sizeof(struct tee_param), |
189 | GFP_KERNEL); |
190 | if (!params) { |
191 | arg->ret = TEEC_ERROR_OUT_OF_MEMORY; |
192 | return; |
193 | } |
194 | |
195 | if (optee->ops->from_msg_param(optee, params, arg->num_params, |
196 | arg->params)) { |
197 | arg->ret = TEEC_ERROR_BAD_PARAMETERS; |
198 | goto out; |
199 | } |
200 | |
201 | arg->ret = optee_supp_thrd_req(ctx, func: arg->cmd, num_params: arg->num_params, param: params); |
202 | |
203 | if (optee->ops->to_msg_param(optee, arg->params, arg->num_params, |
204 | params)) |
205 | arg->ret = TEEC_ERROR_BAD_PARAMETERS; |
206 | out: |
207 | kfree(objp: params); |
208 | } |
209 | |
210 | struct tee_shm *optee_rpc_cmd_alloc_suppl(struct tee_context *ctx, size_t sz) |
211 | { |
212 | u32 ret; |
213 | struct tee_param param; |
214 | struct optee *optee = tee_get_drvdata(teedev: ctx->teedev); |
215 | struct tee_shm *shm; |
216 | |
217 | param.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT; |
218 | param.u.value.a = OPTEE_RPC_SHM_TYPE_APPL; |
219 | param.u.value.b = sz; |
220 | param.u.value.c = 0; |
221 | |
222 | ret = optee_supp_thrd_req(ctx, OPTEE_RPC_CMD_SHM_ALLOC, num_params: 1, param: ¶m); |
223 | if (ret) |
224 | return ERR_PTR(error: -ENOMEM); |
225 | |
226 | mutex_lock(&optee->supp.mutex); |
227 | /* Increases count as secure world doesn't have a reference */ |
228 | shm = tee_shm_get_from_id(ctx: optee->supp.ctx, id: param.u.value.c); |
229 | mutex_unlock(lock: &optee->supp.mutex); |
230 | return shm; |
231 | } |
232 | |
233 | void optee_rpc_cmd_free_suppl(struct tee_context *ctx, struct tee_shm *shm) |
234 | { |
235 | struct tee_param param; |
236 | |
237 | param.attr = TEE_IOCTL_PARAM_ATTR_TYPE_VALUE_INOUT; |
238 | param.u.value.a = OPTEE_RPC_SHM_TYPE_APPL; |
239 | param.u.value.b = tee_shm_get_id(shm); |
240 | param.u.value.c = 0; |
241 | |
242 | /* |
243 | * Match the tee_shm_get_from_id() in cmd_alloc_suppl() as secure |
244 | * world has released its reference. |
245 | * |
246 | * It's better to do this before sending the request to supplicant |
247 | * as we'd like to let the process doing the initial allocation to |
248 | * do release the last reference too in order to avoid stacking |
249 | * many pending fput() on the client process. This could otherwise |
250 | * happen if secure world does many allocate and free in a single |
251 | * invoke. |
252 | */ |
253 | tee_shm_put(shm); |
254 | |
255 | optee_supp_thrd_req(ctx, OPTEE_RPC_CMD_SHM_FREE, num_params: 1, param: ¶m); |
256 | } |
257 | |
258 | void optee_rpc_cmd(struct tee_context *ctx, struct optee *optee, |
259 | struct optee_msg_arg *arg) |
260 | { |
261 | switch (arg->cmd) { |
262 | case OPTEE_RPC_CMD_GET_TIME: |
263 | handle_rpc_func_cmd_get_time(arg); |
264 | break; |
265 | case OPTEE_RPC_CMD_NOTIFICATION: |
266 | handle_rpc_func_cmd_wq(optee, arg); |
267 | break; |
268 | case OPTEE_RPC_CMD_SUSPEND: |
269 | handle_rpc_func_cmd_wait(arg); |
270 | break; |
271 | case OPTEE_RPC_CMD_I2C_TRANSFER: |
272 | handle_rpc_func_cmd_i2c_transfer(ctx, arg); |
273 | break; |
274 | default: |
275 | handle_rpc_supp_cmd(ctx, optee, arg); |
276 | } |
277 | } |
278 | |
279 | |
280 | |