tsp_main.c revision a20a81e5b4a19969673f672523b946647f5d545d
1/*
2 * Copyright (c) 2013-2014, ARM Limited and Contributors. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * Redistributions of source code must retain the above copyright notice, this
8 * list of conditions and the following disclaimer.
9 *
10 * Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * Neither the name of ARM nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific
16 * prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <arch_helpers.h>
32#include <bl_common.h>
33#include <bl32.h>
34#include <debug.h>
35#include <platform.h>
36#include <spinlock.h>
37#include <stdio.h>
38#include <tsp.h>
39
40/*******************************************************************************
41 * Declarations of linker defined symbols which will help us find the layout
42 * of trusted SRAM
43 ******************************************************************************/
44extern unsigned long __RO_START__;
45extern unsigned long __COHERENT_RAM_END__;
46
47/*******************************************************************************
48 * Lock to control access to the console
49 ******************************************************************************/
50spinlock_t console_lock;
51
52/*******************************************************************************
53 * Per cpu data structure to populate parameters for an SMC in C code and use
54 * a pointer to this structure in assembler code to populate x0-x7
55 ******************************************************************************/
56static tsp_args_t tsp_smc_args[PLATFORM_CORE_COUNT];
57
58/*******************************************************************************
59 * Per cpu data structure to keep track of TSP activity
60 ******************************************************************************/
61work_statistics_t tsp_stats[PLATFORM_CORE_COUNT];
62
63/*******************************************************************************
64 * Single reference to the various entry points exported by the test secure
65 * payload.  A single copy should suffice for all cpus as they are not expected
66 * to change.
67 ******************************************************************************/
68static const entry_info_t tsp_entry_info = {
69	tsp_fast_smc_entry,
70	tsp_cpu_on_entry,
71	tsp_cpu_off_entry,
72	tsp_cpu_resume_entry,
73	tsp_cpu_suspend_entry,
74	tsp_fiq_entry,
75};
76
77
78/*******************************************************************************
79 * The BL32 memory footprint starts with an RO sections and ends
80 * with a section for coherent RAM. Use it to find the memory size
81 ******************************************************************************/
82#define BL32_TOTAL_BASE (unsigned long)(&__RO_START__)
83
84#define BL32_TOTAL_LIMIT (unsigned long)(&__COHERENT_RAM_END__)
85
86static tsp_args_t *set_smc_args(uint64_t arg0,
87			     uint64_t arg1,
88			     uint64_t arg2,
89			     uint64_t arg3,
90			     uint64_t arg4,
91			     uint64_t arg5,
92			     uint64_t arg6,
93			     uint64_t arg7)
94{
95	uint64_t mpidr = read_mpidr();
96	uint32_t linear_id;
97	tsp_args_t *pcpu_smc_args;
98
99	/*
100	 * Return to Secure Monitor by raising an SMC. The results of the
101	 * service are passed as an arguments to the SMC
102	 */
103	linear_id = platform_get_core_pos(mpidr);
104	pcpu_smc_args = &tsp_smc_args[linear_id];
105	write_sp_arg(pcpu_smc_args, TSP_ARG0, arg0);
106	write_sp_arg(pcpu_smc_args, TSP_ARG1, arg1);
107	write_sp_arg(pcpu_smc_args, TSP_ARG2, arg2);
108	write_sp_arg(pcpu_smc_args, TSP_ARG3, arg3);
109	write_sp_arg(pcpu_smc_args, TSP_ARG4, arg4);
110	write_sp_arg(pcpu_smc_args, TSP_ARG5, arg5);
111	write_sp_arg(pcpu_smc_args, TSP_ARG6, arg6);
112	write_sp_arg(pcpu_smc_args, TSP_ARG7, arg7);
113
114	return pcpu_smc_args;
115}
116
117/*******************************************************************************
118 * TSP main entry point where it gets the opportunity to initialize its secure
119 * state/applications. Once the state is initialized, it must return to the
120 * SPD with a pointer to the 'tsp_entry_info' structure.
121 ******************************************************************************/
122uint64_t tsp_main(void)
123{
124	uint64_t mpidr = read_mpidr();
125	uint32_t linear_id = platform_get_core_pos(mpidr);
126
127	/* Initialize the platform */
128	bl32_platform_setup();
129
130	/* Initialize secure/applications state here */
131	tsp_generic_timer_start();
132
133	/* Update this cpu's statistics */
134	tsp_stats[linear_id].smc_count++;
135	tsp_stats[linear_id].eret_count++;
136	tsp_stats[linear_id].cpu_on_count++;
137
138	spin_lock(&console_lock);
139	printf("TSP %s\n\r", build_message);
140	INFO("Total memory base : 0x%x\n", (unsigned long)BL32_TOTAL_BASE);
141	INFO("Total memory size : 0x%x bytes\n",
142			 (unsigned long)(BL32_TOTAL_LIMIT - BL32_TOTAL_BASE));
143	INFO("cpu 0x%x: %d smcs, %d erets %d cpu on requests\n", mpidr,
144	     tsp_stats[linear_id].smc_count,
145	     tsp_stats[linear_id].eret_count,
146	     tsp_stats[linear_id].cpu_on_count);
147	spin_unlock(&console_lock);
148
149	/*
150	 * TODO: There is a massive assumption that the SPD and SP can see each
151	 * other's memory without issues so it is safe to pass pointers to
152	 * internal memory. Replace this with a shared communication buffer.
153	 */
154	return (uint64_t) &tsp_entry_info;
155}
156
157/*******************************************************************************
158 * This function performs any remaining book keeping in the test secure payload
159 * after this cpu's architectural state has been setup in response to an earlier
160 * psci cpu_on request.
161 ******************************************************************************/
162tsp_args_t *tsp_cpu_on_main(void)
163{
164	uint64_t mpidr = read_mpidr();
165	uint32_t linear_id = platform_get_core_pos(mpidr);
166
167	/* Initialize secure/applications state here */
168	tsp_generic_timer_start();
169
170	/* Update this cpu's statistics */
171	tsp_stats[linear_id].smc_count++;
172	tsp_stats[linear_id].eret_count++;
173	tsp_stats[linear_id].cpu_on_count++;
174
175	spin_lock(&console_lock);
176	printf("SP: cpu 0x%x turned on\n\r", mpidr);
177	INFO("cpu 0x%x: %d smcs, %d erets %d cpu on requests\n", mpidr,
178	     tsp_stats[linear_id].smc_count,
179	     tsp_stats[linear_id].eret_count,
180	     tsp_stats[linear_id].cpu_on_count);
181	spin_unlock(&console_lock);
182
183	/* Indicate to the SPD that we have completed turned ourselves on */
184	return set_smc_args(TSP_ON_DONE, 0, 0, 0, 0, 0, 0, 0);
185}
186
187/*******************************************************************************
188 * This function performs any remaining book keeping in the test secure payload
189 * before this cpu is turned off in response to a psci cpu_off request.
190 ******************************************************************************/
191tsp_args_t *tsp_cpu_off_main(uint64_t arg0,
192			   uint64_t arg1,
193			   uint64_t arg2,
194			   uint64_t arg3,
195			   uint64_t arg4,
196			   uint64_t arg5,
197			   uint64_t arg6,
198			   uint64_t arg7)
199{
200	uint64_t mpidr = read_mpidr();
201	uint32_t linear_id = platform_get_core_pos(mpidr);
202
203	/*
204	 * This cpu is being turned off, so disable the timer to prevent the
205	 * secure timer interrupt from interfering with power down. A pending
206	 * interrupt will be lost but we do not care as we are turning off.
207	 */
208	tsp_generic_timer_stop();
209
210	/* Update this cpu's statistics */
211	tsp_stats[linear_id].smc_count++;
212	tsp_stats[linear_id].eret_count++;
213	tsp_stats[linear_id].cpu_off_count++;
214
215	spin_lock(&console_lock);
216	printf("SP: cpu 0x%x off request\n\r", mpidr);
217	INFO("cpu 0x%x: %d smcs, %d erets %d cpu off requests\n", mpidr,
218	     tsp_stats[linear_id].smc_count,
219	     tsp_stats[linear_id].eret_count,
220	     tsp_stats[linear_id].cpu_off_count);
221	spin_unlock(&console_lock);
222
223
224	/* Indicate to the SPD that we have completed this request */
225	return set_smc_args(TSP_OFF_DONE, 0, 0, 0, 0, 0, 0, 0);
226}
227
228/*******************************************************************************
229 * This function performs any book keeping in the test secure payload before
230 * this cpu's architectural state is saved in response to an earlier psci
231 * cpu_suspend request.
232 ******************************************************************************/
233tsp_args_t *tsp_cpu_suspend_main(uint64_t power_state,
234			       uint64_t arg1,
235			       uint64_t arg2,
236			       uint64_t arg3,
237			       uint64_t arg4,
238			       uint64_t arg5,
239			       uint64_t arg6,
240			       uint64_t arg7)
241{
242	uint64_t mpidr = read_mpidr();
243	uint32_t linear_id = platform_get_core_pos(mpidr);
244
245	/*
246	 * Save the time context and disable it to prevent the secure timer
247	 * interrupt from interfering with wakeup from the suspend state.
248	 */
249	tsp_generic_timer_save();
250	tsp_generic_timer_stop();
251
252	/* Update this cpu's statistics */
253	tsp_stats[linear_id].smc_count++;
254	tsp_stats[linear_id].eret_count++;
255	tsp_stats[linear_id].cpu_suspend_count++;
256
257	spin_lock(&console_lock);
258	printf("SP: cpu 0x%x suspend request. power state: 0x%x\n\r",
259	       mpidr, power_state);
260	INFO("cpu 0x%x: %d smcs, %d erets %d cpu suspend requests\n", mpidr,
261	     tsp_stats[linear_id].smc_count,
262	     tsp_stats[linear_id].eret_count,
263	     tsp_stats[linear_id].cpu_suspend_count);
264	spin_unlock(&console_lock);
265
266	/* Indicate to the SPD that we have completed this request */
267	return set_smc_args(TSP_SUSPEND_DONE, 0, 0, 0, 0, 0, 0, 0);
268}
269
270/*******************************************************************************
271 * This function performs any book keeping in the test secure payload after this
272 * cpu's architectural state has been restored after wakeup from an earlier psci
273 * cpu_suspend request.
274 ******************************************************************************/
275tsp_args_t *tsp_cpu_resume_main(uint64_t suspend_level,
276			      uint64_t arg1,
277			      uint64_t arg2,
278			      uint64_t arg3,
279			      uint64_t arg4,
280			      uint64_t arg5,
281			      uint64_t arg6,
282			      uint64_t arg7)
283{
284	uint64_t mpidr = read_mpidr();
285	uint32_t linear_id = platform_get_core_pos(mpidr);
286
287	/* Restore the generic timer context */
288	tsp_generic_timer_restore();
289
290	/* Update this cpu's statistics */
291	tsp_stats[linear_id].smc_count++;
292	tsp_stats[linear_id].eret_count++;
293	tsp_stats[linear_id].cpu_resume_count++;
294
295	spin_lock(&console_lock);
296	printf("SP: cpu 0x%x resumed. suspend level %d \n\r",
297	       mpidr, suspend_level);
298	INFO("cpu 0x%x: %d smcs, %d erets %d cpu suspend requests\n", mpidr,
299	     tsp_stats[linear_id].smc_count,
300	     tsp_stats[linear_id].eret_count,
301	     tsp_stats[linear_id].cpu_suspend_count);
302	spin_unlock(&console_lock);
303
304	/* Indicate to the SPD that we have completed this request */
305	return set_smc_args(TSP_RESUME_DONE, 0, 0, 0, 0, 0, 0, 0);
306}
307
308/*******************************************************************************
309 * TSP fast smc handler. The secure monitor jumps to this function by
310 * doing the ERET after populating X0-X7 registers. The arguments are received
311 * in the function arguments in order. Once the service is rendered, this
312 * function returns to Secure Monitor by raising SMC
313 ******************************************************************************/
314tsp_args_t *tsp_fast_smc_handler(uint64_t func,
315			       uint64_t arg1,
316			       uint64_t arg2,
317			       uint64_t arg3,
318			       uint64_t arg4,
319			       uint64_t arg5,
320			       uint64_t arg6,
321			       uint64_t arg7)
322{
323	uint64_t results[2];
324	uint64_t service_args[2];
325	uint64_t mpidr = read_mpidr();
326	uint32_t linear_id = platform_get_core_pos(mpidr);
327
328	/* Update this cpu's statistics */
329	tsp_stats[linear_id].smc_count++;
330	tsp_stats[linear_id].eret_count++;
331
332	printf("SP: cpu 0x%x received fast smc 0x%x\n", read_mpidr(), func);
333	INFO("cpu 0x%x: %d smcs, %d erets\n", mpidr,
334	     tsp_stats[linear_id].smc_count,
335	     tsp_stats[linear_id].eret_count);
336
337	/* Render secure services and obtain results here */
338
339	results[0] = arg1;
340	results[1] = arg2;
341
342	/*
343	 * Request a service back from dispatcher/secure monitor. This call
344	 * return and thereafter resume exectuion
345	 */
346	tsp_get_magic(service_args);
347
348	/* Determine the function to perform based on the function ID */
349	switch (func) {
350	case TSP_FID_ADD:
351		results[0] += service_args[0];
352		results[1] += service_args[1];
353		break;
354	case TSP_FID_SUB:
355		results[0] -= service_args[0];
356		results[1] -= service_args[1];
357		break;
358	case TSP_FID_MUL:
359		results[0] *= service_args[0];
360		results[1] *= service_args[1];
361		break;
362	case TSP_FID_DIV:
363		results[0] /= service_args[0] ? service_args[0] : 1;
364		results[1] /= service_args[1] ? service_args[1] : 1;
365		break;
366	default:
367		break;
368	}
369
370	return set_smc_args(func,
371			    results[0],
372			    results[1],
373			    0, 0, 0, 0, 0);
374}
375
376