137f3d50eSSasha Levin #include <sys/epoll.h> 237f3d50eSSasha Levin #include <sys/ioctl.h> 337f3d50eSSasha Levin #include <pthread.h> 437f3d50eSSasha Levin #include <unistd.h> 537f3d50eSSasha Levin #include <stdio.h> 637f3d50eSSasha Levin #include <signal.h> 737f3d50eSSasha Levin 837f3d50eSSasha Levin #include <linux/kernel.h> 937f3d50eSSasha Levin #include <linux/kvm.h> 1037f3d50eSSasha Levin #include <linux/types.h> 1137f3d50eSSasha Levin 1237f3d50eSSasha Levin #include "kvm/ioeventfd.h" 1337f3d50eSSasha Levin #include "kvm/kvm.h" 1437f3d50eSSasha Levin #include "kvm/util.h" 1537f3d50eSSasha Levin 1637f3d50eSSasha Levin #define IOEVENTFD_MAX_EVENTS 20 1737f3d50eSSasha Levin 1837f3d50eSSasha Levin static struct epoll_event events[IOEVENTFD_MAX_EVENTS]; 19ea6eeb1cSSasha Levin static int epoll_fd, epoll_stop_fd; 2037f3d50eSSasha Levin static LIST_HEAD(used_ioevents); 21e1337781SSasha Levin static bool ioeventfd_avail; 2237f3d50eSSasha Levin 23ea6eeb1cSSasha Levin static void *ioeventfd__thread(void *param) 2437f3d50eSSasha Levin { 25ea6eeb1cSSasha Levin u64 tmp = 1; 26ea6eeb1cSSasha Levin 27a4d8c55eSSasha Levin kvm__set_thread_name("ioeventfd-worker"); 28a4d8c55eSSasha Levin 29ea6eeb1cSSasha Levin for (;;) { 30ea6eeb1cSSasha Levin int nfds, i; 31ea6eeb1cSSasha Levin 32ea6eeb1cSSasha Levin nfds = epoll_wait(epoll_fd, events, IOEVENTFD_MAX_EVENTS, -1); 33ea6eeb1cSSasha Levin for (i = 0; i < nfds; i++) { 34ea6eeb1cSSasha Levin struct ioevent *ioevent; 35ea6eeb1cSSasha Levin 36ea6eeb1cSSasha Levin if (events[i].data.fd == epoll_stop_fd) 37ea6eeb1cSSasha Levin goto done; 38ea6eeb1cSSasha Levin 39ea6eeb1cSSasha Levin ioevent = events[i].data.ptr; 40ea6eeb1cSSasha Levin 41ea6eeb1cSSasha Levin if (read(ioevent->fd, &tmp, sizeof(tmp)) < 0) 42ea6eeb1cSSasha Levin die("Failed reading event"); 43ea6eeb1cSSasha Levin 44ea6eeb1cSSasha Levin ioevent->fn(ioevent->fn_kvm, ioevent->fn_ptr); 45ea6eeb1cSSasha Levin } 46ea6eeb1cSSasha Levin } 47ea6eeb1cSSasha Levin 48ea6eeb1cSSasha Levin done: 49ea6eeb1cSSasha Levin tmp = write(epoll_stop_fd, &tmp, sizeof(tmp)); 50ea6eeb1cSSasha Levin 51ea6eeb1cSSasha Levin return NULL; 52ea6eeb1cSSasha Levin } 53ea6eeb1cSSasha Levin 54ea6eeb1cSSasha Levin static int ioeventfd__start(void) 55ea6eeb1cSSasha Levin { 56ea6eeb1cSSasha Levin pthread_t thread; 57ea6eeb1cSSasha Levin 58ea6eeb1cSSasha Levin if (!ioeventfd_avail) 59ea6eeb1cSSasha Levin return -ENOSYS; 60ea6eeb1cSSasha Levin 61ea6eeb1cSSasha Levin return pthread_create(&thread, NULL, ioeventfd__thread, NULL); 62ea6eeb1cSSasha Levin } 63ea6eeb1cSSasha Levin 64ea6eeb1cSSasha Levin int ioeventfd__init(struct kvm *kvm) 65ea6eeb1cSSasha Levin { 66ea6eeb1cSSasha Levin struct epoll_event epoll_event = {.events = EPOLLIN}; 67ea6eeb1cSSasha Levin int r; 68ea6eeb1cSSasha Levin 691d6fb3f2SSasha Levin ioeventfd_avail = kvm__supports_extension(kvm, KVM_CAP_IOEVENTFD); 70e1337781SSasha Levin if (!ioeventfd_avail) 7185dde7b2SMatt Evans return 1; /* Not fatal, but let caller determine no-go. */ 72e1337781SSasha Levin 7337f3d50eSSasha Levin epoll_fd = epoll_create(IOEVENTFD_MAX_EVENTS); 7437f3d50eSSasha Levin if (epoll_fd < 0) 75ea6eeb1cSSasha Levin return -errno; 76ea6eeb1cSSasha Levin 77ea6eeb1cSSasha Levin epoll_stop_fd = eventfd(0, 0); 78ea6eeb1cSSasha Levin epoll_event.data.fd = epoll_stop_fd; 79ea6eeb1cSSasha Levin 80ea6eeb1cSSasha Levin r = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, epoll_stop_fd, &epoll_event); 81ea6eeb1cSSasha Levin if (r < 0) 82ea6eeb1cSSasha Levin goto cleanup; 83ea6eeb1cSSasha Levin 84ea6eeb1cSSasha Levin r = ioeventfd__start(); 85ea6eeb1cSSasha Levin if (r < 0) 86ea6eeb1cSSasha Levin goto cleanup; 87ea6eeb1cSSasha Levin 88ea6eeb1cSSasha Levin r = 0; 89ea6eeb1cSSasha Levin 90ea6eeb1cSSasha Levin return r; 91ea6eeb1cSSasha Levin 92ea6eeb1cSSasha Levin cleanup: 93ea6eeb1cSSasha Levin close(epoll_stop_fd); 94ea6eeb1cSSasha Levin close(epoll_fd); 95ea6eeb1cSSasha Levin 96ea6eeb1cSSasha Levin return r; 9737f3d50eSSasha Levin } 9849a8afd1SSasha Levin base_init(ioeventfd__init); 9937f3d50eSSasha Levin 100ea6eeb1cSSasha Levin int ioeventfd__exit(struct kvm *kvm) 101ea6eeb1cSSasha Levin { 102ea6eeb1cSSasha Levin u64 tmp = 1; 103ea6eeb1cSSasha Levin int r; 104ea6eeb1cSSasha Levin 10555628a95SMichael Ellerman if (!ioeventfd_avail) 10655628a95SMichael Ellerman return 0; 10755628a95SMichael Ellerman 108ea6eeb1cSSasha Levin r = write(epoll_stop_fd, &tmp, sizeof(tmp)); 109ea6eeb1cSSasha Levin if (r < 0) 110ea6eeb1cSSasha Levin return r; 111ea6eeb1cSSasha Levin 112ea6eeb1cSSasha Levin r = read(epoll_stop_fd, &tmp, sizeof(tmp)); 113ea6eeb1cSSasha Levin if (r < 0) 114ea6eeb1cSSasha Levin return r; 115ea6eeb1cSSasha Levin 116ea6eeb1cSSasha Levin close(epoll_fd); 117ea6eeb1cSSasha Levin close(epoll_stop_fd); 118ea6eeb1cSSasha Levin 119ea6eeb1cSSasha Levin return 0; 120ea6eeb1cSSasha Levin } 12149a8afd1SSasha Levin base_exit(ioeventfd__exit); 122ea6eeb1cSSasha Levin 12327347f76SWill Deacon int ioeventfd__add_event(struct ioevent *ioevent, int flags) 12437f3d50eSSasha Levin { 12537f3d50eSSasha Levin struct kvm_ioeventfd kvm_ioevent; 12637f3d50eSSasha Levin struct epoll_event epoll_event; 12737f3d50eSSasha Levin struct ioevent *new_ioevent; 128ea6eeb1cSSasha Levin int event, r; 12937f3d50eSSasha Levin 130e1337781SSasha Levin if (!ioeventfd_avail) 131ea6eeb1cSSasha Levin return -ENOSYS; 132e1337781SSasha Levin 13337f3d50eSSasha Levin new_ioevent = malloc(sizeof(*new_ioevent)); 13437f3d50eSSasha Levin if (new_ioevent == NULL) 135ea6eeb1cSSasha Levin return -ENOMEM; 13637f3d50eSSasha Levin 13737f3d50eSSasha Levin *new_ioevent = *ioevent; 13837f3d50eSSasha Levin event = new_ioevent->fd; 13937f3d50eSSasha Levin 14037f3d50eSSasha Levin kvm_ioevent = (struct kvm_ioeventfd) { 14137f3d50eSSasha Levin .addr = ioevent->io_addr, 14237f3d50eSSasha Levin .len = ioevent->io_len, 14337f3d50eSSasha Levin .datamatch = ioevent->datamatch, 14437f3d50eSSasha Levin .fd = event, 1459ff91339SAsias He .flags = KVM_IOEVENTFD_FLAG_DATAMATCH, 14637f3d50eSSasha Levin }; 14737f3d50eSSasha Levin 148ed83730fSJean-Philippe Brucker /* 149ed83730fSJean-Philippe Brucker * For architectures that don't recognize PIO accesses, always register 150ed83730fSJean-Philippe Brucker * on the MMIO bus. Otherwise PIO accesses will cause returns to 151ed83730fSJean-Philippe Brucker * userspace. 152ed83730fSJean-Philippe Brucker */ 153ed83730fSJean-Philippe Brucker if (KVM_IOEVENTFD_HAS_PIO && flags & IOEVENTFD_FLAG_PIO) 1549ff91339SAsias He kvm_ioevent.flags |= KVM_IOEVENTFD_FLAG_PIO; 1559ff91339SAsias He 156ea6eeb1cSSasha Levin r = ioctl(ioevent->fn_kvm->vm_fd, KVM_IOEVENTFD, &kvm_ioevent); 157ea6eeb1cSSasha Levin if (r) { 158ea6eeb1cSSasha Levin r = -errno; 159ea6eeb1cSSasha Levin goto cleanup; 160ea6eeb1cSSasha Levin } 16137f3d50eSSasha Levin 1625e9dd852SJean-Philippe Brucker if (flags & IOEVENTFD_FLAG_USER_POLL) { 16337f3d50eSSasha Levin epoll_event = (struct epoll_event) { 16437f3d50eSSasha Levin .events = EPOLLIN, 16537f3d50eSSasha Levin .data.ptr = new_ioevent, 16637f3d50eSSasha Levin }; 16737f3d50eSSasha Levin 168ea6eeb1cSSasha Levin r = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, event, &epoll_event); 169ea6eeb1cSSasha Levin if (r) { 170ea6eeb1cSSasha Levin r = -errno; 171ea6eeb1cSSasha Levin goto cleanup; 17237f3d50eSSasha Levin } 1735e9dd852SJean-Philippe Brucker } 17437f3d50eSSasha Levin 175*56c82a03SJean-Philippe Brucker new_ioevent->flags = kvm_ioevent.flags; 176ea6eeb1cSSasha Levin list_add_tail(&new_ioevent->list, &used_ioevents); 177ea6eeb1cSSasha Levin 178ea6eeb1cSSasha Levin return 0; 179ea6eeb1cSSasha Levin 180ea6eeb1cSSasha Levin cleanup: 181ea6eeb1cSSasha Levin free(new_ioevent); 182ea6eeb1cSSasha Levin return r; 183ea6eeb1cSSasha Levin } 184ea6eeb1cSSasha Levin 185ea6eeb1cSSasha Levin int ioeventfd__del_event(u64 addr, u64 datamatch) 18637f3d50eSSasha Levin { 18737f3d50eSSasha Levin struct kvm_ioeventfd kvm_ioevent; 18837f3d50eSSasha Levin struct ioevent *ioevent; 18937f3d50eSSasha Levin u8 found = 0; 19037f3d50eSSasha Levin 191e1337781SSasha Levin if (!ioeventfd_avail) 192ea6eeb1cSSasha Levin return -ENOSYS; 193e1337781SSasha Levin 19437f3d50eSSasha Levin list_for_each_entry(ioevent, &used_ioevents, list) { 195*56c82a03SJean-Philippe Brucker if (ioevent->io_addr == addr && 196*56c82a03SJean-Philippe Brucker ioevent->datamatch == datamatch) { 19737f3d50eSSasha Levin found = 1; 19837f3d50eSSasha Levin break; 19937f3d50eSSasha Levin } 20037f3d50eSSasha Levin } 20137f3d50eSSasha Levin 20237f3d50eSSasha Levin if (found == 0 || ioevent == NULL) 203ea6eeb1cSSasha Levin return -ENOENT; 20437f3d50eSSasha Levin 20537f3d50eSSasha Levin kvm_ioevent = (struct kvm_ioeventfd) { 206*56c82a03SJean-Philippe Brucker .fd = ioevent->fd, 20737f3d50eSSasha Levin .addr = ioevent->io_addr, 20837f3d50eSSasha Levin .len = ioevent->io_len, 20937f3d50eSSasha Levin .datamatch = ioevent->datamatch, 210ed83730fSJean-Philippe Brucker .flags = ioevent->flags 211ed83730fSJean-Philippe Brucker | KVM_IOEVENTFD_FLAG_DEASSIGN, 21237f3d50eSSasha Levin }; 21337f3d50eSSasha Levin 21437f3d50eSSasha Levin ioctl(ioevent->fn_kvm->vm_fd, KVM_IOEVENTFD, &kvm_ioevent); 21537f3d50eSSasha Levin 21637f3d50eSSasha Levin epoll_ctl(epoll_fd, EPOLL_CTL_DEL, ioevent->fd, NULL); 21737f3d50eSSasha Levin 21837f3d50eSSasha Levin list_del(&ioevent->list); 21937f3d50eSSasha Levin 22037f3d50eSSasha Levin close(ioevent->fd); 22137f3d50eSSasha Levin free(ioevent); 22237f3d50eSSasha Levin 223ea6eeb1cSSasha Levin return 0; 22437f3d50eSSasha Levin } 225