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