tsp_main.c 14.5 KB
Newer Older
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
/*
 * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * Neither the name of ARM nor the names of its contributors may be used
 * to endorse or promote products derived from this software without specific
 * prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <arch_helpers.h>
32
#include <bl_common.h>
33
#include <debug.h>
34
#include <platform.h>
35
#include <platform_def.h>
36
#include <platform_tsp.h>
37
#include <spinlock.h>
38
#include <tsp.h>
39
#include "tsp_private.h"
40

41

42
43
44
45
46
47
48
49
50
/*******************************************************************************
 * Lock to control access to the console
 ******************************************************************************/
spinlock_t console_lock;

/*******************************************************************************
 * Per cpu data structure to populate parameters for an SMC in C code and use
 * a pointer to this structure in assembler code to populate x0-x7
 ******************************************************************************/
51
static tsp_args_t tsp_smc_args[PLATFORM_CORE_COUNT];
52
53
54
55

/*******************************************************************************
 * Per cpu data structure to keep track of TSP activity
 ******************************************************************************/
56
work_statistics_t tsp_stats[PLATFORM_CORE_COUNT];
57

58
59
/*******************************************************************************
 * The BL32 memory footprint starts with an RO sections and ends
60
 * with the linker symbol __BL32_END__. Use it to find the memory size
61
62
63
 ******************************************************************************/
#define BL32_TOTAL_BASE (unsigned long)(&__RO_START__)

64
#define BL32_TOTAL_LIMIT (unsigned long)(&__BL32_END__)
65

66
static tsp_args_t *set_smc_args(uint64_t arg0,
67
68
69
70
71
72
73
74
75
76
			     uint64_t arg1,
			     uint64_t arg2,
			     uint64_t arg3,
			     uint64_t arg4,
			     uint64_t arg5,
			     uint64_t arg6,
			     uint64_t arg7)
{
	uint64_t mpidr = read_mpidr();
	uint32_t linear_id;
77
	tsp_args_t *pcpu_smc_args;
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99

	/*
	 * Return to Secure Monitor by raising an SMC. The results of the
	 * service are passed as an arguments to the SMC
	 */
	linear_id = platform_get_core_pos(mpidr);
	pcpu_smc_args = &tsp_smc_args[linear_id];
	write_sp_arg(pcpu_smc_args, TSP_ARG0, arg0);
	write_sp_arg(pcpu_smc_args, TSP_ARG1, arg1);
	write_sp_arg(pcpu_smc_args, TSP_ARG2, arg2);
	write_sp_arg(pcpu_smc_args, TSP_ARG3, arg3);
	write_sp_arg(pcpu_smc_args, TSP_ARG4, arg4);
	write_sp_arg(pcpu_smc_args, TSP_ARG5, arg5);
	write_sp_arg(pcpu_smc_args, TSP_ARG6, arg6);
	write_sp_arg(pcpu_smc_args, TSP_ARG7, arg7);

	return pcpu_smc_args;
}

/*******************************************************************************
 * TSP main entry point where it gets the opportunity to initialize its secure
 * state/applications. Once the state is initialized, it must return to the
100
 * SPD with a pointer to the 'tsp_vector_table' jump table.
101
102
103
 ******************************************************************************/
uint64_t tsp_main(void)
{
Dan Handley's avatar
Dan Handley committed
104
105
	NOTICE("TSP: %s\n", version_string);
	NOTICE("TSP: %s\n", build_message);
106
107
108
	INFO("TSP: Total memory base : 0x%lx\n", BL32_TOTAL_BASE);
	INFO("TSP: Total memory size : 0x%lx bytes\n",
			 BL32_TOTAL_LIMIT - BL32_TOTAL_BASE);
Dan Handley's avatar
Dan Handley committed
109

110
111
112
113
	uint64_t mpidr = read_mpidr();
	uint32_t linear_id = platform_get_core_pos(mpidr);

	/* Initialize the platform */
114
	tsp_platform_setup();
115
116

	/* Initialize secure/applications state here */
117
	tsp_generic_timer_start();
118
119
120
121
122
123

	/* Update this cpu's statistics */
	tsp_stats[linear_id].smc_count++;
	tsp_stats[linear_id].eret_count++;
	tsp_stats[linear_id].cpu_on_count++;

Dan Handley's avatar
Dan Handley committed
124
#if LOG_LEVEL >= LOG_LEVEL_INFO
125
	spin_lock(&console_lock);
126
	INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu on requests\n", mpidr,
127
128
129
130
	     tsp_stats[linear_id].smc_count,
	     tsp_stats[linear_id].eret_count,
	     tsp_stats[linear_id].cpu_on_count);
	spin_unlock(&console_lock);
Dan Handley's avatar
Dan Handley committed
131
#endif
132
	return (uint64_t) &tsp_vector_table;
133
134
135
136
137
138
139
}

/*******************************************************************************
 * This function performs any remaining book keeping in the test secure payload
 * after this cpu's architectural state has been setup in response to an earlier
 * psci cpu_on request.
 ******************************************************************************/
140
tsp_args_t *tsp_cpu_on_main(void)
141
142
143
144
{
	uint64_t mpidr = read_mpidr();
	uint32_t linear_id = platform_get_core_pos(mpidr);

145
146
147
	/* Initialize secure/applications state here */
	tsp_generic_timer_start();

148
149
150
151
152
	/* Update this cpu's statistics */
	tsp_stats[linear_id].smc_count++;
	tsp_stats[linear_id].eret_count++;
	tsp_stats[linear_id].cpu_on_count++;

Dan Handley's avatar
Dan Handley committed
153
#if LOG_LEVEL >= LOG_LEVEL_INFO
154
	spin_lock(&console_lock);
155
156
	INFO("TSP: cpu 0x%lx turned on\n", mpidr);
	INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu on requests\n", mpidr,
Dan Handley's avatar
Dan Handley committed
157
158
159
		tsp_stats[linear_id].smc_count,
		tsp_stats[linear_id].eret_count,
		tsp_stats[linear_id].cpu_on_count);
160
	spin_unlock(&console_lock);
Dan Handley's avatar
Dan Handley committed
161
#endif
162
163
164
165
166
167
168
169
	/* Indicate to the SPD that we have completed turned ourselves on */
	return set_smc_args(TSP_ON_DONE, 0, 0, 0, 0, 0, 0, 0);
}

/*******************************************************************************
 * This function performs any remaining book keeping in the test secure payload
 * before this cpu is turned off in response to a psci cpu_off request.
 ******************************************************************************/
170
tsp_args_t *tsp_cpu_off_main(uint64_t arg0,
171
172
173
174
175
176
177
178
179
180
181
			   uint64_t arg1,
			   uint64_t arg2,
			   uint64_t arg3,
			   uint64_t arg4,
			   uint64_t arg5,
			   uint64_t arg6,
			   uint64_t arg7)
{
	uint64_t mpidr = read_mpidr();
	uint32_t linear_id = platform_get_core_pos(mpidr);

182
183
184
185
186
187
188
	/*
	 * This cpu is being turned off, so disable the timer to prevent the
	 * secure timer interrupt from interfering with power down. A pending
	 * interrupt will be lost but we do not care as we are turning off.
	 */
	tsp_generic_timer_stop();

189
190
191
192
193
	/* Update this cpu's statistics */
	tsp_stats[linear_id].smc_count++;
	tsp_stats[linear_id].eret_count++;
	tsp_stats[linear_id].cpu_off_count++;

Dan Handley's avatar
Dan Handley committed
194
#if LOG_LEVEL >= LOG_LEVEL_INFO
195
	spin_lock(&console_lock);
196
197
	INFO("TSP: cpu 0x%lx off request\n", mpidr);
	INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu off requests\n", mpidr,
Dan Handley's avatar
Dan Handley committed
198
199
200
		tsp_stats[linear_id].smc_count,
		tsp_stats[linear_id].eret_count,
		tsp_stats[linear_id].cpu_off_count);
201
	spin_unlock(&console_lock);
Dan Handley's avatar
Dan Handley committed
202
#endif
203

204
	/* Indicate to the SPD that we have completed this request */
205
206
207
208
209
210
211
212
	return set_smc_args(TSP_OFF_DONE, 0, 0, 0, 0, 0, 0, 0);
}

/*******************************************************************************
 * This function performs any book keeping in the test secure payload before
 * this cpu's architectural state is saved in response to an earlier psci
 * cpu_suspend request.
 ******************************************************************************/
213
tsp_args_t *tsp_cpu_suspend_main(uint64_t arg0,
214
215
216
217
218
219
220
221
222
223
224
			       uint64_t arg1,
			       uint64_t arg2,
			       uint64_t arg3,
			       uint64_t arg4,
			       uint64_t arg5,
			       uint64_t arg6,
			       uint64_t arg7)
{
	uint64_t mpidr = read_mpidr();
	uint32_t linear_id = platform_get_core_pos(mpidr);

225
226
227
228
229
230
231
	/*
	 * Save the time context and disable it to prevent the secure timer
	 * interrupt from interfering with wakeup from the suspend state.
	 */
	tsp_generic_timer_save();
	tsp_generic_timer_stop();

232
233
234
235
236
	/* Update this cpu's statistics */
	tsp_stats[linear_id].smc_count++;
	tsp_stats[linear_id].eret_count++;
	tsp_stats[linear_id].cpu_suspend_count++;

Dan Handley's avatar
Dan Handley committed
237
#if LOG_LEVEL >= LOG_LEVEL_INFO
238
	spin_lock(&console_lock);
239
	INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu suspend requests\n",
Dan Handley's avatar
Dan Handley committed
240
241
242
243
		mpidr,
		tsp_stats[linear_id].smc_count,
		tsp_stats[linear_id].eret_count,
		tsp_stats[linear_id].cpu_suspend_count);
244
	spin_unlock(&console_lock);
Dan Handley's avatar
Dan Handley committed
245
#endif
246

247
	/* Indicate to the SPD that we have completed this request */
248
249
250
251
252
253
254
255
	return set_smc_args(TSP_SUSPEND_DONE, 0, 0, 0, 0, 0, 0, 0);
}

/*******************************************************************************
 * This function performs any book keeping in the test secure payload after this
 * cpu's architectural state has been restored after wakeup from an earlier psci
 * cpu_suspend request.
 ******************************************************************************/
256
tsp_args_t *tsp_cpu_resume_main(uint64_t suspend_level,
257
258
259
260
261
262
263
264
265
266
267
			      uint64_t arg1,
			      uint64_t arg2,
			      uint64_t arg3,
			      uint64_t arg4,
			      uint64_t arg5,
			      uint64_t arg6,
			      uint64_t arg7)
{
	uint64_t mpidr = read_mpidr();
	uint32_t linear_id = platform_get_core_pos(mpidr);

268
269
270
	/* Restore the generic timer context */
	tsp_generic_timer_restore();

271
272
273
274
275
	/* Update this cpu's statistics */
	tsp_stats[linear_id].smc_count++;
	tsp_stats[linear_id].eret_count++;
	tsp_stats[linear_id].cpu_resume_count++;

Dan Handley's avatar
Dan Handley committed
276
#if LOG_LEVEL >= LOG_LEVEL_INFO
277
	spin_lock(&console_lock);
278
	INFO("TSP: cpu 0x%lx resumed. suspend level %ld\n",
Dan Handley's avatar
Dan Handley committed
279
		mpidr, suspend_level);
280
	INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu suspend requests\n",
Dan Handley's avatar
Dan Handley committed
281
282
283
284
		mpidr,
		tsp_stats[linear_id].smc_count,
		tsp_stats[linear_id].eret_count,
		tsp_stats[linear_id].cpu_suspend_count);
285
	spin_unlock(&console_lock);
Dan Handley's avatar
Dan Handley committed
286
#endif
287
	/* Indicate to the SPD that we have completed this request */
288
289
290
	return set_smc_args(TSP_RESUME_DONE, 0, 0, 0, 0, 0, 0, 0);
}

291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
/*******************************************************************************
 * This function performs any remaining bookkeeping in the test secure payload
 * before the system is switched off (in response to a psci SYSTEM_OFF request)
 ******************************************************************************/
tsp_args_t *tsp_system_off_main(uint64_t arg0,
				uint64_t arg1,
				uint64_t arg2,
				uint64_t arg3,
				uint64_t arg4,
				uint64_t arg5,
				uint64_t arg6,
				uint64_t arg7)
{
	uint64_t mpidr = read_mpidr();
	uint32_t linear_id = platform_get_core_pos(mpidr);

	/* Update this cpu's statistics */
	tsp_stats[linear_id].smc_count++;
	tsp_stats[linear_id].eret_count++;

#if LOG_LEVEL >= LOG_LEVEL_INFO
	spin_lock(&console_lock);
313
314
	INFO("TSP: cpu 0x%lx SYSTEM_OFF request\n", mpidr);
	INFO("TSP: cpu 0x%lx: %d smcs, %d erets requests\n", mpidr,
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
	     tsp_stats[linear_id].smc_count,
	     tsp_stats[linear_id].eret_count);
	spin_unlock(&console_lock);
#endif

	/* Indicate to the SPD that we have completed this request */
	return set_smc_args(TSP_SYSTEM_OFF_DONE, 0, 0, 0, 0, 0, 0, 0);
}

/*******************************************************************************
 * This function performs any remaining bookkeeping in the test secure payload
 * before the system is reset (in response to a psci SYSTEM_RESET request)
 ******************************************************************************/
tsp_args_t *tsp_system_reset_main(uint64_t arg0,
				uint64_t arg1,
				uint64_t arg2,
				uint64_t arg3,
				uint64_t arg4,
				uint64_t arg5,
				uint64_t arg6,
				uint64_t arg7)
{
	uint64_t mpidr = read_mpidr();
	uint32_t linear_id = platform_get_core_pos(mpidr);

	/* Update this cpu's statistics */
	tsp_stats[linear_id].smc_count++;
	tsp_stats[linear_id].eret_count++;

#if LOG_LEVEL >= LOG_LEVEL_INFO
	spin_lock(&console_lock);
346
347
	INFO("TSP: cpu 0x%lx SYSTEM_RESET request\n", mpidr);
	INFO("TSP: cpu 0x%lx: %d smcs, %d erets requests\n", mpidr,
348
349
350
351
352
353
354
355
356
	     tsp_stats[linear_id].smc_count,
	     tsp_stats[linear_id].eret_count);
	spin_unlock(&console_lock);
#endif

	/* Indicate to the SPD that we have completed this request */
	return set_smc_args(TSP_SYSTEM_RESET_DONE, 0, 0, 0, 0, 0, 0, 0);
}

357
358
359
360
/*******************************************************************************
 * TSP fast smc handler. The secure monitor jumps to this function by
 * doing the ERET after populating X0-X7 registers. The arguments are received
 * in the function arguments in order. Once the service is rendered, this
361
 * function returns to Secure Monitor by raising SMC.
362
 ******************************************************************************/
363
tsp_args_t *tsp_smc_handler(uint64_t func,
364
365
366
367
368
369
370
371
			       uint64_t arg1,
			       uint64_t arg2,
			       uint64_t arg3,
			       uint64_t arg4,
			       uint64_t arg5,
			       uint64_t arg6,
			       uint64_t arg7)
{
372
373
374
375
	uint64_t results[2];
	uint64_t service_args[2];
	uint64_t mpidr = read_mpidr();
	uint32_t linear_id = platform_get_core_pos(mpidr);
376

377
378
379
380
	/* Update this cpu's statistics */
	tsp_stats[linear_id].smc_count++;
	tsp_stats[linear_id].eret_count++;

381
	INFO("TSP: cpu 0x%lx received %s smc 0x%lx\n", mpidr,
Dan Handley's avatar
Dan Handley committed
382
383
		((func >> 31) & 1) == 1 ? "fast" : "standard",
		func);
384
	INFO("TSP: cpu 0x%lx: %d smcs, %d erets\n", mpidr,
Dan Handley's avatar
Dan Handley committed
385
386
		tsp_stats[linear_id].smc_count,
		tsp_stats[linear_id].eret_count);
387

388
	/* Render secure services and obtain results here */
389
390
391
392
393
394
395
396
397
398
	results[0] = arg1;
	results[1] = arg2;

	/*
	 * Request a service back from dispatcher/secure monitor. This call
	 * return and thereafter resume exectuion
	 */
	tsp_get_magic(service_args);

	/* Determine the function to perform based on the function ID */
399
400
	switch (TSP_BARE_FID(func)) {
	case TSP_ADD:
401
402
403
		results[0] += service_args[0];
		results[1] += service_args[1];
		break;
404
	case TSP_SUB:
405
406
407
		results[0] -= service_args[0];
		results[1] -= service_args[1];
		break;
408
	case TSP_MUL:
409
410
411
		results[0] *= service_args[0];
		results[1] *= service_args[1];
		break;
412
	case TSP_DIV:
413
414
415
416
417
418
419
		results[0] /= service_args[0] ? service_args[0] : 1;
		results[1] /= service_args[1] ? service_args[1] : 1;
		break;
	default:
		break;
	}

420
	return set_smc_args(func, 0,
421
422
			    results[0],
			    results[1],
423
			    0, 0, 0, 0);
424
425
}