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 "hw/qdev-properties.h" 15 #include "qapi/error.h" 16 #include "qapi/visitor.h" 17 #include "qapi/qapi-types-block.h" 18 #include "qapi/qapi-types-machine.h" 19 #include "qapi/qapi-types-migration.h" 20 #include "qapi/qmp/qerror.h" 21 #include "qemu/ctype.h" 22 #include "qemu/cutils.h" 23 #include "qemu/units.h" 24 #include "qemu/uuid.h" 25 #include "qemu/error-report.h" 26 #include "qdev-prop-internal.h" 27 28 #include "audio/audio.h" 29 #include "chardev/char-fe.h" 30 #include "sysemu/block-backend.h" 31 #include "sysemu/blockdev.h" 32 #include "net/net.h" 33 #include "hw/pci/pci.h" 34 #include "util/block-helpers.h" 35 36 static bool check_prop_still_unset(Object *obj, const char *name, 37 const void *old_val, const char *new_val, 38 Error **errp) 39 { 40 const GlobalProperty *prop = qdev_find_global_prop(obj, name); 41 42 if (!old_val) { 43 return true; 44 } 45 46 if (prop) { 47 error_setg(errp, "-global %s.%s=... conflicts with %s=%s", 48 prop->driver, prop->property, name, new_val); 49 } else { 50 /* Error message is vague, but a better one would be hard */ 51 error_setg(errp, "%s=%s conflicts, and override is not implemented", 52 name, new_val); 53 } 54 return false; 55 } 56 57 58 /* --- drive --- */ 59 60 static void get_drive(Object *obj, Visitor *v, const char *name, void *opaque, 61 Error **errp) 62 { 63 Property *prop = opaque; 64 void **ptr = qdev_get_prop_ptr(obj, prop); 65 const char *value; 66 char *p; 67 68 if (*ptr) { 69 value = blk_name(*ptr); 70 if (!*value) { 71 BlockDriverState *bs = blk_bs(*ptr); 72 if (bs) { 73 value = bdrv_get_node_name(bs); 74 } 75 } 76 } else { 77 value = ""; 78 } 79 80 p = g_strdup(value); 81 visit_type_str(v, name, &p, errp); 82 g_free(p); 83 } 84 85 static void set_drive_helper(Object *obj, Visitor *v, const char *name, 86 void *opaque, bool iothread, Error **errp) 87 { 88 DeviceState *dev = DEVICE(obj); 89 Property *prop = opaque; 90 void **ptr = qdev_get_prop_ptr(obj, prop); 91 char *str; 92 BlockBackend *blk; 93 bool blk_created = false; 94 int ret; 95 96 if (dev->realized) { 97 qdev_prop_set_after_realize(dev, name, errp); 98 return; 99 } 100 101 if (!visit_type_str(v, name, &str, errp)) { 102 return; 103 } 104 105 /* 106 * TODO Should this really be an error? If no, the old value 107 * needs to be released before we store the new one. 108 */ 109 if (!check_prop_still_unset(obj, name, *ptr, str, errp)) { 110 return; 111 } 112 113 if (!*str) { 114 g_free(str); 115 *ptr = NULL; 116 return; 117 } 118 119 blk = blk_by_name(str); 120 if (!blk) { 121 BlockDriverState *bs = bdrv_lookup_bs(NULL, str, NULL); 122 if (bs) { 123 /* 124 * If the device supports iothreads, it will make sure to move the 125 * block node to the right AioContext if necessary (or fail if this 126 * isn't possible because of other users). Devices that are not 127 * aware of iothreads require their BlockBackends to be in the main 128 * AioContext. 129 */ 130 AioContext *ctx = iothread ? bdrv_get_aio_context(bs) : 131 qemu_get_aio_context(); 132 blk = blk_new(ctx, 0, BLK_PERM_ALL); 133 blk_created = true; 134 135 ret = blk_insert_bs(blk, bs, errp); 136 if (ret < 0) { 137 goto fail; 138 } 139 } 140 } 141 if (!blk) { 142 error_setg(errp, "Property '%s.%s' can't find value '%s'", 143 object_get_typename(OBJECT(dev)), prop->name, str); 144 goto fail; 145 } 146 if (blk_attach_dev(blk, dev) < 0) { 147 DriveInfo *dinfo = blk_legacy_dinfo(blk); 148 149 if (dinfo && dinfo->type != IF_NONE) { 150 error_setg(errp, "Drive '%s' is already in use because " 151 "it has been automatically connected to another " 152 "device (did you need 'if=none' in the drive options?)", 153 str); 154 } else { 155 error_setg(errp, "Drive '%s' is already in use by another device", 156 str); 157 } 158 goto fail; 159 } 160 161 *ptr = blk; 162 163 fail: 164 if (blk_created) { 165 /* If we need to keep a reference, blk_attach_dev() took it */ 166 blk_unref(blk); 167 } 168 169 g_free(str); 170 } 171 172 static void set_drive(Object *obj, Visitor *v, const char *name, void *opaque, 173 Error **errp) 174 { 175 set_drive_helper(obj, v, name, opaque, false, errp); 176 } 177 178 static void set_drive_iothread(Object *obj, Visitor *v, const char *name, 179 void *opaque, Error **errp) 180 { 181 set_drive_helper(obj, v, name, opaque, true, errp); 182 } 183 184 static void release_drive(Object *obj, const char *name, void *opaque) 185 { 186 DeviceState *dev = DEVICE(obj); 187 Property *prop = opaque; 188 BlockBackend **ptr = qdev_get_prop_ptr(obj, prop); 189 190 if (*ptr) { 191 AioContext *ctx = blk_get_aio_context(*ptr); 192 193 aio_context_acquire(ctx); 194 blockdev_auto_del(*ptr); 195 blk_detach_dev(*ptr, dev); 196 aio_context_release(ctx); 197 } 198 } 199 200 const PropertyInfo qdev_prop_drive = { 201 .name = "str", 202 .description = "Node name or ID of a block device to use as a backend", 203 .get = get_drive, 204 .set = set_drive, 205 .release = release_drive, 206 }; 207 208 const PropertyInfo qdev_prop_drive_iothread = { 209 .name = "str", 210 .description = "Node name or ID of a block device to use as a backend", 211 .get = get_drive, 212 .set = set_drive_iothread, 213 .release = release_drive, 214 }; 215 216 /* --- character device --- */ 217 218 static void get_chr(Object *obj, Visitor *v, const char *name, void *opaque, 219 Error **errp) 220 { 221 CharBackend *be = qdev_get_prop_ptr(obj, opaque); 222 char *p; 223 224 p = g_strdup(be->chr && be->chr->label ? be->chr->label : ""); 225 visit_type_str(v, name, &p, errp); 226 g_free(p); 227 } 228 229 static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque, 230 Error **errp) 231 { 232 DeviceState *dev = DEVICE(obj); 233 Property *prop = opaque; 234 CharBackend *be = qdev_get_prop_ptr(obj, prop); 235 Chardev *s; 236 char *str; 237 238 if (dev->realized) { 239 qdev_prop_set_after_realize(dev, name, errp); 240 return; 241 } 242 243 if (!visit_type_str(v, name, &str, errp)) { 244 return; 245 } 246 247 /* 248 * TODO Should this really be an error? If no, the old value 249 * needs to be released before we store the new one. 250 */ 251 if (!check_prop_still_unset(obj, name, be->chr, str, errp)) { 252 return; 253 } 254 255 if (!*str) { 256 g_free(str); 257 be->chr = NULL; 258 return; 259 } 260 261 s = qemu_chr_find(str); 262 if (s == NULL) { 263 error_setg(errp, "Property '%s.%s' can't find value '%s'", 264 object_get_typename(obj), prop->name, str); 265 } else if (!qemu_chr_fe_init(be, s, errp)) { 266 error_prepend(errp, "Property '%s.%s' can't take value '%s': ", 267 object_get_typename(obj), prop->name, str); 268 } 269 g_free(str); 270 } 271 272 static void release_chr(Object *obj, const char *name, void *opaque) 273 { 274 Property *prop = opaque; 275 CharBackend *be = qdev_get_prop_ptr(obj, prop); 276 277 qemu_chr_fe_deinit(be, false); 278 } 279 280 const PropertyInfo qdev_prop_chr = { 281 .name = "str", 282 .description = "ID of a chardev to use as a backend", 283 .get = get_chr, 284 .set = set_chr, 285 .release = release_chr, 286 }; 287 288 /* --- mac address --- */ 289 290 /* 291 * accepted syntax versions: 292 * 01:02:03:04:05:06 293 * 01-02-03-04-05-06 294 */ 295 static void get_mac(Object *obj, Visitor *v, const char *name, void *opaque, 296 Error **errp) 297 { 298 Property *prop = opaque; 299 MACAddr *mac = qdev_get_prop_ptr(obj, prop); 300 char buffer[2 * 6 + 5 + 1]; 301 char *p = buffer; 302 303 snprintf(buffer, sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x", 304 mac->a[0], mac->a[1], mac->a[2], 305 mac->a[3], mac->a[4], mac->a[5]); 306 307 visit_type_str(v, name, &p, errp); 308 } 309 310 static void set_mac(Object *obj, Visitor *v, const char *name, void *opaque, 311 Error **errp) 312 { 313 DeviceState *dev = DEVICE(obj); 314 Property *prop = opaque; 315 MACAddr *mac = qdev_get_prop_ptr(obj, prop); 316 int i, pos; 317 char *str; 318 const char *p; 319 320 if (dev->realized) { 321 qdev_prop_set_after_realize(dev, name, errp); 322 return; 323 } 324 325 if (!visit_type_str(v, name, &str, errp)) { 326 return; 327 } 328 329 for (i = 0, pos = 0; i < 6; i++, pos += 3) { 330 long val; 331 332 if (!qemu_isxdigit(str[pos])) { 333 goto inval; 334 } 335 if (!qemu_isxdigit(str[pos + 1])) { 336 goto inval; 337 } 338 if (i == 5) { 339 if (str[pos + 2] != '\0') { 340 goto inval; 341 } 342 } else { 343 if (str[pos + 2] != ':' && str[pos + 2] != '-') { 344 goto inval; 345 } 346 } 347 if (qemu_strtol(str + pos, &p, 16, &val) < 0 || val > 0xff) { 348 goto inval; 349 } 350 mac->a[i] = val; 351 } 352 g_free(str); 353 return; 354 355 inval: 356 error_set_from_qdev_prop_error(errp, EINVAL, obj, prop, str); 357 g_free(str); 358 } 359 360 const PropertyInfo qdev_prop_macaddr = { 361 .name = "str", 362 .description = "Ethernet 6-byte MAC Address, example: 52:54:00:12:34:56", 363 .get = get_mac, 364 .set = set_mac, 365 }; 366 367 void qdev_prop_set_macaddr(DeviceState *dev, const char *name, 368 const uint8_t *value) 369 { 370 char str[2 * 6 + 5 + 1]; 371 snprintf(str, sizeof(str), "%02x:%02x:%02x:%02x:%02x:%02x", 372 value[0], value[1], value[2], value[3], value[4], value[5]); 373 374 object_property_set_str(OBJECT(dev), name, str, &error_abort); 375 } 376 377 /* --- netdev device --- */ 378 static void get_netdev(Object *obj, Visitor *v, const char *name, 379 void *opaque, Error **errp) 380 { 381 Property *prop = opaque; 382 NICPeers *peers_ptr = qdev_get_prop_ptr(obj, prop); 383 char *p = g_strdup(peers_ptr->ncs[0] ? peers_ptr->ncs[0]->name : ""); 384 385 visit_type_str(v, name, &p, errp); 386 g_free(p); 387 } 388 389 static void set_netdev(Object *obj, Visitor *v, const char *name, 390 void *opaque, Error **errp) 391 { 392 DeviceState *dev = DEVICE(obj); 393 Property *prop = opaque; 394 NICPeers *peers_ptr = qdev_get_prop_ptr(obj, prop); 395 NetClientState **ncs = peers_ptr->ncs; 396 NetClientState *peers[MAX_QUEUE_NUM]; 397 int queues, err = 0, i = 0; 398 char *str; 399 400 if (dev->realized) { 401 qdev_prop_set_after_realize(dev, name, errp); 402 return; 403 } 404 405 if (!visit_type_str(v, name, &str, errp)) { 406 return; 407 } 408 409 queues = qemu_find_net_clients_except(str, peers, 410 NET_CLIENT_DRIVER_NIC, 411 MAX_QUEUE_NUM); 412 if (queues == 0) { 413 err = -ENOENT; 414 goto out; 415 } 416 417 if (queues > MAX_QUEUE_NUM) { 418 error_setg(errp, "queues of backend '%s'(%d) exceeds QEMU limitation(%d)", 419 str, queues, MAX_QUEUE_NUM); 420 goto out; 421 } 422 423 for (i = 0; i < queues; i++) { 424 if (peers[i]->peer) { 425 err = -EEXIST; 426 goto out; 427 } 428 429 /* 430 * TODO Should this really be an error? If no, the old value 431 * needs to be released before we store the new one. 432 */ 433 if (!check_prop_still_unset(obj, name, ncs[i], str, errp)) { 434 goto out; 435 } 436 437 ncs[i] = peers[i]; 438 ncs[i]->queue_index = i; 439 } 440 441 peers_ptr->queues = queues; 442 443 out: 444 error_set_from_qdev_prop_error(errp, err, obj, prop, str); 445 g_free(str); 446 } 447 448 const PropertyInfo qdev_prop_netdev = { 449 .name = "str", 450 .description = "ID of a netdev to use as a backend", 451 .get = get_netdev, 452 .set = set_netdev, 453 }; 454 455 456 /* --- audiodev --- */ 457 static void get_audiodev(Object *obj, Visitor *v, const char* name, 458 void *opaque, Error **errp) 459 { 460 Property *prop = opaque; 461 QEMUSoundCard *card = qdev_get_prop_ptr(obj, prop); 462 char *p = g_strdup(audio_get_id(card)); 463 464 visit_type_str(v, name, &p, errp); 465 g_free(p); 466 } 467 468 static void set_audiodev(Object *obj, Visitor *v, const char* name, 469 void *opaque, Error **errp) 470 { 471 DeviceState *dev = DEVICE(obj); 472 Property *prop = opaque; 473 QEMUSoundCard *card = qdev_get_prop_ptr(obj, prop); 474 AudioState *state; 475 int err = 0; 476 char *str; 477 478 if (dev->realized) { 479 qdev_prop_set_after_realize(dev, name, errp); 480 return; 481 } 482 483 if (!visit_type_str(v, name, &str, errp)) { 484 return; 485 } 486 487 state = audio_state_by_name(str); 488 489 if (!state) { 490 err = -ENOENT; 491 goto out; 492 } 493 card->state = state; 494 495 out: 496 error_set_from_qdev_prop_error(errp, err, obj, prop, str); 497 g_free(str); 498 } 499 500 const PropertyInfo qdev_prop_audiodev = { 501 .name = "str", 502 .description = "ID of an audiodev to use as a backend", 503 /* release done on shutdown */ 504 .get = get_audiodev, 505 .set = set_audiodev, 506 }; 507 508 bool qdev_prop_set_drive_err(DeviceState *dev, const char *name, 509 BlockBackend *value, Error **errp) 510 { 511 const char *ref = ""; 512 513 if (value) { 514 ref = blk_name(value); 515 if (!*ref) { 516 const BlockDriverState *bs = blk_bs(value); 517 if (bs) { 518 ref = bdrv_get_node_name(bs); 519 } 520 } 521 } 522 523 return object_property_set_str(OBJECT(dev), name, ref, errp); 524 } 525 526 void qdev_prop_set_drive(DeviceState *dev, const char *name, 527 BlockBackend *value) 528 { 529 qdev_prop_set_drive_err(dev, name, value, &error_abort); 530 } 531 532 void qdev_prop_set_chr(DeviceState *dev, const char *name, 533 Chardev *value) 534 { 535 assert(!value || value->label); 536 object_property_set_str(OBJECT(dev), name, value ? value->label : "", 537 &error_abort); 538 } 539 540 void qdev_prop_set_netdev(DeviceState *dev, const char *name, 541 NetClientState *value) 542 { 543 assert(!value || value->name); 544 object_property_set_str(OBJECT(dev), name, value ? value->name : "", 545 &error_abort); 546 } 547 548 void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd) 549 { 550 qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a); 551 if (nd->netdev) { 552 qdev_prop_set_netdev(dev, "netdev", nd->netdev); 553 } 554 if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED && 555 object_property_find(OBJECT(dev), "vectors")) { 556 qdev_prop_set_uint32(dev, "vectors", nd->nvectors); 557 } 558 nd->instantiated = 1; 559 } 560 561 /* --- lost tick policy --- */ 562 563 QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int)); 564 565 const PropertyInfo qdev_prop_losttickpolicy = { 566 .name = "LostTickPolicy", 567 .enum_table = &LostTickPolicy_lookup, 568 .get = qdev_propinfo_get_enum, 569 .set = qdev_propinfo_set_enum, 570 .set_default_value = qdev_propinfo_set_default_value_enum, 571 }; 572 573 /* --- blocksize --- */ 574 575 static void set_blocksize(Object *obj, Visitor *v, const char *name, 576 void *opaque, Error **errp) 577 { 578 DeviceState *dev = DEVICE(obj); 579 Property *prop = opaque; 580 uint32_t *ptr = qdev_get_prop_ptr(obj, prop); 581 uint64_t value; 582 Error *local_err = NULL; 583 584 if (dev->realized) { 585 qdev_prop_set_after_realize(dev, name, errp); 586 return; 587 } 588 589 if (!visit_type_size(v, name, &value, errp)) { 590 return; 591 } 592 check_block_size(dev->id ? : "", name, value, &local_err); 593 if (local_err) { 594 error_propagate(errp, local_err); 595 return; 596 } 597 *ptr = value; 598 } 599 600 const PropertyInfo qdev_prop_blocksize = { 601 .name = "size", 602 .description = "A power of two between " MIN_BLOCK_SIZE_STR 603 " and " MAX_BLOCK_SIZE_STR, 604 .get = qdev_propinfo_get_size32, 605 .set = set_blocksize, 606 .set_default_value = qdev_propinfo_set_default_value_uint, 607 }; 608 609 /* --- Block device error handling policy --- */ 610 611 QEMU_BUILD_BUG_ON(sizeof(BlockdevOnError) != sizeof(int)); 612 613 const PropertyInfo qdev_prop_blockdev_on_error = { 614 .name = "BlockdevOnError", 615 .description = "Error handling policy, " 616 "report/ignore/enospc/stop/auto", 617 .enum_table = &BlockdevOnError_lookup, 618 .get = qdev_propinfo_get_enum, 619 .set = qdev_propinfo_set_enum, 620 .set_default_value = qdev_propinfo_set_default_value_enum, 621 }; 622 623 /* --- BIOS CHS translation */ 624 625 QEMU_BUILD_BUG_ON(sizeof(BiosAtaTranslation) != sizeof(int)); 626 627 const PropertyInfo qdev_prop_bios_chs_trans = { 628 .name = "BiosAtaTranslation", 629 .description = "Logical CHS translation algorithm, " 630 "auto/none/lba/large/rechs", 631 .enum_table = &BiosAtaTranslation_lookup, 632 .get = qdev_propinfo_get_enum, 633 .set = qdev_propinfo_set_enum, 634 .set_default_value = qdev_propinfo_set_default_value_enum, 635 }; 636 637 /* --- FDC default drive types */ 638 639 const PropertyInfo qdev_prop_fdc_drive_type = { 640 .name = "FdcDriveType", 641 .description = "FDC drive type, " 642 "144/288/120/none/auto", 643 .enum_table = &FloppyDriveType_lookup, 644 .get = qdev_propinfo_get_enum, 645 .set = qdev_propinfo_set_enum, 646 .set_default_value = qdev_propinfo_set_default_value_enum, 647 }; 648 649 /* --- MultiFDCompression --- */ 650 651 const PropertyInfo qdev_prop_multifd_compression = { 652 .name = "MultiFDCompression", 653 .description = "multifd_compression values, " 654 "none/zlib/zstd", 655 .enum_table = &MultiFDCompression_lookup, 656 .get = qdev_propinfo_get_enum, 657 .set = qdev_propinfo_set_enum, 658 .set_default_value = qdev_propinfo_set_default_value_enum, 659 }; 660 661 /* --- Reserved Region --- */ 662 663 /* 664 * Accepted syntax: 665 * <low address>:<high address>:<type> 666 * where low/high addresses are uint64_t in hexadecimal 667 * and type is a non-negative decimal integer 668 */ 669 static void get_reserved_region(Object *obj, Visitor *v, const char *name, 670 void *opaque, Error **errp) 671 { 672 Property *prop = opaque; 673 ReservedRegion *rr = qdev_get_prop_ptr(obj, prop); 674 char buffer[64]; 675 char *p = buffer; 676 int rc; 677 678 rc = snprintf(buffer, sizeof(buffer), "0x%"PRIx64":0x%"PRIx64":%u", 679 rr->low, rr->high, rr->type); 680 assert(rc < sizeof(buffer)); 681 682 visit_type_str(v, name, &p, errp); 683 } 684 685 static void set_reserved_region(Object *obj, Visitor *v, const char *name, 686 void *opaque, Error **errp) 687 { 688 DeviceState *dev = DEVICE(obj); 689 Property *prop = opaque; 690 ReservedRegion *rr = qdev_get_prop_ptr(obj, prop); 691 Error *local_err = NULL; 692 const char *endptr; 693 char *str; 694 int ret; 695 696 if (dev->realized) { 697 qdev_prop_set_after_realize(dev, name, errp); 698 return; 699 } 700 701 visit_type_str(v, name, &str, &local_err); 702 if (local_err) { 703 error_propagate(errp, local_err); 704 return; 705 } 706 707 ret = qemu_strtou64(str, &endptr, 16, &rr->low); 708 if (ret) { 709 error_setg(errp, "start address of '%s'" 710 " must be a hexadecimal integer", name); 711 goto out; 712 } 713 if (*endptr != ':') { 714 goto separator_error; 715 } 716 717 ret = qemu_strtou64(endptr + 1, &endptr, 16, &rr->high); 718 if (ret) { 719 error_setg(errp, "end address of '%s'" 720 " must be a hexadecimal integer", name); 721 goto out; 722 } 723 if (*endptr != ':') { 724 goto separator_error; 725 } 726 727 ret = qemu_strtoui(endptr + 1, &endptr, 10, &rr->type); 728 if (ret) { 729 error_setg(errp, "type of '%s'" 730 " must be a non-negative decimal integer", name); 731 } 732 goto out; 733 734 separator_error: 735 error_setg(errp, "reserved region fields must be separated with ':'"); 736 out: 737 g_free(str); 738 return; 739 } 740 741 const PropertyInfo qdev_prop_reserved_region = { 742 .name = "reserved_region", 743 .description = "Reserved Region, example: 0xFEE00000:0xFEEFFFFF:0", 744 .get = get_reserved_region, 745 .set = set_reserved_region, 746 }; 747 748 /* --- pci address --- */ 749 750 /* 751 * bus-local address, i.e. "$slot" or "$slot.$fn" 752 */ 753 static void set_pci_devfn(Object *obj, Visitor *v, const char *name, 754 void *opaque, Error **errp) 755 { 756 DeviceState *dev = DEVICE(obj); 757 Property *prop = opaque; 758 int32_t value, *ptr = qdev_get_prop_ptr(obj, prop); 759 unsigned int slot, fn, n; 760 char *str; 761 762 if (dev->realized) { 763 qdev_prop_set_after_realize(dev, name, errp); 764 return; 765 } 766 767 if (!visit_type_str(v, name, &str, NULL)) { 768 if (!visit_type_int32(v, name, &value, errp)) { 769 return; 770 } 771 if (value < -1 || value > 255) { 772 error_setg(errp, QERR_INVALID_PARAMETER_VALUE, 773 name ? name : "null", "a value between -1 and 255"); 774 return; 775 } 776 *ptr = value; 777 return; 778 } 779 780 if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) { 781 fn = 0; 782 if (sscanf(str, "%x%n", &slot, &n) != 1) { 783 goto invalid; 784 } 785 } 786 if (str[n] != '\0' || fn > 7 || slot > 31) { 787 goto invalid; 788 } 789 *ptr = slot << 3 | fn; 790 g_free(str); 791 return; 792 793 invalid: 794 error_set_from_qdev_prop_error(errp, EINVAL, obj, prop, str); 795 g_free(str); 796 } 797 798 static int print_pci_devfn(Object *obj, Property *prop, char *dest, 799 size_t len) 800 { 801 int32_t *ptr = qdev_get_prop_ptr(obj, prop); 802 803 if (*ptr == -1) { 804 return snprintf(dest, len, "<unset>"); 805 } else { 806 return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7); 807 } 808 } 809 810 const PropertyInfo qdev_prop_pci_devfn = { 811 .name = "int32", 812 .description = "Slot and optional function number, example: 06.0 or 06", 813 .print = print_pci_devfn, 814 .get = qdev_propinfo_get_int32, 815 .set = set_pci_devfn, 816 .set_default_value = qdev_propinfo_set_default_value_int, 817 }; 818 819 /* --- pci host address --- */ 820 821 static void get_pci_host_devaddr(Object *obj, Visitor *v, const char *name, 822 void *opaque, Error **errp) 823 { 824 Property *prop = opaque; 825 PCIHostDeviceAddress *addr = qdev_get_prop_ptr(obj, prop); 826 char buffer[] = "ffff:ff:ff.f"; 827 char *p = buffer; 828 int rc = 0; 829 830 /* 831 * Catch "invalid" device reference from vfio-pci and allow the 832 * default buffer representing the non-existent device to be used. 833 */ 834 if (~addr->domain || ~addr->bus || ~addr->slot || ~addr->function) { 835 rc = snprintf(buffer, sizeof(buffer), "%04x:%02x:%02x.%0d", 836 addr->domain, addr->bus, addr->slot, addr->function); 837 assert(rc == sizeof(buffer) - 1); 838 } 839 840 visit_type_str(v, name, &p, errp); 841 } 842 843 /* 844 * Parse [<domain>:]<bus>:<slot>.<func> 845 * if <domain> is not supplied, it's assumed to be 0. 846 */ 847 static void set_pci_host_devaddr(Object *obj, Visitor *v, const char *name, 848 void *opaque, Error **errp) 849 { 850 DeviceState *dev = DEVICE(obj); 851 Property *prop = opaque; 852 PCIHostDeviceAddress *addr = qdev_get_prop_ptr(obj, prop); 853 char *str, *p; 854 char *e; 855 unsigned long val; 856 unsigned long dom = 0, bus = 0; 857 unsigned int slot = 0, func = 0; 858 859 if (dev->realized) { 860 qdev_prop_set_after_realize(dev, name, errp); 861 return; 862 } 863 864 if (!visit_type_str(v, name, &str, errp)) { 865 return; 866 } 867 868 p = str; 869 val = strtoul(p, &e, 16); 870 if (e == p || *e != ':') { 871 goto inval; 872 } 873 bus = val; 874 875 p = e + 1; 876 val = strtoul(p, &e, 16); 877 if (e == p) { 878 goto inval; 879 } 880 if (*e == ':') { 881 dom = bus; 882 bus = val; 883 p = e + 1; 884 val = strtoul(p, &e, 16); 885 if (e == p) { 886 goto inval; 887 } 888 } 889 slot = val; 890 891 if (*e != '.') { 892 goto inval; 893 } 894 p = e + 1; 895 val = strtoul(p, &e, 10); 896 if (e == p) { 897 goto inval; 898 } 899 func = val; 900 901 if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) { 902 goto inval; 903 } 904 905 if (*e) { 906 goto inval; 907 } 908 909 addr->domain = dom; 910 addr->bus = bus; 911 addr->slot = slot; 912 addr->function = func; 913 914 g_free(str); 915 return; 916 917 inval: 918 error_set_from_qdev_prop_error(errp, EINVAL, obj, prop, str); 919 g_free(str); 920 } 921 922 const PropertyInfo qdev_prop_pci_host_devaddr = { 923 .name = "str", 924 .description = "Address (bus/device/function) of " 925 "the host device, example: 04:10.0", 926 .get = get_pci_host_devaddr, 927 .set = set_pci_host_devaddr, 928 }; 929 930 /* --- OffAutoPCIBAR off/auto/bar0/bar1/bar2/bar3/bar4/bar5 --- */ 931 932 const PropertyInfo qdev_prop_off_auto_pcibar = { 933 .name = "OffAutoPCIBAR", 934 .description = "off/auto/bar0/bar1/bar2/bar3/bar4/bar5", 935 .enum_table = &OffAutoPCIBAR_lookup, 936 .get = qdev_propinfo_get_enum, 937 .set = qdev_propinfo_set_enum, 938 .set_default_value = qdev_propinfo_set_default_value_enum, 939 }; 940 941 /* --- PCIELinkSpeed 2_5/5/8/16 -- */ 942 943 static void get_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name, 944 void *opaque, Error **errp) 945 { 946 Property *prop = opaque; 947 PCIExpLinkSpeed *p = qdev_get_prop_ptr(obj, prop); 948 int speed; 949 950 switch (*p) { 951 case QEMU_PCI_EXP_LNK_2_5GT: 952 speed = PCIE_LINK_SPEED_2_5; 953 break; 954 case QEMU_PCI_EXP_LNK_5GT: 955 speed = PCIE_LINK_SPEED_5; 956 break; 957 case QEMU_PCI_EXP_LNK_8GT: 958 speed = PCIE_LINK_SPEED_8; 959 break; 960 case QEMU_PCI_EXP_LNK_16GT: 961 speed = PCIE_LINK_SPEED_16; 962 break; 963 default: 964 /* Unreachable */ 965 abort(); 966 } 967 968 visit_type_enum(v, prop->name, &speed, prop->info->enum_table, errp); 969 } 970 971 static void set_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name, 972 void *opaque, Error **errp) 973 { 974 DeviceState *dev = DEVICE(obj); 975 Property *prop = opaque; 976 PCIExpLinkSpeed *p = qdev_get_prop_ptr(obj, prop); 977 int speed; 978 979 if (dev->realized) { 980 qdev_prop_set_after_realize(dev, name, errp); 981 return; 982 } 983 984 if (!visit_type_enum(v, prop->name, &speed, prop->info->enum_table, 985 errp)) { 986 return; 987 } 988 989 switch (speed) { 990 case PCIE_LINK_SPEED_2_5: 991 *p = QEMU_PCI_EXP_LNK_2_5GT; 992 break; 993 case PCIE_LINK_SPEED_5: 994 *p = QEMU_PCI_EXP_LNK_5GT; 995 break; 996 case PCIE_LINK_SPEED_8: 997 *p = QEMU_PCI_EXP_LNK_8GT; 998 break; 999 case PCIE_LINK_SPEED_16: 1000 *p = QEMU_PCI_EXP_LNK_16GT; 1001 break; 1002 default: 1003 /* Unreachable */ 1004 abort(); 1005 } 1006 } 1007 1008 const PropertyInfo qdev_prop_pcie_link_speed = { 1009 .name = "PCIELinkSpeed", 1010 .description = "2_5/5/8/16", 1011 .enum_table = &PCIELinkSpeed_lookup, 1012 .get = get_prop_pcielinkspeed, 1013 .set = set_prop_pcielinkspeed, 1014 .set_default_value = qdev_propinfo_set_default_value_enum, 1015 }; 1016 1017 /* --- PCIELinkWidth 1/2/4/8/12/16/32 -- */ 1018 1019 static void get_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name, 1020 void *opaque, Error **errp) 1021 { 1022 Property *prop = opaque; 1023 PCIExpLinkWidth *p = qdev_get_prop_ptr(obj, prop); 1024 int width; 1025 1026 switch (*p) { 1027 case QEMU_PCI_EXP_LNK_X1: 1028 width = PCIE_LINK_WIDTH_1; 1029 break; 1030 case QEMU_PCI_EXP_LNK_X2: 1031 width = PCIE_LINK_WIDTH_2; 1032 break; 1033 case QEMU_PCI_EXP_LNK_X4: 1034 width = PCIE_LINK_WIDTH_4; 1035 break; 1036 case QEMU_PCI_EXP_LNK_X8: 1037 width = PCIE_LINK_WIDTH_8; 1038 break; 1039 case QEMU_PCI_EXP_LNK_X12: 1040 width = PCIE_LINK_WIDTH_12; 1041 break; 1042 case QEMU_PCI_EXP_LNK_X16: 1043 width = PCIE_LINK_WIDTH_16; 1044 break; 1045 case QEMU_PCI_EXP_LNK_X32: 1046 width = PCIE_LINK_WIDTH_32; 1047 break; 1048 default: 1049 /* Unreachable */ 1050 abort(); 1051 } 1052 1053 visit_type_enum(v, prop->name, &width, prop->info->enum_table, errp); 1054 } 1055 1056 static void set_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name, 1057 void *opaque, Error **errp) 1058 { 1059 DeviceState *dev = DEVICE(obj); 1060 Property *prop = opaque; 1061 PCIExpLinkWidth *p = qdev_get_prop_ptr(obj, prop); 1062 int width; 1063 1064 if (dev->realized) { 1065 qdev_prop_set_after_realize(dev, name, errp); 1066 return; 1067 } 1068 1069 if (!visit_type_enum(v, prop->name, &width, prop->info->enum_table, 1070 errp)) { 1071 return; 1072 } 1073 1074 switch (width) { 1075 case PCIE_LINK_WIDTH_1: 1076 *p = QEMU_PCI_EXP_LNK_X1; 1077 break; 1078 case PCIE_LINK_WIDTH_2: 1079 *p = QEMU_PCI_EXP_LNK_X2; 1080 break; 1081 case PCIE_LINK_WIDTH_4: 1082 *p = QEMU_PCI_EXP_LNK_X4; 1083 break; 1084 case PCIE_LINK_WIDTH_8: 1085 *p = QEMU_PCI_EXP_LNK_X8; 1086 break; 1087 case PCIE_LINK_WIDTH_12: 1088 *p = QEMU_PCI_EXP_LNK_X12; 1089 break; 1090 case PCIE_LINK_WIDTH_16: 1091 *p = QEMU_PCI_EXP_LNK_X16; 1092 break; 1093 case PCIE_LINK_WIDTH_32: 1094 *p = QEMU_PCI_EXP_LNK_X32; 1095 break; 1096 default: 1097 /* Unreachable */ 1098 abort(); 1099 } 1100 } 1101 1102 const PropertyInfo qdev_prop_pcie_link_width = { 1103 .name = "PCIELinkWidth", 1104 .description = "1/2/4/8/12/16/32", 1105 .enum_table = &PCIELinkWidth_lookup, 1106 .get = get_prop_pcielinkwidth, 1107 .set = set_prop_pcielinkwidth, 1108 .set_default_value = qdev_propinfo_set_default_value_enum, 1109 }; 1110 1111 /* --- UUID --- */ 1112 1113 static void get_uuid(Object *obj, Visitor *v, const char *name, void *opaque, 1114 Error **errp) 1115 { 1116 Property *prop = opaque; 1117 QemuUUID *uuid = qdev_get_prop_ptr(obj, prop); 1118 char buffer[UUID_FMT_LEN + 1]; 1119 char *p = buffer; 1120 1121 qemu_uuid_unparse(uuid, buffer); 1122 1123 visit_type_str(v, name, &p, errp); 1124 } 1125 1126 #define UUID_VALUE_AUTO "auto" 1127 1128 static void set_uuid(Object *obj, Visitor *v, const char *name, void *opaque, 1129 Error **errp) 1130 { 1131 DeviceState *dev = DEVICE(obj); 1132 Property *prop = opaque; 1133 QemuUUID *uuid = qdev_get_prop_ptr(obj, prop); 1134 char *str; 1135 1136 if (dev->realized) { 1137 qdev_prop_set_after_realize(dev, name, errp); 1138 return; 1139 } 1140 1141 if (!visit_type_str(v, name, &str, errp)) { 1142 return; 1143 } 1144 1145 if (!strcmp(str, UUID_VALUE_AUTO)) { 1146 qemu_uuid_generate(uuid); 1147 } else if (qemu_uuid_parse(str, uuid) < 0) { 1148 error_set_from_qdev_prop_error(errp, EINVAL, obj, prop, str); 1149 } 1150 g_free(str); 1151 } 1152 1153 static void set_default_uuid_auto(ObjectProperty *op, const Property *prop) 1154 { 1155 object_property_set_default_str(op, UUID_VALUE_AUTO); 1156 } 1157 1158 const PropertyInfo qdev_prop_uuid = { 1159 .name = "str", 1160 .description = "UUID (aka GUID) or \"" UUID_VALUE_AUTO 1161 "\" for random value (default)", 1162 .get = get_uuid, 1163 .set = set_uuid, 1164 .set_default_value = set_default_uuid_auto, 1165 }; 1166