1 /******************************************************************************
2 *
3 * Copyright 2007-2008 Samuel Thibault <samuel.thibault@eu.citrix.com>.
4 * All rights reserved.
5 * Use is subject to license terms.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation;
10 * version 2.1 of the License.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; If not, see <http://www.gnu.org/licenses/>.
19 *
20 * Split off from xc_minios.c
21 */
22
23 #include "xen-external/bsd-sys-queue.h"
24 #include <mini-os/types.h>
25 #include <mini-os/os.h>
26 #include <mini-os/lib.h>
27 #include <mini-os/events.h>
28 #include <mini-os/wait.h>
29
30 #include <assert.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdio.h>
34 #include <stdint.h>
35 #include <unistd.h>
36 #include <inttypes.h>
37 #include <malloc.h>
38
39 #include "private.h"
40
41 extern void minios_evtchn_close_fd(int fd);
42
43 extern struct wait_queue_head event_queue;
44
45 /* XXX Note: This is not threadsafe */
port_alloc(int fd)46 static struct evtchn_port_info* port_alloc(int fd) {
47 struct evtchn_port_info *port_info;
48 port_info = malloc(sizeof(struct evtchn_port_info));
49 if (port_info == NULL)
50 return NULL;
51 port_info->pending = 0;
52 port_info->port = -1;
53 port_info->bound = 0;
54
55 LIST_INSERT_HEAD(&files[fd].evtchn.ports, port_info, list);
56 return port_info;
57 }
58
port_dealloc(struct evtchn_port_info * port_info)59 static void port_dealloc(struct evtchn_port_info *port_info) {
60 if (port_info->bound)
61 unbind_evtchn(port_info->port);
62 LIST_REMOVE(port_info, list);
63 free(port_info);
64 }
65
osdep_evtchn_open(xenevtchn_handle * xce)66 int osdep_evtchn_open(xenevtchn_handle *xce)
67 {
68 int fd = alloc_fd(FTYPE_EVTCHN);
69 if ( fd == -1 )
70 return -1;
71 LIST_INIT(&files[fd].evtchn.ports);
72 xce->fd = fd;
73 printf("evtchn_open() -> %d\n", fd);
74 return 0;
75 }
76
osdep_evtchn_close(xenevtchn_handle * xce)77 int osdep_evtchn_close(xenevtchn_handle *xce)
78 {
79 if ( xce->fd == -1 )
80 return 0;
81
82 return close(xce->fd);
83 }
84
osdep_evtchn_restrict(xenevtchn_handle * xce,domid_t domid)85 int osdep_evtchn_restrict(xenevtchn_handle *xce, domid_t domid)
86 {
87 errno = -EOPNOTSUPP;
88 return -1;
89 }
90
minios_evtchn_close_fd(int fd)91 void minios_evtchn_close_fd(int fd)
92 {
93 struct evtchn_port_info *port_info, *tmp;
94 LIST_FOREACH_SAFE(port_info, &files[fd].evtchn.ports, list, tmp)
95 port_dealloc(port_info);
96
97 files[fd].type = FTYPE_NONE;
98 }
99
xenevtchn_fd(xenevtchn_handle * xce)100 int xenevtchn_fd(xenevtchn_handle *xce)
101 {
102 return xce->fd;
103 }
104
xenevtchn_notify(xenevtchn_handle * xce,evtchn_port_t port)105 int xenevtchn_notify(xenevtchn_handle *xce, evtchn_port_t port)
106 {
107 int ret;
108
109 ret = notify_remote_via_evtchn(port);
110
111 if (ret < 0) {
112 errno = -ret;
113 ret = -1;
114 }
115 return ret;
116 }
117
evtchn_handler(evtchn_port_t port,struct pt_regs * regs,void * data)118 static void evtchn_handler(evtchn_port_t port, struct pt_regs *regs, void *data)
119 {
120 int fd = (int)(intptr_t)data;
121 struct evtchn_port_info *port_info;
122 assert(files[fd].type == FTYPE_EVTCHN);
123 mask_evtchn(port);
124 LIST_FOREACH(port_info, &files[fd].evtchn.ports, list) {
125 if (port_info->port == port)
126 goto found;
127 }
128 printk("Unknown port for handle %d\n", fd);
129 return;
130
131 found:
132 port_info->pending = 1;
133 files[fd].read = 1;
134 wake_up(&event_queue);
135 }
136
xenevtchn_bind_unbound_port(xenevtchn_handle * xce,uint32_t domid)137 xenevtchn_port_or_error_t xenevtchn_bind_unbound_port(xenevtchn_handle *xce, uint32_t domid)
138 {
139 int fd = xce->fd;
140 struct evtchn_port_info *port_info;
141 int ret;
142 evtchn_port_t port;
143
144 assert(get_current() == main_thread);
145 port_info = port_alloc(fd);
146 if (port_info == NULL)
147 return -1;
148
149 printf("xenevtchn_bind_unbound_port(%d)", domid);
150 ret = evtchn_alloc_unbound(domid, evtchn_handler, (void*)(intptr_t)fd, &port);
151 printf(" = %d\n", ret);
152
153 if (ret < 0) {
154 port_dealloc(port_info);
155 errno = -ret;
156 return -1;
157 }
158 port_info->bound = 1;
159 port_info->port = port;
160 unmask_evtchn(port);
161 return port;
162 }
163
xenevtchn_bind_interdomain(xenevtchn_handle * xce,uint32_t domid,evtchn_port_t remote_port)164 xenevtchn_port_or_error_t xenevtchn_bind_interdomain(xenevtchn_handle *xce, uint32_t domid,
165 evtchn_port_t remote_port)
166 {
167 int fd = xce->fd;
168 struct evtchn_port_info *port_info;
169 evtchn_port_t local_port;
170 int ret;
171
172 assert(get_current() == main_thread);
173 port_info = port_alloc(fd);
174 if (port_info == NULL)
175 return -1;
176
177 printf("xenevtchn_bind_interdomain(%d, %"PRId32")", domid, remote_port);
178 ret = evtchn_bind_interdomain(domid, remote_port, evtchn_handler, (void*)(intptr_t)fd, &local_port);
179 printf(" = %d\n", ret);
180
181 if (ret < 0) {
182 port_dealloc(port_info);
183 errno = -ret;
184 return -1;
185 }
186 port_info->bound = 1;
187 port_info->port = local_port;
188 unmask_evtchn(local_port);
189 return local_port;
190 }
191
xenevtchn_unbind(xenevtchn_handle * xce,evtchn_port_t port)192 int xenevtchn_unbind(xenevtchn_handle *xce, evtchn_port_t port)
193 {
194 int fd = xce->fd;
195 struct evtchn_port_info *port_info;
196
197 LIST_FOREACH(port_info, &files[fd].evtchn.ports, list) {
198 if (port_info->port == port) {
199 port_dealloc(port_info);
200 return 0;
201 }
202 }
203 printf("Warning: couldn't find port %"PRId32" for xc handle %x\n", port, fd);
204 errno = EINVAL;
205 return -1;
206 }
207
xenevtchn_bind_virq(xenevtchn_handle * xce,unsigned int virq)208 xenevtchn_port_or_error_t xenevtchn_bind_virq(xenevtchn_handle *xce, unsigned int virq)
209 {
210 int fd = xce->fd;
211 struct evtchn_port_info *port_info;
212 evtchn_port_t port;
213
214 assert(get_current() == main_thread);
215 port_info = port_alloc(fd);
216 if (port_info == NULL)
217 return -1;
218
219 printf("xenevtchn_bind_virq(%d)", virq);
220 port = bind_virq(virq, evtchn_handler, (void*)(intptr_t)fd);
221 printf(" = %d\n", port);
222
223 if (port < 0) {
224 port_dealloc(port_info);
225 errno = -port;
226 return -1;
227 }
228 port_info->bound = 1;
229 port_info->port = port;
230 unmask_evtchn(port);
231 return port;
232 }
233
xenevtchn_pending(xenevtchn_handle * xce)234 xenevtchn_port_or_error_t xenevtchn_pending(xenevtchn_handle *xce)
235 {
236 int fd = xce->fd;
237 struct evtchn_port_info *port_info;
238 unsigned long flags;
239 evtchn_port_t ret = -1;
240
241 local_irq_save(flags);
242 files[fd].read = 0;
243
244 LIST_FOREACH(port_info, &files[fd].evtchn.ports, list) {
245 if (port_info->port != -1 && port_info->pending) {
246 if (ret == -1) {
247 ret = port_info->port;
248 port_info->pending = 0;
249 } else {
250 files[fd].read = 1;
251 break;
252 }
253 }
254 }
255 local_irq_restore(flags);
256 return ret;
257 }
258
xenevtchn_unmask(xenevtchn_handle * xce,evtchn_port_t port)259 int xenevtchn_unmask(xenevtchn_handle *xce, evtchn_port_t port)
260 {
261 unmask_evtchn(port);
262 return 0;
263 }
264
265 /*
266 * Local variables:
267 * mode: C
268 * c-file-style: "BSD"
269 * c-basic-offset: 4
270 * tab-width: 4
271 * indent-tabs-mode: nil
272 * End:
273 */
274