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