1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
|
#include <linux/module.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/kthread.h>
#include <linux/uaccess.h>
#include "trustzone/tz_cross/trustzone.h"
#include "trustzone/tz_cross/ta_system.h"
#include "trustzone/kree/system.h"
#include "kree_int.h"
#include "sys_ipc.h"
#ifdef CONFIG_ARM64
#define ARM_SMC_CALLING_CONVENTION
#endif
static TZ_RESULT KREE_ServPuts(u32 op, u8 param[REE_SERVICE_BUFFER_SIZE]);
static TZ_RESULT KREE_ServUSleep(u32 op, u8 param[REE_SERVICE_BUFFER_SIZE]);
static TZ_RESULT tz_ree_service(u32 op, u8 param[REE_SERVICE_BUFFER_SIZE]);
static TZ_RESULT KREE_ServThread_Create (u32 op, u8 uparam[REE_SERVICE_BUFFER_SIZE]);
static const KREE_REE_Service_Func ree_service_funcs[] =
{
0,
KREE_ServPuts,
KREE_ServUSleep,
KREE_ServMutexCreate,
KREE_ServMutexDestroy,
KREE_ServMutexLock,
KREE_ServMutexUnlock,
KREE_ServMutexTrylock,
KREE_ServMutexIslock,
KREE_ServSemaphoreCreate,
KREE_ServSemaphoreDestroy,
KREE_ServSemaphoreDown,
KREE_ServSemaphoreDownTimeout,
KREE_ServSemaphoreDowntrylock,
KREE_ServSemaphoreUp,
#if 0
KREE_ServWaitqCreate,
KREE_ServWaitqDestroy,
KREE_ServWaitqWaitevent,
KREE_ServWaitqWaiteventTimeout,
KREE_ServWaitqWakeup,
#endif
KREE_ServRequestIrq,
KREE_ServEnableIrq,
KREE_ServEnableClock,
KREE_ServDisableClock,
KREE_ServThread_Create,
};
#define ree_service_funcs_num (sizeof(ree_service_funcs)/sizeof(ree_service_funcs[0]))
#if defined( ARM_SMC_CALLING_CONVENTION )
#define SMC_UNK 0xffffffff
#define SMC_MTEE_SERVICE_CALL (0x32000008)
static u32 tz_service_call(u32 handle, u32 op, u32 arg1, unsigned long arg2)
{
#ifdef CONFIG_ARM64
/* Reserve buffer for REE service call parameters */
u64 param[REE_SERVICE_BUFFER_SIZE / sizeof(u64)];
register u64 x0 asm("x0") = SMC_MTEE_SERVICE_CALL; //trusted os call function id for mtee
register u64 x1 asm("x1") = handle;
register u64 x2 asm("x2") = op;
register u64 x3 asm("x3") = arg1;
register u64 x4 asm("x4") = arg2;
register u64 x5 asm("x5") = (unsigned long)param;
asm volatile (
__asmeq("%0", "x0")
__asmeq("%1", "x1")
__asmeq("%2", "x2")
__asmeq("%3", "x3")
__asmeq("%4", "x0")
__asmeq("%5", "x1")
__asmeq("%6", "x2")
__asmeq("%7", "x3")
__asmeq("%8", "x4")
__asmeq("%9", "x5")
"smc #0\n" :
"=r"(x0), "=r"(x1), "=r"(x2), "=r" (x3) :
"r"(x0), "r"(x1), "r"(x2), "r" (x3), "r"(x4), "r"(x5) : "memory");
while (x1 != 0 && x0 != SMC_UNK) {
/* Need REE service */
/* r0 is the command, paramter in param buffer */
x1 = tz_ree_service(x2, (u8 *) param);
/* Work complete. Going Back to TZ again */
x0 = SMC_MTEE_SERVICE_CALL;
asm volatile (
__asmeq("%0", "x0")
__asmeq("%1", "x1")
__asmeq("%2", "x2")
__asmeq("%3", "x3")
__asmeq("%4", "x0")
__asmeq("%5", "x1")
__asmeq("%6", "x2")
__asmeq("%7", "x3")
"smc #0\n" :
"=r"(x0), "=r"(x1), "=r"(x2), "=r"(x3) :
"r"(x0), "r"(x1), "r"(x2), "r"(x3) : "memory");
}
return x3;
#else
/* Reserve buffer for REE service call parameters */
u32 param[REE_SERVICE_BUFFER_SIZE/sizeof(u32)];
register u32 r0 asm("r0") = SMC_MTEE_SERVICE_CALL; //trusted os call function id for mtee
register u32 r1 asm("r1") = handle;
register u32 r2 asm("r2") = op;
register u32 r3 asm("r3") = arg1;
register u32 r4 asm("r4") = arg2;
register u32 r5 asm("r5") = (unsigned long)param;
asm volatile(
".arch_extension sec\n"
__asmeq("%0", "r0")
__asmeq("%1", "r1")
__asmeq("%2", "r2")
__asmeq("%3", "r0")
__asmeq("%4", "r1")
__asmeq("%5", "r2")
__asmeq("%6", "r3")
__asmeq("%7", "r4")
__asmeq("%8", "r5")
"smc #0\n" :
"=r" (r0), "=r" (r1), "=r" (r2) :
"r" (r0), "r" (r1), "r" (r2), "r" (r3), "r" (r4), "r" (r5) :
"memory");
while (r1 != 0)
{
/* Need REE service */
/* r0 is the command, paramter in param buffer */
r1 = tz_ree_service(r0, (u8*)param);
/* Work complete. Going Back to TZ again */
r0 = SMC_MTEE_SERVICE_CALL;
asm volatile(
".arch_extension sec\n"
__asmeq("%0", "r0")
__asmeq("%1", "r1")
__asmeq("%2", "r2")
__asmeq("%3", "r0")
__asmeq("%4", "r1")
__asmeq("%5", "r5")
"smc #0\n" :
"=r" (r0), "=r" (r1), "=r" (r2) :
"r" (r0), "r" (r1), "r" (r5) :
"memory");
}
return r2;
#endif
}
TZ_RESULT KREE_TeeServiceCallNoCheck(KREE_SESSION_HANDLE handle,
uint32_t command,
uint32_t paramTypes,
MTEEC_PARAM param[4])
{
return (TZ_RESULT)tz_service_call(handle, command,
paramTypes, (unsigned long)param);
}
#else
static u32 tz_service_call(u32 handle, u32 op, u32 arg1, u32 arg2)
{ /* Reserve buffer for REE service call parameters */
u32 param[REE_SERVICE_BUFFER_SIZE / sizeof(u32)];
register u32 r0 asm("r0") = handle;
register u32 r1 asm("r1") = op;
register u32 r2 asm("r2") = arg1;
register u32 r3 asm("r3") = arg2;
register u32 r4 asm("r4") = (u32) param;
asm volatile (".arch_extension sec\n"
__asmeq("%0", "r0")
__asmeq("%1", "r1")
__asmeq("%2", "r0")
__asmeq("%3", "r1")
__asmeq("%4", "r2")
__asmeq("%5", "r3")
__asmeq("%6", "r4")
"smc #0\n" :
"=r"(r0), "=r"(r1) :
"r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4) :
"memory");
while (r1 != 0) {
/* Need REE service */
/* r0 is the command, paramter in param buffer */
r1 = tz_ree_service(r0, (u8 *) param);
/* Work complete. Going Back to TZ again */
r0 = 0xffffffff;
asm volatile (".arch_extension sec\n"
__asmeq("%0", "r0")
__asmeq("%1", "r1")
__asmeq("%2", "r0")
__asmeq("%3", "r1")
__asmeq("%4", "r4")
"smc #0\n" :
"=r"(r0), "=r"(r1) :
"r"(r0), "r"(r1), "r"(r4) :
"memory");
}
return r0;
}
TZ_RESULT KREE_TeeServiceCallNoCheck(KREE_SESSION_HANDLE handle,
uint32_t command, uint32_t paramTypes, MTEEC_PARAM param[4])
{
return (TZ_RESULT) tz_service_call(handle, command, paramTypes, (u32) param);
}
#endif
TZ_RESULT KREE_TeeServiceCall(KREE_SESSION_HANDLE handle, uint32_t command,
uint32_t paramTypes, MTEEC_PARAM oparam[4])
{
int i, do_copy = 0;
TZ_RESULT ret;
uint32_t tmpTypes;
MTEEC_PARAM param[4];
// Parameter processing.
memset(param, 0, sizeof(param));
tmpTypes = paramTypes;
for (i=0; tmpTypes; i++)
{
TZ_PARAM_TYPES type = tmpTypes & 0xff;
tmpTypes >>= 8;
switch (type)
{
case TZPT_VALUE_INPUT:
case TZPT_VALUE_INOUT:
case TZPT_VALUE_OUTPUT:
param[i] = oparam[i];
break;
case TZPT_MEM_INPUT:
case TZPT_MEM_OUTPUT:
case TZPT_MEM_INOUT:
// Check if point to kernel low memory
param[i] = oparam[i];
if (param[i].mem.buffer < (void *)PAGE_OFFSET ||
param[i].mem.buffer >= high_memory)
{
// No, we need to copy....
if (param[i].mem.size > TEE_PARAM_MEM_LIMIT)
{
param[i].mem.buffer = 0;
ret = TZ_RESULT_ERROR_OUT_OF_MEMORY;
goto error;
}
param[i].mem.buffer = kmalloc(param[i].mem.size, GFP_KERNEL);
if (!param[i].mem.buffer)
{
ret = TZ_RESULT_ERROR_OUT_OF_MEMORY;
goto error;
}
memcpy(param[i].mem.buffer, oparam[i].mem.buffer,
param[i].mem.size);
}
break;
case TZPT_MEMREF_INPUT:
case TZPT_MEMREF_OUTPUT:
case TZPT_MEMREF_INOUT:
// Check if share memory is valid.
// Not done yet.
param[i] = oparam[i];
break;
default:
// Bad format, return.
return TZ_RESULT_ERROR_BAD_FORMAT;
}
}
// Real call.
do_copy = 1;
ret = KREE_TeeServiceCallNoCheck(handle, command, paramTypes, param);
error:
tmpTypes = paramTypes;
for (i=0; tmpTypes; i++)
{
TZ_PARAM_TYPES type = tmpTypes & 0xff;
tmpTypes >>= 8;
switch (type)
{
case TZPT_VALUE_INOUT:
case TZPT_VALUE_OUTPUT:
oparam[i] = param[i];
break;
case TZPT_MEM_INPUT:
case TZPT_MEM_OUTPUT:
case TZPT_MEM_INOUT:
// Check if point to kernel memory
if (param[i].mem.buffer &&
(param[i].mem.buffer != oparam[i].mem.buffer))
{
if (type != TZPT_MEM_INPUT && do_copy)
memcpy(oparam[i].mem.buffer, param[i].mem.buffer,
param[i].mem.size);
kfree(param[i].mem.buffer);
}
break;
case TZPT_MEMREF_INPUT:
case TZPT_MEMREF_OUTPUT:
case TZPT_MEMREF_INOUT:
case TZPT_VALUE_INPUT:
default:
// Nothing to do
break;
}
}
return ret;
}
EXPORT_SYMBOL(KREE_TeeServiceCall);
static TZ_RESULT KREE_ServPuts(u32 op, u8 param[REE_SERVICE_BUFFER_SIZE])
{
param[REE_SERVICE_BUFFER_SIZE-1]=0;
printk(param);
return TZ_RESULT_SUCCESS;
}
static TZ_RESULT KREE_ServUSleep(u32 op, u8 uparam[REE_SERVICE_BUFFER_SIZE])
{
struct ree_service_usleep *param = (struct ree_service_usleep*)uparam;
usleep_range(param->ustime, param->ustime);
return TZ_RESULT_SUCCESS;
}
/* TEE Kthread create by REE service, TEE service call body
*/
static int kree_thread_function (void *arg)
{
MTEEC_PARAM param[4];
uint32_t paramTypes;
int ret;
struct REE_THREAD_INFO *info = (struct REE_THREAD_INFO *) arg;
paramTypes = TZ_ParamTypes2(TZPT_VALUE_INPUT, TZPT_VALUE_OUTPUT);
param[0].value.a = (uint32_t) info->handle;
// free parameter resource
kfree (info);
// create TEE kthread
ret = KREE_TeeServiceCall((KREE_SESSION_HANDLE)MTEE_SESSION_HANDLE_SYSTEM,
TZCMD_SYS_THREAD_CREATE,
paramTypes, param);
return ret;
}
/* TEE Kthread create by REE service
*/
static TZ_RESULT KREE_ServThread_Create (u32 op, u8 uparam[REE_SERVICE_BUFFER_SIZE])
{
struct REE_THREAD_INFO *info;
// get parameters
// the resource will be freed after the thread stops
info = (struct REE_THREAD_INFO *) kmalloc (sizeof (struct REE_THREAD_INFO), GFP_KERNEL);
if (info == NULL)
{
return TZ_RESULT_ERROR_OUT_OF_MEMORY;
}
memcpy (info, uparam, sizeof (struct REE_THREAD_INFO));
// create thread and run ...
if (!kthread_run (kree_thread_function, info, info->name))
{
return TZ_RESULT_ERROR_GENERIC;
}
return TZ_RESULT_SUCCESS;
}
static TZ_RESULT tz_ree_service(u32 op, u8 param[REE_SERVICE_BUFFER_SIZE])
{
KREE_REE_Service_Func func;
if (op >= ree_service_funcs_num)
return TZ_RESULT_ERROR_BAD_PARAMETERS;
func = ree_service_funcs[op];
if (!func)
return TZ_RESULT_ERROR_BAD_PARAMETERS;
return (func)(op, param);
}
TZ_RESULT KREE_InitTZ(void)
{
uint32_t paramTypes;
MTEEC_PARAM param[4];
TZ_RESULT ret;
paramTypes = TZPT_NONE;
ret = KREE_TeeServiceCall((KREE_SESSION_HANDLE)MTEE_SESSION_HANDLE_SYSTEM,
TZCMD_SYS_INIT,
paramTypes, param);
return ret;
}
TZ_RESULT KREE_CreateSession(const char *ta_uuid, KREE_SESSION_HANDLE *pHandle)
{
uint32_t paramTypes;
MTEEC_PARAM param[4];
TZ_RESULT ret;
if (!ta_uuid || !pHandle)
return TZ_RESULT_ERROR_BAD_PARAMETERS;
param[0].mem.buffer = (char*)ta_uuid;
param[0].mem.size = strlen(ta_uuid)+1;
paramTypes = TZ_ParamTypes2(TZPT_MEM_INPUT, TZPT_VALUE_OUTPUT);
ret = KREE_TeeServiceCall((KREE_SESSION_HANDLE)MTEE_SESSION_HANDLE_SYSTEM,
TZCMD_SYS_SESSION_CREATE,
paramTypes, param);
if (ret == TZ_RESULT_SUCCESS)
*pHandle = (KREE_SESSION_HANDLE)param[1].value.a;
return ret;
}
EXPORT_SYMBOL(KREE_CreateSession);
TZ_RESULT KREE_CloseSession(KREE_SESSION_HANDLE handle)
{
uint32_t paramTypes;
MTEEC_PARAM param[4];
TZ_RESULT ret;
param[0].value.a = (uint32_t)handle;
paramTypes = TZ_ParamTypes1(TZPT_VALUE_INPUT);
ret = KREE_TeeServiceCall((KREE_SESSION_HANDLE)MTEE_SESSION_HANDLE_SYSTEM,
TZCMD_SYS_SESSION_CLOSE,
paramTypes, param);
return ret;
}
EXPORT_SYMBOL(KREE_CloseSession);
#include "trustzone/tz_cross/tz_error_strings.h"
const char *TZ_GetErrorString(TZ_RESULT res)
{
return _TZ_GetErrorString(res);
}
EXPORT_SYMBOL(TZ_GetErrorString);
|