diff options
Diffstat (limited to 'security/tf_driver/tf_device.c')
-rw-r--r-- | security/tf_driver/tf_device.c | 796 |
1 files changed, 796 insertions, 0 deletions
diff --git a/security/tf_driver/tf_device.c b/security/tf_driver/tf_device.c new file mode 100644 index 00000000000..ad44b46c206 --- /dev/null +++ b/security/tf_driver/tf_device.c | |||
@@ -0,0 +1,796 @@ | |||
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 <linux/atomic.h> | ||
21 | #include <linux/uaccess.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/errno.h> | ||
24 | #include <linux/mm.h> | ||
25 | #include <linux/page-flags.h> | ||
26 | #include <linux/pm.h> | ||
27 | #include <linux/syscore_ops.h> | ||
28 | #include <linux/vmalloc.h> | ||
29 | #include <linux/signal.h> | ||
30 | #ifdef CONFIG_ANDROID | ||
31 | #include <linux/device.h> | ||
32 | #endif | ||
33 | |||
34 | #include "tf_protocol.h" | ||
35 | #include "tf_defs.h" | ||
36 | #include "tf_util.h" | ||
37 | #include "tf_conn.h" | ||
38 | #include "tf_comm.h" | ||
39 | #ifdef CONFIG_TF_ZEBRA | ||
40 | #include <plat/cpu.h> | ||
41 | #include "tf_zebra.h" | ||
42 | #endif | ||
43 | #ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS | ||
44 | #include "tf_crypto.h" | ||
45 | #endif | ||
46 | |||
47 | #include "s_version.h" | ||
48 | |||
49 | /*---------------------------------------------------------------------------- | ||
50 | * Forward Declarations | ||
51 | *----------------------------------------------------------------------------*/ | ||
52 | |||
53 | /* | ||
54 | * Creates and registers the device to be managed by the specified driver. | ||
55 | * | ||
56 | * Returns zero upon successful completion, or an appropriate error code upon | ||
57 | * failure. | ||
58 | */ | ||
59 | static int tf_device_register(void); | ||
60 | |||
61 | |||
62 | /* | ||
63 | * Implements the device Open callback. | ||
64 | */ | ||
65 | static int tf_device_open( | ||
66 | struct inode *inode, | ||
67 | struct file *file); | ||
68 | |||
69 | |||
70 | /* | ||
71 | * Implements the device Release callback. | ||
72 | */ | ||
73 | static int tf_device_release( | ||
74 | struct inode *inode, | ||
75 | struct file *file); | ||
76 | |||
77 | |||
78 | /* | ||
79 | * Implements the device ioctl callback. | ||
80 | */ | ||
81 | static long tf_device_ioctl( | ||
82 | struct file *file, | ||
83 | unsigned int ioctl_num, | ||
84 | unsigned long ioctl_param); | ||
85 | |||
86 | |||
87 | /* | ||
88 | * Implements the device shutdown callback. | ||
89 | */ | ||
90 | static int tf_device_shutdown(void); | ||
91 | |||
92 | |||
93 | /* | ||
94 | * Implements the device suspend callback. | ||
95 | */ | ||
96 | static int tf_device_suspend(void); | ||
97 | |||
98 | |||
99 | /* | ||
100 | * Implements the device resume callback. | ||
101 | */ | ||
102 | static int tf_device_resume(void); | ||
103 | |||
104 | |||
105 | /*--------------------------------------------------------------------------- | ||
106 | * Module Parameters | ||
107 | *---------------------------------------------------------------------------*/ | ||
108 | |||
109 | /* | ||
110 | * The device major number used to register a unique character device driver. | ||
111 | * Let the default value be 122 | ||
112 | */ | ||
113 | static int device_major_number = 122; | ||
114 | |||
115 | module_param(device_major_number, int, 0000); | ||
116 | MODULE_PARM_DESC(device_major_number, | ||
117 | "The device major number used to register a unique character " | ||
118 | "device driver"); | ||
119 | |||
120 | #ifdef CONFIG_TF_TRUSTZONE | ||
121 | /** | ||
122 | * The softint interrupt line used by the Secure World. | ||
123 | */ | ||
124 | static int soft_interrupt = -1; | ||
125 | |||
126 | module_param(soft_interrupt, int, 0000); | ||
127 | MODULE_PARM_DESC(soft_interrupt, | ||
128 | "The softint interrupt line used by the Secure world"); | ||
129 | #endif | ||
130 | |||
131 | #ifdef CONFIG_TF_DRIVER_DEBUG_SUPPORT | ||
132 | unsigned tf_debug_level = UINT_MAX; | ||
133 | module_param_named(debug, tf_debug_level, uint, 0644); | ||
134 | #endif | ||
135 | |||
136 | #ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS | ||
137 | char *tf_integrity_hmac_sha256_expected_value; | ||
138 | module_param_named(hmac_sha256, tf_integrity_hmac_sha256_expected_value, | ||
139 | charp, 0444); | ||
140 | |||
141 | #ifdef CONFIG_TF_DRIVER_FAULT_INJECTION | ||
142 | unsigned tf_fault_injection_mask; | ||
143 | module_param_named(fault, tf_fault_injection_mask, uint, 0644); | ||
144 | #endif | ||
145 | |||
146 | int tf_self_test_blkcipher_align; | ||
147 | module_param_named(post_align, tf_self_test_blkcipher_align, int, 0644); | ||
148 | int tf_self_test_blkcipher_use_vmalloc; | ||
149 | module_param_named(post_vmalloc, tf_self_test_blkcipher_use_vmalloc, int, 0644); | ||
150 | #endif | ||
151 | |||
152 | #ifdef CONFIG_ANDROID | ||
153 | static struct class *tf_class; | ||
154 | #endif | ||
155 | |||
156 | /*---------------------------------------------------------------------------- | ||
157 | * Global Variables | ||
158 | *----------------------------------------------------------------------------*/ | ||
159 | |||
160 | /* | ||
161 | * tf_driver character device definitions. | ||
162 | * read and write methods are not defined | ||
163 | * and will return an error if used by user space | ||
164 | */ | ||
165 | static const struct file_operations g_tf_device_file_ops = { | ||
166 | .owner = THIS_MODULE, | ||
167 | .open = tf_device_open, | ||
168 | .release = tf_device_release, | ||
169 | .unlocked_ioctl = tf_device_ioctl, | ||
170 | .llseek = no_llseek, | ||
171 | }; | ||
172 | |||
173 | |||
174 | static struct syscore_ops g_tf_device_syscore_ops = { | ||
175 | .shutdown = tf_device_shutdown, | ||
176 | .suspend = tf_device_suspend, | ||
177 | .resume = tf_device_resume, | ||
178 | }; | ||
179 | |||
180 | /* The single device supported by this driver */ | ||
181 | static struct tf_device g_tf_dev; | ||
182 | |||
183 | /*---------------------------------------------------------------------------- | ||
184 | * Implementations | ||
185 | *----------------------------------------------------------------------------*/ | ||
186 | |||
187 | struct tf_device *tf_get_device(void) | ||
188 | { | ||
189 | return &g_tf_dev; | ||
190 | } | ||
191 | |||
192 | /* | ||
193 | * sysfs entries | ||
194 | */ | ||
195 | struct tf_sysfs_entry { | ||
196 | struct attribute attr; | ||
197 | ssize_t (*show)(struct tf_device *, char *); | ||
198 | ssize_t (*store)(struct tf_device *, const char *, size_t); | ||
199 | }; | ||
200 | |||
201 | /* | ||
202 | * sysfs entry showing allocation stats | ||
203 | */ | ||
204 | static ssize_t info_show(struct tf_device *dev, char *buf) | ||
205 | { | ||
206 | struct tf_device_stats *dev_stats = &dev->stats; | ||
207 | |||
208 | return snprintf(buf, PAGE_SIZE, | ||
209 | "stat.memories.allocated: %d\n" | ||
210 | "stat.pages.allocated: %d\n" | ||
211 | "stat.pages.locked: %d\n", | ||
212 | atomic_read(&dev_stats->stat_memories_allocated), | ||
213 | atomic_read(&dev_stats->stat_pages_allocated), | ||
214 | atomic_read(&dev_stats->stat_pages_locked)); | ||
215 | } | ||
216 | static struct tf_sysfs_entry tf_info_entry = __ATTR_RO(info); | ||
217 | |||
218 | #ifdef CONFIG_TF_ZEBRA | ||
219 | /* | ||
220 | * sysfs entry showing whether secure world is up and running | ||
221 | */ | ||
222 | static ssize_t tf_started_show(struct tf_device *dev, char *buf) | ||
223 | { | ||
224 | int tf_started = test_bit(TF_COMM_FLAG_PA_AVAILABLE, | ||
225 | &dev->sm.flags); | ||
226 | |||
227 | return snprintf(buf, PAGE_SIZE, "%s\n", tf_started ? "yes" : "no"); | ||
228 | } | ||
229 | static struct tf_sysfs_entry tf_started_entry = | ||
230 | __ATTR_RO(tf_started); | ||
231 | |||
232 | static ssize_t workspace_addr_show(struct tf_device *dev, char *buf) | ||
233 | { | ||
234 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", dev->workspace_addr); | ||
235 | } | ||
236 | static struct tf_sysfs_entry tf_workspace_addr_entry = | ||
237 | __ATTR_RO(workspace_addr); | ||
238 | |||
239 | static ssize_t workspace_size_show(struct tf_device *dev, char *buf) | ||
240 | { | ||
241 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", dev->workspace_size); | ||
242 | } | ||
243 | static struct tf_sysfs_entry tf_workspace_size_entry = | ||
244 | __ATTR_RO(workspace_size); | ||
245 | #endif | ||
246 | |||
247 | static ssize_t tf_attr_show(struct kobject *kobj, struct attribute *attr, | ||
248 | char *page) | ||
249 | { | ||
250 | struct tf_sysfs_entry *entry = container_of(attr, struct tf_sysfs_entry, | ||
251 | attr); | ||
252 | struct tf_device *dev = container_of(kobj, struct tf_device, kobj); | ||
253 | |||
254 | if (!entry->show) | ||
255 | return -EIO; | ||
256 | |||
257 | return entry->show(dev, page); | ||
258 | } | ||
259 | |||
260 | static ssize_t tf_attr_store(struct kobject *kobj, struct attribute *attr, | ||
261 | const char *page, size_t length) | ||
262 | { | ||
263 | struct tf_sysfs_entry *entry = container_of(attr, struct tf_sysfs_entry, | ||
264 | attr); | ||
265 | struct tf_device *dev = container_of(kobj, struct tf_device, kobj); | ||
266 | |||
267 | if (!entry->store) | ||
268 | return -EIO; | ||
269 | |||
270 | return entry->store(dev, page, length); | ||
271 | } | ||
272 | |||
273 | static void tf_kobj_release(struct kobject *kobj) {} | ||
274 | |||
275 | static struct attribute *tf_default_attrs[] = { | ||
276 | &tf_info_entry.attr, | ||
277 | #ifdef CONFIG_TF_ZEBRA | ||
278 | &tf_started_entry.attr, | ||
279 | &tf_workspace_addr_entry.attr, | ||
280 | &tf_workspace_size_entry.attr, | ||
281 | #endif | ||
282 | NULL, | ||
283 | }; | ||
284 | static const struct sysfs_ops tf_sysfs_ops = { | ||
285 | .show = tf_attr_show, | ||
286 | .store = tf_attr_store, | ||
287 | }; | ||
288 | static struct kobj_type tf_ktype = { | ||
289 | .release = tf_kobj_release, | ||
290 | .sysfs_ops = &tf_sysfs_ops, | ||
291 | .default_attrs = tf_default_attrs | ||
292 | }; | ||
293 | |||
294 | /*----------------------------------------------------------------------------*/ | ||
295 | |||
296 | #if defined(MODULE) && defined(CONFIG_TF_ZEBRA) | ||
297 | static char *smc_mem; | ||
298 | module_param(smc_mem, charp, S_IRUGO); | ||
299 | #endif | ||
300 | |||
301 | /* | ||
302 | * First routine called when the kernel module is loaded | ||
303 | */ | ||
304 | static int __init tf_device_register(void) | ||
305 | { | ||
306 | int error; | ||
307 | struct tf_device *dev = &g_tf_dev; | ||
308 | |||
309 | dprintk(KERN_INFO "tf_device_register()\n"); | ||
310 | |||
311 | /* | ||
312 | * Initialize the device | ||
313 | */ | ||
314 | dev->dev_number = MKDEV(device_major_number, | ||
315 | TF_DEVICE_MINOR_NUMBER); | ||
316 | cdev_init(&dev->cdev, &g_tf_device_file_ops); | ||
317 | dev->cdev.owner = THIS_MODULE; | ||
318 | |||
319 | INIT_LIST_HEAD(&dev->connection_list); | ||
320 | spin_lock_init(&dev->connection_list_lock); | ||
321 | |||
322 | #if defined(MODULE) && defined(CONFIG_TF_ZEBRA) | ||
323 | error = (*tf_comm_early_init)(); | ||
324 | if (error) | ||
325 | goto module_early_init_failed; | ||
326 | |||
327 | error = tf_device_mshield_init(smc_mem); | ||
328 | if (error) | ||
329 | goto mshield_init_failed; | ||
330 | |||
331 | #ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS | ||
332 | error = tf_crypto_hmac_module_init(); | ||
333 | if (error) | ||
334 | goto hmac_init_failed; | ||
335 | |||
336 | error = tf_self_test_register_device(); | ||
337 | if (error) | ||
338 | goto self_test_register_device_failed; | ||
339 | #endif | ||
340 | #endif | ||
341 | |||
342 | /* register the sysfs object driver stats */ | ||
343 | error = kobject_init_and_add(&dev->kobj, &tf_ktype, NULL, "%s", | ||
344 | TF_DEVICE_BASE_NAME); | ||
345 | if (error) { | ||
346 | printk(KERN_ERR "tf_device_register(): " | ||
347 | "kobject_init_and_add failed (error %d)!\n", error); | ||
348 | kobject_put(&dev->kobj); | ||
349 | goto kobject_init_and_add_failed; | ||
350 | } | ||
351 | |||
352 | /* | ||
353 | * Register the system device. | ||
354 | */ | ||
355 | register_syscore_ops(&g_tf_device_syscore_ops); | ||
356 | |||
357 | /* | ||
358 | * Register the char device. | ||
359 | */ | ||
360 | printk(KERN_INFO "Registering char device %s (%u:%u)\n", | ||
361 | TF_DEVICE_BASE_NAME, | ||
362 | MAJOR(dev->dev_number), | ||
363 | MINOR(dev->dev_number)); | ||
364 | error = register_chrdev_region(dev->dev_number, 1, | ||
365 | TF_DEVICE_BASE_NAME); | ||
366 | if (error != 0) { | ||
367 | printk(KERN_ERR "tf_device_register():" | ||
368 | " register_chrdev_region failed (error %d)!\n", | ||
369 | error); | ||
370 | goto register_chrdev_region_failed; | ||
371 | } | ||
372 | |||
373 | error = cdev_add(&dev->cdev, dev->dev_number, 1); | ||
374 | if (error != 0) { | ||
375 | printk(KERN_ERR "tf_device_register(): " | ||
376 | "cdev_add failed (error %d)!\n", | ||
377 | error); | ||
378 | goto cdev_add_failed; | ||
379 | } | ||
380 | |||
381 | /* | ||
382 | * Initialize the communication with the Secure World. | ||
383 | */ | ||
384 | #ifdef CONFIG_TF_TRUSTZONE | ||
385 | dev->sm.soft_int_irq = soft_interrupt; | ||
386 | #endif | ||
387 | error = tf_init(&g_tf_dev.sm); | ||
388 | if (error != S_SUCCESS) { | ||
389 | dprintk(KERN_ERR "tf_device_register(): " | ||
390 | "tf_init failed (error %d)!\n", | ||
391 | error); | ||
392 | goto init_failed; | ||
393 | } | ||
394 | |||
395 | #ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS | ||
396 | error = tf_self_test_post_init(&(dev_stats->kobj)); | ||
397 | /* N.B. error > 0 indicates a POST failure, which will not | ||
398 | prevent the module from loading. */ | ||
399 | if (error < 0) { | ||
400 | dprintk(KERN_ERR "tf_device_register(): " | ||
401 | "tf_self_test_post_vectors failed (error %d)!\n", | ||
402 | error); | ||
403 | goto post_failed; | ||
404 | } | ||
405 | #endif | ||
406 | |||
407 | #ifdef CONFIG_ANDROID | ||
408 | tf_class = class_create(THIS_MODULE, TF_DEVICE_BASE_NAME); | ||
409 | device_create(tf_class, NULL, | ||
410 | dev->dev_number, | ||
411 | NULL, TF_DEVICE_BASE_NAME); | ||
412 | #endif | ||
413 | |||
414 | #ifdef CONFIG_TF_ZEBRA | ||
415 | /* | ||
416 | * Initializes the /dev/tf_ctrl device node. | ||
417 | */ | ||
418 | error = tf_ctrl_device_register(); | ||
419 | if (error) | ||
420 | goto ctrl_failed; | ||
421 | #endif | ||
422 | |||
423 | #ifdef CONFIG_TF_DRIVER_DEBUG_SUPPORT | ||
424 | address_cache_property((unsigned long) &tf_device_register); | ||
425 | #endif | ||
426 | /* | ||
427 | * Successful completion. | ||
428 | */ | ||
429 | |||
430 | dprintk(KERN_INFO "tf_device_register(): Success\n"); | ||
431 | return 0; | ||
432 | |||
433 | /* | ||
434 | * Error: undo all operations in the reverse order | ||
435 | */ | ||
436 | #ifdef CONFIG_TF_ZEBRA | ||
437 | ctrl_failed: | ||
438 | #endif | ||
439 | #ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS | ||
440 | tf_self_test_post_exit(); | ||
441 | post_failed: | ||
442 | #endif | ||
443 | init_failed: | ||
444 | cdev_del(&dev->cdev); | ||
445 | cdev_add_failed: | ||
446 | unregister_chrdev_region(dev->dev_number, 1); | ||
447 | register_chrdev_region_failed: | ||
448 | unregister_syscore_ops(&g_tf_device_syscore_ops); | ||
449 | kobject_init_and_add_failed: | ||
450 | kobject_del(&g_tf_dev.kobj); | ||
451 | |||
452 | #if defined(MODULE) && defined(CONFIG_TF_ZEBRA) | ||
453 | #ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS | ||
454 | tf_self_test_unregister_device(); | ||
455 | self_test_register_device_failed: | ||
456 | tf_crypto_hmac_module_exit(); | ||
457 | hmac_init_failed: | ||
458 | #endif | ||
459 | tf_device_mshield_exit(); | ||
460 | mshield_init_failed: | ||
461 | module_early_init_failed: | ||
462 | #endif | ||
463 | dprintk(KERN_INFO "tf_device_register(): Failure (error %d)\n", | ||
464 | error); | ||
465 | return error; | ||
466 | } | ||
467 | |||
468 | /*----------------------------------------------------------------------------*/ | ||
469 | |||
470 | static int tf_device_open(struct inode *inode, struct file *file) | ||
471 | { | ||
472 | int error; | ||
473 | struct tf_device *dev = &g_tf_dev; | ||
474 | struct tf_connection *connection = NULL; | ||
475 | |||
476 | dprintk(KERN_INFO "tf_device_open(%u:%u, %p)\n", | ||
477 | imajor(inode), iminor(inode), file); | ||
478 | |||
479 | /* Dummy lseek for non-seekable driver */ | ||
480 | error = nonseekable_open(inode, file); | ||
481 | if (error != 0) { | ||
482 | dprintk(KERN_ERR "tf_device_open(%p): " | ||
483 | "nonseekable_open failed (error %d)!\n", | ||
484 | file, error); | ||
485 | goto error; | ||
486 | } | ||
487 | |||
488 | #ifndef CONFIG_ANDROID | ||
489 | /* | ||
490 | * Check file flags. We only autthorize the O_RDWR access | ||
491 | */ | ||
492 | if (file->f_flags != O_RDWR) { | ||
493 | dprintk(KERN_ERR "tf_device_open(%p): " | ||
494 | "Invalid access mode %u\n", | ||
495 | file, file->f_flags); | ||
496 | error = -EACCES; | ||
497 | goto error; | ||
498 | } | ||
499 | #endif | ||
500 | |||
501 | /* | ||
502 | * Open a new connection. | ||
503 | */ | ||
504 | |||
505 | error = tf_open(dev, file, &connection); | ||
506 | if (error != 0) { | ||
507 | dprintk(KERN_ERR "tf_device_open(%p): " | ||
508 | "tf_open failed (error %d)!\n", | ||
509 | file, error); | ||
510 | goto error; | ||
511 | } | ||
512 | |||
513 | file->private_data = connection; | ||
514 | |||
515 | /* | ||
516 | * Send the CreateDeviceContext command to the secure | ||
517 | */ | ||
518 | error = tf_create_device_context(connection); | ||
519 | if (error != 0) { | ||
520 | dprintk(KERN_ERR "tf_device_open(%p): " | ||
521 | "tf_create_device_context failed (error %d)!\n", | ||
522 | file, error); | ||
523 | goto error1; | ||
524 | } | ||
525 | |||
526 | /* | ||
527 | * Successful completion. | ||
528 | */ | ||
529 | |||
530 | dprintk(KERN_INFO "tf_device_open(%p): Success (connection=%p)\n", | ||
531 | file, connection); | ||
532 | return 0; | ||
533 | |||
534 | /* | ||
535 | * Error handling. | ||
536 | */ | ||
537 | |||
538 | error1: | ||
539 | tf_close(connection); | ||
540 | error: | ||
541 | dprintk(KERN_INFO "tf_device_open(%p): Failure (error %d)\n", | ||
542 | file, error); | ||
543 | return error; | ||
544 | } | ||
545 | |||
546 | /*----------------------------------------------------------------------------*/ | ||
547 | |||
548 | static int tf_device_release(struct inode *inode, struct file *file) | ||
549 | { | ||
550 | struct tf_connection *connection; | ||
551 | |||
552 | dprintk(KERN_INFO "tf_device_release(%u:%u, %p)\n", | ||
553 | imajor(inode), iminor(inode), file); | ||
554 | |||
555 | connection = tf_conn_from_file(file); | ||
556 | tf_close(connection); | ||
557 | |||
558 | dprintk(KERN_INFO "tf_device_release(%p): Success\n", file); | ||
559 | return 0; | ||
560 | } | ||
561 | |||
562 | /*----------------------------------------------------------------------------*/ | ||
563 | |||
564 | static long tf_device_ioctl(struct file *file, unsigned int ioctl_num, | ||
565 | unsigned long ioctl_param) | ||
566 | { | ||
567 | int result = S_SUCCESS; | ||
568 | struct tf_connection *connection; | ||
569 | union tf_command command; | ||
570 | struct tf_command_header header; | ||
571 | union tf_answer answer; | ||
572 | u32 command_size; | ||
573 | u32 answer_size; | ||
574 | void *user_answer; | ||
575 | |||
576 | dprintk(KERN_INFO "tf_device_ioctl(%p, %u, %p)\n", | ||
577 | file, ioctl_num, (void *) ioctl_param); | ||
578 | |||
579 | switch (ioctl_num) { | ||
580 | case IOCTL_TF_GET_VERSION: | ||
581 | /* ioctl is asking for the driver interface version */ | ||
582 | result = TF_DRIVER_INTERFACE_VERSION; | ||
583 | goto exit; | ||
584 | |||
585 | case IOCTL_TF_EXCHANGE: | ||
586 | /* | ||
587 | * ioctl is asking to perform a message exchange with the Secure | ||
588 | * Module | ||
589 | */ | ||
590 | |||
591 | /* | ||
592 | * Make a local copy of the data from the user application | ||
593 | * This routine checks the data is readable | ||
594 | * | ||
595 | * Get the header first. | ||
596 | */ | ||
597 | if (copy_from_user(&header, | ||
598 | (struct tf_command_header *)ioctl_param, | ||
599 | sizeof(struct tf_command_header))) { | ||
600 | dprintk(KERN_ERR "tf_device_ioctl(%p): " | ||
601 | "Cannot access ioctl parameter %p\n", | ||
602 | file, (void *) ioctl_param); | ||
603 | result = -EFAULT; | ||
604 | goto exit; | ||
605 | } | ||
606 | |||
607 | /* size in words of u32 */ | ||
608 | command_size = header.message_size + | ||
609 | sizeof(struct tf_command_header)/sizeof(u32); | ||
610 | if (command_size > sizeof(command)/sizeof(u32)) { | ||
611 | dprintk(KERN_ERR "tf_device_ioctl(%p): " | ||
612 | "Buffer overflow: too many bytes to copy %d\n", | ||
613 | file, command_size); | ||
614 | result = -EFAULT; | ||
615 | goto exit; | ||
616 | } | ||
617 | |||
618 | if (copy_from_user(&command, | ||
619 | (union tf_command *)ioctl_param, | ||
620 | command_size * sizeof(u32))) { | ||
621 | dprintk(KERN_ERR "tf_device_ioctl(%p): " | ||
622 | "Cannot access ioctl parameter %p\n", | ||
623 | file, (void *) ioctl_param); | ||
624 | result = -EFAULT; | ||
625 | goto exit; | ||
626 | } | ||
627 | |||
628 | connection = tf_conn_from_file(file); | ||
629 | BUG_ON(connection == NULL); | ||
630 | |||
631 | /* | ||
632 | * The answer memory space address is in the operation_id field | ||
633 | */ | ||
634 | user_answer = (void *) command.header.operation_id; | ||
635 | |||
636 | atomic_inc(&(connection->pending_op_count)); | ||
637 | |||
638 | dprintk(KERN_WARNING "tf_device_ioctl(%p): " | ||
639 | "Sending message type 0x%08x\n", | ||
640 | file, command.header.message_type); | ||
641 | |||
642 | switch (command.header.message_type) { | ||
643 | case TF_MESSAGE_TYPE_OPEN_CLIENT_SESSION: | ||
644 | result = tf_open_client_session(connection, | ||
645 | &command, &answer); | ||
646 | break; | ||
647 | |||
648 | case TF_MESSAGE_TYPE_CLOSE_CLIENT_SESSION: | ||
649 | result = tf_close_client_session(connection, | ||
650 | &command, &answer); | ||
651 | break; | ||
652 | |||
653 | case TF_MESSAGE_TYPE_REGISTER_SHARED_MEMORY: | ||
654 | result = tf_register_shared_memory(connection, | ||
655 | &command, &answer); | ||
656 | break; | ||
657 | |||
658 | case TF_MESSAGE_TYPE_RELEASE_SHARED_MEMORY: | ||
659 | result = tf_release_shared_memory(connection, | ||
660 | &command, &answer); | ||
661 | break; | ||
662 | |||
663 | case TF_MESSAGE_TYPE_INVOKE_CLIENT_COMMAND: | ||
664 | result = tf_invoke_client_command(connection, | ||
665 | &command, &answer); | ||
666 | break; | ||
667 | |||
668 | case TF_MESSAGE_TYPE_CANCEL_CLIENT_COMMAND: | ||
669 | result = tf_cancel_client_command(connection, | ||
670 | &command, &answer); | ||
671 | break; | ||
672 | |||
673 | default: | ||
674 | dprintk(KERN_ERR "tf_device_ioctl(%p): " | ||
675 | "Incorrect message type (0x%08x)!\n", | ||
676 | connection, command.header.message_type); | ||
677 | result = -EOPNOTSUPP; | ||
678 | break; | ||
679 | } | ||
680 | |||
681 | atomic_dec(&(connection->pending_op_count)); | ||
682 | |||
683 | if (result != 0) { | ||
684 | dprintk(KERN_WARNING "tf_device_ioctl(%p): " | ||
685 | "Operation returning error code 0x%08x)!\n", | ||
686 | file, result); | ||
687 | goto exit; | ||
688 | } | ||
689 | |||
690 | /* | ||
691 | * Copy the answer back to the user space application. | ||
692 | * The driver does not check this field, only copy back to user | ||
693 | * space the data handed over by Secure World | ||
694 | */ | ||
695 | answer_size = answer.header.message_size + | ||
696 | sizeof(struct tf_answer_header)/sizeof(u32); | ||
697 | if (copy_to_user(user_answer, | ||
698 | &answer, answer_size * sizeof(u32))) { | ||
699 | dprintk(KERN_WARNING "tf_device_ioctl(%p): " | ||
700 | "Failed to copy back the full command " | ||
701 | "answer to %p\n", file, user_answer); | ||
702 | result = -EFAULT; | ||
703 | goto exit; | ||
704 | } | ||
705 | |||
706 | /* successful completion */ | ||
707 | dprintk(KERN_INFO "tf_device_ioctl(%p): Success\n", file); | ||
708 | break; | ||
709 | |||
710 | case IOCTL_TF_GET_DESCRIPTION: { | ||
711 | /* ioctl asking for the version information buffer */ | ||
712 | struct tf_version_information_buffer *pInfoBuffer; | ||
713 | |||
714 | dprintk(KERN_INFO "IOCTL_TF_GET_DESCRIPTION:(%p, %u, %p)\n", | ||
715 | file, ioctl_num, (void *) ioctl_param); | ||
716 | |||
717 | pInfoBuffer = | ||
718 | ((struct tf_version_information_buffer *) ioctl_param); | ||
719 | |||
720 | dprintk(KERN_INFO "IOCTL_TF_GET_DESCRIPTION1: " | ||
721 | "driver_description=\"%64s\"\n", S_VERSION_STRING); | ||
722 | |||
723 | if (copy_to_user(pInfoBuffer->driver_description, | ||
724 | S_VERSION_STRING, | ||
725 | strlen(S_VERSION_STRING) + 1)) { | ||
726 | dprintk(KERN_ERR "tf_device_ioctl(%p): " | ||
727 | "Fail to copy back the driver description " | ||
728 | "to %p\n", | ||
729 | file, pInfoBuffer->driver_description); | ||
730 | result = -EFAULT; | ||
731 | goto exit; | ||
732 | } | ||
733 | |||
734 | dprintk(KERN_INFO "IOCTL_TF_GET_DESCRIPTION2: " | ||
735 | "secure_world_description=\"%64s\"\n", | ||
736 | tf_get_description(&g_tf_dev.sm)); | ||
737 | |||
738 | if (copy_to_user(pInfoBuffer->secure_world_description, | ||
739 | tf_get_description(&g_tf_dev.sm), | ||
740 | TF_DESCRIPTION_BUFFER_LENGTH)) { | ||
741 | dprintk(KERN_WARNING "tf_device_ioctl(%p): " | ||
742 | "Failed to copy back the secure world " | ||
743 | "description to %p\n", | ||
744 | file, pInfoBuffer->secure_world_description); | ||
745 | result = -EFAULT; | ||
746 | goto exit; | ||
747 | } | ||
748 | break; | ||
749 | } | ||
750 | |||
751 | default: | ||
752 | dprintk(KERN_ERR "tf_device_ioctl(%p): " | ||
753 | "Unknown IOCTL code 0x%08x!\n", | ||
754 | file, ioctl_num); | ||
755 | result = -EOPNOTSUPP; | ||
756 | goto exit; | ||
757 | } | ||
758 | |||
759 | exit: | ||
760 | return result; | ||
761 | } | ||
762 | |||
763 | /*----------------------------------------------------------------------------*/ | ||
764 | |||
765 | static int tf_device_shutdown(void) | ||
766 | { | ||
767 | |||
768 | return tf_power_management(&g_tf_dev.sm, | ||
769 | TF_POWER_OPERATION_SHUTDOWN); | ||
770 | } | ||
771 | |||
772 | /*----------------------------------------------------------------------------*/ | ||
773 | |||
774 | static int tf_device_suspend(void) | ||
775 | { | ||
776 | dprintk(KERN_INFO "tf_device_suspend: Enter\n"); | ||
777 | return tf_power_management(&g_tf_dev.sm, | ||
778 | TF_POWER_OPERATION_HIBERNATE); | ||
779 | } | ||
780 | |||
781 | |||
782 | /*----------------------------------------------------------------------------*/ | ||
783 | |||
784 | static int tf_device_resume(void) | ||
785 | { | ||
786 | return tf_power_management(&g_tf_dev.sm, | ||
787 | TF_POWER_OPERATION_RESUME); | ||
788 | } | ||
789 | |||
790 | |||
791 | /*----------------------------------------------------------------------------*/ | ||
792 | |||
793 | module_init(tf_device_register); | ||
794 | |||
795 | MODULE_LICENSE("GPL"); | ||
796 | MODULE_AUTHOR("Trusted Logic S.A."); | ||