blob: ed2928a14090d10e62b140f5d754c4da1a56bfc0 [file] [log] [blame]
Lukas Hänelca267132012-09-04 12:28:40 +02001/*
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02002 * MobiCore Driver Kernel Module.
Lukas Hänelca267132012-09-04 12:28:40 +02003 *
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02004 * This driver represents the command proxy on the lowest layer, from the
5 * secure world to the non secure world, and vice versa.
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09006
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02007 * This driver offers IOCTL commands, for access to the secure world, and has
8 * the interface from the secure world to the normal world.
9 * The access to the driver is possible with a file descriptor,
Lukas Hänel28a9ffd2012-11-07 13:17:39 +090010 * which has to be created by the fd = open(/dev/mobicore) command or
11 * fd = open(/dev/mobicore-user)
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +020012 *
Lukas Hänelca267132012-09-04 12:28:40 +020013 * <-- Copyright Giesecke & Devrient GmbH 2009-2012 -->
Oana Medvesan9f099cf2013-02-08 09:50:46 +010014 * <-- Copyright Trustonic Limited 2013 -->
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +020015 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License version 2 as
18 * published by the Free Software Foundation.
19 */
Lukas Hänelca267132012-09-04 12:28:40 +020020#include <linux/miscdevice.h>
21#include <linux/interrupt.h>
22#include <linux/highmem.h>
23#include <linux/slab.h>
24#include <linux/kthread.h>
Lukas Hänelca267132012-09-04 12:28:40 +020025#include <linux/device.h>
Steve Mucklef132c6c2012-06-06 18:30:57 -070026#include <linux/module.h>
Lukas Hänel28a9ffd2012-11-07 13:17:39 +090027#include <linux/ioctl.h>
28#include <linux/mm.h>
29#include <linux/mman.h>
30#include <linux/completion.h>
Oana Medvesanf317d3e2013-03-04 19:06:26 +010031#include <linux/fdtable.h>
Oana Medvesanbd1a95d2013-04-25 10:34:08 +020032#include <linux/cdev.h>
Oana Medvesanf317d3e2013-03-04 19:06:26 +010033#include <net/net_namespace.h>
34#include <net/sock.h>
35#include <net/tcp_states.h>
36#include <net/af_unix.h>
Lukas Hänelca267132012-09-04 12:28:40 +020037
Lukas Hänel28a9ffd2012-11-07 13:17:39 +090038#include "main.h"
39#include "fastcall.h"
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +020040
Lukas Hänel28a9ffd2012-11-07 13:17:39 +090041#include "arm.h"
42#include "mem.h"
43#include "ops.h"
44#include "pm.h"
45#include "debug.h"
46#include "logging.h"
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +020047
Lukas Hänelca267132012-09-04 12:28:40 +020048/* Define a MobiCore device structure for use with dev_debug() etc */
49struct device_driver mcd_debug_name = {
Oana Medvesan579245e2013-07-04 14:46:31 +020050 .name = "MobiCore"
Lukas Hänelca267132012-09-04 12:28:40 +020051};
52
53struct device mcd_debug_subname = {
Lukas Hänelca267132012-09-04 12:28:40 +020054 .driver = &mcd_debug_name
55};
56
57struct device *mcd = &mcd_debug_subname;
58
Oana Medvesanbd1a95d2013-04-25 10:34:08 +020059/* We need 2 devices for admin and user interface*/
60#define MC_DEV_MAX 2
61
62/* Need to discover a chrdev region for the driver */
63static dev_t mc_dev_admin, mc_dev_user;
64struct cdev mc_admin_cdev, mc_user_cdev;
65/* Device class for the driver assigned major */
66static struct class *mc_device_class;
67
Oana Medvesanf317d3e2013-03-04 19:06:26 +010068#ifndef FMODE_PATH
69 #define FMODE_PATH 0x0
70#endif
71
72static struct sock *__get_socket(struct file *filp)
73{
74 struct sock *u_sock = NULL;
75 struct inode *inode = filp->f_path.dentry->d_inode;
76
77 /*
78 * Socket ?
79 */
80 if (S_ISSOCK(inode->i_mode) && !(filp->f_mode & FMODE_PATH)) {
81 struct socket *sock = SOCKET_I(inode);
82 struct sock *s = sock->sk;
83
84 /*
85 * PF_UNIX ?
86 */
87 if (s && sock->ops && sock->ops->family == PF_UNIX)
88 u_sock = s;
89 }
90 return u_sock;
91}
92
93
Lukas Hänelca267132012-09-04 12:28:40 +020094/* MobiCore interrupt context data */
Lukas Hänel28a9ffd2012-11-07 13:17:39 +090095struct mc_context ctx;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +020096
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +020097/* Get process context from file pointer */
Lukas Hänelca267132012-09-04 12:28:40 +020098static struct mc_instance *get_instance(struct file *file)
99{
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200100 return (struct mc_instance *)(file->private_data);
101}
102
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200103/* Get a unique ID */
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900104unsigned int get_unique_id(void)
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200105{
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900106 return (unsigned int)atomic_inc_return(&ctx.unique_counter);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200107}
108
Lukas Hänelca267132012-09-04 12:28:40 +0200109/* Clears the reserved bit of each page and frees the pages */
110static inline void free_continguous_pages(void *addr, unsigned int order)
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200111{
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200112 int i;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900113 struct page *page = virt_to_page(addr);
114 for (i = 0; i < (1<<order); i++) {
Oana Medvesana0361802013-12-20 13:52:46 +0100115 MCDRV_DBG_VERBOSE(mcd, "free page at 0x%p", page);
116 clear_bit(PG_reserved, &page->flags);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200117 page++;
118 }
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900119
Oana Medvesana0361802013-12-20 13:52:46 +0100120 MCDRV_DBG_VERBOSE(mcd, "freeing addr:%p, order:%x", addr, order);
Lukas Hänelca267132012-09-04 12:28:40 +0200121 free_pages((unsigned long)addr, order);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200122}
123
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900124/* Frees the memory associated with a buffer */
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100125static int free_buffer(struct mc_buffer *buffer, bool unlock)
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200126{
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900127 if (buffer->handle == 0)
128 return -EINVAL;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200129
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900130 if (buffer->addr == 0)
131 return -EINVAL;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200132
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100133 MCDRV_DBG_VERBOSE(mcd,
Oana Medvesana0361802013-12-20 13:52:46 +0100134 "handle=%u phys_addr=0x%llx, virt_addr=0x%p len=%u",
135 buffer->handle, (u64)buffer->phys,
136 buffer->addr, buffer->len);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200137
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100138 if (!atomic_dec_and_test(&buffer->usage)) {
139 MCDRV_DBG_VERBOSE(mcd, "Could not free %u", buffer->handle);
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900140 return 0;
141 }
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200142
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900143 list_del(&buffer->list);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200144
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900145 free_continguous_pages(buffer->addr, buffer->order);
146 kfree(buffer);
147 return 0;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200148}
149
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100150static uint32_t mc_find_cont_wsm_addr(struct mc_instance *instance, void *uaddr,
Oana Medvesana0361802013-12-20 13:52:46 +0100151 void **addr, uint32_t len)
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100152{
153 int ret = 0;
154 struct mc_buffer *buffer;
155
156 if (WARN(!instance, "No instance data available"))
157 return -EFAULT;
158
159 mutex_lock(&instance->lock);
160
161 mutex_lock(&ctx.bufs_lock);
162
163 /* search for the given handle in the buffers list */
164 list_for_each_entry(buffer, &ctx.cont_bufs, list) {
165 if (buffer->uaddr == uaddr && buffer->len == len) {
Oana Medvesana0361802013-12-20 13:52:46 +0100166 *addr = buffer->addr;
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100167 goto found;
168 }
169 }
170
171 /* Coundn't find the buffer */
172 ret = -EINVAL;
173
174found:
175 mutex_unlock(&ctx.bufs_lock);
176 mutex_unlock(&instance->lock);
177
178 return ret;
179}
180
Oana Medvesanf317d3e2013-03-04 19:06:26 +0100181bool mc_check_owner_fd(struct mc_instance *instance, int32_t fd)
182{
183#ifndef __ARM_VE_A9X4_STD__
184 struct file *fp;
185 struct sock *s;
186 struct files_struct *files;
187 struct task_struct *peer = NULL;
188 bool ret = false;
189
Oana Medvesana0361802013-12-20 13:52:46 +0100190 MCDRV_DBG_VERBOSE(mcd, "Finding wsm for fd = %d", fd);
Oana Medvesanf317d3e2013-03-04 19:06:26 +0100191 if (!instance)
192 return false;
193
194 if (is_daemon(instance))
195 return true;
196
197 fp = fcheck_files(current->files, fd);
198 s = __get_socket(fp);
199 if (s) {
200 peer = get_pid_task(s->sk_peer_pid, PIDTYPE_PID);
Oana Medvesana0361802013-12-20 13:52:46 +0100201 MCDRV_DBG_VERBOSE(mcd, "Found pid for fd %d", peer->pid);
Oana Medvesanf317d3e2013-03-04 19:06:26 +0100202 }
203 if (peer) {
204 task_lock(peer);
205 files = peer->files;
206 if (!files)
207 goto out;
208 for (fd = 0; fd < files_fdtable(files)->max_fds; fd++) {
209 fp = fcheck_files(files, fd);
210 if (!fp)
211 continue;
212 if (fp->private_data == instance) {
Oana Medvesana0361802013-12-20 13:52:46 +0100213 MCDRV_DBG_VERBOSE(mcd, "Found owner!");
Oana Medvesanf317d3e2013-03-04 19:06:26 +0100214 ret = true;
215 goto out;
216 }
Oana Medvesanf317d3e2013-03-04 19:06:26 +0100217 }
218 } else {
219 MCDRV_DBG(mcd, "Owner not found!");
220 return false;
221 }
222out:
223 if (peer)
224 task_unlock(peer);
225 if (!ret)
226 MCDRV_DBG(mcd, "Owner not found!");
227 return ret;
228#else
229 return true;
230#endif
231}
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900232static uint32_t mc_find_cont_wsm(struct mc_instance *instance, uint32_t handle,
Oana Medvesana0361802013-12-20 13:52:46 +0100233 int32_t fd, phys_addr_t *phys, uint32_t *len)
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200234{
Lukas Hänelca267132012-09-04 12:28:40 +0200235 int ret = 0;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900236 struct mc_buffer *buffer;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200237
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900238 if (WARN(!instance, "No instance data available"))
239 return -EFAULT;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200240
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900241 if (WARN_ON(!is_daemon(instance))) {
Oana Medvesana0361802013-12-20 13:52:46 +0100242 MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900243 return -EPERM;
244 }
245
246 mutex_lock(&instance->lock);
247
248 mutex_lock(&ctx.bufs_lock);
249
250 /* search for the given handle in the buffers list */
251 list_for_each_entry(buffer, &ctx.cont_bufs, list) {
252 if (buffer->handle == handle) {
Oana Medvesanf317d3e2013-03-04 19:06:26 +0100253 if (mc_check_owner_fd(buffer->instance, fd)) {
Oana Medvesana0361802013-12-20 13:52:46 +0100254 *phys = buffer->phys;
Oana Medvesanf317d3e2013-03-04 19:06:26 +0100255 *len = buffer->len;
256 goto found;
257 } else {
258 break;
259 }
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200260 }
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900261 }
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200262
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900263 /* Couldn't find the buffer */
264 ret = -EINVAL;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200265
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900266found:
267 mutex_unlock(&ctx.bufs_lock);
268 mutex_unlock(&instance->lock);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200269
270 return ret;
271}
272
Lukas Hänelca267132012-09-04 12:28:40 +0200273/*
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900274 * __free_buffer - Free a WSM buffer allocated with mobicore_allocate_wsm
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200275 *
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900276 * @instance
277 * @handle handle of the buffer
278 *
279 * Returns 0 if no error
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200280 *
281 */
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100282static int __free_buffer(struct mc_instance *instance, uint32_t handle,
283 bool unlock)
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900284{
285 int ret = 0;
286 struct mc_buffer *buffer;
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100287 void *uaddr = NULL;
288 size_t len = 0;
289#ifndef MC_VM_UNMAP
290 struct mm_struct *mm = current->mm;
291#endif
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900292
293 if (WARN(!instance, "No instance data available"))
294 return -EFAULT;
295
296 mutex_lock(&ctx.bufs_lock);
297 /* search for the given handle in the buffers list */
298 list_for_each_entry(buffer, &ctx.cont_bufs, list) {
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100299 if (buffer->handle == handle) {
300 uaddr = buffer->uaddr;
301 len = buffer->len;
302 goto found_buffer;
303 }
304 }
Oana Medvesaneedd9e92013-02-21 19:39:04 +0100305 ret = -EINVAL;
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100306 goto err;
307found_buffer:
Oana Medvesaneedd9e92013-02-21 19:39:04 +0100308 if (!is_daemon(instance) && buffer->instance != instance) {
309 ret = -EPERM;
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100310 goto err;
Oana Medvesaneedd9e92013-02-21 19:39:04 +0100311 }
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100312 mutex_unlock(&ctx.bufs_lock);
313 /* Only unmap if the request is comming from the user space and
314 * it hasn't already been unmapped */
Oana Medvesaneedd9e92013-02-21 19:39:04 +0100315 if (unlock == false && uaddr != NULL) {
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100316#ifndef MC_VM_UNMAP
317 /* do_munmap must be done with mm->mmap_sem taken */
318 down_write(&mm->mmap_sem);
319 ret = do_munmap(mm, (long unsigned int)uaddr, len);
Oana Medvesaneedd9e92013-02-21 19:39:04 +0100320 up_write(&mm->mmap_sem);
321
322#else
323 ret = vm_munmap((long unsigned int)uaddr, len);
324#endif
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100325 if (ret < 0) {
326 /* Something is not right if we end up here, better not
327 * clean the buffer so we just leak memory instead of
328 * creating security issues */
Oana Medvesana0361802013-12-20 13:52:46 +0100329 MCDRV_DBG_ERROR(mcd, "Memory can't be unmapped");
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100330 return -EINVAL;
331 }
Oana Medvesaneedd9e92013-02-21 19:39:04 +0100332 }
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100333
334 mutex_lock(&ctx.bufs_lock);
335 /* search for the given handle in the buffers list */
336 list_for_each_entry(buffer, &ctx.cont_bufs, list) {
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900337 if (buffer->handle == handle)
338 goto del_buffer;
339 }
340 ret = -EINVAL;
341 goto err;
342
343del_buffer:
Oana Medvesaneedd9e92013-02-21 19:39:04 +0100344 if (is_daemon(instance) || buffer->instance == instance)
345 ret = free_buffer(buffer, unlock);
346 else
347 ret = -EPERM;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900348err:
349 mutex_unlock(&ctx.bufs_lock);
350 return ret;
351}
352
353int mc_free_buffer(struct mc_instance *instance, uint32_t handle)
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200354{
Lukas Hänelca267132012-09-04 12:28:40 +0200355 int ret = 0;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200356
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900357 if (WARN(!instance, "No instance data available"))
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200358 return -EFAULT;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900359
360 mutex_lock(&instance->lock);
361
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100362 ret = __free_buffer(instance, handle, false);
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900363 mutex_unlock(&instance->lock);
364 return ret;
365}
366
367
368int mc_get_buffer(struct mc_instance *instance,
369 struct mc_buffer **buffer, unsigned long len)
370{
371 struct mc_buffer *cbuffer = NULL;
372 void *addr = 0;
Oana Medvesana0361802013-12-20 13:52:46 +0100373 phys_addr_t phys = 0;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900374 unsigned int order;
375 unsigned long allocated_size;
376 int ret = 0;
377
378 if (WARN(!instance, "No instance data available"))
379 return -EFAULT;
380
381 if (len == 0) {
Oana Medvesana0361802013-12-20 13:52:46 +0100382 MCDRV_DBG_WARN(mcd, "cannot allocate size 0");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900383 return -ENOMEM;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200384 }
385
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900386 order = get_order(len);
387 if (order > MAX_ORDER) {
Oana Medvesana0361802013-12-20 13:52:46 +0100388 MCDRV_DBG_WARN(mcd, "Buffer size too large");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900389 return -ENOMEM;
390 }
391 allocated_size = (1 << order) * PAGE_SIZE;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200392
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900393 if (mutex_lock_interruptible(&instance->lock))
394 return -ERESTARTSYS;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200395
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900396 /* allocate a new buffer. */
397 cbuffer = kzalloc(sizeof(struct mc_buffer), GFP_KERNEL);
398
399 if (cbuffer == NULL) {
400 MCDRV_DBG_WARN(mcd,
Oana Medvesana0361802013-12-20 13:52:46 +0100401 "MMAP_WSM request: could not allocate buffer");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900402 ret = -ENOMEM;
403 goto unlock_instance;
404 }
405 mutex_lock(&ctx.bufs_lock);
406
Oana Medvesana0361802013-12-20 13:52:46 +0100407 MCDRV_DBG_VERBOSE(mcd, "size %ld -> order %d --> %ld (2^n pages)",
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900408 len, order, allocated_size);
409
410 addr = (void *)__get_free_pages(GFP_USER | __GFP_ZERO, order);
411
412 if (addr == NULL) {
Oana Medvesana0361802013-12-20 13:52:46 +0100413 MCDRV_DBG_WARN(mcd, "get_free_pages failed");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900414 ret = -ENOMEM;
415 goto err;
416 }
Oana Medvesana0361802013-12-20 13:52:46 +0100417 phys = virt_to_phys(addr);
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900418 cbuffer->handle = get_unique_id();
419 cbuffer->phys = phys;
420 cbuffer->addr = addr;
421 cbuffer->order = order;
422 cbuffer->len = len;
423 cbuffer->instance = instance;
Oana Medvesaneedd9e92013-02-21 19:39:04 +0100424 cbuffer->uaddr = 0;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900425 /* Refcount +1 because the TLC is requesting it */
426 atomic_set(&cbuffer->usage, 1);
427
428 INIT_LIST_HEAD(&cbuffer->list);
429 list_add(&cbuffer->list, &ctx.cont_bufs);
430
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100431 MCDRV_DBG_VERBOSE(mcd,
Oana Medvesana0361802013-12-20 13:52:46 +0100432 "allocated phys=0x%llx - 0x%llx, size=%ld, kvirt=0x%p"
433 ", h=%d",
434 (u64)phys,
435 (u64)(phys+allocated_size),
436 allocated_size, addr, cbuffer->handle);
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900437 *buffer = cbuffer;
438 goto unlock;
439
440err:
441 kfree(cbuffer);
442unlock:
443 mutex_unlock(&ctx.bufs_lock);
444unlock_instance:
445 mutex_unlock(&instance->lock);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200446 return ret;
447}
448
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900449/*
450 * __lock_buffer() - Locks a contiguous buffer - +1 refcount.
451 * Assumes the instance lock is already taken!
452 */
453static int __lock_buffer(struct mc_instance *instance, uint32_t handle)
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200454{
Lukas Hänelca267132012-09-04 12:28:40 +0200455 int ret = 0;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900456 struct mc_buffer *buffer;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200457
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900458 if (WARN(!instance, "No instance data available"))
459 return -EFAULT;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200460
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900461 if (WARN_ON(!is_daemon(instance))) {
Oana Medvesana0361802013-12-20 13:52:46 +0100462 MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900463 return -EPERM;
464 }
465
466 mutex_lock(&ctx.bufs_lock);
467 /* search for the given handle in the buffers list */
468 list_for_each_entry(buffer, &ctx.cont_bufs, list) {
469 if (buffer->handle == handle) {
470 atomic_inc(&buffer->usage);
471 goto unlock;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200472 }
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900473 }
474 ret = -EINVAL;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200475
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900476unlock:
477 mutex_unlock(&ctx.bufs_lock);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200478 return ret;
479}
480
Oana Medvesana0361802013-12-20 13:52:46 +0100481static phys_addr_t get_mci_base_phys(unsigned int len)
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900482{
483 if (ctx.mci_base.phys) {
484 return ctx.mci_base.phys;
485 } else {
486 unsigned int order = get_order(len);
487 ctx.mcp = NULL;
488 ctx.mci_base.order = order;
489 ctx.mci_base.addr =
490 (void *)__get_free_pages(GFP_USER | __GFP_ZERO, order);
491 if (ctx.mci_base.addr == NULL) {
Oana Medvesana0361802013-12-20 13:52:46 +0100492 MCDRV_DBG_WARN(mcd, "get_free_pages failed");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900493 memset(&ctx.mci_base, 0, sizeof(ctx.mci_base));
Oana Medvesana0361802013-12-20 13:52:46 +0100494 return 0;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900495 }
Oana Medvesana0361802013-12-20 13:52:46 +0100496 ctx.mci_base.phys = virt_to_phys(ctx.mci_base.addr);
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900497 return ctx.mci_base.phys;
498 }
499}
Lukas Hänelca267132012-09-04 12:28:40 +0200500
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900501/*
Oana Medvesana0361802013-12-20 13:52:46 +0100502 * Create a MMU table from a virtual memory buffer which can be vmalloc
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900503 * or user space virtual memory
504 */
Oana Medvesana0361802013-12-20 13:52:46 +0100505int mc_register_wsm_mmu(struct mc_instance *instance,
506 void *buffer, uint32_t len,
507 uint32_t *handle, phys_addr_t *phys)
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200508{
509 int ret = 0;
Oana Medvesana0361802013-12-20 13:52:46 +0100510 struct mc_mmu_table *table = NULL;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900511 struct task_struct *task = current;
Oana Medvesana0361802013-12-20 13:52:46 +0100512 void *kbuff = NULL;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200513
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900514 if (WARN(!instance, "No instance data available"))
515 return -EFAULT;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200516
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900517 if (len == 0) {
Oana Medvesana0361802013-12-20 13:52:46 +0100518 MCDRV_DBG_ERROR(mcd, "len=0 is not supported!");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900519 return -EINVAL;
520 }
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200521
Oana Medvesana0361802013-12-20 13:52:46 +0100522 MCDRV_DBG_VERBOSE(mcd, "buffer: %p, len=%08x", buffer, len);
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100523
Oana Medvesana0361802013-12-20 13:52:46 +0100524 if (!mc_find_cont_wsm_addr(instance, buffer, &kbuff, len))
525 table = mc_alloc_mmu_table(instance, NULL, kbuff, len);
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100526 else
Oana Medvesana0361802013-12-20 13:52:46 +0100527 table = mc_alloc_mmu_table(instance, task, buffer, len);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200528
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900529 if (IS_ERR(table)) {
Oana Medvesana0361802013-12-20 13:52:46 +0100530 MCDRV_DBG_ERROR(mcd, "mc_alloc_mmu_table() failed");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900531 return -EINVAL;
532 }
533
534 /* set response */
535 *handle = table->handle;
536 /* WARNING: daemon shouldn't know this either, but live with it */
537 if (is_daemon(instance))
Oana Medvesana0361802013-12-20 13:52:46 +0100538 *phys = table->phys;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900539 else
540 *phys = 0;
541
Oana Medvesana0361802013-12-20 13:52:46 +0100542 MCDRV_DBG_VERBOSE(mcd, "handle: %d, phys=0x%llX",
543 *handle, (u64)(*phys));
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200544
Oana Medvesana0361802013-12-20 13:52:46 +0100545 MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X", ret, ret);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200546
547 return ret;
548}
549
Oana Medvesana0361802013-12-20 13:52:46 +0100550int mc_unregister_wsm_mmu(struct mc_instance *instance, uint32_t handle)
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200551{
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900552 int ret = 0;
553
554 if (WARN(!instance, "No instance data available"))
555 return -EFAULT;
556
557 /* free table (if no further locks exist) */
Oana Medvesana0361802013-12-20 13:52:46 +0100558 mc_free_mmu_table(instance, handle);
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900559
560 return ret;
561}
Oana Medvesana0361802013-12-20 13:52:46 +0100562/* Lock the object from handle, it could be a WSM MMU table or a cont buffer! */
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900563static int mc_lock_handle(struct mc_instance *instance, uint32_t handle)
564{
565 int ret = 0;
566
567 if (WARN(!instance, "No instance data available"))
568 return -EFAULT;
569
570 if (WARN_ON(!is_daemon(instance))) {
Oana Medvesana0361802013-12-20 13:52:46 +0100571 MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900572 return -EPERM;
573 }
574
575 mutex_lock(&instance->lock);
Oana Medvesana0361802013-12-20 13:52:46 +0100576 ret = mc_lock_mmu_table(instance, handle);
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900577
Oana Medvesana0361802013-12-20 13:52:46 +0100578 /* Handle was not a MMU table but a cont buffer */
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900579 if (ret == -EINVAL) {
580 /* Call the non locking variant! */
581 ret = __lock_buffer(instance, handle);
582 }
583
584 mutex_unlock(&instance->lock);
585
586 return ret;
587}
588
589static int mc_unlock_handle(struct mc_instance *instance, uint32_t handle)
590{
591 int ret = 0;
592
593 if (WARN(!instance, "No instance data available"))
594 return -EFAULT;
595
596 if (WARN_ON(!is_daemon(instance))) {
Oana Medvesana0361802013-12-20 13:52:46 +0100597 MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900598 return -EPERM;
599 }
600
601 mutex_lock(&instance->lock);
Oana Medvesana0361802013-12-20 13:52:46 +0100602 ret = mc_free_mmu_table(instance, handle);
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900603
Oana Medvesana0361802013-12-20 13:52:46 +0100604 /* Not a MMU table, then it must be a buffer */
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900605 if (ret == -EINVAL) {
606 /* Call the non locking variant! */
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100607 ret = __free_buffer(instance, handle, true);
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900608 }
609 mutex_unlock(&instance->lock);
610
611 return ret;
612}
613
Oana Medvesana0361802013-12-20 13:52:46 +0100614static phys_addr_t mc_find_wsm_mmu(struct mc_instance *instance,
Oana Medvesanf317d3e2013-03-04 19:06:26 +0100615 uint32_t handle, int32_t fd)
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900616{
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900617 if (WARN(!instance, "No instance data available"))
618 return 0;
619
620 if (WARN_ON(!is_daemon(instance))) {
Oana Medvesana0361802013-12-20 13:52:46 +0100621 MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900622 return 0;
623 }
624
Oana Medvesana0361802013-12-20 13:52:46 +0100625 return mc_find_mmu_table(handle, fd);
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900626}
627
Oana Medvesana0361802013-12-20 13:52:46 +0100628static int mc_clean_wsm_mmu(struct mc_instance *instance)
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900629{
630 if (WARN(!instance, "No instance data available"))
631 return -EFAULT;
632
633 if (WARN_ON(!is_daemon(instance))) {
Oana Medvesana0361802013-12-20 13:52:46 +0100634 MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900635 return -EPERM;
636 }
637
Oana Medvesana0361802013-12-20 13:52:46 +0100638 mc_clean_mmu_tables();
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900639
640 return 0;
641}
642
643static int mc_fd_mmap(struct file *file, struct vm_area_struct *vmarea)
644{
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200645 struct mc_instance *instance = get_instance(file);
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900646 unsigned long len = vmarea->vm_end - vmarea->vm_start;
Oana Medvesana0361802013-12-20 13:52:46 +0100647 phys_addr_t paddr = (vmarea->vm_pgoff << PAGE_SHIFT);
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900648 unsigned int pfn;
649 struct mc_buffer *buffer = 0;
650 int ret = 0;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200651
Oana Medvesana0361802013-12-20 13:52:46 +0100652 MCDRV_DBG_VERBOSE(mcd, "enter (vma start=0x%p, size=%ld, mci=0x%llX)",
653 (void *)vmarea->vm_start, len,
654 (u64)ctx.mci_base.phys);
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900655
656 if (WARN(!instance, "No instance data available"))
657 return -EFAULT;
658
659 if (len == 0) {
Oana Medvesana0361802013-12-20 13:52:46 +0100660 MCDRV_DBG_ERROR(mcd, "cannot allocate size 0");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900661 return -ENOMEM;
662 }
663 if (paddr) {
664 mutex_lock(&ctx.bufs_lock);
665
666 /* search for the buffer list. */
667 list_for_each_entry(buffer, &ctx.cont_bufs, list) {
Oana Medvesaneedd9e92013-02-21 19:39:04 +0100668 /* Only allow mapping if the client owns it!*/
669 if (buffer->phys == paddr &&
670 buffer->instance == instance) {
Oana Medvesanf317d3e2013-03-04 19:06:26 +0100671 /* We shouldn't do remap with larger size */
672 if (buffer->len > len)
673 break;
674 /* We can't allow mapping the buffer twice */
Oana Medvesaneedd9e92013-02-21 19:39:04 +0100675 if (!buffer->uaddr)
676 goto found;
677 else
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900678 break;
Oana Medvesaneedd9e92013-02-21 19:39:04 +0100679 }
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900680 }
681 /* Nothing found return */
682 mutex_unlock(&ctx.bufs_lock);
683 return -EINVAL;
684
685found:
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100686 buffer->uaddr = (void *)vmarea->vm_start;
687 vmarea->vm_flags |= VM_IO;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900688 /*
689 * Convert kernel address to user address. Kernel address begins
690 * at PAGE_OFFSET, user address range is below PAGE_OFFSET.
691 * Remapping the area is always done, so multiple mappings
692 * of one region are possible. Now remap kernel address
693 * space into user space
694 */
695 pfn = (unsigned int)paddr >> PAGE_SHIFT;
696 ret = (int)remap_pfn_range(vmarea, vmarea->vm_start, pfn,
697 buffer->len, vmarea->vm_page_prot);
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100698 /* If the remap failed then don't mark this buffer as marked
699 * since the unmaping will also fail */
700 if (ret)
701 buffer->uaddr = NULL;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900702 mutex_unlock(&ctx.bufs_lock);
703 } else {
704 if (!is_daemon(instance))
705 return -EPERM;
706
707 paddr = get_mci_base_phys(len);
708 if (!paddr)
709 return -EFAULT;
710
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100711 vmarea->vm_flags |= VM_IO;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900712 /*
713 * Convert kernel address to user address. Kernel address begins
714 * at PAGE_OFFSET, user address range is below PAGE_OFFSET.
715 * Remapping the area is always done, so multiple mappings
716 * of one region are possible. Now remap kernel address
717 * space into user space
718 */
719 pfn = (unsigned int)paddr >> PAGE_SHIFT;
720 ret = (int)remap_pfn_range(vmarea, vmarea->vm_start, pfn, len,
721 vmarea->vm_page_prot);
722 }
723
Oana Medvesana0361802013-12-20 13:52:46 +0100724 MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X", ret, ret);
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900725
726 return ret;
727}
728
729static inline int ioctl_check_pointer(unsigned int cmd, int __user *uarg)
730{
731 int err = 0;
732 if (_IOC_DIR(cmd) & _IOC_READ)
733 err = !access_ok(VERIFY_WRITE, uarg, _IOC_SIZE(cmd));
734 else if (_IOC_DIR(cmd) & _IOC_WRITE)
735 err = !access_ok(VERIFY_READ, uarg, _IOC_SIZE(cmd));
736 if (err)
737 return -EFAULT;
738
739 return 0;
740}
741
742/*
743 * mc_fd_user_ioctl() - Will be called from user space as ioctl(..)
744 * @file pointer to file
745 * @cmd command
746 * @arg arguments
747 *
748 * Returns 0 for OK and an errno in case of error
749 */
750static long mc_fd_user_ioctl(struct file *file, unsigned int cmd,
751 unsigned long arg)
752{
753 struct mc_instance *instance = get_instance(file);
754 int __user *uarg = (int __user *)arg;
755 int ret = -EINVAL;
756
757 if (WARN(!instance, "No instance data available"))
758 return -EFAULT;
759
760 if (ioctl_check_pointer(cmd, uarg))
761 return -EFAULT;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200762
763 switch (cmd) {
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900764 case MC_IO_FREE:
765 ret = mc_free_buffer(instance, (uint32_t)arg);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200766 break;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900767
768 case MC_IO_REG_WSM:{
769 struct mc_ioctl_reg_wsm reg;
Oana Medvesana0361802013-12-20 13:52:46 +0100770 phys_addr_t phys;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900771 if (copy_from_user(&reg, uarg, sizeof(reg)))
772 return -EFAULT;
773
Oana Medvesana0361802013-12-20 13:52:46 +0100774 ret = mc_register_wsm_mmu(instance, (void *)reg.buffer,
775 reg.len, &reg.handle, &phys);
776 reg.table_phys = phys;
777
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900778 if (!ret) {
779 if (copy_to_user(uarg, &reg, sizeof(reg))) {
780 ret = -EFAULT;
Oana Medvesana0361802013-12-20 13:52:46 +0100781 mc_unregister_wsm_mmu(instance, reg.handle);
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900782 }
783 }
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200784 break;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900785 }
786 case MC_IO_UNREG_WSM:
Oana Medvesana0361802013-12-20 13:52:46 +0100787 ret = mc_unregister_wsm_mmu(instance, (uint32_t)arg);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200788 break;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900789
790 case MC_IO_VERSION:
791 ret = put_user(mc_get_version(), uarg);
792 if (ret)
793 MCDRV_DBG_ERROR(mcd,
794 "IOCTL_GET_VERSION failed to put data");
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200795 break;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900796
797 case MC_IO_MAP_WSM:{
798 struct mc_ioctl_map map;
799 struct mc_buffer *buffer = 0;
800 if (copy_from_user(&map, uarg, sizeof(map)))
801 return -EFAULT;
802
803 /* Setup the WSM buffer structure! */
804 if (mc_get_buffer(instance, &buffer, map.len))
805 return -EFAULT;
806
807 map.handle = buffer->handle;
Oana Medvesana0361802013-12-20 13:52:46 +0100808 map.phys_addr = buffer->phys;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900809 map.reused = 0;
810 if (copy_to_user(uarg, &map, sizeof(map)))
811 ret = -EFAULT;
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100812 else
813 ret = 0;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200814 break;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900815 }
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200816 default:
Oana Medvesana0361802013-12-20 13:52:46 +0100817 MCDRV_DBG_ERROR(mcd, "unsupported cmd=0x%x", cmd);
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900818 ret = -ENOIOCTLCMD;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200819 break;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900820
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200821 } /* end switch(cmd) */
822
823#ifdef MC_MEM_TRACES
824 mobicore_log_read();
825#endif
826
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900827 return (int)ret;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200828}
829
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900830static long mc_fd_admin_ioctl(struct file *file, unsigned int cmd,
831 unsigned long arg)
832{
833 struct mc_instance *instance = get_instance(file);
834 int __user *uarg = (int __user *)arg;
835 int ret = -EINVAL;
836
837 if (WARN(!instance, "No instance data available"))
838 return -EFAULT;
839
840 if (WARN_ON(!is_daemon(instance))) {
Oana Medvesana0361802013-12-20 13:52:46 +0100841 MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900842 return -EPERM;
843 }
844
845 if (ioctl_check_pointer(cmd, uarg))
846 return -EFAULT;
847
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900848 switch (cmd) {
849 case MC_IO_INIT: {
850 struct mc_ioctl_init init;
851 ctx.mcp = NULL;
852 if (!ctx.mci_base.phys) {
853 MCDRV_DBG_ERROR(mcd,
854 "Cannot init MobiCore without MCI!");
855 return -EINVAL;
856 }
857 if (copy_from_user(&init, uarg, sizeof(init)))
858 return -EFAULT;
859
860 ctx.mcp = ctx.mci_base.addr + init.mcp_offset;
Oana Medvesana0361802013-12-20 13:52:46 +0100861 ret = mc_init(ctx.mci_base.phys, init.nq_length,
862 init.mcp_offset, init.mcp_length);
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900863 break;
864 }
865 case MC_IO_INFO: {
866 struct mc_ioctl_info info;
867 if (copy_from_user(&info, uarg, sizeof(info)))
868 return -EFAULT;
869
870 ret = mc_info(info.ext_info_id, &info.state,
871 &info.ext_info);
872
873 if (!ret) {
874 if (copy_to_user(uarg, &info, sizeof(info)))
875 ret = -EFAULT;
876 }
877 break;
878 }
879 case MC_IO_YIELD:
880 ret = mc_yield();
881 break;
882
883 case MC_IO_NSIQ:
884 ret = mc_nsiq();
885 break;
886
887 case MC_IO_LOCK_WSM: {
888 ret = mc_lock_handle(instance, (uint32_t)arg);
889 break;
890 }
891 case MC_IO_UNLOCK_WSM:
892 ret = mc_unlock_handle(instance, (uint32_t)arg);
893 break;
894 case MC_IO_CLEAN_WSM:
Oana Medvesana0361802013-12-20 13:52:46 +0100895 ret = mc_clean_wsm_mmu(instance);
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900896 break;
897 case MC_IO_RESOLVE_WSM: {
Oana Medvesana0361802013-12-20 13:52:46 +0100898 phys_addr_t phys;
Oana Medvesanf317d3e2013-03-04 19:06:26 +0100899 struct mc_ioctl_resolv_wsm wsm;
900 if (copy_from_user(&wsm, uarg, sizeof(wsm)))
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900901 return -EFAULT;
Oana Medvesana0361802013-12-20 13:52:46 +0100902 phys = mc_find_wsm_mmu(instance, wsm.handle, wsm.fd);
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900903 if (!phys)
Oana Medvesanf317d3e2013-03-04 19:06:26 +0100904 return -EINVAL;
905
906 wsm.phys = phys;
907 if (copy_to_user(uarg, &wsm, sizeof(wsm)))
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900908 return -EFAULT;
Oana Medvesanf317d3e2013-03-04 19:06:26 +0100909 ret = 0;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900910 break;
911 }
912 case MC_IO_RESOLVE_CONT_WSM: {
913 struct mc_ioctl_resolv_cont_wsm cont_wsm;
Oana Medvesana0361802013-12-20 13:52:46 +0100914 phys_addr_t phys = 0;
915 uint32_t len = 0;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900916 if (copy_from_user(&cont_wsm, uarg, sizeof(cont_wsm)))
917 return -EFAULT;
Oana Medvesanf317d3e2013-03-04 19:06:26 +0100918 ret = mc_find_cont_wsm(instance, cont_wsm.handle, cont_wsm.fd,
919 &phys, &len);
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900920 if (!ret) {
921 cont_wsm.phys = phys;
922 cont_wsm.length = len;
923 if (copy_to_user(uarg, &cont_wsm, sizeof(cont_wsm)))
924 ret = -EFAULT;
925 }
926 break;
927 }
928 case MC_IO_MAP_MCI:{
929 struct mc_ioctl_map map;
930 if (copy_from_user(&map, uarg, sizeof(map)))
931 return -EFAULT;
932
933 map.reused = (ctx.mci_base.phys != 0);
Oana Medvesana0361802013-12-20 13:52:46 +0100934 map.phys_addr = get_mci_base_phys(map.len);
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900935 if (!map.phys_addr) {
936 MCDRV_DBG_ERROR(mcd, "Failed to setup MCI buffer!");
937 return -EFAULT;
938 }
939
940 if (copy_to_user(uarg, &map, sizeof(map)))
941 ret = -EFAULT;
942 ret = 0;
943 break;
944 }
Oana Medvesan9f099cf2013-02-08 09:50:46 +0100945 case MC_IO_LOG_SETUP: {
946#ifdef MC_MEM_TRACES
947 ret = mobicore_log_setup();
948#endif
949 break;
950 }
951
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900952 /* The rest is handled commonly by user IOCTL */
953 default:
954 ret = mc_fd_user_ioctl(file, cmd, arg);
955 } /* end switch(cmd) */
956
957#ifdef MC_MEM_TRACES
958 mobicore_log_read();
959#endif
960
961 return (int)ret;
962}
963
964/*
965 * mc_fd_read() - This will be called from user space as read(...)
Lukas Hänelca267132012-09-04 12:28:40 +0200966 * @file: file pointer
967 * @buffer: buffer where to copy to(userspace)
968 * @buffer_len: number of requested data
969 * @pos: not used
970 *
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200971 * The read function is blocking until a interrupt occurs. In that case the
972 * event counter is copied into user space and the function is finished.
Lukas Hänelca267132012-09-04 12:28:40 +0200973 *
974 * If OK this function returns the number of copied data otherwise it returns
975 * errno
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200976 */
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900977static ssize_t mc_fd_read(struct file *file, char *buffer, size_t buffer_len,
978 loff_t *pos)
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200979{
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900980 int ret = 0, ssiq_counter;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200981 struct mc_instance *instance = get_instance(file);
982
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900983 if (WARN(!instance, "No instance data available"))
984 return -EFAULT;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200985
986 /* avoid debug output on non-error, because this is call quite often */
Oana Medvesana0361802013-12-20 13:52:46 +0100987 MCDRV_DBG_VERBOSE(mcd, "enter");
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +0200988
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900989 /* only the MobiCore Daemon is allowed to call this function */
990 if (WARN_ON(!is_daemon(instance))) {
Oana Medvesana0361802013-12-20 13:52:46 +0100991 MCDRV_DBG_ERROR(mcd, "caller not MobiCore Daemon");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900992 return -EPERM;
993 }
994
995 if (buffer_len < sizeof(unsigned int)) {
Oana Medvesana0361802013-12-20 13:52:46 +0100996 MCDRV_DBG_ERROR(mcd, "invalid length");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +0900997 return -EINVAL;
998 }
999
1000 for (;;) {
1001 if (wait_for_completion_interruptible(&ctx.isr_comp)) {
Oana Medvesana0361802013-12-20 13:52:46 +01001002 MCDRV_DBG_VERBOSE(mcd, "read interrupted");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001003 return -ERESTARTSYS;
1004 }
1005
1006 ssiq_counter = atomic_read(&ctx.isr_counter);
Oana Medvesana0361802013-12-20 13:52:46 +01001007 MCDRV_DBG_VERBOSE(mcd, "ssiq_counter=%i, ctx.counter=%i",
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001008 ssiq_counter, ctx.evt_counter);
1009
1010 if (ssiq_counter != ctx.evt_counter) {
1011 /* read data and exit loop without error */
1012 ctx.evt_counter = ssiq_counter;
1013 ret = 0;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001014 break;
1015 }
1016
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001017 /* end loop if non-blocking */
1018 if (file->f_flags & O_NONBLOCK) {
Oana Medvesana0361802013-12-20 13:52:46 +01001019 MCDRV_DBG_ERROR(mcd, "non-blocking read");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001020 return -EAGAIN;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001021 }
1022
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001023 if (signal_pending(current)) {
Oana Medvesana0361802013-12-20 13:52:46 +01001024 MCDRV_DBG_VERBOSE(mcd, "received signal.");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001025 return -ERESTARTSYS;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001026 }
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001027 }
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001028
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001029 /* read data and exit loop */
1030 ret = copy_to_user(buffer, &ctx.evt_counter, sizeof(unsigned int));
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001031
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001032 if (ret != 0) {
Oana Medvesana0361802013-12-20 13:52:46 +01001033 MCDRV_DBG_ERROR(mcd, "copy_to_user failed");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001034 return -EFAULT;
1035 }
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001036
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001037 ret = sizeof(unsigned int);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001038
1039 return (ssize_t)ret;
1040}
1041
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001042/*
1043 * Initialize a new mobicore API instance object
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001044 *
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001045 * @return Instance or NULL if no allocation was possible.
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001046 */
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001047struct mc_instance *mc_alloc_instance(void)
Lukas Hänelca267132012-09-04 12:28:40 +02001048{
1049 struct mc_instance *instance;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001050
1051 instance = kzalloc(sizeof(*instance), GFP_KERNEL);
1052 if (instance == NULL)
1053 return NULL;
1054
1055 /* get a unique ID for this instance (PIDs are not unique) */
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001056 instance->handle = get_unique_id();
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001057
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001058 mutex_init(&instance->lock);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001059
1060 return instance;
1061}
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001062
Oana Medvesana0361802013-12-20 13:52:46 +01001063#if defined(TBASE_CORE_SWITCHER) && defined(DEBUG)
1064static ssize_t mc_fd_write(struct file *file, const char __user *buffer,
1065 size_t buffer_len, loff_t *x)
1066{
1067 uint32_t cpu_new;
1068 /* we only consider one digit */
1069 char buf[2];
1070 struct mc_instance *instance = get_instance(file);
1071
1072 if (WARN(!instance, "No instance data available"))
1073 return -EFAULT;
1074
1075 /* Invalid data, nothing to do */
1076 if (buffer_len < 1)
1077 return -EINVAL;
1078
1079 /* Invalid data, nothing to do */
1080 if (copy_from_user(buf, buffer, min(sizeof(buf), buffer_len)))
1081 return -EFAULT;
1082
1083 if (buf[0] == 'n') {
1084 mc_nsiq();
1085 /* If it's a digit then switch cores */
1086 } else if ((buf[0] >= '0') && (buf[0] <= '9')) {
1087 cpu_new = buf[0] - '0';
1088 if (cpu_new <= 8) {
1089 MCDRV_DBG_VERBOSE(mcd, "Set Active Cpu: %d\n", cpu_new);
1090 mc_switch_core(cpu_new);
1091 }
1092 } else {
1093 return -EINVAL;
1094 }
1095
1096 return buffer_len;
1097}
1098#endif
1099
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001100/*
1101 * Release a mobicore instance object and all objects related to it
1102 * @instance: instance
1103 * Returns 0 if Ok or -E ERROR
1104 */
1105int mc_release_instance(struct mc_instance *instance)
1106{
1107 struct mc_buffer *buffer, *tmp;
1108
1109 if (WARN(!instance, "No instance data available"))
1110 return -EFAULT;
1111
1112 mutex_lock(&instance->lock);
Oana Medvesana0361802013-12-20 13:52:46 +01001113 mc_clear_mmu_tables(instance);
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001114
1115 mutex_lock(&ctx.bufs_lock);
1116 /* release all mapped data */
1117
1118 /* Check if some buffers are orphaned. */
1119 list_for_each_entry_safe(buffer, tmp, &ctx.cont_bufs, list) {
Oana Medvesaneedd9e92013-02-21 19:39:04 +01001120 /* It's safe here to only call free_buffer() without unmapping
1121 * because mmap() takes a refcount to the file's fd so only
1122 * time we end up here is when everything has been unmaped or
1123 * the process called exit() */
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001124 if (buffer->instance == instance) {
1125 buffer->instance = NULL;
Oana Medvesan9f099cf2013-02-08 09:50:46 +01001126 free_buffer(buffer, false);
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001127 }
1128 }
1129 mutex_unlock(&ctx.bufs_lock);
1130
1131 mutex_unlock(&instance->lock);
1132
1133 /* release instance context */
1134 kfree(instance);
1135
1136 return 0;
1137}
1138
1139/*
1140 * mc_fd_user_open() - Will be called from user space as fd = open(...)
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001141 * A set of internal instance data are created and initialized.
1142 *
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001143 * @inode
1144 * @file
1145 * Returns 0 if OK or -ENOMEM if no allocation was possible.
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001146 */
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001147static int mc_fd_user_open(struct inode *inode, struct file *file)
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001148{
Lukas Hänelca267132012-09-04 12:28:40 +02001149 struct mc_instance *instance;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001150
Oana Medvesana0361802013-12-20 13:52:46 +01001151 MCDRV_DBG_VERBOSE(mcd, "enter");
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001152
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001153 instance = mc_alloc_instance();
1154 if (instance == NULL)
1155 return -ENOMEM;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001156
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001157 /* store instance data reference */
1158 file->private_data = instance;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001159
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001160 return 0;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001161}
1162
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001163static int mc_fd_admin_open(struct inode *inode, struct file *file)
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001164{
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001165 struct mc_instance *instance;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001166
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001167 /*
1168 * The daemon is already set so we can't allow anybody else to open
1169 * the admin interface.
1170 */
1171 if (ctx.daemon_inst) {
1172 MCDRV_DBG_ERROR(mcd, "Daemon is already connected");
1173 return -EPERM;
1174 }
1175 /* Setup the usual variables */
1176 if (mc_fd_user_open(inode, file))
1177 return -ENOMEM;
1178 instance = get_instance(file);
Lukas Hänelca267132012-09-04 12:28:40 +02001179
Oana Medvesana0361802013-12-20 13:52:46 +01001180 MCDRV_DBG(mcd, "accept this as MobiCore Daemon");
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001181
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001182 ctx.daemon_inst = instance;
1183 ctx.daemon = current;
1184 instance->admin = true;
1185 init_completion(&ctx.isr_comp);
1186 /* init ssiq event counter */
1187 ctx.evt_counter = atomic_read(&(ctx.isr_counter));
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001188
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001189 return 0;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001190}
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001191
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001192/*
1193 * mc_fd_release() - This function will be called from user space as close(...)
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001194 * The instance data are freed and the associated memory pages are unreserved.
1195 *
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001196 * @inode
1197 * @file
1198 *
1199 * Returns 0
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001200 */
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001201static int mc_fd_release(struct inode *inode, struct file *file)
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001202{
Lukas Hänelca267132012-09-04 12:28:40 +02001203 int ret = 0;
1204 struct mc_instance *instance = get_instance(file);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001205
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001206 if (WARN(!instance, "No instance data available"))
1207 return -EFAULT;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001208
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001209 /* check if daemon closes us. */
1210 if (is_daemon(instance)) {
Oana Medvesana0361802013-12-20 13:52:46 +01001211 MCDRV_DBG_WARN(mcd, "MobiCore Daemon died");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001212 ctx.daemon_inst = NULL;
1213 ctx.daemon = NULL;
1214 }
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001215
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001216 ret = mc_release_instance(instance);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001217
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001218 /*
1219 * ret is quite irrelevant here as most apps don't care about the
1220 * return value from close() and it's quite difficult to recover
1221 */
Oana Medvesana0361802013-12-20 13:52:46 +01001222 MCDRV_DBG_VERBOSE(mcd, "exit with %d/0x%08X", ret, ret);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001223
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001224 return (int)ret;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001225}
1226
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001227/*
1228 * This function represents the interrupt function of the mcDrvModule.
1229 * It signals by incrementing of an event counter and the start of the read
1230 * waiting queue, the read function a interrupt has occurred.
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001231 */
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001232static irqreturn_t mc_ssiq_isr(int intr, void *context)
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001233{
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001234 /* increment interrupt event counter */
1235 atomic_inc(&(ctx.isr_counter));
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001236
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001237 /* signal the daemon */
1238 complete(&ctx.isr_comp);
Oana Medvesana0361802013-12-20 13:52:46 +01001239#ifdef MC_MEM_TRACES
1240 mobicore_log_read();
1241#endif
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001242 return IRQ_HANDLED;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001243}
1244
Lukas Hänelca267132012-09-04 12:28:40 +02001245/* function table structure of this device driver. */
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001246static const struct file_operations mc_admin_fops = {
1247 .owner = THIS_MODULE,
1248 .open = mc_fd_admin_open,
1249 .release = mc_fd_release,
1250 .unlocked_ioctl = mc_fd_admin_ioctl,
1251 .mmap = mc_fd_mmap,
1252 .read = mc_fd_read,
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001253};
1254
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001255/* function table structure of this device driver. */
1256static const struct file_operations mc_user_fops = {
1257 .owner = THIS_MODULE,
1258 .open = mc_fd_user_open,
1259 .release = mc_fd_release,
1260 .unlocked_ioctl = mc_fd_user_ioctl,
1261 .mmap = mc_fd_mmap,
Oana Medvesana0361802013-12-20 13:52:46 +01001262#if defined(TBASE_CORE_SWITCHER) && defined(DEBUG)
1263 .write = mc_fd_write,
1264#endif
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001265};
1266
Oana Medvesanbd1a95d2013-04-25 10:34:08 +02001267static int create_devices(void)
1268{
1269 int ret = 0;
1270
1271 cdev_init(&mc_admin_cdev, &mc_admin_fops);
1272 cdev_init(&mc_user_cdev, &mc_user_fops);
1273
1274 mc_device_class = class_create(THIS_MODULE, "mobicore");
1275 if (IS_ERR(mc_device_class)) {
1276 MCDRV_DBG_ERROR(mcd, "failed to create device class");
1277 ret = PTR_ERR(mc_device_class);
1278 goto out;
1279 }
1280
1281 ret = alloc_chrdev_region(&mc_dev_admin, 0, MC_DEV_MAX, "mobicore");
1282 if (ret < 0) {
Oana Medvesana0361802013-12-20 13:52:46 +01001283 MCDRV_DBG_ERROR(mcd, "failed to allocate char dev region");
Oana Medvesanbd1a95d2013-04-25 10:34:08 +02001284 goto error;
1285 }
1286 mc_dev_user = MKDEV(MAJOR(mc_dev_admin), 1);
1287
Oana Medvesana0361802013-12-20 13:52:46 +01001288 MCDRV_DBG_VERBOSE(mcd, "%s: dev %d", "mobicore", MAJOR(mc_dev_admin));
Oana Medvesanbd1a95d2013-04-25 10:34:08 +02001289
1290 /* First the ADMIN node */
1291 ret = cdev_add(&mc_admin_cdev, mc_dev_admin, 1);
1292 if (ret != 0) {
Oana Medvesana0361802013-12-20 13:52:46 +01001293 MCDRV_DBG_ERROR(mcd, "admin device register failed");
Oana Medvesanbd1a95d2013-04-25 10:34:08 +02001294 goto error;
1295 }
1296 mc_admin_cdev.owner = THIS_MODULE;
1297 device_create(mc_device_class, NULL, mc_dev_admin, NULL,
1298 MC_ADMIN_DEVNODE);
1299
1300 /* Then the user node */
1301
1302 ret = cdev_add(&mc_user_cdev, mc_dev_user, 1);
1303 if (ret != 0) {
Oana Medvesana0361802013-12-20 13:52:46 +01001304 MCDRV_DBG_ERROR(mcd, "user device register failed");
Oana Medvesanbd1a95d2013-04-25 10:34:08 +02001305 goto error_unregister;
1306 }
1307 mc_user_cdev.owner = THIS_MODULE;
1308 device_create(mc_device_class, NULL, mc_dev_user, NULL,
1309 MC_USER_DEVNODE);
1310
1311 goto out;
1312error_unregister:
1313 device_destroy(mc_device_class, mc_dev_admin);
1314 device_destroy(mc_device_class, mc_dev_user);
1315
1316 cdev_del(&mc_admin_cdev);
1317 cdev_del(&mc_user_cdev);
1318 unregister_chrdev_region(mc_dev_admin, MC_DEV_MAX);
1319error:
1320 class_destroy(mc_device_class);
1321out:
1322 return ret;
1323}
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001324
1325/*
1326 * This function is called the kernel during startup or by a insmod command.
Oana Medvesanbd1a95d2013-04-25 10:34:08 +02001327 * This device is installed and registered as cdev, then interrupt and
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001328 * queue handling is set up
1329 */
1330static int __init mobicore_init(void)
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001331{
1332 int ret = 0;
Lukas Hänelca267132012-09-04 12:28:40 +02001333 dev_set_name(mcd, "mcd");
1334
Oana Medvesanbd1a95d2013-04-25 10:34:08 +02001335 dev_info(mcd, "MobiCore Driver, Build: " __TIMESTAMP__ "\n");
1336 dev_info(mcd, "MobiCore mcDrvModuleApi version is %i.%i\n",
1337 MCDRVMODULEAPI_VERSION_MAJOR,
1338 MCDRVMODULEAPI_VERSION_MINOR);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001339#ifdef MOBICORE_COMPONENT_BUILD_TAG
Oana Medvesanbd1a95d2013-04-25 10:34:08 +02001340 dev_info(mcd, "MobiCore %s\n", MOBICORE_COMPONENT_BUILD_TAG);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001341#endif
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001342 /* Hardware does not support ARM TrustZone -> Cannot continue! */
1343 if (!has_security_extensions()) {
1344 MCDRV_DBG_ERROR(mcd,
Oana Medvesana0361802013-12-20 13:52:46 +01001345 "Hardware doesn't support ARM TrustZone!");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001346 return -ENODEV;
1347 }
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001348
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001349 /* Running in secure mode -> Cannot load the driver! */
1350 if (is_secure_mode()) {
Oana Medvesana0361802013-12-20 13:52:46 +01001351 MCDRV_DBG_ERROR(mcd, "Running in secure MODE!");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001352 return -ENODEV;
1353 }
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001354
Oana Medvesaneedd9e92013-02-21 19:39:04 +01001355 ret = mc_fastcall_init(&ctx);
1356 if (ret)
1357 goto error;
1358
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001359 init_completion(&ctx.isr_comp);
Oana Medvesanbd1a95d2013-04-25 10:34:08 +02001360
1361 /* initialize event counter for signaling of an IRQ to zero */
1362 atomic_set(&ctx.isr_counter, 0);
1363
Oana Medvesana0361802013-12-20 13:52:46 +01001364 /* set up S-SIQ interrupt handler ************************/
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001365 ret = request_irq(MC_INTR_SSIQ, mc_ssiq_isr, IRQF_TRIGGER_RISING,
1366 MC_ADMIN_DEVNODE, &ctx);
1367 if (ret != 0) {
Oana Medvesana0361802013-12-20 13:52:46 +01001368 MCDRV_DBG_ERROR(mcd, "interrupt request failed");
Oana Medvesaneedd9e92013-02-21 19:39:04 +01001369 goto err_req_irq;
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001370 }
Lukas Hänelca267132012-09-04 12:28:40 +02001371
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001372#ifdef MC_PM_RUNTIME
1373 ret = mc_pm_initialize(&ctx);
1374 if (ret != 0) {
Oana Medvesana0361802013-12-20 13:52:46 +01001375 MCDRV_DBG_ERROR(mcd, "Power Management init failed!");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001376 goto free_isr;
1377 }
1378#endif
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001379
Oana Medvesanbd1a95d2013-04-25 10:34:08 +02001380 ret = create_devices();
1381 if (ret != 0)
1382 goto free_pm;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001383
Oana Medvesana0361802013-12-20 13:52:46 +01001384 ret = mc_init_mmu_tables();
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001385
Oana Medvesan5b88b802013-05-07 15:34:00 +02001386#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
1387 ret = mc_pm_clock_initialize();
1388#endif
1389
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001390 /*
1391 * initialize unique number counter which we can use for
1392 * handles. It is limited to 2^32, but this should be
1393 * enough to be roll-over safe for us. We start with 1
1394 * instead of 0.
1395 */
1396 atomic_set(&ctx.unique_counter, 1);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001397
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001398 /* init list for contiguous buffers */
1399 INIT_LIST_HEAD(&ctx.cont_bufs);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001400
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001401 /* init lock for the buffers list */
1402 mutex_init(&ctx.bufs_lock);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001403
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001404 memset(&ctx.mci_base, 0, sizeof(ctx.mci_base));
Oana Medvesana0361802013-12-20 13:52:46 +01001405 MCDRV_DBG(mcd, "initialized");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001406 return 0;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001407
Oana Medvesanbd1a95d2013-04-25 10:34:08 +02001408free_pm:
1409#ifdef MC_PM_RUNTIME
1410 mc_pm_free();
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001411free_isr:
1412 free_irq(MC_INTR_SSIQ, &ctx);
Oana Medvesanbd1a95d2013-04-25 10:34:08 +02001413#endif
Oana Medvesaneedd9e92013-02-21 19:39:04 +01001414err_req_irq:
1415 mc_fastcall_destroy();
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001416error:
Lukas Hänelca267132012-09-04 12:28:40 +02001417 return ret;
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001418}
1419
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001420/*
1421 * This function removes this device driver from the Linux device manager .
1422 */
1423static void __exit mobicore_exit(void)
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001424{
Oana Medvesana0361802013-12-20 13:52:46 +01001425 MCDRV_DBG_VERBOSE(mcd, "enter");
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001426#ifdef MC_MEM_TRACES
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001427 mobicore_log_free();
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001428#endif
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001429
Oana Medvesana0361802013-12-20 13:52:46 +01001430 mc_release_mmu_tables();
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001431
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001432#ifdef MC_PM_RUNTIME
1433 mc_pm_free();
1434#endif
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001435
Oana Medvesanbd1a95d2013-04-25 10:34:08 +02001436 device_destroy(mc_device_class, mc_dev_admin);
1437 device_destroy(mc_device_class, mc_dev_user);
1438 class_destroy(mc_device_class);
1439 unregister_chrdev_region(mc_dev_admin, MC_DEV_MAX);
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001440
Oana Medvesanbd1a95d2013-04-25 10:34:08 +02001441 free_irq(MC_INTR_SSIQ, &ctx);
Oana Medvesaneedd9e92013-02-21 19:39:04 +01001442
1443 mc_fastcall_destroy();
1444
Oana Medvesan5b88b802013-05-07 15:34:00 +02001445#ifdef MC_CRYPTO_CLOCK_MANAGEMENT
1446 mc_pm_clock_finalize();
1447#endif
1448
Lukas Hänelca267132012-09-04 12:28:40 +02001449 MCDRV_DBG_VERBOSE(mcd, "exit");
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001450}
1451
Oana Medvesana0361802013-12-20 13:52:46 +01001452bool mc_sleep_ready(void)
1453{
1454#ifdef MC_PM_RUNTIME
1455 return mc_pm_sleep_ready();
1456#else
1457 return true;
1458#endif
1459}
1460
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001461/* Linux Driver Module Macros */
Lukas Hänel28a9ffd2012-11-07 13:17:39 +09001462module_init(mobicore_init);
1463module_exit(mobicore_exit);
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001464MODULE_AUTHOR("Giesecke & Devrient GmbH");
Oana Medvesan9f099cf2013-02-08 09:50:46 +01001465MODULE_AUTHOR("Trustonic Limited");
Lukas Hänel8fd2cdd2012-06-01 19:12:09 +02001466MODULE_LICENSE("GPL v2");
1467MODULE_DESCRIPTION("MobiCore driver");