xref: /kvmtool/ioeventfd.c (revision 37f3d50e6a7a78471e344e12411533eea1596fa2)
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