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