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