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