1*37f3d50eSSasha Levin #include <sys/epoll.h> 2*37f3d50eSSasha Levin #include <sys/ioctl.h> 3*37f3d50eSSasha Levin #include <pthread.h> 4*37f3d50eSSasha Levin #include <unistd.h> 5*37f3d50eSSasha Levin #include <stdio.h> 6*37f3d50eSSasha Levin #include <signal.h> 7*37f3d50eSSasha Levin 8*37f3d50eSSasha Levin #include <linux/kernel.h> 9*37f3d50eSSasha Levin #include <linux/kvm.h> 10*37f3d50eSSasha Levin #include <linux/types.h> 11*37f3d50eSSasha Levin 12*37f3d50eSSasha Levin #include "kvm/ioeventfd.h" 13*37f3d50eSSasha Levin #include "kvm/kvm.h" 14*37f3d50eSSasha Levin #include "kvm/util.h" 15*37f3d50eSSasha Levin 16*37f3d50eSSasha Levin #define IOEVENTFD_MAX_EVENTS 20 17*37f3d50eSSasha Levin 18*37f3d50eSSasha Levin static struct epoll_event events[IOEVENTFD_MAX_EVENTS]; 19*37f3d50eSSasha Levin static int epoll_fd; 20*37f3d50eSSasha Levin static LIST_HEAD(used_ioevents); 21*37f3d50eSSasha Levin 22*37f3d50eSSasha Levin void ioeventfd__init(void) 23*37f3d50eSSasha Levin { 24*37f3d50eSSasha Levin epoll_fd = epoll_create(IOEVENTFD_MAX_EVENTS); 25*37f3d50eSSasha Levin if (epoll_fd < 0) 26*37f3d50eSSasha Levin die("Failed creating epoll fd"); 27*37f3d50eSSasha Levin } 28*37f3d50eSSasha Levin 29*37f3d50eSSasha Levin void ioeventfd__add_event(struct ioevent *ioevent) 30*37f3d50eSSasha Levin { 31*37f3d50eSSasha Levin struct kvm_ioeventfd kvm_ioevent; 32*37f3d50eSSasha Levin struct epoll_event epoll_event; 33*37f3d50eSSasha Levin struct ioevent *new_ioevent; 34*37f3d50eSSasha Levin int event; 35*37f3d50eSSasha Levin 36*37f3d50eSSasha Levin new_ioevent = malloc(sizeof(*new_ioevent)); 37*37f3d50eSSasha Levin if (new_ioevent == NULL) 38*37f3d50eSSasha Levin die("Failed allocating memory for new ioevent"); 39*37f3d50eSSasha Levin 40*37f3d50eSSasha Levin *new_ioevent = *ioevent; 41*37f3d50eSSasha Levin event = new_ioevent->fd; 42*37f3d50eSSasha Levin 43*37f3d50eSSasha Levin kvm_ioevent = (struct kvm_ioeventfd) { 44*37f3d50eSSasha Levin .addr = ioevent->io_addr, 45*37f3d50eSSasha Levin .len = ioevent->io_len, 46*37f3d50eSSasha Levin .datamatch = ioevent->datamatch, 47*37f3d50eSSasha Levin .fd = event, 48*37f3d50eSSasha Levin .flags = KVM_IOEVENTFD_FLAG_PIO | KVM_IOEVENTFD_FLAG_DATAMATCH, 49*37f3d50eSSasha Levin }; 50*37f3d50eSSasha Levin 51*37f3d50eSSasha Levin if (ioctl(ioevent->fn_kvm->vm_fd, KVM_IOEVENTFD, &kvm_ioevent) != 0) 52*37f3d50eSSasha Levin die("Failed creating new ioeventfd"); 53*37f3d50eSSasha Levin 54*37f3d50eSSasha Levin epoll_event = (struct epoll_event) { 55*37f3d50eSSasha Levin .events = EPOLLIN, 56*37f3d50eSSasha Levin .data.ptr = new_ioevent, 57*37f3d50eSSasha Levin }; 58*37f3d50eSSasha Levin 59*37f3d50eSSasha Levin if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, event, &epoll_event) != 0) 60*37f3d50eSSasha Levin die("Failed assigning new event to the epoll fd"); 61*37f3d50eSSasha Levin 62*37f3d50eSSasha Levin list_add_tail(&new_ioevent->list, &used_ioevents); 63*37f3d50eSSasha Levin } 64*37f3d50eSSasha Levin 65*37f3d50eSSasha Levin void ioeventfd__del_event(u64 addr, u64 datamatch) 66*37f3d50eSSasha Levin { 67*37f3d50eSSasha Levin struct kvm_ioeventfd kvm_ioevent; 68*37f3d50eSSasha Levin struct ioevent *ioevent; 69*37f3d50eSSasha Levin u8 found = 0; 70*37f3d50eSSasha Levin 71*37f3d50eSSasha Levin list_for_each_entry(ioevent, &used_ioevents, list) { 72*37f3d50eSSasha Levin if (ioevent->io_addr == addr) { 73*37f3d50eSSasha Levin found = 1; 74*37f3d50eSSasha Levin break; 75*37f3d50eSSasha Levin } 76*37f3d50eSSasha Levin } 77*37f3d50eSSasha Levin 78*37f3d50eSSasha Levin if (found == 0 || ioevent == NULL) 79*37f3d50eSSasha Levin return; 80*37f3d50eSSasha Levin 81*37f3d50eSSasha Levin kvm_ioevent = (struct kvm_ioeventfd) { 82*37f3d50eSSasha Levin .addr = ioevent->io_addr, 83*37f3d50eSSasha Levin .len = ioevent->io_len, 84*37f3d50eSSasha Levin .datamatch = ioevent->datamatch, 85*37f3d50eSSasha Levin .flags = KVM_IOEVENTFD_FLAG_PIO 86*37f3d50eSSasha Levin | KVM_IOEVENTFD_FLAG_DEASSIGN 87*37f3d50eSSasha Levin | KVM_IOEVENTFD_FLAG_DATAMATCH, 88*37f3d50eSSasha Levin }; 89*37f3d50eSSasha Levin 90*37f3d50eSSasha Levin ioctl(ioevent->fn_kvm->vm_fd, KVM_IOEVENTFD, &kvm_ioevent); 91*37f3d50eSSasha Levin 92*37f3d50eSSasha Levin epoll_ctl(epoll_fd, EPOLL_CTL_DEL, ioevent->fd, NULL); 93*37f3d50eSSasha Levin 94*37f3d50eSSasha Levin list_del(&ioevent->list); 95*37f3d50eSSasha Levin 96*37f3d50eSSasha Levin close(ioevent->fd); 97*37f3d50eSSasha Levin free(ioevent); 98*37f3d50eSSasha Levin } 99*37f3d50eSSasha Levin 100*37f3d50eSSasha Levin static void *ioeventfd__thread(void *param) 101*37f3d50eSSasha Levin { 102*37f3d50eSSasha Levin for (;;) { 103*37f3d50eSSasha Levin int nfds, i; 104*37f3d50eSSasha Levin 105*37f3d50eSSasha Levin nfds = epoll_wait(epoll_fd, events, IOEVENTFD_MAX_EVENTS, -1); 106*37f3d50eSSasha Levin for (i = 0; i < nfds; i++) { 107*37f3d50eSSasha Levin u64 tmp; 108*37f3d50eSSasha Levin struct ioevent *ioevent; 109*37f3d50eSSasha Levin 110*37f3d50eSSasha Levin ioevent = events[i].data.ptr; 111*37f3d50eSSasha Levin 112*37f3d50eSSasha Levin if (read(ioevent->fd, &tmp, sizeof(tmp)) < 0) 113*37f3d50eSSasha Levin die("Failed reading event"); 114*37f3d50eSSasha Levin 115*37f3d50eSSasha Levin ioevent->fn(ioevent->fn_kvm, ioevent->fn_ptr); 116*37f3d50eSSasha Levin } 117*37f3d50eSSasha Levin } 118*37f3d50eSSasha Levin 119*37f3d50eSSasha Levin return NULL; 120*37f3d50eSSasha Levin } 121*37f3d50eSSasha Levin 122*37f3d50eSSasha Levin void ioeventfd__start(void) 123*37f3d50eSSasha Levin { 124*37f3d50eSSasha Levin pthread_t thread; 125*37f3d50eSSasha Levin 126*37f3d50eSSasha Levin if (pthread_create(&thread, NULL, ioeventfd__thread, NULL) != 0) 127*37f3d50eSSasha Levin die("Failed starting ioeventfd thread"); 128*37f3d50eSSasha Levin } 129