diff options
Diffstat (limited to 'virt/kvm/eventfd.c')
-rw-r--r-- | virt/kvm/eventfd.c | 251 |
1 files changed, 250 insertions, 1 deletions
diff --git a/virt/kvm/eventfd.c b/virt/kvm/eventfd.c index 4092b8dcd510..99017e8a92ac 100644 --- a/virt/kvm/eventfd.c +++ b/virt/kvm/eventfd.c | |||
@@ -21,6 +21,7 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <linux/kvm_host.h> | 23 | #include <linux/kvm_host.h> |
24 | #include <linux/kvm.h> | ||
24 | #include <linux/workqueue.h> | 25 | #include <linux/workqueue.h> |
25 | #include <linux/syscalls.h> | 26 | #include <linux/syscalls.h> |
26 | #include <linux/wait.h> | 27 | #include <linux/wait.h> |
@@ -28,6 +29,9 @@ | |||
28 | #include <linux/file.h> | 29 | #include <linux/file.h> |
29 | #include <linux/list.h> | 30 | #include <linux/list.h> |
30 | #include <linux/eventfd.h> | 31 | #include <linux/eventfd.h> |
32 | #include <linux/kernel.h> | ||
33 | |||
34 | #include "iodev.h" | ||
31 | 35 | ||
32 | /* | 36 | /* |
33 | * -------------------------------------------------------------------- | 37 | * -------------------------------------------------------------------- |
@@ -234,10 +238,11 @@ fail: | |||
234 | } | 238 | } |
235 | 239 | ||
236 | void | 240 | void |
237 | kvm_irqfd_init(struct kvm *kvm) | 241 | kvm_eventfd_init(struct kvm *kvm) |
238 | { | 242 | { |
239 | spin_lock_init(&kvm->irqfds.lock); | 243 | spin_lock_init(&kvm->irqfds.lock); |
240 | INIT_LIST_HEAD(&kvm->irqfds.items); | 244 | INIT_LIST_HEAD(&kvm->irqfds.items); |
245 | INIT_LIST_HEAD(&kvm->ioeventfds); | ||
241 | } | 246 | } |
242 | 247 | ||
243 | /* | 248 | /* |
@@ -327,3 +332,247 @@ static void __exit irqfd_module_exit(void) | |||
327 | 332 | ||
328 | module_init(irqfd_module_init); | 333 | module_init(irqfd_module_init); |
329 | module_exit(irqfd_module_exit); | 334 | module_exit(irqfd_module_exit); |
335 | |||
336 | /* | ||
337 | * -------------------------------------------------------------------- | ||
338 | * ioeventfd: translate a PIO/MMIO memory write to an eventfd signal. | ||
339 | * | ||
340 | * userspace can register a PIO/MMIO address with an eventfd for receiving | ||
341 | * notification when the memory has been touched. | ||
342 | * -------------------------------------------------------------------- | ||
343 | */ | ||
344 | |||
345 | struct _ioeventfd { | ||
346 | struct list_head list; | ||
347 | u64 addr; | ||
348 | int length; | ||
349 | struct eventfd_ctx *eventfd; | ||
350 | u64 datamatch; | ||
351 | struct kvm_io_device dev; | ||
352 | bool wildcard; | ||
353 | }; | ||
354 | |||
355 | static inline struct _ioeventfd * | ||
356 | to_ioeventfd(struct kvm_io_device *dev) | ||
357 | { | ||
358 | return container_of(dev, struct _ioeventfd, dev); | ||
359 | } | ||
360 | |||
361 | static void | ||
362 | ioeventfd_release(struct _ioeventfd *p) | ||
363 | { | ||
364 | eventfd_ctx_put(p->eventfd); | ||
365 | list_del(&p->list); | ||
366 | kfree(p); | ||
367 | } | ||
368 | |||
369 | static bool | ||
370 | ioeventfd_in_range(struct _ioeventfd *p, gpa_t addr, int len, const void *val) | ||
371 | { | ||
372 | u64 _val; | ||
373 | |||
374 | if (!(addr == p->addr && len == p->length)) | ||
375 | /* address-range must be precise for a hit */ | ||
376 | return false; | ||
377 | |||
378 | if (p->wildcard) | ||
379 | /* all else equal, wildcard is always a hit */ | ||
380 | return true; | ||
381 | |||
382 | /* otherwise, we have to actually compare the data */ | ||
383 | |||
384 | BUG_ON(!IS_ALIGNED((unsigned long)val, len)); | ||
385 | |||
386 | switch (len) { | ||
387 | case 1: | ||
388 | _val = *(u8 *)val; | ||
389 | break; | ||
390 | case 2: | ||
391 | _val = *(u16 *)val; | ||
392 | break; | ||
393 | case 4: | ||
394 | _val = *(u32 *)val; | ||
395 | break; | ||
396 | case 8: | ||
397 | _val = *(u64 *)val; | ||
398 | break; | ||
399 | default: | ||
400 | return false; | ||
401 | } | ||
402 | |||
403 | return _val == p->datamatch ? true : false; | ||
404 | } | ||
405 | |||
406 | /* MMIO/PIO writes trigger an event if the addr/val match */ | ||
407 | static int | ||
408 | ioeventfd_write(struct kvm_io_device *this, gpa_t addr, int len, | ||
409 | const void *val) | ||
410 | { | ||
411 | struct _ioeventfd *p = to_ioeventfd(this); | ||
412 | |||
413 | if (!ioeventfd_in_range(p, addr, len, val)) | ||
414 | return -EOPNOTSUPP; | ||
415 | |||
416 | eventfd_signal(p->eventfd, 1); | ||
417 | return 0; | ||
418 | } | ||
419 | |||
420 | /* | ||
421 | * This function is called as KVM is completely shutting down. We do not | ||
422 | * need to worry about locking just nuke anything we have as quickly as possible | ||
423 | */ | ||
424 | static void | ||
425 | ioeventfd_destructor(struct kvm_io_device *this) | ||
426 | { | ||
427 | struct _ioeventfd *p = to_ioeventfd(this); | ||
428 | |||
429 | ioeventfd_release(p); | ||
430 | } | ||
431 | |||
432 | static const struct kvm_io_device_ops ioeventfd_ops = { | ||
433 | .write = ioeventfd_write, | ||
434 | .destructor = ioeventfd_destructor, | ||
435 | }; | ||
436 | |||
437 | /* assumes kvm->slots_lock held */ | ||
438 | static bool | ||
439 | ioeventfd_check_collision(struct kvm *kvm, struct _ioeventfd *p) | ||
440 | { | ||
441 | struct _ioeventfd *_p; | ||
442 | |||
443 | list_for_each_entry(_p, &kvm->ioeventfds, list) | ||
444 | if (_p->addr == p->addr && _p->length == p->length && | ||
445 | (_p->wildcard || p->wildcard || | ||
446 | _p->datamatch == p->datamatch)) | ||
447 | return true; | ||
448 | |||
449 | return false; | ||
450 | } | ||
451 | |||
452 | static int | ||
453 | kvm_assign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args) | ||
454 | { | ||
455 | int pio = args->flags & KVM_IOEVENTFD_FLAG_PIO; | ||
456 | struct kvm_io_bus *bus = pio ? &kvm->pio_bus : &kvm->mmio_bus; | ||
457 | struct _ioeventfd *p; | ||
458 | struct eventfd_ctx *eventfd; | ||
459 | int ret; | ||
460 | |||
461 | /* must be natural-word sized */ | ||
462 | switch (args->len) { | ||
463 | case 1: | ||
464 | case 2: | ||
465 | case 4: | ||
466 | case 8: | ||
467 | break; | ||
468 | default: | ||
469 | return -EINVAL; | ||
470 | } | ||
471 | |||
472 | /* check for range overflow */ | ||
473 | if (args->addr + args->len < args->addr) | ||
474 | return -EINVAL; | ||
475 | |||
476 | /* check for extra flags that we don't understand */ | ||
477 | if (args->flags & ~KVM_IOEVENTFD_VALID_FLAG_MASK) | ||
478 | return -EINVAL; | ||
479 | |||
480 | eventfd = eventfd_ctx_fdget(args->fd); | ||
481 | if (IS_ERR(eventfd)) | ||
482 | return PTR_ERR(eventfd); | ||
483 | |||
484 | p = kzalloc(sizeof(*p), GFP_KERNEL); | ||
485 | if (!p) { | ||
486 | ret = -ENOMEM; | ||
487 | goto fail; | ||
488 | } | ||
489 | |||
490 | INIT_LIST_HEAD(&p->list); | ||
491 | p->addr = args->addr; | ||
492 | p->length = args->len; | ||
493 | p->eventfd = eventfd; | ||
494 | |||
495 | /* The datamatch feature is optional, otherwise this is a wildcard */ | ||
496 | if (args->flags & KVM_IOEVENTFD_FLAG_DATAMATCH) | ||
497 | p->datamatch = args->datamatch; | ||
498 | else | ||
499 | p->wildcard = true; | ||
500 | |||
501 | down_write(&kvm->slots_lock); | ||
502 | |||
503 | /* Verify that there isnt a match already */ | ||
504 | if (ioeventfd_check_collision(kvm, p)) { | ||
505 | ret = -EEXIST; | ||
506 | goto unlock_fail; | ||
507 | } | ||
508 | |||
509 | kvm_iodevice_init(&p->dev, &ioeventfd_ops); | ||
510 | |||
511 | ret = __kvm_io_bus_register_dev(bus, &p->dev); | ||
512 | if (ret < 0) | ||
513 | goto unlock_fail; | ||
514 | |||
515 | list_add_tail(&p->list, &kvm->ioeventfds); | ||
516 | |||
517 | up_write(&kvm->slots_lock); | ||
518 | |||
519 | return 0; | ||
520 | |||
521 | unlock_fail: | ||
522 | up_write(&kvm->slots_lock); | ||
523 | |||
524 | fail: | ||
525 | kfree(p); | ||
526 | eventfd_ctx_put(eventfd); | ||
527 | |||
528 | return ret; | ||
529 | } | ||
530 | |||
531 | static int | ||
532 | kvm_deassign_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args) | ||
533 | { | ||
534 | int pio = args->flags & KVM_IOEVENTFD_FLAG_PIO; | ||
535 | struct kvm_io_bus *bus = pio ? &kvm->pio_bus : &kvm->mmio_bus; | ||
536 | struct _ioeventfd *p, *tmp; | ||
537 | struct eventfd_ctx *eventfd; | ||
538 | int ret = -ENOENT; | ||
539 | |||
540 | eventfd = eventfd_ctx_fdget(args->fd); | ||
541 | if (IS_ERR(eventfd)) | ||
542 | return PTR_ERR(eventfd); | ||
543 | |||
544 | down_write(&kvm->slots_lock); | ||
545 | |||
546 | list_for_each_entry_safe(p, tmp, &kvm->ioeventfds, list) { | ||
547 | bool wildcard = !(args->flags & KVM_IOEVENTFD_FLAG_DATAMATCH); | ||
548 | |||
549 | if (p->eventfd != eventfd || | ||
550 | p->addr != args->addr || | ||
551 | p->length != args->len || | ||
552 | p->wildcard != wildcard) | ||
553 | continue; | ||
554 | |||
555 | if (!p->wildcard && p->datamatch != args->datamatch) | ||
556 | continue; | ||
557 | |||
558 | __kvm_io_bus_unregister_dev(bus, &p->dev); | ||
559 | ioeventfd_release(p); | ||
560 | ret = 0; | ||
561 | break; | ||
562 | } | ||
563 | |||
564 | up_write(&kvm->slots_lock); | ||
565 | |||
566 | eventfd_ctx_put(eventfd); | ||
567 | |||
568 | return ret; | ||
569 | } | ||
570 | |||
571 | int | ||
572 | kvm_ioeventfd(struct kvm *kvm, struct kvm_ioeventfd *args) | ||
573 | { | ||
574 | if (args->flags & KVM_IOEVENTFD_FLAG_DEASSIGN) | ||
575 | return kvm_deassign_ioeventfd(kvm, args); | ||
576 | |||
577 | return kvm_assign_ioeventfd(kvm, args); | ||
578 | } | ||