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