diff options
Diffstat (limited to 'security/tf_driver/tf_comm_tz.c')
-rw-r--r-- | security/tf_driver/tf_comm_tz.c | 885 |
1 files changed, 885 insertions, 0 deletions
diff --git a/security/tf_driver/tf_comm_tz.c b/security/tf_driver/tf_comm_tz.c new file mode 100644 index 00000000000..4c89de84acc --- /dev/null +++ b/security/tf_driver/tf_comm_tz.c | |||
@@ -0,0 +1,885 @@ | |||
1 | /** | ||
2 | * Copyright (c) 2011 Trusted Logic S.A. | ||
3 | * All Rights Reserved. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License | ||
7 | * version 2 as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
17 | * MA 02111-1307 USA | ||
18 | */ | ||
19 | |||
20 | #include <asm/div64.h> | ||
21 | #include <asm/system.h> | ||
22 | #include <linux/version.h> | ||
23 | #include <asm/cputype.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/page-flags.h> | ||
26 | #include <linux/pagemap.h> | ||
27 | #include <linux/vmalloc.h> | ||
28 | #include <linux/jiffies.h> | ||
29 | |||
30 | #include "tf_defs.h" | ||
31 | #include "tf_comm.h" | ||
32 | #include "tf_protocol.h" | ||
33 | #include "tf_util.h" | ||
34 | #include "tf_conn.h" | ||
35 | |||
36 | /* | ||
37 | * Structure common to all SMC operations | ||
38 | */ | ||
39 | struct tf_generic_smc { | ||
40 | u32 reg0; | ||
41 | u32 reg1; | ||
42 | u32 reg2; | ||
43 | u32 reg3; | ||
44 | u32 reg4; | ||
45 | }; | ||
46 | |||
47 | /*---------------------------------------------------------------------------- | ||
48 | * SMC operations | ||
49 | *----------------------------------------------------------------------------*/ | ||
50 | |||
51 | static inline void tf_smc_generic_call( | ||
52 | struct tf_generic_smc *generic_smc) | ||
53 | { | ||
54 | #ifdef CONFIG_SMP | ||
55 | long ret; | ||
56 | cpumask_t saved_cpu_mask; | ||
57 | cpumask_t local_cpu_mask = CPU_MASK_NONE; | ||
58 | |||
59 | cpu_set(0, local_cpu_mask); | ||
60 | sched_getaffinity(0, &saved_cpu_mask); | ||
61 | ret = sched_setaffinity(0, &local_cpu_mask); | ||
62 | if (ret != 0) | ||
63 | dprintk(KERN_ERR "sched_setaffinity #1 -> 0x%lX", ret); | ||
64 | #endif | ||
65 | |||
66 | __asm__ volatile( | ||
67 | "mov r0, %2\n" | ||
68 | "mov r1, %3\n" | ||
69 | "mov r2, %4\n" | ||
70 | "mov r3, %5\n" | ||
71 | "mov r4, %6\n" | ||
72 | ".word 0xe1600070 @ SMC 0\n" | ||
73 | "mov %0, r0\n" | ||
74 | "mov %1, r1\n" | ||
75 | : "=r" (generic_smc->reg0), "=r" (generic_smc->reg1) | ||
76 | : "r" (generic_smc->reg0), "r" (generic_smc->reg1), | ||
77 | "r" (generic_smc->reg2), "r" (generic_smc->reg3), | ||
78 | "r" (generic_smc->reg4) | ||
79 | : "r0", "r1", "r2", "r3", "r4"); | ||
80 | |||
81 | #ifdef CONFIG_SMP | ||
82 | ret = sched_setaffinity(0, &saved_cpu_mask); | ||
83 | if (ret != 0) | ||
84 | dprintk(KERN_ERR "sched_setaffinity #2 -> 0x%lX", ret); | ||
85 | #endif | ||
86 | } | ||
87 | |||
88 | /* | ||
89 | * Calls the get protocol version SMC. | ||
90 | * Fills the parameter pProtocolVersion with the version number returned by the | ||
91 | * SMC | ||
92 | */ | ||
93 | static inline void tf_smc_get_protocol_version(u32 *protocol_version) | ||
94 | { | ||
95 | struct tf_generic_smc generic_smc; | ||
96 | |||
97 | generic_smc.reg0 = TF_SMC_GET_PROTOCOL_VERSION; | ||
98 | generic_smc.reg1 = 0; | ||
99 | generic_smc.reg2 = 0; | ||
100 | generic_smc.reg3 = 0; | ||
101 | generic_smc.reg4 = 0; | ||
102 | |||
103 | tf_smc_generic_call(&generic_smc); | ||
104 | *protocol_version = generic_smc.reg1; | ||
105 | } | ||
106 | |||
107 | |||
108 | /* | ||
109 | * Calls the init SMC with the specified parameters. | ||
110 | * Returns zero upon successful completion, or an appropriate error code upon | ||
111 | * failure. | ||
112 | */ | ||
113 | static inline int tf_smc_init(u32 shared_page_descriptor) | ||
114 | { | ||
115 | struct tf_generic_smc generic_smc; | ||
116 | |||
117 | generic_smc.reg0 = TF_SMC_INIT; | ||
118 | /* Descriptor for the layer 1 shared buffer */ | ||
119 | generic_smc.reg1 = shared_page_descriptor; | ||
120 | generic_smc.reg2 = 0; | ||
121 | generic_smc.reg3 = 0; | ||
122 | generic_smc.reg4 = 0; | ||
123 | |||
124 | tf_smc_generic_call(&generic_smc); | ||
125 | if (generic_smc.reg0 != S_SUCCESS) | ||
126 | printk(KERN_ERR "tf_smc_init:" | ||
127 | " r0=0x%08X upon return (expected 0x%08X)!\n", | ||
128 | generic_smc.reg0, | ||
129 | S_SUCCESS); | ||
130 | |||
131 | return generic_smc.reg0; | ||
132 | } | ||
133 | |||
134 | |||
135 | /* | ||
136 | * Calls the reset irq SMC. | ||
137 | */ | ||
138 | static inline void tf_smc_reset_irq(void) | ||
139 | { | ||
140 | struct tf_generic_smc generic_smc; | ||
141 | |||
142 | generic_smc.reg0 = TF_SMC_RESET_IRQ; | ||
143 | generic_smc.reg1 = 0; | ||
144 | generic_smc.reg2 = 0; | ||
145 | generic_smc.reg3 = 0; | ||
146 | generic_smc.reg4 = 0; | ||
147 | |||
148 | tf_smc_generic_call(&generic_smc); | ||
149 | } | ||
150 | |||
151 | |||
152 | /* | ||
153 | * Calls the WAKE_UP SMC. | ||
154 | * Returns zero upon successful completion, or an appropriate error code upon | ||
155 | * failure. | ||
156 | */ | ||
157 | static inline int tf_smc_wake_up(u32 l1_shared_buffer_descriptor, | ||
158 | u32 shared_mem_start_offset, | ||
159 | u32 shared_mem_size) | ||
160 | { | ||
161 | struct tf_generic_smc generic_smc; | ||
162 | |||
163 | generic_smc.reg0 = TF_SMC_WAKE_UP; | ||
164 | generic_smc.reg1 = shared_mem_start_offset; | ||
165 | /* long form command */ | ||
166 | generic_smc.reg2 = shared_mem_size | 0x80000000; | ||
167 | generic_smc.reg3 = l1_shared_buffer_descriptor; | ||
168 | generic_smc.reg4 = 0; | ||
169 | |||
170 | tf_smc_generic_call(&generic_smc); | ||
171 | |||
172 | if (generic_smc.reg0 != S_SUCCESS) | ||
173 | printk(KERN_ERR "tf_smc_wake_up:" | ||
174 | " r0=0x%08X upon return (expected 0x%08X)!\n", | ||
175 | generic_smc.reg0, | ||
176 | S_SUCCESS); | ||
177 | |||
178 | return generic_smc.reg0; | ||
179 | } | ||
180 | |||
181 | /* | ||
182 | * Calls the N-Yield SMC. | ||
183 | */ | ||
184 | static inline void tf_smc_nyield(void) | ||
185 | { | ||
186 | struct tf_generic_smc generic_smc; | ||
187 | |||
188 | generic_smc.reg0 = TF_SMC_N_YIELD; | ||
189 | generic_smc.reg1 = 0; | ||
190 | generic_smc.reg2 = 0; | ||
191 | generic_smc.reg3 = 0; | ||
192 | generic_smc.reg4 = 0; | ||
193 | |||
194 | tf_smc_generic_call(&generic_smc); | ||
195 | } | ||
196 | |||
197 | /* Yields the Secure World */ | ||
198 | int tf_schedule_secure_world(struct tf_comm *comm) | ||
199 | { | ||
200 | tf_set_current_time(comm); | ||
201 | |||
202 | /* yield to the Secure World */ | ||
203 | tf_smc_nyield(); | ||
204 | |||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | /* | ||
209 | * Returns the L2 descriptor for the specified user page. | ||
210 | */ | ||
211 | |||
212 | #define L2_INIT_DESCRIPTOR_BASE (0x00000003) | ||
213 | #define L2_INIT_DESCRIPTOR_V13_12_SHIFT (4) | ||
214 | |||
215 | static u32 tf_get_l2init_descriptor(u32 vaddr) | ||
216 | { | ||
217 | struct page *page; | ||
218 | u32 paddr; | ||
219 | u32 descriptor; | ||
220 | |||
221 | descriptor = L2_INIT_DESCRIPTOR_BASE; | ||
222 | |||
223 | /* get physical address and add to descriptor */ | ||
224 | page = virt_to_page(vaddr); | ||
225 | paddr = page_to_phys(page); | ||
226 | descriptor |= (paddr & L2_DESCRIPTOR_ADDR_MASK); | ||
227 | |||
228 | /* Add virtual address v[13:12] bits to descriptor */ | ||
229 | descriptor |= (DESCRIPTOR_V13_12_GET(vaddr) | ||
230 | << L2_INIT_DESCRIPTOR_V13_12_SHIFT); | ||
231 | |||
232 | descriptor |= tf_get_l2_descriptor_common(vaddr, &init_mm); | ||
233 | |||
234 | |||
235 | return descriptor; | ||
236 | } | ||
237 | |||
238 | |||
239 | /*---------------------------------------------------------------------------- | ||
240 | * Power management | ||
241 | *----------------------------------------------------------------------------*/ | ||
242 | |||
243 | /* | ||
244 | * Free the memory used by the W3B buffer for the specified comm. | ||
245 | * This function does nothing if no W3B buffer is allocated for the device. | ||
246 | */ | ||
247 | static inline void tf_free_w3b(struct tf_comm *comm) | ||
248 | { | ||
249 | tf_cleanup_shared_memory( | ||
250 | &(comm->w3b_cpt_alloc_context), | ||
251 | &(comm->w3b_shmem_desc), | ||
252 | 0); | ||
253 | |||
254 | tf_release_coarse_page_table_allocator(&(comm->w3b_cpt_alloc_context)); | ||
255 | |||
256 | internal_vfree((void *)comm->w3b); | ||
257 | comm->w3b = 0; | ||
258 | comm->w3b_shmem_size = 0; | ||
259 | clear_bit(TF_COMM_FLAG_W3B_ALLOCATED, &(comm->flags)); | ||
260 | } | ||
261 | |||
262 | |||
263 | /* | ||
264 | * Allocates the W3B buffer for the specified comm. | ||
265 | * Returns zero upon successful completion, or an appropriate error code upon | ||
266 | * failure. | ||
267 | */ | ||
268 | static inline int tf_allocate_w3b(struct tf_comm *comm) | ||
269 | { | ||
270 | int error; | ||
271 | u32 flags; | ||
272 | u32 config_flag_s; | ||
273 | u32 *w3b_descriptors; | ||
274 | u32 w3b_descriptor_count; | ||
275 | u32 w3b_current_size; | ||
276 | |||
277 | config_flag_s = tf_read_reg32(&comm->l1_buffer->config_flag_s); | ||
278 | |||
279 | retry: | ||
280 | if ((test_bit(TF_COMM_FLAG_W3B_ALLOCATED, &(comm->flags))) == 0) { | ||
281 | /* | ||
282 | * Initialize the shared memory for the W3B | ||
283 | */ | ||
284 | tf_init_coarse_page_table_allocator( | ||
285 | &comm->w3b_cpt_alloc_context); | ||
286 | } else { | ||
287 | /* | ||
288 | * The W3B is allocated but do we have to reallocate a bigger | ||
289 | * one? | ||
290 | */ | ||
291 | /* Check H bit */ | ||
292 | if ((config_flag_s & (1<<4)) != 0) { | ||
293 | /* The size of the W3B may change after SMC_INIT */ | ||
294 | /* Read the current value */ | ||
295 | w3b_current_size = tf_read_reg32( | ||
296 | &comm->l1_buffer->w3b_size_current_s); | ||
297 | if (comm->w3b_shmem_size > w3b_current_size) | ||
298 | return 0; | ||
299 | |||
300 | tf_free_w3b(comm); | ||
301 | goto retry; | ||
302 | } else { | ||
303 | return 0; | ||
304 | } | ||
305 | } | ||
306 | |||
307 | /* check H bit */ | ||
308 | if ((config_flag_s & (1<<4)) != 0) | ||
309 | /* The size of the W3B may change after SMC_INIT */ | ||
310 | /* Read the current value */ | ||
311 | comm->w3b_shmem_size = tf_read_reg32( | ||
312 | &comm->l1_buffer->w3b_size_current_s); | ||
313 | else | ||
314 | comm->w3b_shmem_size = tf_read_reg32( | ||
315 | &comm->l1_buffer->w3b_size_max_s); | ||
316 | |||
317 | comm->w3b = (u32) internal_vmalloc(comm->w3b_shmem_size); | ||
318 | if (comm->w3b == 0) { | ||
319 | printk(KERN_ERR "tf_allocate_w3b():" | ||
320 | " Out of memory for W3B buffer (%u bytes)!\n", | ||
321 | (unsigned int)(comm->w3b_shmem_size)); | ||
322 | error = -ENOMEM; | ||
323 | goto error; | ||
324 | } | ||
325 | |||
326 | /* initialize the w3b_shmem_desc structure */ | ||
327 | comm->w3b_shmem_desc.type = TF_SHMEM_TYPE_PM_HIBERNATE; | ||
328 | INIT_LIST_HEAD(&(comm->w3b_shmem_desc.list)); | ||
329 | |||
330 | flags = (TF_SHMEM_TYPE_READ | TF_SHMEM_TYPE_WRITE); | ||
331 | |||
332 | /* directly point to the L1 shared buffer W3B descriptors */ | ||
333 | w3b_descriptors = comm->l1_buffer->w3b_descriptors; | ||
334 | |||
335 | /* | ||
336 | * tf_fill_descriptor_table uses the following parameter as an | ||
337 | * IN/OUT | ||
338 | */ | ||
339 | |||
340 | error = tf_fill_descriptor_table( | ||
341 | &(comm->w3b_cpt_alloc_context), | ||
342 | &(comm->w3b_shmem_desc), | ||
343 | comm->w3b, | ||
344 | NULL, | ||
345 | w3b_descriptors, | ||
346 | comm->w3b_shmem_size, | ||
347 | &(comm->w3b_shmem_offset), | ||
348 | false, | ||
349 | flags, | ||
350 | &w3b_descriptor_count); | ||
351 | if (error != 0) { | ||
352 | printk(KERN_ERR "tf_allocate_w3b():" | ||
353 | " tf_fill_descriptor_table failed with " | ||
354 | "error code 0x%08x!\n", | ||
355 | error); | ||
356 | goto error; | ||
357 | } | ||
358 | |||
359 | set_bit(TF_COMM_FLAG_W3B_ALLOCATED, &(comm->flags)); | ||
360 | |||
361 | /* successful completion */ | ||
362 | return 0; | ||
363 | |||
364 | error: | ||
365 | tf_free_w3b(comm); | ||
366 | |||
367 | return error; | ||
368 | } | ||
369 | |||
370 | /* | ||
371 | * Perform a Secure World shutdown operation. | ||
372 | * The routine does not return if the operation succeeds. | ||
373 | * the routine returns an appropriate error code if | ||
374 | * the operation fails. | ||
375 | */ | ||
376 | int tf_pm_shutdown(struct tf_comm *comm) | ||
377 | { | ||
378 | #ifdef CONFIG_TFN | ||
379 | /* this function is useless for the TEGRA product */ | ||
380 | return 0; | ||
381 | #else | ||
382 | int error; | ||
383 | union tf_command command; | ||
384 | union tf_answer answer; | ||
385 | |||
386 | dprintk(KERN_INFO "tf_pm_shutdown()\n"); | ||
387 | |||
388 | memset(&command, 0, sizeof(command)); | ||
389 | |||
390 | command.header.message_type = TF_MESSAGE_TYPE_MANAGEMENT; | ||
391 | command.header.message_size = | ||
392 | (sizeof(struct tf_command_management) - | ||
393 | sizeof(struct tf_command_header))/sizeof(u32); | ||
394 | |||
395 | command.management.command = TF_MANAGEMENT_SHUTDOWN; | ||
396 | |||
397 | error = tf_send_receive( | ||
398 | comm, | ||
399 | &command, | ||
400 | &answer, | ||
401 | NULL, | ||
402 | false); | ||
403 | |||
404 | if (error != 0) { | ||
405 | dprintk(KERN_ERR "tf_pm_shutdown(): " | ||
406 | "tf_send_receive failed (error %d)!\n", | ||
407 | error); | ||
408 | return error; | ||
409 | } | ||
410 | |||
411 | #ifdef CONFIG_TF_DRIVER_DEBUG_SUPPORT | ||
412 | if (answer.header.error_code != 0) | ||
413 | dprintk(KERN_ERR "tf_driver: shutdown failed.\n"); | ||
414 | else | ||
415 | dprintk(KERN_INFO "tf_driver: shutdown succeeded.\n"); | ||
416 | #endif | ||
417 | |||
418 | return answer.header.error_code; | ||
419 | #endif | ||
420 | } | ||
421 | |||
422 | |||
423 | /* | ||
424 | * Perform a Secure World hibernate operation. | ||
425 | * The routine does not return if the operation succeeds. | ||
426 | * the routine returns an appropriate error code if | ||
427 | * the operation fails. | ||
428 | */ | ||
429 | int tf_pm_hibernate(struct tf_comm *comm) | ||
430 | { | ||
431 | #ifdef CONFIG_TFN | ||
432 | /* this function is useless for the TEGRA product */ | ||
433 | return 0; | ||
434 | #else | ||
435 | int error; | ||
436 | union tf_command command; | ||
437 | union tf_answer answer; | ||
438 | u32 first_command; | ||
439 | u32 first_free_command; | ||
440 | |||
441 | dprintk(KERN_INFO "tf_pm_hibernate()\n"); | ||
442 | |||
443 | error = tf_allocate_w3b(comm); | ||
444 | if (error != 0) { | ||
445 | dprintk(KERN_ERR "tf_pm_hibernate(): " | ||
446 | "tf_allocate_w3b failed (error %d)!\n", | ||
447 | error); | ||
448 | return error; | ||
449 | } | ||
450 | |||
451 | /* | ||
452 | * As the polling thread is already hibernating, we | ||
453 | * should send the message and receive the answer ourself | ||
454 | */ | ||
455 | |||
456 | /* build the "prepare to hibernate" message */ | ||
457 | command.header.message_type = TF_MESSAGE_TYPE_MANAGEMENT; | ||
458 | command.management.command = TF_MANAGEMENT_HIBERNATE; | ||
459 | /* Long Form Command */ | ||
460 | command.management.shared_mem_descriptors[0] = 0; | ||
461 | command.management.shared_mem_descriptors[1] = 0; | ||
462 | command.management.w3b_size = | ||
463 | comm->w3b_shmem_size | 0x80000000; | ||
464 | command.management.w3b_start_offset = | ||
465 | comm->w3b_shmem_offset; | ||
466 | command.header.operation_id = (u32) &answer; | ||
467 | |||
468 | tf_dump_command(&command); | ||
469 | |||
470 | /* find a slot to send the message in */ | ||
471 | |||
472 | /* AFY: why not use the function tf_send_receive?? We are | ||
473 | * duplicating a lot of subtle code here. And it's not going to be | ||
474 | * tested because power management is currently not supported by the | ||
475 | * secure world. */ | ||
476 | for (;;) { | ||
477 | int queue_words_count, command_size; | ||
478 | |||
479 | spin_lock(&(comm->lock)); | ||
480 | |||
481 | first_command = tf_read_reg32( | ||
482 | &comm->l1_buffer->first_command); | ||
483 | first_free_command = tf_read_reg32( | ||
484 | &comm->l1_buffer->first_free_command); | ||
485 | |||
486 | queue_words_count = first_free_command - first_command; | ||
487 | command_size = command.header.message_size | ||
488 | + sizeof(struct tf_command_header); | ||
489 | if ((queue_words_count + command_size) < | ||
490 | TF_N_MESSAGE_QUEUE_CAPACITY) { | ||
491 | /* Command queue is not full */ | ||
492 | memcpy(&comm->l1_buffer->command_queue[ | ||
493 | first_free_command % | ||
494 | TF_N_MESSAGE_QUEUE_CAPACITY], | ||
495 | &command, | ||
496 | command_size * sizeof(u32)); | ||
497 | |||
498 | tf_write_reg32(&comm->l1_buffer->first_free_command, | ||
499 | first_free_command + command_size); | ||
500 | |||
501 | spin_unlock(&(comm->lock)); | ||
502 | break; | ||
503 | } | ||
504 | |||
505 | spin_unlock(&(comm->lock)); | ||
506 | (void)tf_schedule_secure_world(comm); | ||
507 | } | ||
508 | |||
509 | /* now wait for the answer, dispatching other answers */ | ||
510 | while (1) { | ||
511 | u32 first_answer; | ||
512 | u32 first_free_answer; | ||
513 | |||
514 | /* check all the answers */ | ||
515 | first_free_answer = tf_read_reg32( | ||
516 | &comm->l1_buffer->first_free_answer); | ||
517 | first_answer = tf_read_reg32( | ||
518 | &comm->l1_buffer->first_answer); | ||
519 | |||
520 | if (first_answer != first_free_answer) { | ||
521 | int bFoundAnswer = 0; | ||
522 | |||
523 | do { | ||
524 | /* answer queue not empty */ | ||
525 | union tf_answer tmp_answer; | ||
526 | struct tf_answer_header header; | ||
527 | /* size of the command in words of 32bit */ | ||
528 | int command_size; | ||
529 | |||
530 | /* get the message_size */ | ||
531 | memcpy(&header, | ||
532 | &comm->l1_buffer->answer_queue[ | ||
533 | first_answer % | ||
534 | TF_S_ANSWER_QUEUE_CAPACITY], | ||
535 | sizeof(struct tf_answer_header)); | ||
536 | command_size = header.message_size + | ||
537 | sizeof(struct tf_answer_header); | ||
538 | |||
539 | /* | ||
540 | * NOTE: message_size is the number of words | ||
541 | * following the first word | ||
542 | */ | ||
543 | memcpy(&tmp_answer, | ||
544 | &comm->l1_buffer->answer_queue[ | ||
545 | first_answer % | ||
546 | TF_S_ANSWER_QUEUE_CAPACITY], | ||
547 | command_size * sizeof(u32)); | ||
548 | |||
549 | tf_dump_answer(&tmp_answer); | ||
550 | |||
551 | if (tmp_answer.header.operation_id == | ||
552 | (u32) &answer) { | ||
553 | /* | ||
554 | * this is the answer to the "prepare to | ||
555 | * hibernate" message | ||
556 | */ | ||
557 | memcpy(&answer, | ||
558 | &tmp_answer, | ||
559 | command_size * sizeof(u32)); | ||
560 | |||
561 | bFoundAnswer = 1; | ||
562 | tf_write_reg32( | ||
563 | &comm->l1_buffer->first_answer, | ||
564 | first_answer + command_size); | ||
565 | break; | ||
566 | } else { | ||
567 | /* | ||
568 | * this is a standard message answer, | ||
569 | * dispatch it | ||
570 | */ | ||
571 | struct tf_answer_struct | ||
572 | *answerStructure; | ||
573 | |||
574 | answerStructure = | ||
575 | (struct tf_answer_struct *) | ||
576 | tmp_answer.header.operation_id; | ||
577 | |||
578 | memcpy(answerStructure->answer, | ||
579 | &tmp_answer, | ||
580 | command_size * sizeof(u32)); | ||
581 | |||
582 | answerStructure->answer_copied = true; | ||
583 | } | ||
584 | |||
585 | tf_write_reg32( | ||
586 | &comm->l1_buffer->first_answer, | ||
587 | first_answer + command_size); | ||
588 | } while (first_answer != first_free_answer); | ||
589 | |||
590 | if (bFoundAnswer) | ||
591 | break; | ||
592 | } | ||
593 | |||
594 | /* | ||
595 | * since the Secure World is at least running the "prepare to | ||
596 | * hibernate" message, its timeout must be immediate So there is | ||
597 | * no need to check its timeout and schedule() the current | ||
598 | * thread | ||
599 | */ | ||
600 | (void)tf_schedule_secure_world(comm); | ||
601 | } /* while (1) */ | ||
602 | |||
603 | printk(KERN_INFO "tf_driver: hibernate.\n"); | ||
604 | return 0; | ||
605 | #endif | ||
606 | } | ||
607 | |||
608 | |||
609 | /* | ||
610 | * Perform a Secure World resume operation. | ||
611 | * The routine returns once the Secure World is active again | ||
612 | * or if an error occurs during the "resume" process | ||
613 | */ | ||
614 | int tf_pm_resume(struct tf_comm *comm) | ||
615 | { | ||
616 | #ifdef CONFIG_TFN | ||
617 | /* this function is useless for the TEGRA product */ | ||
618 | return 0; | ||
619 | #else | ||
620 | int error; | ||
621 | u32 status; | ||
622 | |||
623 | dprintk(KERN_INFO "tf_pm_resume()\n"); | ||
624 | |||
625 | error = tf_smc_wake_up( | ||
626 | tf_get_l2init_descriptor((u32)comm->l1_buffer), | ||
627 | comm->w3b_shmem_offset, | ||
628 | comm->w3b_shmem_size); | ||
629 | |||
630 | if (error != 0) { | ||
631 | dprintk(KERN_ERR "tf_pm_resume(): " | ||
632 | "tf_smc_wake_up failed (error %d)!\n", | ||
633 | error); | ||
634 | return error; | ||
635 | } | ||
636 | |||
637 | status = ((tf_read_reg32(&(comm->l1_buffer->status_s)) | ||
638 | & TF_STATUS_POWER_STATE_MASK) | ||
639 | >> TF_STATUS_POWER_STATE_SHIFT); | ||
640 | |||
641 | while ((status != TF_POWER_MODE_ACTIVE) | ||
642 | && (status != TF_POWER_MODE_PANIC)) { | ||
643 | tf_smc_nyield(); | ||
644 | |||
645 | status = ((tf_read_reg32(&(comm->l1_buffer->status_s)) | ||
646 | & TF_STATUS_POWER_STATE_MASK) | ||
647 | >> TF_STATUS_POWER_STATE_SHIFT); | ||
648 | |||
649 | /* | ||
650 | * As this may last quite a while, call the kernel scheduler to | ||
651 | * hand over CPU for other operations | ||
652 | */ | ||
653 | schedule(); | ||
654 | } | ||
655 | |||
656 | switch (status) { | ||
657 | case TF_POWER_MODE_ACTIVE: | ||
658 | break; | ||
659 | |||
660 | case TF_POWER_MODE_PANIC: | ||
661 | dprintk(KERN_ERR "tf_pm_resume(): " | ||
662 | "Secure World POWER_MODE_PANIC!\n"); | ||
663 | return -EINVAL; | ||
664 | |||
665 | default: | ||
666 | dprintk(KERN_ERR "tf_pm_resume(): " | ||
667 | "unexpected Secure World POWER_MODE (%d)!\n", status); | ||
668 | return -EINVAL; | ||
669 | } | ||
670 | |||
671 | dprintk(KERN_INFO "tf_pm_resume() succeeded\n"); | ||
672 | return 0; | ||
673 | #endif | ||
674 | } | ||
675 | |||
676 | /*---------------------------------------------------------------------------- | ||
677 | * Communication initialization and termination | ||
678 | *----------------------------------------------------------------------------*/ | ||
679 | |||
680 | /* | ||
681 | * Handles the software interrupts issued by the Secure World. | ||
682 | */ | ||
683 | static irqreturn_t tf_soft_int_handler(int irq, void *dev_id) | ||
684 | { | ||
685 | struct tf_comm *comm = (struct tf_comm *) dev_id; | ||
686 | |||
687 | if (comm->l1_buffer == NULL) | ||
688 | return IRQ_NONE; | ||
689 | |||
690 | if ((tf_read_reg32(&comm->l1_buffer->status_s) & | ||
691 | TF_STATUS_P_MASK) == 0) | ||
692 | /* interrupt not issued by the Trusted Foundations Software */ | ||
693 | return IRQ_NONE; | ||
694 | |||
695 | tf_smc_reset_irq(); | ||
696 | |||
697 | /* signal N_SM_EVENT */ | ||
698 | wake_up(&comm->wait_queue); | ||
699 | |||
700 | return IRQ_HANDLED; | ||
701 | } | ||
702 | |||
703 | /* | ||
704 | * Initializes the communication with the Secure World. | ||
705 | * The L1 shared buffer is allocated and the Secure World | ||
706 | * is yielded for the first time. | ||
707 | * returns successfuly once the communication with | ||
708 | * the Secure World is up and running | ||
709 | * | ||
710 | * Returns 0 upon success or appropriate error code | ||
711 | * upon failure | ||
712 | */ | ||
713 | int tf_init(struct tf_comm *comm) | ||
714 | { | ||
715 | int error; | ||
716 | struct page *buffer_page; | ||
717 | u32 protocol_version; | ||
718 | |||
719 | dprintk(KERN_INFO "tf_init()\n"); | ||
720 | |||
721 | spin_lock_init(&(comm->lock)); | ||
722 | comm->flags = 0; | ||
723 | comm->l1_buffer = NULL; | ||
724 | init_waitqueue_head(&(comm->wait_queue)); | ||
725 | |||
726 | /* | ||
727 | * Check the Secure World protocol version is the expected one. | ||
728 | */ | ||
729 | tf_smc_get_protocol_version(&protocol_version); | ||
730 | |||
731 | if ((GET_PROTOCOL_MAJOR_VERSION(protocol_version)) | ||
732 | != TF_S_PROTOCOL_MAJOR_VERSION) { | ||
733 | printk(KERN_ERR "tf_init():" | ||
734 | " Unsupported Secure World Major Version " | ||
735 | "(0x%02X, expected 0x%02X)!\n", | ||
736 | GET_PROTOCOL_MAJOR_VERSION(protocol_version), | ||
737 | TF_S_PROTOCOL_MAJOR_VERSION); | ||
738 | error = -EIO; | ||
739 | goto error; | ||
740 | } | ||
741 | |||
742 | /* | ||
743 | * Register the software interrupt handler if required to. | ||
744 | */ | ||
745 | if (comm->soft_int_irq != -1) { | ||
746 | dprintk(KERN_INFO "tf_init(): " | ||
747 | "Registering software interrupt handler (IRQ %d)\n", | ||
748 | comm->soft_int_irq); | ||
749 | |||
750 | error = request_irq(comm->soft_int_irq, | ||
751 | tf_soft_int_handler, | ||
752 | IRQF_SHARED, | ||
753 | TF_DEVICE_BASE_NAME, | ||
754 | comm); | ||
755 | if (error != 0) { | ||
756 | dprintk(KERN_ERR "tf_init(): " | ||
757 | "request_irq failed for irq %d (error %d)\n", | ||
758 | comm->soft_int_irq, error); | ||
759 | goto error; | ||
760 | } | ||
761 | set_bit(TF_COMM_FLAG_IRQ_REQUESTED, &(comm->flags)); | ||
762 | } | ||
763 | |||
764 | /* | ||
765 | * Allocate and initialize the L1 shared buffer. | ||
766 | */ | ||
767 | comm->l1_buffer = (void *) internal_get_zeroed_page(GFP_KERNEL); | ||
768 | if (comm->l1_buffer == NULL) { | ||
769 | printk(KERN_ERR "tf_init():" | ||
770 | " get_zeroed_page failed for L1 shared buffer!\n"); | ||
771 | error = -ENOMEM; | ||
772 | goto error; | ||
773 | } | ||
774 | |||
775 | /* | ||
776 | * Ensure the page storing the L1 shared buffer is mapped. | ||
777 | */ | ||
778 | buffer_page = virt_to_page(comm->l1_buffer); | ||
779 | trylock_page(buffer_page); | ||
780 | |||
781 | dprintk(KERN_INFO "tf_init(): " | ||
782 | "L1 shared buffer allocated at virtual:%p, " | ||
783 | "physical:%p (page:%p)\n", | ||
784 | comm->l1_buffer, | ||
785 | (void *)virt_to_phys(comm->l1_buffer), | ||
786 | buffer_page); | ||
787 | |||
788 | set_bit(TF_COMM_FLAG_L1_SHARED_ALLOCATED, &(comm->flags)); | ||
789 | |||
790 | /* | ||
791 | * Init SMC | ||
792 | */ | ||
793 | error = tf_smc_init( | ||
794 | tf_get_l2init_descriptor((u32)comm->l1_buffer)); | ||
795 | if (error != S_SUCCESS) { | ||
796 | dprintk(KERN_ERR "tf_init(): " | ||
797 | "tf_smc_init failed (error 0x%08X)!\n", | ||
798 | error); | ||
799 | goto error; | ||
800 | } | ||
801 | |||
802 | /* | ||
803 | * check whether the interrupts are actually enabled | ||
804 | * If not, remove irq handler | ||
805 | */ | ||
806 | if ((tf_read_reg32(&comm->l1_buffer->config_flag_s) & | ||
807 | TF_CONFIG_FLAG_S) == 0) { | ||
808 | if (test_and_clear_bit(TF_COMM_FLAG_IRQ_REQUESTED, | ||
809 | &(comm->flags)) != 0) { | ||
810 | dprintk(KERN_INFO "tf_init(): " | ||
811 | "Interrupts not used, unregistering " | ||
812 | "softint (IRQ %d)\n", | ||
813 | comm->soft_int_irq); | ||
814 | |||
815 | free_irq(comm->soft_int_irq, comm); | ||
816 | } | ||
817 | } else { | ||
818 | if (test_bit(TF_COMM_FLAG_IRQ_REQUESTED, | ||
819 | &(comm->flags)) == 0) { | ||
820 | /* | ||
821 | * Interrupts are enabled in the Secure World, but not | ||
822 | * handled by driver | ||
823 | */ | ||
824 | dprintk(KERN_ERR "tf_init(): " | ||
825 | "soft_interrupt argument not provided\n"); | ||
826 | error = -EINVAL; | ||
827 | goto error; | ||
828 | } | ||
829 | } | ||
830 | |||
831 | /* | ||
832 | * Successful completion. | ||
833 | */ | ||
834 | |||
835 | /* yield for the first time */ | ||
836 | (void)tf_schedule_secure_world(comm); | ||
837 | |||
838 | dprintk(KERN_INFO "tf_init(): Success\n"); | ||
839 | return S_SUCCESS; | ||
840 | |||
841 | error: | ||
842 | /* | ||
843 | * Error handling. | ||
844 | */ | ||
845 | dprintk(KERN_INFO "tf_init(): Failure (error %d)\n", | ||
846 | error); | ||
847 | tf_terminate(comm); | ||
848 | return error; | ||
849 | } | ||
850 | |||
851 | |||
852 | /* | ||
853 | * Attempt to terminate the communication with the Secure World. | ||
854 | * The L1 shared buffer is freed. | ||
855 | * Calling this routine terminates definitaly the communication | ||
856 | * with the Secure World : there is no way to inform the Secure World of a new | ||
857 | * L1 shared buffer to be used once it has been initialized. | ||
858 | */ | ||
859 | void tf_terminate(struct tf_comm *comm) | ||
860 | { | ||
861 | dprintk(KERN_INFO "tf_terminate()\n"); | ||
862 | |||
863 | set_bit(TF_COMM_FLAG_TERMINATING, &(comm->flags)); | ||
864 | |||
865 | if ((test_bit(TF_COMM_FLAG_W3B_ALLOCATED, | ||
866 | &(comm->flags))) != 0) { | ||
867 | dprintk(KERN_INFO "tf_terminate(): " | ||
868 | "Freeing the W3B buffer...\n"); | ||
869 | tf_free_w3b(comm); | ||
870 | } | ||
871 | |||
872 | if ((test_bit(TF_COMM_FLAG_L1_SHARED_ALLOCATED, | ||
873 | &(comm->flags))) != 0) { | ||
874 | __clear_page_locked(virt_to_page(comm->l1_buffer)); | ||
875 | internal_free_page((unsigned long) comm->l1_buffer); | ||
876 | } | ||
877 | |||
878 | if ((test_bit(TF_COMM_FLAG_IRQ_REQUESTED, | ||
879 | &(comm->flags))) != 0) { | ||
880 | dprintk(KERN_INFO "tf_terminate(): " | ||
881 | "Unregistering softint (IRQ %d)\n", | ||
882 | comm->soft_int_irq); | ||
883 | free_irq(comm->soft_int_irq, comm); | ||
884 | } | ||
885 | } | ||