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