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