aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/xen/Kconfig10
-rw-r--r--drivers/xen/Makefile3
-rw-r--r--drivers/xen/evtchn.c494
-rw-r--r--include/xen/evtchn.h88
4 files changed, 594 insertions, 1 deletions
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig
index 526187c8a12d..1bbb9108f31e 100644
--- a/drivers/xen/Kconfig
+++ b/drivers/xen/Kconfig
@@ -18,6 +18,16 @@ config XEN_SCRUB_PAGES
18 secure, but slightly less efficient. 18 secure, but slightly less efficient.
19 If in doubt, say yes. 19 If in doubt, say yes.
20 20
21config XEN_DEV_EVTCHN
22 tristate "Xen /dev/xen/evtchn device"
23 depends on XEN
24 default y
25 help
26 The evtchn driver allows a userspace process to triger event
27 channels and to receive notification of an event channel
28 firing.
29 If in doubt, say yes.
30
21config XENFS 31config XENFS
22 tristate "Xen filesystem" 32 tristate "Xen filesystem"
23 depends on XEN 33 depends on XEN
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index ff8accc9e103..1567639847e7 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -4,4 +4,5 @@ obj-y += xenbus/
4obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o 4obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
5obj-$(CONFIG_XEN_XENCOMM) += xencomm.o 5obj-$(CONFIG_XEN_XENCOMM) += xencomm.o
6obj-$(CONFIG_XEN_BALLOON) += balloon.o 6obj-$(CONFIG_XEN_BALLOON) += balloon.o
7obj-$(CONFIG_XENFS) += xenfs/ \ No newline at end of file 7obj-$(CONFIG_XEN_DEV_EVTCHN) += evtchn.o
8obj-$(CONFIG_XENFS) += xenfs/
diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c
new file mode 100644
index 000000000000..517b9ee63e18
--- /dev/null
+++ b/drivers/xen/evtchn.c
@@ -0,0 +1,494 @@
1/******************************************************************************
2 * evtchn.c
3 *
4 * Driver for receiving and demuxing event-channel signals.
5 *
6 * Copyright (c) 2004-2005, K A Fraser
7 * Multi-process extensions Copyright (c) 2004, Steven Smith
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License version 2
11 * as published by the Free Software Foundation; or, when distributed
12 * separately from the Linux kernel or incorporated into other
13 * software packages, subject to the following license:
14 *
15 * Permission is hereby granted, free of charge, to any person obtaining a copy
16 * of this source file (the "Software"), to deal in the Software without
17 * restriction, including without limitation the rights to use, copy, modify,
18 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
19 * and to permit persons to whom the Software is furnished to do so, subject to
20 * the following conditions:
21 *
22 * The above copyright notice and this permission notice shall be included in
23 * all copies or substantial portions of the Software.
24 *
25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
31 * IN THE SOFTWARE.
32 */
33
34#include <linux/module.h>
35#include <linux/kernel.h>
36#include <linux/sched.h>
37#include <linux/slab.h>
38#include <linux/string.h>
39#include <linux/errno.h>
40#include <linux/fs.h>
41#include <linux/errno.h>
42#include <linux/miscdevice.h>
43#include <linux/major.h>
44#include <linux/proc_fs.h>
45#include <linux/stat.h>
46#include <linux/poll.h>
47#include <linux/irq.h>
48#include <linux/init.h>
49#include <linux/gfp.h>
50#include <linux/mutex.h>
51#include <linux/cpu.h>
52#include <xen/events.h>
53#include <xen/evtchn.h>
54#include <asm/xen/hypervisor.h>
55
56struct per_user_data {
57 /* Notification ring, accessed via /dev/xen/evtchn. */
58#define EVTCHN_RING_SIZE (PAGE_SIZE / sizeof(evtchn_port_t))
59#define EVTCHN_RING_MASK(_i) ((_i)&(EVTCHN_RING_SIZE-1))
60 evtchn_port_t *ring;
61 unsigned int ring_cons, ring_prod, ring_overflow;
62 struct mutex ring_cons_mutex; /* protect against concurrent readers */
63
64 /* Processes wait on this queue when ring is empty. */
65 wait_queue_head_t evtchn_wait;
66 struct fasync_struct *evtchn_async_queue;
67 const char *name;
68};
69
70/* Who's bound to each port? */
71static struct per_user_data *port_user[NR_EVENT_CHANNELS];
72static DEFINE_SPINLOCK(port_user_lock);
73
74irqreturn_t evtchn_interrupt(int irq, void *data)
75{
76 unsigned int port = (unsigned long)data;
77 struct per_user_data *u;
78
79 spin_lock(&port_user_lock);
80
81 u = port_user[port];
82
83 disable_irq_nosync(irq);
84
85 if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) {
86 u->ring[EVTCHN_RING_MASK(u->ring_prod)] = port;
87 wmb(); /* Ensure ring contents visible */
88 if (u->ring_cons == u->ring_prod++) {
89 wake_up_interruptible(&u->evtchn_wait);
90 kill_fasync(&u->evtchn_async_queue,
91 SIGIO, POLL_IN);
92 }
93 } else {
94 u->ring_overflow = 1;
95 }
96
97 spin_unlock(&port_user_lock);
98
99 return IRQ_HANDLED;
100}
101
102static ssize_t evtchn_read(struct file *file, char __user *buf,
103 size_t count, loff_t *ppos)
104{
105 int rc;
106 unsigned int c, p, bytes1 = 0, bytes2 = 0;
107 struct per_user_data *u = file->private_data;
108
109 /* Whole number of ports. */
110 count &= ~(sizeof(evtchn_port_t)-1);
111
112 if (count == 0)
113 return 0;
114
115 if (count > PAGE_SIZE)
116 count = PAGE_SIZE;
117
118 for (;;) {
119 mutex_lock(&u->ring_cons_mutex);
120
121 rc = -EFBIG;
122 if (u->ring_overflow)
123 goto unlock_out;
124
125 c = u->ring_cons;
126 p = u->ring_prod;
127 if (c != p)
128 break;
129
130 mutex_unlock(&u->ring_cons_mutex);
131
132 if (file->f_flags & O_NONBLOCK)
133 return -EAGAIN;
134
135 rc = wait_event_interruptible(u->evtchn_wait,
136 u->ring_cons != u->ring_prod);
137 if (rc)
138 return rc;
139 }
140
141 /* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */
142 if (((c ^ p) & EVTCHN_RING_SIZE) != 0) {
143 bytes1 = (EVTCHN_RING_SIZE - EVTCHN_RING_MASK(c)) *
144 sizeof(evtchn_port_t);
145 bytes2 = EVTCHN_RING_MASK(p) * sizeof(evtchn_port_t);
146 } else {
147 bytes1 = (p - c) * sizeof(evtchn_port_t);
148 bytes2 = 0;
149 }
150
151 /* Truncate chunks according to caller's maximum byte count. */
152 if (bytes1 > count) {
153 bytes1 = count;
154 bytes2 = 0;
155 } else if ((bytes1 + bytes2) > count) {
156 bytes2 = count - bytes1;
157 }
158
159 rc = -EFAULT;
160 rmb(); /* Ensure that we see the port before we copy it. */
161 if (copy_to_user(buf, &u->ring[EVTCHN_RING_MASK(c)], bytes1) ||
162 ((bytes2 != 0) &&
163 copy_to_user(&buf[bytes1], &u->ring[0], bytes2)))
164 goto unlock_out;
165
166 u->ring_cons += (bytes1 + bytes2) / sizeof(evtchn_port_t);
167 rc = bytes1 + bytes2;
168
169 unlock_out:
170 mutex_unlock(&u->ring_cons_mutex);
171 return rc;
172}
173
174static ssize_t evtchn_write(struct file *file, const char __user *buf,
175 size_t count, loff_t *ppos)
176{
177 int rc, i;
178 evtchn_port_t *kbuf = (evtchn_port_t *)__get_free_page(GFP_KERNEL);
179 struct per_user_data *u = file->private_data;
180
181 if (kbuf == NULL)
182 return -ENOMEM;
183
184 /* Whole number of ports. */
185 count &= ~(sizeof(evtchn_port_t)-1);
186
187 rc = 0;
188 if (count == 0)
189 goto out;
190
191 if (count > PAGE_SIZE)
192 count = PAGE_SIZE;
193
194 rc = -EFAULT;
195 if (copy_from_user(kbuf, buf, count) != 0)
196 goto out;
197
198 spin_lock_irq(&port_user_lock);
199 for (i = 0; i < (count/sizeof(evtchn_port_t)); i++)
200 if ((kbuf[i] < NR_EVENT_CHANNELS) && (port_user[kbuf[i]] == u))
201 enable_irq(irq_from_evtchn(kbuf[i]));
202 spin_unlock_irq(&port_user_lock);
203
204 rc = count;
205
206 out:
207 free_page((unsigned long)kbuf);
208 return rc;
209}
210
211static int evtchn_bind_to_user(struct per_user_data *u, int port)
212{
213 int irq;
214 int rc = 0;
215
216 spin_lock_irq(&port_user_lock);
217
218 BUG_ON(port_user[port] != NULL);
219
220 irq = bind_evtchn_to_irqhandler(port, evtchn_interrupt, IRQF_DISABLED,
221 u->name, (void *)(unsigned long)port);
222 if (rc < 0)
223 goto fail;
224
225 port_user[port] = u;
226
227fail:
228 spin_unlock_irq(&port_user_lock);
229 return rc;
230}
231
232static void evtchn_unbind_from_user(struct per_user_data *u, int port)
233{
234 int irq = irq_from_evtchn(port);
235
236 unbind_from_irqhandler(irq, (void *)(unsigned long)port);
237 port_user[port] = NULL;
238}
239
240static long evtchn_ioctl(struct file *file,
241 unsigned int cmd, unsigned long arg)
242{
243 int rc;
244 struct per_user_data *u = file->private_data;
245 void __user *uarg = (void __user *) arg;
246
247 switch (cmd) {
248 case IOCTL_EVTCHN_BIND_VIRQ: {
249 struct ioctl_evtchn_bind_virq bind;
250 struct evtchn_bind_virq bind_virq;
251
252 rc = -EFAULT;
253 if (copy_from_user(&bind, uarg, sizeof(bind)))
254 break;
255
256 bind_virq.virq = bind.virq;
257 bind_virq.vcpu = 0;
258 rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
259 &bind_virq);
260 if (rc != 0)
261 break;
262
263 rc = evtchn_bind_to_user(u, bind_virq.port);
264 if (rc == 0)
265 rc = bind_virq.port;
266 break;
267 }
268
269 case IOCTL_EVTCHN_BIND_INTERDOMAIN: {
270 struct ioctl_evtchn_bind_interdomain bind;
271 struct evtchn_bind_interdomain bind_interdomain;
272
273 rc = -EFAULT;
274 if (copy_from_user(&bind, uarg, sizeof(bind)))
275 break;
276
277 bind_interdomain.remote_dom = bind.remote_domain;
278 bind_interdomain.remote_port = bind.remote_port;
279 rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
280 &bind_interdomain);
281 if (rc != 0)
282 break;
283
284 rc = evtchn_bind_to_user(u, bind_interdomain.local_port);
285 if (rc == 0)
286 rc = bind_interdomain.local_port;
287 break;
288 }
289
290 case IOCTL_EVTCHN_BIND_UNBOUND_PORT: {
291 struct ioctl_evtchn_bind_unbound_port bind;
292 struct evtchn_alloc_unbound alloc_unbound;
293
294 rc = -EFAULT;
295 if (copy_from_user(&bind, uarg, sizeof(bind)))
296 break;
297
298 alloc_unbound.dom = DOMID_SELF;
299 alloc_unbound.remote_dom = bind.remote_domain;
300 rc = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
301 &alloc_unbound);
302 if (rc != 0)
303 break;
304
305 rc = evtchn_bind_to_user(u, alloc_unbound.port);
306 if (rc == 0)
307 rc = alloc_unbound.port;
308 break;
309 }
310
311 case IOCTL_EVTCHN_UNBIND: {
312 struct ioctl_evtchn_unbind unbind;
313
314 rc = -EFAULT;
315 if (copy_from_user(&unbind, uarg, sizeof(unbind)))
316 break;
317
318 rc = -EINVAL;
319 if (unbind.port >= NR_EVENT_CHANNELS)
320 break;
321
322 spin_lock_irq(&port_user_lock);
323
324 rc = -ENOTCONN;
325 if (port_user[unbind.port] != u) {
326 spin_unlock_irq(&port_user_lock);
327 break;
328 }
329
330 evtchn_unbind_from_user(u, unbind.port);
331
332 spin_unlock_irq(&port_user_lock);
333
334 rc = 0;
335 break;
336 }
337
338 case IOCTL_EVTCHN_NOTIFY: {
339 struct ioctl_evtchn_notify notify;
340
341 rc = -EFAULT;
342 if (copy_from_user(&notify, uarg, sizeof(notify)))
343 break;
344
345 if (notify.port >= NR_EVENT_CHANNELS) {
346 rc = -EINVAL;
347 } else if (port_user[notify.port] != u) {
348 rc = -ENOTCONN;
349 } else {
350 notify_remote_via_evtchn(notify.port);
351 rc = 0;
352 }
353 break;
354 }
355
356 case IOCTL_EVTCHN_RESET: {
357 /* Initialise the ring to empty. Clear errors. */
358 mutex_lock(&u->ring_cons_mutex);
359 spin_lock_irq(&port_user_lock);
360 u->ring_cons = u->ring_prod = u->ring_overflow = 0;
361 spin_unlock_irq(&port_user_lock);
362 mutex_unlock(&u->ring_cons_mutex);
363 rc = 0;
364 break;
365 }
366
367 default:
368 rc = -ENOSYS;
369 break;
370 }
371
372 return rc;
373}
374
375static unsigned int evtchn_poll(struct file *file, poll_table *wait)
376{
377 unsigned int mask = POLLOUT | POLLWRNORM;
378 struct per_user_data *u = file->private_data;
379
380 poll_wait(file, &u->evtchn_wait, wait);
381 if (u->ring_cons != u->ring_prod)
382 mask |= POLLIN | POLLRDNORM;
383 if (u->ring_overflow)
384 mask = POLLERR;
385 return mask;
386}
387
388static int evtchn_fasync(int fd, struct file *filp, int on)
389{
390 struct per_user_data *u = filp->private_data;
391 return fasync_helper(fd, filp, on, &u->evtchn_async_queue);
392}
393
394static int evtchn_open(struct inode *inode, struct file *filp)
395{
396 struct per_user_data *u;
397
398 u = kzalloc(sizeof(*u), GFP_KERNEL);
399 if (u == NULL)
400 return -ENOMEM;
401
402 u->name = kasprintf(GFP_KERNEL, "evtchn:%s", current->comm);
403 if (u->name == NULL) {
404 kfree(u);
405 return -ENOMEM;
406 }
407
408 init_waitqueue_head(&u->evtchn_wait);
409
410 u->ring = (evtchn_port_t *)__get_free_page(GFP_KERNEL);
411 if (u->ring == NULL) {
412 kfree(u->name);
413 kfree(u);
414 return -ENOMEM;
415 }
416
417 mutex_init(&u->ring_cons_mutex);
418
419 filp->private_data = u;
420
421 return 0;
422}
423
424static int evtchn_release(struct inode *inode, struct file *filp)
425{
426 int i;
427 struct per_user_data *u = filp->private_data;
428
429 spin_lock_irq(&port_user_lock);
430
431 free_page((unsigned long)u->ring);
432
433 for (i = 0; i < NR_EVENT_CHANNELS; i++) {
434 if (port_user[i] != u)
435 continue;
436
437 evtchn_unbind_from_user(port_user[i], i);
438 }
439
440 spin_unlock_irq(&port_user_lock);
441
442 kfree(u->name);
443 kfree(u);
444
445 return 0;
446}
447
448static const struct file_operations evtchn_fops = {
449 .owner = THIS_MODULE,
450 .read = evtchn_read,
451 .write = evtchn_write,
452 .unlocked_ioctl = evtchn_ioctl,
453 .poll = evtchn_poll,
454 .fasync = evtchn_fasync,
455 .open = evtchn_open,
456 .release = evtchn_release,
457};
458
459static struct miscdevice evtchn_miscdev = {
460 .minor = MISC_DYNAMIC_MINOR,
461 .name = "evtchn",
462 .fops = &evtchn_fops,
463};
464static int __init evtchn_init(void)
465{
466 int err;
467
468 if (!xen_domain())
469 return -ENODEV;
470
471 spin_lock_init(&port_user_lock);
472 memset(port_user, 0, sizeof(port_user));
473
474 /* Create '/dev/misc/evtchn'. */
475 err = misc_register(&evtchn_miscdev);
476 if (err != 0) {
477 printk(KERN_ALERT "Could not register /dev/misc/evtchn\n");
478 return err;
479 }
480
481 printk(KERN_INFO "Event-channel device installed.\n");
482
483 return 0;
484}
485
486static void __exit evtchn_cleanup(void)
487{
488 misc_deregister(&evtchn_miscdev);
489}
490
491module_init(evtchn_init);
492module_exit(evtchn_cleanup);
493
494MODULE_LICENSE("GPL");
diff --git a/include/xen/evtchn.h b/include/xen/evtchn.h
new file mode 100644
index 000000000000..14e833ee4e0b
--- /dev/null
+++ b/include/xen/evtchn.h
@@ -0,0 +1,88 @@
1/******************************************************************************
2 * evtchn.h
3 *
4 * Interface to /dev/xen/evtchn.
5 *
6 * Copyright (c) 2003-2005, K A Fraser
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version 2
10 * as published by the Free Software Foundation; or, when distributed
11 * separately from the Linux kernel or incorporated into other
12 * software packages, subject to the following license:
13 *
14 * Permission is hereby granted, free of charge, to any person obtaining a copy
15 * of this source file (the "Software"), to deal in the Software without
16 * restriction, including without limitation the rights to use, copy, modify,
17 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
18 * and to permit persons to whom the Software is furnished to do so, subject to
19 * the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be included in
22 * all copies or substantial portions of the Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30 * IN THE SOFTWARE.
31 */
32
33#ifndef __LINUX_PUBLIC_EVTCHN_H__
34#define __LINUX_PUBLIC_EVTCHN_H__
35
36/*
37 * Bind a fresh port to VIRQ @virq.
38 * Return allocated port.
39 */
40#define IOCTL_EVTCHN_BIND_VIRQ \
41 _IOC(_IOC_NONE, 'E', 0, sizeof(struct ioctl_evtchn_bind_virq))
42struct ioctl_evtchn_bind_virq {
43 unsigned int virq;
44};
45
46/*
47 * Bind a fresh port to remote <@remote_domain, @remote_port>.
48 * Return allocated port.
49 */
50#define IOCTL_EVTCHN_BIND_INTERDOMAIN \
51 _IOC(_IOC_NONE, 'E', 1, sizeof(struct ioctl_evtchn_bind_interdomain))
52struct ioctl_evtchn_bind_interdomain {
53 unsigned int remote_domain, remote_port;
54};
55
56/*
57 * Allocate a fresh port for binding to @remote_domain.
58 * Return allocated port.
59 */
60#define IOCTL_EVTCHN_BIND_UNBOUND_PORT \
61 _IOC(_IOC_NONE, 'E', 2, sizeof(struct ioctl_evtchn_bind_unbound_port))
62struct ioctl_evtchn_bind_unbound_port {
63 unsigned int remote_domain;
64};
65
66/*
67 * Unbind previously allocated @port.
68 */
69#define IOCTL_EVTCHN_UNBIND \
70 _IOC(_IOC_NONE, 'E', 3, sizeof(struct ioctl_evtchn_unbind))
71struct ioctl_evtchn_unbind {
72 unsigned int port;
73};
74
75/*
76 * Unbind previously allocated @port.
77 */
78#define IOCTL_EVTCHN_NOTIFY \
79 _IOC(_IOC_NONE, 'E', 4, sizeof(struct ioctl_evtchn_notify))
80struct ioctl_evtchn_notify {
81 unsigned int port;
82};
83
84/* Clear and reinitialise the event buffer. Clear error condition. */
85#define IOCTL_EVTCHN_RESET \
86 _IOC(_IOC_NONE, 'E', 5, 0)
87
88#endif /* __LINUX_PUBLIC_EVTCHN_H__ */