xref: /illumos-kvm-cmd/hw/xen_backend.c (revision 68396ea9)
1 /*
2  *  xen backend driver infrastructure
3  *  (c) 2008 Gerd Hoffmann <kraxel@redhat.com>
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; under version 2 of the License.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License along
15  *  with this program; if not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /*
19  * TODO: add some xenbus / xenstore concepts overview here.
20  */
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <inttypes.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/mman.h>
32 #include <sys/signal.h>
33 
34 #include <xs.h>
35 #include <xenctrl.h>
36 #include <xen/grant_table.h>
37 
38 #include "hw.h"
39 #include "qemu-char.h"
40 #include "qemu-log.h"
41 #include "xen_backend.h"
42 
43 /* ------------------------------------------------------------- */
44 
45 /* public */
46 int xen_xc;
47 struct xs_handle *xenstore = NULL;
48 const char *xen_protocol;
49 
50 /* private */
51 static QTAILQ_HEAD(XenDeviceHead, XenDevice) xendevs = QTAILQ_HEAD_INITIALIZER(xendevs);
52 static int debug = 0;
53 
54 /* ------------------------------------------------------------- */
55 
xenstore_write_str(const char * base,const char * node,const char * val)56 int xenstore_write_str(const char *base, const char *node, const char *val)
57 {
58     char abspath[XEN_BUFSIZE];
59 
60     snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
61     if (!xs_write(xenstore, 0, abspath, val, strlen(val)))
62 	return -1;
63     return 0;
64 }
65 
xenstore_read_str(const char * base,const char * node)66 char *xenstore_read_str(const char *base, const char *node)
67 {
68     char abspath[XEN_BUFSIZE];
69     unsigned int len;
70     char *str, *ret = NULL;
71 
72     snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
73     str = xs_read(xenstore, 0, abspath, &len);
74     if (str != NULL) {
75         /* move to qemu-allocated memory to make sure
76          * callers can savely qemu_free() stuff. */
77         ret = qemu_strdup(str);
78         free(str);
79     }
80     return ret;
81 }
82 
xenstore_write_int(const char * base,const char * node,int ival)83 int xenstore_write_int(const char *base, const char *node, int ival)
84 {
85     char val[32];
86 
87     snprintf(val, sizeof(val), "%d", ival);
88     return xenstore_write_str(base, node, val);
89 }
90 
xenstore_read_int(const char * base,const char * node,int * ival)91 int xenstore_read_int(const char *base, const char *node, int *ival)
92 {
93     char *val;
94     int rc = -1;
95 
96     val = xenstore_read_str(base, node);
97     if (val && 1 == sscanf(val, "%d", ival))
98 	rc = 0;
99     qemu_free(val);
100     return rc;
101 }
102 
xenstore_write_be_str(struct XenDevice * xendev,const char * node,const char * val)103 int xenstore_write_be_str(struct XenDevice *xendev, const char *node, const char *val)
104 {
105     return xenstore_write_str(xendev->be, node, val);
106 }
107 
xenstore_write_be_int(struct XenDevice * xendev,const char * node,int ival)108 int xenstore_write_be_int(struct XenDevice *xendev, const char *node, int ival)
109 {
110     return xenstore_write_int(xendev->be, node, ival);
111 }
112 
xenstore_read_be_str(struct XenDevice * xendev,const char * node)113 char *xenstore_read_be_str(struct XenDevice *xendev, const char *node)
114 {
115     return xenstore_read_str(xendev->be, node);
116 }
117 
xenstore_read_be_int(struct XenDevice * xendev,const char * node,int * ival)118 int xenstore_read_be_int(struct XenDevice *xendev, const char *node, int *ival)
119 {
120     return xenstore_read_int(xendev->be, node, ival);
121 }
122 
xenstore_read_fe_str(struct XenDevice * xendev,const char * node)123 char *xenstore_read_fe_str(struct XenDevice *xendev, const char *node)
124 {
125     return xenstore_read_str(xendev->fe, node);
126 }
127 
xenstore_read_fe_int(struct XenDevice * xendev,const char * node,int * ival)128 int xenstore_read_fe_int(struct XenDevice *xendev, const char *node, int *ival)
129 {
130     return xenstore_read_int(xendev->fe, node, ival);
131 }
132 
133 /* ------------------------------------------------------------- */
134 
xenbus_strstate(enum xenbus_state state)135 const char *xenbus_strstate(enum xenbus_state state)
136 {
137 	static const char *const name[] = {
138 		[ XenbusStateUnknown      ] = "Unknown",
139 		[ XenbusStateInitialising ] = "Initialising",
140 		[ XenbusStateInitWait     ] = "InitWait",
141 		[ XenbusStateInitialised  ] = "Initialised",
142 		[ XenbusStateConnected    ] = "Connected",
143 		[ XenbusStateClosing      ] = "Closing",
144 		[ XenbusStateClosed	  ] = "Closed",
145 	};
146 	return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
147 }
148 
xen_be_set_state(struct XenDevice * xendev,enum xenbus_state state)149 int xen_be_set_state(struct XenDevice *xendev, enum xenbus_state state)
150 {
151     int rc;
152 
153     rc = xenstore_write_be_int(xendev, "state", state);
154     if (rc < 0)
155 	return rc;
156     xen_be_printf(xendev, 1, "backend state: %s -> %s\n",
157 		  xenbus_strstate(xendev->be_state), xenbus_strstate(state));
158     xendev->be_state = state;
159     return 0;
160 }
161 
162 /* ------------------------------------------------------------- */
163 
xen_be_find_xendev(const char * type,int dom,int dev)164 struct XenDevice *xen_be_find_xendev(const char *type, int dom, int dev)
165 {
166     struct XenDevice *xendev;
167 
168     QTAILQ_FOREACH(xendev, &xendevs, next) {
169 	if (xendev->dom != dom)
170 	    continue;
171 	if (xendev->dev != dev)
172 	    continue;
173 	if (strcmp(xendev->type, type) != 0)
174 	    continue;
175 	return xendev;
176     }
177     return NULL;
178 }
179 
180 /*
181  * get xen backend device, allocate a new one if it doesn't exist.
182  */
xen_be_get_xendev(const char * type,int dom,int dev,struct XenDevOps * ops)183 static struct XenDevice *xen_be_get_xendev(const char *type, int dom, int dev,
184                                            struct XenDevOps *ops)
185 {
186     struct XenDevice *xendev;
187     char *dom0;
188 
189     xendev = xen_be_find_xendev(type, dom, dev);
190     if (xendev)
191 	return xendev;
192 
193     /* init new xendev */
194     xendev = qemu_mallocz(ops->size);
195     xendev->type  = type;
196     xendev->dom   = dom;
197     xendev->dev   = dev;
198     xendev->ops   = ops;
199 
200     dom0 = xs_get_domain_path(xenstore, 0);
201     snprintf(xendev->be, sizeof(xendev->be), "%s/backend/%s/%d/%d",
202 	     dom0, xendev->type, xendev->dom, xendev->dev);
203     snprintf(xendev->name, sizeof(xendev->name), "%s-%d",
204 	     xendev->type, xendev->dev);
205     free(dom0);
206 
207     xendev->debug      = debug;
208     xendev->local_port = -1;
209 
210     xendev->evtchndev = xc_evtchn_open();
211     if (xendev->evtchndev < 0) {
212 	xen_be_printf(NULL, 0, "can't open evtchn device\n");
213 	qemu_free(xendev);
214 	return NULL;
215     }
216     fcntl(xc_evtchn_fd(xendev->evtchndev), F_SETFD, FD_CLOEXEC);
217 
218     if (ops->flags & DEVOPS_FLAG_NEED_GNTDEV) {
219 	xendev->gnttabdev = xc_gnttab_open();
220 	if (xendev->gnttabdev < 0) {
221 	    xen_be_printf(NULL, 0, "can't open gnttab device\n");
222 	    xc_evtchn_close(xendev->evtchndev);
223 	    qemu_free(xendev);
224 	    return NULL;
225 	}
226     } else {
227 	xendev->gnttabdev = -1;
228     }
229 
230     QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
231 
232     if (xendev->ops->alloc)
233 	xendev->ops->alloc(xendev);
234 
235     return xendev;
236 }
237 
238 /*
239  * release xen backend device.
240  */
xen_be_del_xendev(int dom,int dev)241 static struct XenDevice *xen_be_del_xendev(int dom, int dev)
242 {
243     struct XenDevice *xendev, *xnext;
244 
245     /*
246      * This is pretty much like QTAILQ_FOREACH(xendev, &xendevs, next) but
247      * we save the next pointer in xnext because we might free xendev.
248      */
249     xnext = xendevs.tqh_first;
250     while (xnext) {
251         xendev = xnext;
252         xnext = xendev->next.tqe_next;
253 
254 	if (xendev->dom != dom)
255 	    continue;
256 	if (xendev->dev != dev && dev != -1)
257 	    continue;
258 
259 	if (xendev->ops->free)
260 	    xendev->ops->free(xendev);
261 
262 	if (xendev->fe) {
263 	    char token[XEN_BUFSIZE];
264 	    snprintf(token, sizeof(token), "fe:%p", xendev);
265 	    xs_unwatch(xenstore, xendev->fe, token);
266 	    qemu_free(xendev->fe);
267 	}
268 
269 	if (xendev->evtchndev >= 0)
270 	    xc_evtchn_close(xendev->evtchndev);
271 	if (xendev->gnttabdev >= 0)
272 	    xc_gnttab_close(xendev->gnttabdev);
273 
274 	QTAILQ_REMOVE(&xendevs, xendev, next);
275 	qemu_free(xendev);
276     }
277     return NULL;
278 }
279 
280 /*
281  * Sync internal data structures on xenstore updates.
282  * Node specifies the changed field.  node = NULL means
283  * update all fields (used for initialization).
284  */
xen_be_backend_changed(struct XenDevice * xendev,const char * node)285 static void xen_be_backend_changed(struct XenDevice *xendev, const char *node)
286 {
287     if (node == NULL  ||  strcmp(node, "online") == 0) {
288 	if (xenstore_read_be_int(xendev, "online", &xendev->online) == -1)
289 	    xendev->online = 0;
290     }
291 
292     if (node) {
293 	xen_be_printf(xendev, 2, "backend update: %s\n", node);
294 	if (xendev->ops->backend_changed)
295 	    xendev->ops->backend_changed(xendev, node);
296     }
297 }
298 
xen_be_frontend_changed(struct XenDevice * xendev,const char * node)299 static void xen_be_frontend_changed(struct XenDevice *xendev, const char *node)
300 {
301     int fe_state;
302 
303     if (node == NULL  ||  strcmp(node, "state") == 0) {
304 	if (xenstore_read_fe_int(xendev, "state", &fe_state) == -1)
305 	    fe_state = XenbusStateUnknown;
306 	if (xendev->fe_state != fe_state)
307 	    xen_be_printf(xendev, 1, "frontend state: %s -> %s\n",
308 			  xenbus_strstate(xendev->fe_state),
309 			  xenbus_strstate(fe_state));
310 	xendev->fe_state = fe_state;
311     }
312     if (node == NULL  ||  strcmp(node, "protocol") == 0) {
313 	qemu_free(xendev->protocol);
314 	xendev->protocol = xenstore_read_fe_str(xendev, "protocol");
315 	if (xendev->protocol)
316 	    xen_be_printf(xendev, 1, "frontend protocol: %s\n", xendev->protocol);
317     }
318 
319     if (node) {
320 	xen_be_printf(xendev, 2, "frontend update: %s\n", node);
321 	if (xendev->ops->frontend_changed)
322 	    xendev->ops->frontend_changed(xendev, node);
323     }
324 }
325 
326 /* ------------------------------------------------------------- */
327 /* Check for possible state transitions and perform them.        */
328 
329 /*
330  * Initial xendev setup.  Read frontend path, register watch for it.
331  * Should succeed once xend finished setting up the backend device.
332  *
333  * Also sets initial state (-> Initializing) when done.  Which
334  * only affects the xendev->be_state variable as xenbus should
335  * already be put into that state by xend.
336  */
xen_be_try_setup(struct XenDevice * xendev)337 static int xen_be_try_setup(struct XenDevice *xendev)
338 {
339     char token[XEN_BUFSIZE];
340     int be_state;
341 
342     if (xenstore_read_be_int(xendev, "state", &be_state) == -1) {
343 	xen_be_printf(xendev, 0, "reading backend state failed\n");
344 	return -1;
345     }
346 
347     if (be_state != XenbusStateInitialising) {
348 	xen_be_printf(xendev, 0, "initial backend state is wrong (%s)\n",
349 		      xenbus_strstate(be_state));
350 	return -1;
351     }
352 
353     xendev->fe = xenstore_read_be_str(xendev, "frontend");
354     if (xendev->fe == NULL) {
355 	xen_be_printf(xendev, 0, "reading frontend path failed\n");
356 	return -1;
357     }
358 
359     /* setup frontend watch */
360     snprintf(token, sizeof(token), "fe:%p", xendev);
361     if (!xs_watch(xenstore, xendev->fe, token)) {
362 	xen_be_printf(xendev, 0, "watching frontend path (%s) failed\n",
363 		      xendev->fe);
364 	return -1;
365     }
366     xen_be_set_state(xendev, XenbusStateInitialising);
367 
368     xen_be_backend_changed(xendev, NULL);
369     xen_be_frontend_changed(xendev, NULL);
370     return 0;
371 }
372 
373 /*
374  * Try initialize xendev.  Prepare everything the backend can do
375  * without synchronizing with the frontend.  Fakes hotplug-status.  No
376  * hotplug involved here because this is about userspace drivers, thus
377  * there are kernel backend devices which could invoke hotplug.
378  *
379  * Goes to InitWait on success.
380  */
xen_be_try_init(struct XenDevice * xendev)381 static int xen_be_try_init(struct XenDevice *xendev)
382 {
383     int rc = 0;
384 
385     if (!xendev->online) {
386 	xen_be_printf(xendev, 1, "not online\n");
387 	return -1;
388     }
389 
390     if (xendev->ops->init)
391 	rc = xendev->ops->init(xendev);
392     if (rc != 0) {
393 	xen_be_printf(xendev, 1, "init() failed\n");
394 	return rc;
395     }
396 
397     xenstore_write_be_str(xendev, "hotplug-status", "connected");
398     xen_be_set_state(xendev, XenbusStateInitWait);
399     return 0;
400 }
401 
402 /*
403  * Try to connect xendev.  Depends on the frontend being ready
404  * for it (shared ring and evtchn info in xenstore, state being
405  * Initialised or Connected).
406  *
407  * Goes to Connected on success.
408  */
xen_be_try_connect(struct XenDevice * xendev)409 static int xen_be_try_connect(struct XenDevice *xendev)
410 {
411     int rc = 0;
412 
413     if (xendev->fe_state != XenbusStateInitialised  &&
414 	xendev->fe_state != XenbusStateConnected) {
415 	if (xendev->ops->flags & DEVOPS_FLAG_IGNORE_STATE) {
416 	    xen_be_printf(xendev, 2, "frontend not ready, ignoring\n");
417 	} else {
418 	    xen_be_printf(xendev, 2, "frontend not ready (yet)\n");
419 	    return -1;
420 	}
421     }
422 
423     if (xendev->ops->connect)
424 	rc = xendev->ops->connect(xendev);
425     if (rc != 0) {
426 	xen_be_printf(xendev, 0, "connect() failed\n");
427 	return rc;
428     }
429 
430     xen_be_set_state(xendev, XenbusStateConnected);
431     return 0;
432 }
433 
434 /*
435  * Teardown connection.
436  *
437  * Goes to Closed when done.
438  */
xen_be_disconnect(struct XenDevice * xendev,enum xenbus_state state)439 static void xen_be_disconnect(struct XenDevice *xendev, enum xenbus_state state)
440 {
441     if (xendev->be_state != XenbusStateClosing &&
442         xendev->be_state != XenbusStateClosed  &&
443         xendev->ops->disconnect)
444 	xendev->ops->disconnect(xendev);
445     if (xendev->be_state != state)
446         xen_be_set_state(xendev, state);
447 }
448 
449 /*
450  * Try to reset xendev, for reconnection by another frontend instance.
451  */
xen_be_try_reset(struct XenDevice * xendev)452 static int xen_be_try_reset(struct XenDevice *xendev)
453 {
454     if (xendev->fe_state != XenbusStateInitialising)
455         return -1;
456 
457     xen_be_printf(xendev, 1, "device reset (for re-connect)\n");
458     xen_be_set_state(xendev, XenbusStateInitialising);
459     return 0;
460 }
461 
462 /*
463  * state change dispatcher function
464  */
xen_be_check_state(struct XenDevice * xendev)465 void xen_be_check_state(struct XenDevice *xendev)
466 {
467     int rc = 0;
468 
469     /* frontend may request shutdown from almost anywhere */
470     if (xendev->fe_state == XenbusStateClosing ||
471 	xendev->fe_state == XenbusStateClosed) {
472 	xen_be_disconnect(xendev, xendev->fe_state);
473 	return;
474     }
475 
476     /* check for possible backend state transitions */
477     for (;;) {
478 	switch (xendev->be_state) {
479 	case XenbusStateUnknown:
480 	    rc = xen_be_try_setup(xendev);
481 	    break;
482 	case XenbusStateInitialising:
483 	    rc = xen_be_try_init(xendev);
484 	    break;
485 	case XenbusStateInitWait:
486 	    rc = xen_be_try_connect(xendev);
487 	    break;
488         case XenbusStateClosed:
489             rc = xen_be_try_reset(xendev);
490             break;
491 	default:
492 	    rc = -1;
493 	}
494 	if (rc != 0)
495 	    break;
496     }
497 }
498 
499 /* ------------------------------------------------------------- */
500 
xenstore_scan(const char * type,int dom,struct XenDevOps * ops)501 static int xenstore_scan(const char *type, int dom, struct XenDevOps *ops)
502 {
503     struct XenDevice *xendev;
504     char path[XEN_BUFSIZE], token[XEN_BUFSIZE];
505     char **dev = NULL, *dom0;
506     unsigned int cdev, j;
507 
508     /* setup watch */
509     dom0 = xs_get_domain_path(xenstore, 0);
510     snprintf(token, sizeof(token), "be:%p:%d:%p", type, dom, ops);
511     snprintf(path, sizeof(path), "%s/backend/%s/%d", dom0, type, dom);
512     free(dom0);
513     if (!xs_watch(xenstore, path, token)) {
514 	xen_be_printf(NULL, 0, "xen be: watching backend path (%s) failed\n", path);
515 	return -1;
516     }
517 
518     /* look for backends */
519     dev = xs_directory(xenstore, 0, path, &cdev);
520     if (!dev)
521 	return 0;
522     for (j = 0; j < cdev; j++) {
523 	xendev = xen_be_get_xendev(type, dom, atoi(dev[j]), ops);
524 	if (xendev == NULL)
525 	    continue;
526 	xen_be_check_state(xendev);
527     }
528     free(dev);
529     return 0;
530 }
531 
xenstore_update_be(char * watch,char * type,int dom,struct XenDevOps * ops)532 static void xenstore_update_be(char *watch, char *type, int dom,
533 			       struct XenDevOps *ops)
534 {
535     struct XenDevice *xendev;
536     char path[XEN_BUFSIZE], *dom0;
537     unsigned int len, dev;
538 
539     dom0 = xs_get_domain_path(xenstore, 0);
540     len = snprintf(path, sizeof(path), "%s/backend/%s/%d", dom0, type, dom);
541     free(dom0);
542     if (strncmp(path, watch, len) != 0)
543 	return;
544     if (sscanf(watch+len, "/%u/%255s", &dev, path) != 2) {
545 	strcpy(path, "");
546 	if (sscanf(watch+len, "/%u", &dev) != 1)
547 	    dev = -1;
548     }
549     if (dev == -1)
550 	return;
551 
552     if (0) {
553 	/* FIXME: detect devices being deleted from xenstore ... */
554 	xen_be_del_xendev(dom, dev);
555     }
556 
557     xendev = xen_be_get_xendev(type, dom, dev, ops);
558     if (xendev != NULL) {
559 	xen_be_backend_changed(xendev, path);
560 	xen_be_check_state(xendev);
561     }
562 }
563 
xenstore_update_fe(char * watch,struct XenDevice * xendev)564 static void xenstore_update_fe(char *watch, struct XenDevice *xendev)
565 {
566     char *node;
567     unsigned int len;
568 
569     len = strlen(xendev->fe);
570     if (strncmp(xendev->fe, watch, len) != 0)
571 	return;
572     if (watch[len] != '/')
573 	return;
574     node = watch + len + 1;
575 
576     xen_be_frontend_changed(xendev, node);
577     xen_be_check_state(xendev);
578 }
579 
xenstore_update(void * unused)580 static void xenstore_update(void *unused)
581 {
582     char **vec = NULL;
583     intptr_t type, ops, ptr;
584     unsigned int dom, count;
585 
586     vec = xs_read_watch(xenstore, &count);
587     if (vec == NULL)
588 	goto cleanup;
589 
590     if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
591                &type, &dom, &ops) == 3)
592 	xenstore_update_be(vec[XS_WATCH_PATH], (void*)type, dom, (void*)ops);
593     if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1)
594 	xenstore_update_fe(vec[XS_WATCH_PATH], (void*)ptr);
595 
596 cleanup:
597     free(vec);
598 }
599 
xen_be_evtchn_event(void * opaque)600 static void xen_be_evtchn_event(void *opaque)
601 {
602     struct XenDevice *xendev = opaque;
603     evtchn_port_t port;
604 
605     port = xc_evtchn_pending(xendev->evtchndev);
606     if (port != xendev->local_port) {
607 	xen_be_printf(xendev, 0, "xc_evtchn_pending returned %d (expected %d)\n",
608 		      port, xendev->local_port);
609 	return;
610     }
611     xc_evtchn_unmask(xendev->evtchndev, port);
612 
613     if (xendev->ops->event)
614 	xendev->ops->event(xendev);
615 }
616 
617 /* -------------------------------------------------------------------- */
618 
xen_be_init(void)619 int xen_be_init(void)
620 {
621     xenstore = xs_daemon_open();
622     if (!xenstore) {
623 	xen_be_printf(NULL, 0, "can't connect to xenstored\n");
624 	return -1;
625     }
626 
627     if (qemu_set_fd_handler(xs_fileno(xenstore), xenstore_update, NULL, NULL) < 0)
628 	goto err;
629 
630     xen_xc = xc_interface_open();
631     if (xen_xc == -1) {
632 	xen_be_printf(NULL, 0, "can't open xen interface\n");
633 	goto err;
634     }
635     return 0;
636 
637 err:
638     qemu_set_fd_handler(xs_fileno(xenstore), NULL, NULL, NULL);
639     xs_daemon_close(xenstore);
640     xenstore = NULL;
641 
642     return -1;
643 }
644 
xen_be_register(const char * type,struct XenDevOps * ops)645 int xen_be_register(const char *type, struct XenDevOps *ops)
646 {
647     return xenstore_scan(type, xen_domid, ops);
648 }
649 
xen_be_bind_evtchn(struct XenDevice * xendev)650 int xen_be_bind_evtchn(struct XenDevice *xendev)
651 {
652     if (xendev->local_port != -1)
653 	return 0;
654     xendev->local_port = xc_evtchn_bind_interdomain
655 	(xendev->evtchndev, xendev->dom, xendev->remote_port);
656     if (xendev->local_port == -1) {
657 	xen_be_printf(xendev, 0, "xc_evtchn_bind_interdomain failed\n");
658 	return -1;
659     }
660     xen_be_printf(xendev, 2, "bind evtchn port %d\n", xendev->local_port);
661     qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev),
662 			xen_be_evtchn_event, NULL, xendev);
663     return 0;
664 }
665 
xen_be_unbind_evtchn(struct XenDevice * xendev)666 void xen_be_unbind_evtchn(struct XenDevice *xendev)
667 {
668     if (xendev->local_port == -1)
669 	return;
670     qemu_set_fd_handler(xc_evtchn_fd(xendev->evtchndev), NULL, NULL, NULL);
671     xc_evtchn_unbind(xendev->evtchndev, xendev->local_port);
672     xen_be_printf(xendev, 2, "unbind evtchn port %d\n", xendev->local_port);
673     xendev->local_port = -1;
674 }
675 
xen_be_send_notify(struct XenDevice * xendev)676 int xen_be_send_notify(struct XenDevice *xendev)
677 {
678     return xc_evtchn_notify(xendev->evtchndev, xendev->local_port);
679 }
680 
681 /*
682  * msg_level:
683  *  0 == errors (stderr + logfile).
684  *  1 == informative debug messages (logfile only).
685  *  2 == noisy debug messages (logfile only).
686  *  3 == will flood your log (logfile only).
687  */
xen_be_printf(struct XenDevice * xendev,int msg_level,const char * fmt,...)688 void xen_be_printf(struct XenDevice *xendev, int msg_level, const char *fmt, ...)
689 {
690     va_list args;
691 
692     if (xendev) {
693         if (msg_level > xendev->debug)
694             return;
695         qemu_log("xen be: %s: ", xendev->name);
696         if (msg_level == 0)
697             fprintf(stderr, "xen be: %s: ", xendev->name);
698     } else {
699         if (msg_level > debug)
700             return;
701         qemu_log("xen be core: ");
702         if (msg_level == 0)
703             fprintf(stderr, "xen be core: ");
704     }
705     va_start(args, fmt);
706     qemu_log_vprintf(fmt, args);
707     va_end(args);
708     if (msg_level == 0) {
709         va_start(args, fmt);
710         vfprintf(stderr, fmt, args);
711         va_end(args);
712     }
713     qemu_log_flush();
714 }
715