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