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]; 1937f3d50eSSasha Levin static int epoll_fd; 2037f3d50eSSasha Levin static LIST_HEAD(used_ioevents); 21e1337781SSasha Levin static bool ioeventfd_avail; 2237f3d50eSSasha Levin 23e1337781SSasha Levin void ioeventfd__init(struct kvm *kvm) 2437f3d50eSSasha Levin { 25*1d6fb3f2SSasha Levin ioeventfd_avail = kvm__supports_extension(kvm, KVM_CAP_IOEVENTFD); 26e1337781SSasha Levin if (!ioeventfd_avail) 27e1337781SSasha Levin return; 28e1337781SSasha Levin 2937f3d50eSSasha Levin epoll_fd = epoll_create(IOEVENTFD_MAX_EVENTS); 3037f3d50eSSasha Levin if (epoll_fd < 0) 3137f3d50eSSasha Levin die("Failed creating epoll fd"); 3237f3d50eSSasha Levin } 3337f3d50eSSasha Levin 3437f3d50eSSasha Levin void ioeventfd__add_event(struct ioevent *ioevent) 3537f3d50eSSasha Levin { 3637f3d50eSSasha Levin struct kvm_ioeventfd kvm_ioevent; 3737f3d50eSSasha Levin struct epoll_event epoll_event; 3837f3d50eSSasha Levin struct ioevent *new_ioevent; 3937f3d50eSSasha Levin int event; 4037f3d50eSSasha Levin 41e1337781SSasha Levin if (!ioeventfd_avail) 42e1337781SSasha Levin return; 43e1337781SSasha Levin 4437f3d50eSSasha Levin new_ioevent = malloc(sizeof(*new_ioevent)); 4537f3d50eSSasha Levin if (new_ioevent == NULL) 4637f3d50eSSasha Levin die("Failed allocating memory for new ioevent"); 4737f3d50eSSasha Levin 4837f3d50eSSasha Levin *new_ioevent = *ioevent; 4937f3d50eSSasha Levin event = new_ioevent->fd; 5037f3d50eSSasha Levin 5137f3d50eSSasha Levin kvm_ioevent = (struct kvm_ioeventfd) { 5237f3d50eSSasha Levin .addr = ioevent->io_addr, 5337f3d50eSSasha Levin .len = ioevent->io_len, 5437f3d50eSSasha Levin .datamatch = ioevent->datamatch, 5537f3d50eSSasha Levin .fd = event, 5637f3d50eSSasha Levin .flags = KVM_IOEVENTFD_FLAG_PIO | KVM_IOEVENTFD_FLAG_DATAMATCH, 5737f3d50eSSasha Levin }; 5837f3d50eSSasha Levin 5937f3d50eSSasha Levin if (ioctl(ioevent->fn_kvm->vm_fd, KVM_IOEVENTFD, &kvm_ioevent) != 0) 6037f3d50eSSasha Levin die("Failed creating new ioeventfd"); 6137f3d50eSSasha Levin 6237f3d50eSSasha Levin epoll_event = (struct epoll_event) { 6337f3d50eSSasha Levin .events = EPOLLIN, 6437f3d50eSSasha Levin .data.ptr = new_ioevent, 6537f3d50eSSasha Levin }; 6637f3d50eSSasha Levin 6737f3d50eSSasha Levin if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, event, &epoll_event) != 0) 6837f3d50eSSasha Levin die("Failed assigning new event to the epoll fd"); 6937f3d50eSSasha Levin 7037f3d50eSSasha Levin list_add_tail(&new_ioevent->list, &used_ioevents); 7137f3d50eSSasha Levin } 7237f3d50eSSasha Levin 7337f3d50eSSasha Levin void ioeventfd__del_event(u64 addr, u64 datamatch) 7437f3d50eSSasha Levin { 7537f3d50eSSasha Levin struct kvm_ioeventfd kvm_ioevent; 7637f3d50eSSasha Levin struct ioevent *ioevent; 7737f3d50eSSasha Levin u8 found = 0; 7837f3d50eSSasha Levin 79e1337781SSasha Levin if (!ioeventfd_avail) 80e1337781SSasha Levin return; 81e1337781SSasha Levin 8237f3d50eSSasha Levin list_for_each_entry(ioevent, &used_ioevents, list) { 8337f3d50eSSasha Levin if (ioevent->io_addr == addr) { 8437f3d50eSSasha Levin found = 1; 8537f3d50eSSasha Levin break; 8637f3d50eSSasha Levin } 8737f3d50eSSasha Levin } 8837f3d50eSSasha Levin 8937f3d50eSSasha Levin if (found == 0 || ioevent == NULL) 9037f3d50eSSasha Levin return; 9137f3d50eSSasha Levin 9237f3d50eSSasha Levin kvm_ioevent = (struct kvm_ioeventfd) { 9337f3d50eSSasha Levin .addr = ioevent->io_addr, 9437f3d50eSSasha Levin .len = ioevent->io_len, 9537f3d50eSSasha Levin .datamatch = ioevent->datamatch, 9637f3d50eSSasha Levin .flags = KVM_IOEVENTFD_FLAG_PIO 9737f3d50eSSasha Levin | KVM_IOEVENTFD_FLAG_DEASSIGN 9837f3d50eSSasha Levin | KVM_IOEVENTFD_FLAG_DATAMATCH, 9937f3d50eSSasha Levin }; 10037f3d50eSSasha Levin 10137f3d50eSSasha Levin ioctl(ioevent->fn_kvm->vm_fd, KVM_IOEVENTFD, &kvm_ioevent); 10237f3d50eSSasha Levin 10337f3d50eSSasha Levin epoll_ctl(epoll_fd, EPOLL_CTL_DEL, ioevent->fd, NULL); 10437f3d50eSSasha Levin 10537f3d50eSSasha Levin list_del(&ioevent->list); 10637f3d50eSSasha Levin 10737f3d50eSSasha Levin close(ioevent->fd); 10837f3d50eSSasha Levin free(ioevent); 10937f3d50eSSasha Levin } 11037f3d50eSSasha Levin 11137f3d50eSSasha Levin static void *ioeventfd__thread(void *param) 11237f3d50eSSasha Levin { 11337f3d50eSSasha Levin for (;;) { 11437f3d50eSSasha Levin int nfds, i; 11537f3d50eSSasha Levin 11637f3d50eSSasha Levin nfds = epoll_wait(epoll_fd, events, IOEVENTFD_MAX_EVENTS, -1); 11737f3d50eSSasha Levin for (i = 0; i < nfds; i++) { 11837f3d50eSSasha Levin u64 tmp; 11937f3d50eSSasha Levin struct ioevent *ioevent; 12037f3d50eSSasha Levin 12137f3d50eSSasha Levin ioevent = events[i].data.ptr; 12237f3d50eSSasha Levin 12337f3d50eSSasha Levin if (read(ioevent->fd, &tmp, sizeof(tmp)) < 0) 12437f3d50eSSasha Levin die("Failed reading event"); 12537f3d50eSSasha Levin 12637f3d50eSSasha Levin ioevent->fn(ioevent->fn_kvm, ioevent->fn_ptr); 12737f3d50eSSasha Levin } 12837f3d50eSSasha Levin } 12937f3d50eSSasha Levin 13037f3d50eSSasha Levin return NULL; 13137f3d50eSSasha Levin } 13237f3d50eSSasha Levin 13337f3d50eSSasha Levin void ioeventfd__start(void) 13437f3d50eSSasha Levin { 13537f3d50eSSasha Levin pthread_t thread; 13637f3d50eSSasha Levin 137e1337781SSasha Levin if (!ioeventfd_avail) 138e1337781SSasha Levin return; 139e1337781SSasha Levin 14037f3d50eSSasha Levin if (pthread_create(&thread, NULL, ioeventfd__thread, NULL) != 0) 14137f3d50eSSasha Levin die("Failed starting ioeventfd thread"); 14237f3d50eSSasha Levin } 143