qemu/hw/core/qdev-properties-system.c
<<
>>
Prefs
   1/*
   2 * qdev property parsing
   3 * (parts specific for qemu-system-*)
   4 *
   5 * This file is based on code from hw/qdev-properties.c from
   6 * commit 074a86fccd185616469dfcdc0e157f438aebba18,
   7 * Copyright (c) Gerd Hoffmann <kraxel@redhat.com> and other contributors.
   8 *
   9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  10 * See the COPYING file in the top-level directory.
  11 */
  12
  13#include "qemu/osdep.h"
  14#include "net/net.h"
  15#include "hw/qdev.h"
  16#include "qapi/error.h"
  17#include "qapi/qmp/qerror.h"
  18#include "sysemu/block-backend.h"
  19#include "sysemu/blockdev.h"
  20#include "hw/block/block.h"
  21#include "net/hub.h"
  22#include "qapi/visitor.h"
  23#include "chardev/char-fe.h"
  24#include "sysemu/iothread.h"
  25#include "sysemu/tpm_backend.h"
  26
  27static void get_pointer(Object *obj, Visitor *v, Property *prop,
  28                        char *(*print)(void *ptr),
  29                        const char *name, Error **errp)
  30{
  31    DeviceState *dev = DEVICE(obj);
  32    void **ptr = qdev_get_prop_ptr(dev, prop);
  33    char *p;
  34
  35    p = *ptr ? print(*ptr) : g_strdup("");
  36    visit_type_str(v, name, &p, errp);
  37    g_free(p);
  38}
  39
  40static void set_pointer(Object *obj, Visitor *v, Property *prop,
  41                        void (*parse)(DeviceState *dev, const char *str,
  42                                      void **ptr, const char *propname,
  43                                      Error **errp),
  44                        const char *name, Error **errp)
  45{
  46    DeviceState *dev = DEVICE(obj);
  47    Error *local_err = NULL;
  48    void **ptr = qdev_get_prop_ptr(dev, prop);
  49    char *str;
  50
  51    if (dev->realized) {
  52        qdev_prop_set_after_realize(dev, name, errp);
  53        return;
  54    }
  55
  56    visit_type_str(v, name, &str, &local_err);
  57    if (local_err) {
  58        error_propagate(errp, local_err);
  59        return;
  60    }
  61    if (!*str) {
  62        g_free(str);
  63        *ptr = NULL;
  64        return;
  65    }
  66    parse(dev, str, ptr, prop->name, errp);
  67    g_free(str);
  68}
  69
  70/* --- drive --- */
  71
  72static void do_parse_drive(DeviceState *dev, const char *str, void **ptr,
  73                           const char *propname, bool iothread, Error **errp)
  74{
  75    BlockBackend *blk;
  76    bool blk_created = false;
  77    int ret;
  78
  79    blk = blk_by_name(str);
  80    if (!blk) {
  81        BlockDriverState *bs = bdrv_lookup_bs(NULL, str, NULL);
  82        if (bs) {
  83            /*
  84             * If the device supports iothreads, it will make sure to move the
  85             * block node to the right AioContext if necessary (or fail if this
  86             * isn't possible because of other users). Devices that are not
  87             * aware of iothreads require their BlockBackends to be in the main
  88             * AioContext.
  89             */
  90            AioContext *ctx = iothread ? bdrv_get_aio_context(bs) :
  91                                         qemu_get_aio_context();
  92            blk = blk_new(ctx, 0, BLK_PERM_ALL);
  93            blk_created = true;
  94
  95            ret = blk_insert_bs(blk, bs, errp);
  96            if (ret < 0) {
  97                goto fail;
  98            }
  99        }
 100    }
 101    if (!blk) {
 102        error_setg(errp, "Property '%s.%s' can't find value '%s'",
 103                   object_get_typename(OBJECT(dev)), propname, str);
 104        goto fail;
 105    }
 106    if (blk_attach_dev(blk, dev) < 0) {
 107        DriveInfo *dinfo = blk_legacy_dinfo(blk);
 108
 109        if (dinfo && dinfo->type != IF_NONE) {
 110            error_setg(errp, "Drive '%s' is already in use because "
 111                       "it has been automatically connected to another "
 112                       "device (did you need 'if=none' in the drive options?)",
 113                       str);
 114        } else {
 115            error_setg(errp, "Drive '%s' is already in use by another device",
 116                       str);
 117        }
 118        goto fail;
 119    }
 120
 121    *ptr = blk;
 122
 123fail:
 124    if (blk_created) {
 125        /* If we need to keep a reference, blk_attach_dev() took it */
 126        blk_unref(blk);
 127    }
 128}
 129
 130static void parse_drive(DeviceState *dev, const char *str, void **ptr,
 131                        const char *propname, Error **errp)
 132{
 133    do_parse_drive(dev, str, ptr, propname, false, errp);
 134}
 135
 136static void parse_drive_iothread(DeviceState *dev, const char *str, void **ptr,
 137                                 const char *propname, Error **errp)
 138{
 139    do_parse_drive(dev, str, ptr, propname, true, errp);
 140}
 141
 142static void release_drive(Object *obj, const char *name, void *opaque)
 143{
 144    DeviceState *dev = DEVICE(obj);
 145    Property *prop = opaque;
 146    BlockBackend **ptr = qdev_get_prop_ptr(dev, prop);
 147
 148    if (*ptr) {
 149        AioContext *ctx = blk_get_aio_context(*ptr);
 150
 151        aio_context_acquire(ctx);
 152        blockdev_auto_del(*ptr);
 153        blk_detach_dev(*ptr, dev);
 154        aio_context_release(ctx);
 155    }
 156}
 157
 158static char *print_drive(void *ptr)
 159{
 160    const char *name;
 161
 162    name = blk_name(ptr);
 163    if (!*name) {
 164        BlockDriverState *bs = blk_bs(ptr);
 165        if (bs) {
 166            name = bdrv_get_node_name(bs);
 167        }
 168    }
 169    return g_strdup(name);
 170}
 171
 172static void get_drive(Object *obj, Visitor *v, const char *name, void *opaque,
 173                      Error **errp)
 174{
 175    get_pointer(obj, v, opaque, print_drive, name, errp);
 176}
 177
 178static void set_drive(Object *obj, Visitor *v, const char *name, void *opaque,
 179                      Error **errp)
 180{
 181    set_pointer(obj, v, opaque, parse_drive, name, errp);
 182}
 183
 184static void set_drive_iothread(Object *obj, Visitor *v, const char *name,
 185                               void *opaque, Error **errp)
 186{
 187    set_pointer(obj, v, opaque, parse_drive_iothread, name, errp);
 188}
 189
 190const PropertyInfo qdev_prop_drive = {
 191    .name  = "str",
 192    .description = "Node name or ID of a block device to use as a backend",
 193    .get   = get_drive,
 194    .set   = set_drive,
 195    .release = release_drive,
 196};
 197
 198const PropertyInfo qdev_prop_drive_iothread = {
 199    .name  = "str",
 200    .description = "Node name or ID of a block device to use as a backend",
 201    .get   = get_drive,
 202    .set   = set_drive_iothread,
 203    .release = release_drive,
 204};
 205
 206/* --- character device --- */
 207
 208static void get_chr(Object *obj, Visitor *v, const char *name, void *opaque,
 209                    Error **errp)
 210{
 211    DeviceState *dev = DEVICE(obj);
 212    CharBackend *be = qdev_get_prop_ptr(dev, opaque);
 213    char *p;
 214
 215    p = g_strdup(be->chr && be->chr->label ? be->chr->label : "");
 216    visit_type_str(v, name, &p, errp);
 217    g_free(p);
 218}
 219
 220static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque,
 221                    Error **errp)
 222{
 223    DeviceState *dev = DEVICE(obj);
 224    Error *local_err = NULL;
 225    Property *prop = opaque;
 226    CharBackend *be = qdev_get_prop_ptr(dev, prop);
 227    Chardev *s;
 228    char *str;
 229
 230    if (dev->realized) {
 231        qdev_prop_set_after_realize(dev, name, errp);
 232        return;
 233    }
 234
 235    visit_type_str(v, name, &str, &local_err);
 236    if (local_err) {
 237        error_propagate(errp, local_err);
 238        return;
 239    }
 240
 241    if (!*str) {
 242        g_free(str);
 243        be->chr = NULL;
 244        return;
 245    }
 246
 247    s = qemu_chr_find(str);
 248    if (s == NULL) {
 249        error_setg(errp, "Property '%s.%s' can't find value '%s'",
 250                   object_get_typename(obj), prop->name, str);
 251    } else if (!qemu_chr_fe_init(be, s, errp)) {
 252        error_prepend(errp, "Property '%s.%s' can't take value '%s': ",
 253                      object_get_typename(obj), prop->name, str);
 254    }
 255    g_free(str);
 256}
 257
 258static void release_chr(Object *obj, const char *name, void *opaque)
 259{
 260    DeviceState *dev = DEVICE(obj);
 261    Property *prop = opaque;
 262    CharBackend *be = qdev_get_prop_ptr(dev, prop);
 263
 264    qemu_chr_fe_deinit(be, false);
 265}
 266
 267const PropertyInfo qdev_prop_chr = {
 268    .name  = "str",
 269    .description = "ID of a chardev to use as a backend",
 270    .get   = get_chr,
 271    .set   = set_chr,
 272    .release = release_chr,
 273};
 274
 275/* --- netdev device --- */
 276static void get_netdev(Object *obj, Visitor *v, const char *name,
 277                       void *opaque, Error **errp)
 278{
 279    DeviceState *dev = DEVICE(obj);
 280    Property *prop = opaque;
 281    NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop);
 282    char *p = g_strdup(peers_ptr->ncs[0] ? peers_ptr->ncs[0]->name : "");
 283
 284    visit_type_str(v, name, &p, errp);
 285    g_free(p);
 286}
 287
 288static void set_netdev(Object *obj, Visitor *v, const char *name,
 289                       void *opaque, Error **errp)
 290{
 291    DeviceState *dev = DEVICE(obj);
 292    Property *prop = opaque;
 293    NICPeers *peers_ptr = qdev_get_prop_ptr(dev, prop);
 294    NetClientState **ncs = peers_ptr->ncs;
 295    NetClientState *peers[MAX_QUEUE_NUM];
 296    Error *local_err = NULL;
 297    int queues, err = 0, i = 0;
 298    char *str;
 299
 300    if (dev->realized) {
 301        qdev_prop_set_after_realize(dev, name, errp);
 302        return;
 303    }
 304
 305    visit_type_str(v, name, &str, &local_err);
 306    if (local_err) {
 307        error_propagate(errp, local_err);
 308        return;
 309    }
 310
 311    queues = qemu_find_net_clients_except(str, peers,
 312                                          NET_CLIENT_DRIVER_NIC,
 313                                          MAX_QUEUE_NUM);
 314    if (queues == 0) {
 315        err = -ENOENT;
 316        goto out;
 317    }
 318
 319    if (queues > MAX_QUEUE_NUM) {
 320        error_setg(errp, "queues of backend '%s'(%d) exceeds QEMU limitation(%d)",
 321                   str, queues, MAX_QUEUE_NUM);
 322        goto out;
 323    }
 324
 325    for (i = 0; i < queues; i++) {
 326
 327        if (peers[i]->peer) {
 328            err = -EEXIST;
 329            goto out;
 330        }
 331
 332        if (ncs[i]) {
 333            err = -EINVAL;
 334            goto out;
 335        }
 336
 337        ncs[i] = peers[i];
 338        ncs[i]->queue_index = i;
 339    }
 340
 341    peers_ptr->queues = queues;
 342
 343out:
 344    error_set_from_qdev_prop_error(errp, err, dev, prop, str);
 345    g_free(str);
 346}
 347
 348const PropertyInfo qdev_prop_netdev = {
 349    .name  = "str",
 350    .description = "ID of a netdev to use as a backend",
 351    .get   = get_netdev,
 352    .set   = set_netdev,
 353};
 354
 355
 356void qdev_prop_set_drive(DeviceState *dev, const char *name,
 357                         BlockBackend *value, Error **errp)
 358{
 359    const char *ref = "";
 360
 361    if (value) {
 362        ref = blk_name(value);
 363        if (!*ref) {
 364            const BlockDriverState *bs = blk_bs(value);
 365            if (bs) {
 366                ref = bdrv_get_node_name(bs);
 367            }
 368        }
 369    }
 370
 371    object_property_set_str(OBJECT(dev), ref, name, errp);
 372}
 373
 374void qdev_prop_set_chr(DeviceState *dev, const char *name,
 375                       Chardev *value)
 376{
 377    assert(!value || value->label);
 378    object_property_set_str(OBJECT(dev),
 379                            value ? value->label : "", name, &error_abort);
 380}
 381
 382void qdev_prop_set_netdev(DeviceState *dev, const char *name,
 383                          NetClientState *value)
 384{
 385    assert(!value || value->name);
 386    object_property_set_str(OBJECT(dev),
 387                            value ? value->name : "", name, &error_abort);
 388}
 389
 390void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
 391{
 392    qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
 393    if (nd->netdev) {
 394        qdev_prop_set_netdev(dev, "netdev", nd->netdev);
 395    }
 396    if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
 397        object_property_find(OBJECT(dev), "vectors", NULL)) {
 398        qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
 399    }
 400    nd->instantiated = 1;
 401}
 402