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        qemu_xen_xs_destroy(xenstore, 0, d->xs_dir);
  58    }
  59}
  60
  61int xenstore_mkdir(char *path, int p)
  62{
  63    if (!qemu_xen_xs_create(xenstore, 0, 0, xen_domid, p, path)) {
  64        xen_pv_printf(NULL, 0, "xs_mkdir %s: failed\n", path);
  65        return -1;
  66    }
  67    xenstore_cleanup_dir(g_strdup(path));
  68    return 0;
  69}
  70
  71int xenstore_write_str(const char *base, const char *node, const char *val)
  72{
  73    char abspath[XEN_BUFSIZE];
  74
  75    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
  76    if (!qemu_xen_xs_write(xenstore, 0, abspath, val, strlen(val))) {
  77        return -1;
  78    }
  79    return 0;
  80}
  81
  82char *xenstore_read_str(const char *base, const char *node)
  83{
  84    char abspath[XEN_BUFSIZE];
  85    unsigned int len;
  86    char *str, *ret = NULL;
  87
  88    snprintf(abspath, sizeof(abspath), "%s/%s", base, node);
  89    str = qemu_xen_xs_read(xenstore, 0, abspath, &len);
  90    if (str != NULL) {
  91        /* move to qemu-allocated memory to make sure
  92         * callers can savely g_free() stuff. */
  93        ret = g_strdup(str);
  94        free(str);
  95    }
  96    return ret;
  97}
  98
  99int xenstore_write_int(const char *base, const char *node, int ival)
 100{
 101    char val[12];
 102
 103    snprintf(val, sizeof(val), "%d", ival);
 104    return xenstore_write_str(base, node, val);
 105}
 106
 107int xenstore_write_int64(const char *base, const char *node, int64_t ival)
 108{
 109    char val[21];
 110
 111    snprintf(val, sizeof(val), "%"PRId64, ival);
 112    return xenstore_write_str(base, node, val);
 113}
 114
 115int xenstore_read_int(const char *base, const char *node, int *ival)
 116{
 117    char *val;
 118    int rc = -1;
 119
 120    val = xenstore_read_str(base, node);
 121    if (val && 1 == sscanf(val, "%d", ival)) {
 122        rc = 0;
 123    }
 124    g_free(val);
 125    return rc;
 126}
 127
 128int xenstore_read_uint64(const char *base, const char *node, uint64_t *uval)
 129{
 130    char *val;
 131    int rc = -1;
 132
 133    val = xenstore_read_str(base, node);
 134    if (val && 1 == sscanf(val, "%"SCNu64, uval)) {
 135        rc = 0;
 136    }
 137    g_free(val);
 138    return rc;
 139}
 140
 141const char *xenbus_strstate(enum xenbus_state state)
 142{
 143    static const char *const name[] = {
 144        [XenbusStateUnknown]       = "Unknown",
 145        [XenbusStateInitialising]  = "Initialising",
 146        [XenbusStateInitWait]      = "InitWait",
 147        [XenbusStateInitialised]   = "Initialised",
 148        [XenbusStateConnected]     = "Connected",
 149        [XenbusStateClosing]       = "Closing",
 150        [XenbusStateClosed]        = "Closed",
 151    };
 152    return (state < ARRAY_SIZE(name)) ? name[state] : "INVALID";
 153}
 154
 155/*
 156 * msg_level:
 157 *  0 == errors (stderr + logfile).
 158 *  1 == informative debug messages (logfile only).
 159 *  2 == noisy debug messages (logfile only).
 160 *  3 == will flood your log (logfile only).
 161 */
 162G_GNUC_PRINTF(3, 0)
 163static void xen_pv_output_msg(struct XenLegacyDevice *xendev,
 164                              FILE *f, const char *fmt, va_list args)
 165{
 166    if (xendev) {
 167        fprintf(f, "xen be: %s: ", xendev->name);
 168    } else {
 169        fprintf(f, "xen be core: ");
 170    }
 171    vfprintf(f, fmt, args);
 172}
 173
 174void xen_pv_printf(struct XenLegacyDevice *xendev, int msg_level,
 175                   const char *fmt, ...)
 176{
 177    FILE *logfile;
 178    va_list args;
 179
 180    if (msg_level > (xendev ? xendev->debug : debug)) {
 181        return;
 182    }
 183
 184    logfile = qemu_log_trylock();
 185    if (logfile) {
 186        va_start(args, fmt);
 187        xen_pv_output_msg(xendev, logfile, fmt, args);
 188        va_end(args);
 189        qemu_log_unlock(logfile);
 190    }
 191
 192    if (msg_level == 0) {
 193        va_start(args, fmt);
 194        xen_pv_output_msg(xendev, stderr, fmt, args);
 195        va_end(args);
 196    }
 197}
 198
 199void xen_pv_evtchn_event(void *opaque)
 200{
 201    struct XenLegacyDevice *xendev = opaque;
 202    evtchn_port_t port;
 203
 204    port = qemu_xen_evtchn_pending(xendev->evtchndev);
 205    if (port != xendev->local_port) {
 206        xen_pv_printf(xendev, 0,
 207                      "xenevtchn_pending returned %d (expected %d)\n",
 208                      port, xendev->local_port);
 209        return;
 210    }
 211    qemu_xen_evtchn_unmask(xendev->evtchndev, port);
 212
 213    if (xendev->ops->event) {
 214        xendev->ops->event(xendev);
 215    }
 216}
 217
 218void xen_pv_unbind_evtchn(struct XenLegacyDevice *xendev)
 219{
 220    if (xendev->local_port == -1) {
 221        return;
 222    }
 223    qemu_set_fd_handler(qemu_xen_evtchn_fd(xendev->evtchndev), NULL, NULL, NULL);
 224    qemu_xen_evtchn_unbind(xendev->evtchndev, xendev->local_port);
 225    xen_pv_printf(xendev, 2, "unbind evtchn port %d\n", xendev->local_port);
 226    xendev->local_port = -1;
 227}
 228
 229int xen_pv_send_notify(struct XenLegacyDevice *xendev)
 230{
 231    return qemu_xen_evtchn_notify(xendev->evtchndev, xendev->local_port);
 232}
 233
 234/* ------------------------------------------------------------- */
 235
 236struct XenLegacyDevice *xen_pv_find_xendev(const char *type, int dom, int dev)
 237{
 238    struct XenLegacyDevice *xendev;
 239
 240    QTAILQ_FOREACH(xendev, &xendevs, next) {
 241        if (xendev->dom != dom) {
 242            continue;
 243        }
 244        if (xendev->dev != dev) {
 245            continue;
 246        }
 247        if (strcmp(xendev->type, type) != 0) {
 248            continue;
 249        }
 250        return xendev;
 251    }
 252    return NULL;
 253}
 254
 255/*
 256 * release xen backend device.
 257 */
 258void xen_pv_del_xendev(struct XenLegacyDevice *xendev)
 259{
 260    if (xendev->ops->free) {
 261        xendev->ops->free(xendev);
 262    }
 263
 264    if (xendev->fe) {
 265        qemu_xen_xs_unwatch(xenstore, xendev->watch);
 266        g_free(xendev->fe);
 267    }
 268
 269    if (xendev->evtchndev != NULL) {
 270        qemu_xen_evtchn_close(xendev->evtchndev);
 271    }
 272    if (xendev->gnttabdev != NULL) {
 273        qemu_xen_gnttab_close(xendev->gnttabdev);
 274    }
 275
 276    QTAILQ_REMOVE(&xendevs, xendev, next);
 277
 278    qdev_unplug(&xendev->qdev, NULL);
 279}
 280
 281void xen_pv_insert_xendev(struct XenLegacyDevice *xendev)
 282{
 283    QTAILQ_INSERT_TAIL(&xendevs, xendev, next);
 284}
 285