qemu/hw/xen/xen_pvdev.c
<<
>>
Prefs
   1/*
   2 * Xen para-virtualization device
   3 *
   4 *  (c) 2008 Gerd Hoffmann <kraxel@redhat.com>
   5 *
   6 * This library is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU Lesser General Public
   8 * License as published by the Free Software Foundation; either
   9 * version 2.1 of the License, or (at your option) any later version.
  10 *
  11 * This library is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14 * Lesser General Public License for more details.
  15 *
  16 * You should have received a copy of the GNU Lesser General Public
  17 * License along with this library; if not, see <http://www.gnu.org/licenses/>
  18 */
  19
  20#include "qemu/osdep.h"
  21#include "qemu/log.h"
  22#include "qemu/main-loop.h"
  23#include "hw/qdev-core.h"
  24#include "hw/xen/xen-legacy-backend.h"
  25#include "hw/xen/xen_pvdev.h"
  26
  27/* private */
  28static int debug;
  29
  30struct xs_dirs {
  31    char *xs_dir;
  32    QTAILQ_ENTRY(xs_dirs) list;
  33};
  34
  35static QTAILQ_HEAD(, xs_dirs) xs_cleanup =
  36    QTAILQ_HEAD_INITIALIZER(xs_cleanup);
  37
  38static QTAILQ_HEAD(, XenLegacyDevice) xendevs =
  39    QTAILQ_HEAD_INITIALIZER(xendevs);
  40
  41/* ------------------------------------------------------------- */
  42
  43static void xenstore_cleanup_dir(char *dir)
  44{
  45    struct xs_dirs *d;
  46
  47    d = g_malloc(sizeof(*d));
  48    d->xs_dir = dir;
  49    QTAILQ_INSERT_TAIL(&xs_cleanup, d, list);
  50}
  51
  52void xen_config_cleanup(void)
  53{
  54    struct xs_dirs *d;
  55
  56    QTAILQ_FOREACH(d, &xs_cleanup, list) {
  57        xs_rm(xenstore, 0, d->xs_dir);
  58    }
  59}
  60
  61int xenstore_mkdir(char *path, int p)
  62{
  63    struct xs_permissions perms[2] = {
  64        {
  65            .id    = 0, /* set owner: dom0 */
  66        }, {
  67            .id    = xen_domid,
  68            .perms = p,
  69        }
  70    };
  71
  72    if (!xs_mkdir(xenstore, 0, path)) {
  73        xen_pv_printf(NULL, 0, "xs_mkdir %s: failed\n", path);
  74        return -1;
  75    }
  76    xenstore_cleanup_dir(g_strdup(path));
  77
  78    if (!xs_set_permissions(xenstore, 0, path, perms, 2)) {
  79        xen_pv_printf(NULL, 0, "xs_set_permissions %s: failed\n", path);
  80        return -1;
  81    }
  82    return 0;
  83}
  84
  85int xenstore_write_str(const char *base, const char *node, const char *val)
  86{
  87    char abspath[XEN_BUFSIZE];
  88
  89    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
  90    if (!xs_write(xenstore, 0, abspath, val, strlen(val))) {
  91        return -1;
  92    }
  93    return 0;
  94}
  95
  96char *xenstore_read_str(const char *base, const char *node)
  97{
  98    char abspath[XEN_BUFSIZE];
  99    unsigned int len;
 100    char *str, *ret = NULL;
 101
 102    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
 103    str = xs_read(xenstore, 0, abspath, &len);
 104    if (str != NULL) {
 105        /* move to qemu-allocated memory to make sure
 106         * callers can savely g_free() stuff. */
 107        ret = g_strdup(str);
 108        free(str);
 109    }
 110    return ret;
 111}
 112
 113int xenstore_write_int(const char *base, const char *node, int ival)
 114{
 115    char val[12];
 116
 117    snprintf(val, sizeof(val), "%d", ival);
 118    return xenstore_write_str(base, node, val);
 119}
 120
 121int xenstore_write_int64(const char *base, const char *node, int64_t ival)
 122{
 123    char val[21];
 124
 125    snprintf(val, sizeof(val), "%"PRId64, ival);
 126    return xenstore_write_str(base, node, val);
 127}
 128
 129int xenstore_read_int(const char *base, const char *node, int *ival)
 130{
 131    char *val;
 132    int rc = -1;
 133
 134    val = xenstore_read_str(base, node);
 135    if (val && 1 == sscanf(val, "%d", ival)) {
 136        rc = 0;
 137    }
 138    g_free(val);
 139    return rc;
 140}
 141
 142int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval)
 143{
 144    char *val;
 145    int rc = -1;
 146
 147    val = xenstore_read_str(base, node);
 148    if (val && 1 == sscanf(val, "%"SCNu64, uval)) {
 149        rc = 0;
 150    }
 151    g_free(val);
 152    return rc;
 153}
 154
 155void xenstore_update(void *unused)
 156{
 157    char **vec = NULL;
 158    intptr_t type, ops, ptr;
 159    unsigned int dom, count;
 160
 161    vec = xs_read_watch(xenstore, &count);
 162    if (vec == NULL) {
 163        goto cleanup;
 164    }
 165
 166    if (sscanf(vec[XS_WATCH_TOKEN], "be:%" PRIxPTR ":%d:%" PRIxPTR,
 167               &type, &dom, &ops) == 3) {
 168        xenstore_update_be(vec[XS_WATCH_PATH], (void *)type, dom, (void*)ops);
 169    }
 170    if (sscanf(vec[XS_WATCH_TOKEN], "fe:%" PRIxPTR, &ptr) == 1) {
 171        xenstore_update_fe(vec[XS_WATCH_PATH], (void *)ptr);
 172    }
 173
 174cleanup:
 175    free(vec);
 176}
 177
 178const char *xenbus_strstate(enum xenbus_state state)
 179{
 180    static const char *const name[] = {
 181        [XenbusStateUnknown]       = "Unknown",
 182        [XenbusStateInitialising]  = "Initialising",
 183        [XenbusStateInitWait]      = "InitWait",
 184        [XenbusStateInitialised]   = "Initialised",
 185        [XenbusStateConnected]     = "Connected",
 186        [XenbusStateClosing]       = "Closing",
 187        [XenbusStateClosed]        = "Closed",
 188    };
 189    return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
 190}
 191
 192/*
 193 * msg_level:
 194 *  0 == errors (stderr + logfile).
 195 *  1 == informative debug messages (logfile only).
 196 *  2 == noisy debug messages (logfile only).
 197 *  3 == will flood your log (logfile only).
 198 */
 199static void xen_pv_output_msg(struct XenLegacyDevice *xendev,
 200                              FILE *f, const char *fmt, va_list args)
 201{
 202    if (xendev) {
 203        fprintf(f, "xen be: %s: ", xendev->name);
 204    } else {
 205        fprintf(f, "xen be core: ");
 206    }
 207    vfprintf(f, fmt, args);
 208}
 209
 210void xen_pv_printf(struct XenLegacyDevice *xendev, int msg_level,
 211                   const char *fmt, ...)
 212{
 213    FILE *logfile;
 214    va_list args;
 215
 216    if (msg_level > (xendev ? xendev->debug : debug)) {
 217        return;
 218    }
 219
 220    logfile = qemu_log_trylock();
 221    if (logfile) {
 222        va_start(args, fmt);
 223        xen_pv_output_msg(xendev, logfile, fmt, args);
 224        va_end(args);
 225        qemu_log_unlock(logfile);
 226    }
 227
 228    if (msg_level == 0) {
 229        va_start(args, fmt);
 230        xen_pv_output_msg(xendev, stderr, fmt, args);
 231        va_end(args);
 232    }
 233}
 234
 235void xen_pv_evtchn_event(void *opaque)
 236{
 237    struct XenLegacyDevice *xendev = opaque;
 238    evtchn_port_t port;
 239
 240    port = xenevtchn_pending(xendev->evtchndev);
 241    if (port != xendev->local_port) {
 242        xen_pv_printf(xendev, 0,
 243                      "xenevtchn_pending returned %d (expected %d)\n",
 244                      port, xendev->local_port);
 245        return;
 246    }
 247    xenevtchn_unmask(xendev->evtchndev, port);
 248
 249    if (xendev->ops->event) {
 250        xendev->ops->event(xendev);
 251    }
 252}
 253
 254void xen_pv_unbind_evtchn(struct XenLegacyDevice *xendev)
 255{
 256    if (xendev->local_port == -1) {
 257        return;
 258    }
 259    qemu_set_fd_handler(xenevtchn_fd(xendev->evtchndev), NULL, NULL, NULL);
 260    xenevtchn_unbind(xendev->evtchndev, xendev->local_port);
 261    xen_pv_printf(xendev, 2, "unbind evtchn port %d\n", xendev->local_port);
 262    xendev->local_port = -1;
 263}
 264
 265int xen_pv_send_notify(struct XenLegacyDevice *xendev)
 266{
 267    return xenevtchn_notify(xendev->evtchndev, xendev->local_port);
 268}
 269
 270/* ------------------------------------------------------------- */
 271
 272struct XenLegacyDevice *xen_pv_find_xendev(const char *type, int dom, int dev)
 273{
 274    struct XenLegacyDevice *xendev;
 275
 276    QTAILQ_FOREACH(xendev, &xendevs, next) {
 277        if (xendev->dom != dom) {
 278            continue;
 279        }
 280        if (xendev->dev != dev) {
 281            continue;
 282        }
 283        if (strcmp(xendev->type, type) != 0) {
 284            continue;
 285        }
 286        return xendev;
 287    }
 288    return NULL;
 289}
 290
 291/*
 292 * release xen backend device.
 293 */
 294void xen_pv_del_xendev(struct XenLegacyDevice *xendev)
 295{
 296    if (xendev->ops->free) {
 297        xendev->ops->free(xendev);
 298    }
 299
 300    if (xendev->fe) {
 301        char token[XEN_BUFSIZE];
 302        snprintf(token, sizeof(token), "fe:%p", xendev);
 303        xs_unwatch(xenstore, xendev->fe, token);
 304        g_free(xendev->fe);
 305    }
 306
 307    if (xendev->evtchndev != NULL) {
 308        xenevtchn_close(xendev->evtchndev);
 309    }
 310    if (xendev->gnttabdev != NULL) {
 311        xengnttab_close(xendev->gnttabdev);
 312    }
 313
 314    QTAILQ_REMOVE(&xendevs, xendev, next);
 315
 316    qdev_unplug(&xendev->qdev, NULL);
 317}
 318
 319void xen_pv_insert_xendev(struct XenLegacyDevice *xendev)
 320{
 321    QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
 322}
 323