blob: 2f3355c7b77d5d04245f082facc11086463f3ad1 [file] [log] [blame]
Jens Wiklanderc7b443a2018-09-25 16:40:18 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018 Linaro Limited
4 */
5#include <common.h>
6#include <dm.h>
7#include <sandboxtee.h>
8#include <tee.h>
9#include <tee/optee_ta_avb.h>
10
11/*
12 * The sandbox tee driver tries to emulate a generic Trusted Exectution
13 * Environment (TEE) with the Trusted Application (TA) OPTEE_TA_AVB
14 * available.
15 */
16
Igor Opaniuk78b0b9d2019-04-09 15:38:14 +020017static const u32 pstorage_max = 16;
Jens Wiklanderc7b443a2018-09-25 16:40:18 +020018/**
19 * struct ta_entry - TA entries
20 * @uuid: UUID of an emulated TA
21 * @open_session Called when a session is openened to the TA
22 * @invoke_func Called when a function in the TA is to be invoked
23 *
24 * This struct is used to register TAs in this sandbox emulation of a TEE.
25 */
26struct ta_entry {
27 struct tee_optee_ta_uuid uuid;
Igor Opaniuk78b0b9d2019-04-09 15:38:14 +020028 u32 (*open_session)(struct udevice *dev, uint num_params,
29 struct tee_param *params);
30 u32 (*invoke_func)(struct udevice *dev,
31 u32 func, uint num_params,
32 struct tee_param *params);
Jens Wiklanderc7b443a2018-09-25 16:40:18 +020033};
34
35#ifdef CONFIG_OPTEE_TA_AVB
36static u32 get_attr(uint n, uint num_params, struct tee_param *params)
37{
38 if (n >= num_params)
39 return TEE_PARAM_ATTR_TYPE_NONE;
40
41 return params[n].attr;
42}
43
44static u32 check_params(u8 p0, u8 p1, u8 p2, u8 p3, uint num_params,
45 struct tee_param *params)
46{
47 u8 p[] = { p0, p1, p2, p3};
48 uint n;
49
50 for (n = 0; n < ARRAY_SIZE(p); n++)
51 if (p[n] != get_attr(n, num_params, params))
52 goto bad_params;
53
54 for (; n < num_params; n++)
55 if (get_attr(n, num_params, params))
56 goto bad_params;
57
58 return TEE_SUCCESS;
59
60bad_params:
61 printf("Bad param attrs\n");
62
63 return TEE_ERROR_BAD_PARAMETERS;
64}
65
Igor Opaniuk78b0b9d2019-04-09 15:38:14 +020066static u32 ta_avb_open_session(struct udevice *dev, uint num_params,
67 struct tee_param *params)
Jens Wiklanderc7b443a2018-09-25 16:40:18 +020068{
69 /*
70 * We don't expect additional parameters when opening a session to
71 * this TA.
72 */
73 return check_params(TEE_PARAM_ATTR_TYPE_NONE, TEE_PARAM_ATTR_TYPE_NONE,
74 TEE_PARAM_ATTR_TYPE_NONE, TEE_PARAM_ATTR_TYPE_NONE,
75 num_params, params);
76}
77
Igor Opaniuk78b0b9d2019-04-09 15:38:14 +020078static u32 ta_avb_invoke_func(struct udevice *dev, u32 func, uint num_params,
Jens Wiklanderc7b443a2018-09-25 16:40:18 +020079 struct tee_param *params)
80{
Igor Opaniuk78b0b9d2019-04-09 15:38:14 +020081 struct sandbox_tee_state *state = dev_get_priv(dev);
82 ENTRY e, *ep;
83 char *name;
Jens Wiklanderc7b443a2018-09-25 16:40:18 +020084 u32 res;
85 uint slot;
86 u64 val;
Igor Opaniuk78b0b9d2019-04-09 15:38:14 +020087 char *value;
88 u32 value_sz;
Jens Wiklanderc7b443a2018-09-25 16:40:18 +020089
90 switch (func) {
91 case TA_AVB_CMD_READ_ROLLBACK_INDEX:
92 res = check_params(TEE_PARAM_ATTR_TYPE_VALUE_INPUT,
93 TEE_PARAM_ATTR_TYPE_VALUE_OUTPUT,
94 TEE_PARAM_ATTR_TYPE_NONE,
95 TEE_PARAM_ATTR_TYPE_NONE,
96 num_params, params);
97 if (res)
98 return res;
99
100 slot = params[0].u.value.a;
Igor Opaniuk78b0b9d2019-04-09 15:38:14 +0200101 if (slot >= ARRAY_SIZE(state->ta_avb_rollback_indexes)) {
Jens Wiklanderc7b443a2018-09-25 16:40:18 +0200102 printf("Rollback index slot out of bounds %u\n", slot);
103 return TEE_ERROR_BAD_PARAMETERS;
104 }
105
Igor Opaniuk78b0b9d2019-04-09 15:38:14 +0200106 val = state->ta_avb_rollback_indexes[slot];
Jens Wiklanderc7b443a2018-09-25 16:40:18 +0200107 params[1].u.value.a = val >> 32;
108 params[1].u.value.b = val;
109 return TEE_SUCCESS;
110
111 case TA_AVB_CMD_WRITE_ROLLBACK_INDEX:
112 res = check_params(TEE_PARAM_ATTR_TYPE_VALUE_INPUT,
113 TEE_PARAM_ATTR_TYPE_VALUE_INPUT,
114 TEE_PARAM_ATTR_TYPE_NONE,
115 TEE_PARAM_ATTR_TYPE_NONE,
116 num_params, params);
117 if (res)
118 return res;
119
120 slot = params[0].u.value.a;
Igor Opaniuk78b0b9d2019-04-09 15:38:14 +0200121 if (slot >= ARRAY_SIZE(state->ta_avb_rollback_indexes)) {
Jens Wiklanderc7b443a2018-09-25 16:40:18 +0200122 printf("Rollback index slot out of bounds %u\n", slot);
123 return TEE_ERROR_BAD_PARAMETERS;
124 }
125
126 val = (u64)params[1].u.value.a << 32 | params[1].u.value.b;
Igor Opaniuk78b0b9d2019-04-09 15:38:14 +0200127 if (val < state->ta_avb_rollback_indexes[slot])
Jens Wiklanderc7b443a2018-09-25 16:40:18 +0200128 return TEE_ERROR_SECURITY;
129
Igor Opaniuk78b0b9d2019-04-09 15:38:14 +0200130 state->ta_avb_rollback_indexes[slot] = val;
Jens Wiklanderc7b443a2018-09-25 16:40:18 +0200131 return TEE_SUCCESS;
132
133 case TA_AVB_CMD_READ_LOCK_STATE:
134 res = check_params(TEE_PARAM_ATTR_TYPE_VALUE_OUTPUT,
135 TEE_PARAM_ATTR_TYPE_NONE,
136 TEE_PARAM_ATTR_TYPE_NONE,
137 TEE_PARAM_ATTR_TYPE_NONE,
138 num_params, params);
139 if (res)
140 return res;
141
Igor Opaniuk78b0b9d2019-04-09 15:38:14 +0200142 params[0].u.value.a = state->ta_avb_lock_state;
Jens Wiklanderc7b443a2018-09-25 16:40:18 +0200143 return TEE_SUCCESS;
144
145 case TA_AVB_CMD_WRITE_LOCK_STATE:
146 res = check_params(TEE_PARAM_ATTR_TYPE_VALUE_INPUT,
147 TEE_PARAM_ATTR_TYPE_NONE,
148 TEE_PARAM_ATTR_TYPE_NONE,
149 TEE_PARAM_ATTR_TYPE_NONE,
150 num_params, params);
151 if (res)
152 return res;
153
Igor Opaniuk78b0b9d2019-04-09 15:38:14 +0200154 if (state->ta_avb_lock_state != params[0].u.value.a) {
155 state->ta_avb_lock_state = params[0].u.value.a;
156 memset(state->ta_avb_rollback_indexes, 0,
157 sizeof(state->ta_avb_rollback_indexes));
Jens Wiklanderc7b443a2018-09-25 16:40:18 +0200158 }
159
160 return TEE_SUCCESS;
Igor Opaniuk78b0b9d2019-04-09 15:38:14 +0200161 case TA_AVB_CMD_READ_PERSIST_VALUE:
162 res = check_params(TEE_PARAM_ATTR_TYPE_MEMREF_INPUT,
163 TEE_PARAM_ATTR_TYPE_MEMREF_INOUT,
164 TEE_PARAM_ATTR_TYPE_NONE,
165 TEE_PARAM_ATTR_TYPE_NONE,
166 num_params, params);
167 if (res)
168 return res;
169
170 name = params[0].u.memref.shm->addr;
171
172 value = params[1].u.memref.shm->addr;
173 value_sz = params[1].u.memref.size;
174
175 e.key = name;
176 e.data = NULL;
177 hsearch_r(e, FIND, &ep, &state->pstorage_htab, 0);
178 if (!ep)
179 return TEE_ERROR_ITEM_NOT_FOUND;
180
Igor Opaniukce32c022019-05-06 12:07:31 +0300181 value_sz = strlen(ep->data) + 1;
Igor Opaniuk78b0b9d2019-04-09 15:38:14 +0200182 memcpy(value, ep->data, value_sz);
183
184 return TEE_SUCCESS;
185 case TA_AVB_CMD_WRITE_PERSIST_VALUE:
186 res = check_params(TEE_PARAM_ATTR_TYPE_MEMREF_INPUT,
187 TEE_PARAM_ATTR_TYPE_MEMREF_INPUT,
188 TEE_PARAM_ATTR_TYPE_NONE,
189 TEE_PARAM_ATTR_TYPE_NONE,
190 num_params, params);
191 if (res)
192 return res;
193
194 name = params[0].u.memref.shm->addr;
195
196 value = params[1].u.memref.shm->addr;
197 value_sz = params[1].u.memref.size;
198
199 e.key = name;
200 e.data = NULL;
201 hsearch_r(e, FIND, &ep, &state->pstorage_htab, 0);
202 if (ep)
203 hdelete_r(e.key, &state->pstorage_htab, 0);
204
205 e.key = name;
206 e.data = value;
207 hsearch_r(e, ENTER, &ep, &state->pstorage_htab, 0);
208 if (!ep)
209 return TEE_ERROR_OUT_OF_MEMORY;
210
211 return TEE_SUCCESS;
Jens Wiklanderc7b443a2018-09-25 16:40:18 +0200212
213 default:
214 return TEE_ERROR_NOT_SUPPORTED;
215 }
216}
217#endif /*OPTEE_TA_AVB*/
218
219static const struct ta_entry ta_entries[] = {
220#ifdef CONFIG_OPTEE_TA_AVB
221 { .uuid = TA_AVB_UUID,
222 .open_session = ta_avb_open_session,
223 .invoke_func = ta_avb_invoke_func,
224 },
225#endif
226};
227
228static void sandbox_tee_get_version(struct udevice *dev,
229 struct tee_version_data *vers)
230{
231 struct tee_version_data v = {
232 .gen_caps = TEE_GEN_CAP_GP | TEE_GEN_CAP_REG_MEM,
233 };
234
235 *vers = v;
236}
237
238static int sandbox_tee_close_session(struct udevice *dev, u32 session)
239{
240 struct sandbox_tee_state *state = dev_get_priv(dev);
241
242 if (!state->ta || state->session != session)
243 return -EINVAL;
244
245 state->session = 0;
246 state->ta = NULL;
247
248 return 0;
249}
250
251static const struct ta_entry *find_ta_entry(u8 uuid[TEE_UUID_LEN])
252{
253 struct tee_optee_ta_uuid u;
254 uint n;
255
256 tee_optee_ta_uuid_from_octets(&u, uuid);
257
258 for (n = 0; n < ARRAY_SIZE(ta_entries); n++)
259 if (!memcmp(&u, &ta_entries[n].uuid, sizeof(u)))
260 return ta_entries + n;
261
262 return NULL;
263}
264
265static int sandbox_tee_open_session(struct udevice *dev,
266 struct tee_open_session_arg *arg,
267 uint num_params, struct tee_param *params)
268{
269 struct sandbox_tee_state *state = dev_get_priv(dev);
270 const struct ta_entry *ta;
271
272 if (state->ta) {
273 printf("A session is already open\n");
274 return -EBUSY;
275 }
276
277 ta = find_ta_entry(arg->uuid);
278 if (!ta) {
279 printf("Cannot find TA\n");
280 arg->ret = TEE_ERROR_ITEM_NOT_FOUND;
281 arg->ret_origin = TEE_ORIGIN_TEE;
282
283 return 0;
284 }
285
Igor Opaniuk78b0b9d2019-04-09 15:38:14 +0200286 arg->ret = ta->open_session(dev, num_params, params);
Jens Wiklanderc7b443a2018-09-25 16:40:18 +0200287 arg->ret_origin = TEE_ORIGIN_TRUSTED_APP;
288
289 if (!arg->ret) {
290 state->ta = (void *)ta;
291 state->session = 1;
292 arg->session = state->session;
293 } else {
294 printf("Cannot open session, TA returns error\n");
295 }
296
297 return 0;
298}
299
300static int sandbox_tee_invoke_func(struct udevice *dev,
301 struct tee_invoke_arg *arg,
302 uint num_params, struct tee_param *params)
303{
304 struct sandbox_tee_state *state = dev_get_priv(dev);
305 struct ta_entry *ta = state->ta;
306
307 if (!arg->session) {
308 printf("Missing session\n");
309 return -EINVAL;
310 }
311
312 if (!ta) {
313 printf("TA session not available\n");
314 return -EINVAL;
315 }
316
317 if (arg->session != state->session) {
318 printf("Session mismatch\n");
319 return -EINVAL;
320 }
321
Igor Opaniuk78b0b9d2019-04-09 15:38:14 +0200322 arg->ret = ta->invoke_func(dev, arg->func, num_params, params);
Jens Wiklanderc7b443a2018-09-25 16:40:18 +0200323 arg->ret_origin = TEE_ORIGIN_TRUSTED_APP;
324
325 return 0;
326}
327
328static int sandbox_tee_shm_register(struct udevice *dev, struct tee_shm *shm)
329{
330 struct sandbox_tee_state *state = dev_get_priv(dev);
331
332 state->num_shms++;
333
334 return 0;
335}
336
337static int sandbox_tee_shm_unregister(struct udevice *dev, struct tee_shm *shm)
338{
339 struct sandbox_tee_state *state = dev_get_priv(dev);
340
341 state->num_shms--;
342
343 return 0;
344}
345
Igor Opaniuk78b0b9d2019-04-09 15:38:14 +0200346static int sandbox_tee_remove(struct udevice *dev)
347{
348 struct sandbox_tee_state *state = dev_get_priv(dev);
349
350 hdestroy_r(&state->pstorage_htab);
351
352 return 0;
353}
354
355static int sandbox_tee_probe(struct udevice *dev)
356{
357 struct sandbox_tee_state *state = dev_get_priv(dev);
358 /*
359 * With this hastable we emulate persistent storage,
360 * which should contain persistent values
361 * between different sessions/command invocations.
362 */
363 if (!hcreate_r(pstorage_max, &state->pstorage_htab))
364 return TEE_ERROR_OUT_OF_MEMORY;
365
366 return 0;
367}
368
Jens Wiklanderc7b443a2018-09-25 16:40:18 +0200369static const struct tee_driver_ops sandbox_tee_ops = {
370 .get_version = sandbox_tee_get_version,
371 .open_session = sandbox_tee_open_session,
372 .close_session = sandbox_tee_close_session,
373 .invoke_func = sandbox_tee_invoke_func,
374 .shm_register = sandbox_tee_shm_register,
375 .shm_unregister = sandbox_tee_shm_unregister,
376};
377
378static const struct udevice_id sandbox_tee_match[] = {
379 { .compatible = "sandbox,tee" },
380 {},
381};
382
383U_BOOT_DRIVER(sandbox_tee) = {
384 .name = "sandbox_tee",
385 .id = UCLASS_TEE,
386 .of_match = sandbox_tee_match,
387 .ops = &sandbox_tee_ops,
388 .priv_auto_alloc_size = sizeof(struct sandbox_tee_state),
Igor Opaniuk78b0b9d2019-04-09 15:38:14 +0200389 .probe = sandbox_tee_probe,
390 .remove = sandbox_tee_remove,
Jens Wiklanderc7b443a2018-09-25 16:40:18 +0200391};