Merge tag 'pull-loongarch-20241016' of https://gitlab.com/gaosong/qemu into staging
[qemu/armbru.git] / hw / core / qdev-properties-system.c
blob60bcd821de32ff2412b756cefb06d6ccabcf5e7c
1 /*
2 * qdev property parsing
3 * (parts specific for qemu-system-*)
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.
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.
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/qapi-visit-virtio.h"
22 #include "qapi/qmp/qerror.h"
23 #include "qemu/ctype.h"
24 #include "qemu/cutils.h"
25 #include "qemu/units.h"
26 #include "qemu/uuid.h"
27 #include "qemu/error-report.h"
28 #include "qdev-prop-internal.h"
30 #include "audio/audio.h"
31 #include "chardev/char-fe.h"
32 #include "sysemu/block-backend.h"
33 #include "sysemu/blockdev.h"
34 #include "net/net.h"
35 #include "hw/pci/pci.h"
36 #include "hw/pci/pcie.h"
37 #include "hw/i386/x86.h"
38 #include "util/block-helpers.h"
40 static bool check_prop_still_unset(Object *obj, const char *name,
41 const void *old_val, const char *new_val,
42 bool allow_override, Error **errp)
44 const GlobalProperty *prop = qdev_find_global_prop(obj, name);
46 if (!old_val || (!prop && allow_override)) {
47 return true;
50 if (prop) {
51 error_setg(errp, "-global %s.%s=... conflicts with %s=%s",
52 prop->driver, prop->property, name, new_val);
53 } else {
54 /* Error message is vague, but a better one would be hard */
55 error_setg(errp, "%s=%s conflicts, and override is not implemented",
56 name, new_val);
58 return false;
62 /* --- drive --- */
64 static void get_drive(Object *obj, Visitor *v, const char *name, void *opaque,
65 Error **errp)
67 Property *prop = opaque;
68 void **ptr = object_field_prop_ptr(obj, prop);
69 const char *value;
70 char *p;
72 if (*ptr) {
73 value = blk_name(*ptr);
74 if (!*value) {
75 BlockDriverState *bs = blk_bs(*ptr);
76 if (bs) {
77 value = bdrv_get_node_name(bs);
80 } else {
81 value = "";
84 p = g_strdup(value);
85 visit_type_str(v, name, &p, errp);
86 g_free(p);
89 static void set_drive_helper(Object *obj, Visitor *v, const char *name,
90 void *opaque, bool iothread, Error **errp)
92 DeviceState *dev = DEVICE(obj);
93 Property *prop = opaque;
94 void **ptr = object_field_prop_ptr(obj, prop);
95 char *str;
96 BlockBackend *blk;
97 bool blk_created = false;
98 int ret;
99 BlockDriverState *bs;
100 AioContext *ctx;
102 if (!visit_type_str(v, name, &str, errp)) {
103 return;
106 if (!check_prop_still_unset(obj, name, *ptr, str, true, errp)) {
107 return;
110 if (*ptr) {
111 /* BlockBackend already exists. So, we want to change attached node */
112 blk = *ptr;
113 ctx = blk_get_aio_context(blk);
114 bs = bdrv_lookup_bs(NULL, str, errp);
115 if (!bs) {
116 return;
119 if (ctx != bdrv_get_aio_context(bs)) {
120 error_setg(errp, "Different aio context is not supported for new "
121 "node");
124 blk_replace_bs(blk, bs, errp);
125 return;
128 if (!*str) {
129 g_free(str);
130 *ptr = NULL;
131 return;
134 blk = blk_by_name(str);
135 if (!blk) {
136 bs = bdrv_lookup_bs(NULL, str, NULL);
137 if (bs) {
139 * If the device supports iothreads, it will make sure to move the
140 * block node to the right AioContext if necessary (or fail if this
141 * isn't possible because of other users). Devices that are not
142 * aware of iothreads require their BlockBackends to be in the main
143 * AioContext.
145 ctx = bdrv_get_aio_context(bs);
146 blk = blk_new(iothread ? ctx : qemu_get_aio_context(),
147 0, BLK_PERM_ALL);
148 blk_created = true;
150 ret = blk_insert_bs(blk, bs, errp);
151 if (ret < 0) {
152 goto fail;
156 if (!blk) {
157 error_setg(errp, "Property '%s.%s' can't find value '%s'",
158 object_get_typename(OBJECT(dev)), name, str);
159 goto fail;
161 if (blk_attach_dev(blk, dev) < 0) {
162 DriveInfo *dinfo = blk_legacy_dinfo(blk);
164 if (dinfo && dinfo->type != IF_NONE) {
165 error_setg(errp, "Drive '%s' is already in use because "
166 "it has been automatically connected to another "
167 "device (did you need 'if=none' in the drive options?)",
168 str);
169 } else {
170 error_setg(errp, "Drive '%s' is already in use by another device",
171 str);
173 goto fail;
176 *ptr = blk;
178 fail:
179 if (blk_created) {
180 /* If we need to keep a reference, blk_attach_dev() took it */
181 blk_unref(blk);
184 g_free(str);
187 static void set_drive(Object *obj, Visitor *v, const char *name, void *opaque,
188 Error **errp)
190 set_drive_helper(obj, v, name, opaque, false, errp);
193 static void set_drive_iothread(Object *obj, Visitor *v, const char *name,
194 void *opaque, Error **errp)
196 set_drive_helper(obj, v, name, opaque, true, errp);
199 static void release_drive(Object *obj, const char *name, void *opaque)
201 DeviceState *dev = DEVICE(obj);
202 Property *prop = opaque;
203 BlockBackend **ptr = object_field_prop_ptr(obj, prop);
205 if (*ptr) {
206 blockdev_auto_del(*ptr);
207 blk_detach_dev(*ptr, dev);
211 const PropertyInfo qdev_prop_drive = {
212 .name = "str",
213 .description = "Node name or ID of a block device to use as a backend",
214 .realized_set_allowed = true,
215 .get = get_drive,
216 .set = set_drive,
217 .release = release_drive,
220 const PropertyInfo qdev_prop_drive_iothread = {
221 .name = "str",
222 .description = "Node name or ID of a block device to use as a backend",
223 .realized_set_allowed = true,
224 .get = get_drive,
225 .set = set_drive_iothread,
226 .release = release_drive,
229 /* --- character device --- */
231 static void get_chr(Object *obj, Visitor *v, const char *name, void *opaque,
232 Error **errp)
234 CharBackend *be = object_field_prop_ptr(obj, opaque);
235 char *p;
237 p = g_strdup(be->chr && be->chr->label ? be->chr->label : "");
238 visit_type_str(v, name, &p, errp);
239 g_free(p);
242 static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque,
243 Error **errp)
245 ERRP_GUARD();
246 Property *prop = opaque;
247 CharBackend *be = object_field_prop_ptr(obj, prop);
248 Chardev *s;
249 char *str;
251 if (!visit_type_str(v, name, &str, errp)) {
252 return;
256 * TODO Should this really be an error? If no, the old value
257 * needs to be released before we store the new one.
259 if (!check_prop_still_unset(obj, name, be->chr, str, false, errp)) {
260 return;
263 if (!*str) {
264 g_free(str);
265 be->chr = NULL;
266 return;
269 s = qemu_chr_find(str);
270 if (s == NULL) {
271 error_setg(errp, "Property '%s.%s' can't find value '%s'",
272 object_get_typename(obj), name, str);
273 } else if (!qemu_chr_fe_init(be, s, errp)) {
274 error_prepend(errp, "Property '%s.%s' can't take value '%s': ",
275 object_get_typename(obj), name, str);
277 g_free(str);
280 static void release_chr(Object *obj, const char *name, void *opaque)
282 Property *prop = opaque;
283 CharBackend *be = object_field_prop_ptr(obj, prop);
285 qemu_chr_fe_deinit(be, false);
288 const PropertyInfo qdev_prop_chr = {
289 .name = "str",
290 .description = "ID of a chardev to use as a backend",
291 .get = get_chr,
292 .set = set_chr,
293 .release = release_chr,
296 /* --- mac address --- */
299 * accepted syntax versions:
300 * 01:02:03:04:05:06
301 * 01-02-03-04-05-06
303 static void get_mac(Object *obj, Visitor *v, const char *name, void *opaque,
304 Error **errp)
306 Property *prop = opaque;
307 MACAddr *mac = object_field_prop_ptr(obj, prop);
308 char buffer[2 * 6 + 5 + 1];
309 char *p = buffer;
311 snprintf(buffer, sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x",
312 mac->a[0], mac->a[1], mac->a[2],
313 mac->a[3], mac->a[4], mac->a[5]);
315 visit_type_str(v, name, &p, errp);
318 static void set_mac(Object *obj, Visitor *v, const char *name, void *opaque,
319 Error **errp)
321 Property *prop = opaque;
322 MACAddr *mac = object_field_prop_ptr(obj, prop);
323 int i, pos;
324 char *str;
325 const char *p;
327 if (!visit_type_str(v, name, &str, errp)) {
328 return;
331 for (i = 0, pos = 0; i < 6; i++, pos += 3) {
332 long val;
334 if (!qemu_isxdigit(str[pos])) {
335 goto inval;
337 if (!qemu_isxdigit(str[pos + 1])) {
338 goto inval;
340 if (i == 5) {
341 if (str[pos + 2] != '\0') {
342 goto inval;
344 } else {
345 if (str[pos + 2] != ':' && str[pos + 2] != '-') {
346 goto inval;
349 if (qemu_strtol(str + pos, &p, 16, &val) < 0 || val > 0xff) {
350 goto inval;
352 mac->a[i] = val;
354 g_free(str);
355 return;
357 inval:
358 error_set_from_qdev_prop_error(errp, EINVAL, obj, name, str);
359 g_free(str);
362 const PropertyInfo qdev_prop_macaddr = {
363 .name = "str",
364 .description = "Ethernet 6-byte MAC Address, example: 52:54:00:12:34:56",
365 .get = get_mac,
366 .set = set_mac,
369 void qdev_prop_set_macaddr(DeviceState *dev, const char *name,
370 const uint8_t *value)
372 char str[2 * 6 + 5 + 1];
373 snprintf(str, sizeof(str), "%02x:%02x:%02x:%02x:%02x:%02x",
374 value[0], value[1], value[2], value[3], value[4], value[5]);
376 object_property_set_str(OBJECT(dev), name, str, &error_abort);
379 /* --- netdev device --- */
380 static void get_netdev(Object *obj, Visitor *v, const char *name,
381 void *opaque, Error **errp)
383 Property *prop = opaque;
384 NICPeers *peers_ptr = object_field_prop_ptr(obj, prop);
385 char *p = g_strdup(peers_ptr->ncs[0] ? peers_ptr->ncs[0]->name : "");
387 visit_type_str(v, name, &p, errp);
388 g_free(p);
391 static void set_netdev(Object *obj, Visitor *v, const char *name,
392 void *opaque, Error **errp)
394 Property *prop = opaque;
395 NICPeers *peers_ptr = object_field_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;
401 if (!visit_type_str(v, name, &str, errp)) {
402 return;
405 queues = qemu_find_net_clients_except(str, peers,
406 NET_CLIENT_DRIVER_NIC,
407 MAX_QUEUE_NUM);
408 if (queues == 0) {
409 err = -ENOENT;
410 goto out;
413 if (queues > MAX_QUEUE_NUM) {
414 error_setg(errp, "queues of backend '%s'(%d) exceeds QEMU limitation(%d)",
415 str, queues, MAX_QUEUE_NUM);
416 goto out;
419 for (i = 0; i < queues; i++) {
420 if (peers[i]->peer) {
421 err = -EEXIST;
422 goto out;
426 * TODO Should this really be an error? If no, the old value
427 * needs to be released before we store the new one.
429 if (!check_prop_still_unset(obj, name, ncs[i], str, false, errp)) {
430 goto out;
433 if (peers[i]->info->check_peer_type) {
434 if (!peers[i]->info->check_peer_type(peers[i], obj->class, errp)) {
435 goto out;
439 ncs[i] = peers[i];
440 ncs[i]->queue_index = i;
443 peers_ptr->queues = queues;
445 out:
446 error_set_from_qdev_prop_error(errp, err, obj, prop->name, str);
447 g_free(str);
450 const PropertyInfo qdev_prop_netdev = {
451 .name = "str",
452 .description = "ID of a netdev to use as a backend",
453 .get = get_netdev,
454 .set = set_netdev,
458 /* --- audiodev --- */
459 static void get_audiodev(Object *obj, Visitor *v, const char* name,
460 void *opaque, Error **errp)
462 Property *prop = opaque;
463 QEMUSoundCard *card = object_field_prop_ptr(obj, prop);
464 char *p = g_strdup(audio_get_id(card));
466 visit_type_str(v, name, &p, errp);
467 g_free(p);
470 static void set_audiodev(Object *obj, Visitor *v, const char* name,
471 void *opaque, Error **errp)
473 Property *prop = opaque;
474 QEMUSoundCard *card = object_field_prop_ptr(obj, prop);
475 AudioState *state;
476 g_autofree char *str = NULL;
478 if (!visit_type_str(v, name, &str, errp)) {
479 return;
482 state = audio_state_by_name(str, errp);
483 if (state) {
484 card->state = state;
488 const PropertyInfo qdev_prop_audiodev = {
489 .name = "str",
490 .description = "ID of an audiodev to use as a backend",
491 /* release done on shutdown */
492 .get = get_audiodev,
493 .set = set_audiodev,
496 bool qdev_prop_set_drive_err(DeviceState *dev, const char *name,
497 BlockBackend *value, Error **errp)
499 const char *ref = "";
501 if (value) {
502 ref = blk_name(value);
503 if (!*ref) {
504 const BlockDriverState *bs = blk_bs(value);
505 if (bs) {
506 ref = bdrv_get_node_name(bs);
511 return object_property_set_str(OBJECT(dev), name, ref, errp);
514 void qdev_prop_set_drive(DeviceState *dev, const char *name,
515 BlockBackend *value)
517 qdev_prop_set_drive_err(dev, name, value, &error_abort);
520 void qdev_prop_set_chr(DeviceState *dev, const char *name,
521 Chardev *value)
523 assert(!value || value->label);
524 object_property_set_str(OBJECT(dev), name, value ? value->label : "",
525 &error_abort);
528 void qdev_prop_set_netdev(DeviceState *dev, const char *name,
529 NetClientState *value)
531 assert(!value || value->name);
532 object_property_set_str(OBJECT(dev), name, value ? value->name : "",
533 &error_abort);
536 void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
538 qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
539 if (nd->netdev) {
540 qdev_prop_set_netdev(dev, "netdev", nd->netdev);
542 if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
543 object_property_find(OBJECT(dev), "vectors")) {
544 qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
546 nd->instantiated = 1;
549 /* --- lost tick policy --- */
551 static void qdev_propinfo_set_losttickpolicy(Object *obj, Visitor *v,
552 const char *name, void *opaque,
553 Error **errp)
555 Property *prop = opaque;
556 int *ptr = object_field_prop_ptr(obj, prop);
557 int value;
559 if (!visit_type_enum(v, name, &value, prop->info->enum_table, errp)) {
560 return;
563 if (value == LOST_TICK_POLICY_SLEW) {
564 MachineState *ms = MACHINE(qdev_get_machine());
566 if (!object_dynamic_cast(OBJECT(ms), TYPE_X86_MACHINE)) {
567 error_setg(errp,
568 "the 'slew' policy is only available for x86 machines");
569 return;
573 *ptr = value;
576 QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int));
578 const PropertyInfo qdev_prop_losttickpolicy = {
579 .name = "LostTickPolicy",
580 .enum_table = &LostTickPolicy_lookup,
581 .get = qdev_propinfo_get_enum,
582 .set = qdev_propinfo_set_losttickpolicy,
583 .set_default_value = qdev_propinfo_set_default_value_enum,
586 /* --- blocksize --- */
588 static void set_blocksize(Object *obj, Visitor *v, const char *name,
589 void *opaque, Error **errp)
591 DeviceState *dev = DEVICE(obj);
592 Property *prop = opaque;
593 uint32_t *ptr = object_field_prop_ptr(obj, prop);
594 uint64_t value;
595 Error *local_err = NULL;
597 if (!visit_type_size(v, name, &value, errp)) {
598 return;
600 check_block_size(dev->id ? : "", name, value, &local_err);
601 if (local_err) {
602 error_propagate(errp, local_err);
603 return;
605 *ptr = value;
608 const PropertyInfo qdev_prop_blocksize = {
609 .name = "size",
610 .description = "A power of two between " MIN_BLOCK_SIZE_STR
611 " and " MAX_BLOCK_SIZE_STR,
612 .get = qdev_propinfo_get_size32,
613 .set = set_blocksize,
614 .set_default_value = qdev_propinfo_set_default_value_uint,
617 /* --- Block device error handling policy --- */
619 QEMU_BUILD_BUG_ON(sizeof(BlockdevOnError) != sizeof(int));
621 const PropertyInfo qdev_prop_blockdev_on_error = {
622 .name = "BlockdevOnError",
623 .description = "Error handling policy, "
624 "report/ignore/enospc/stop/auto",
625 .enum_table = &BlockdevOnError_lookup,
626 .get = qdev_propinfo_get_enum,
627 .set = qdev_propinfo_set_enum,
628 .set_default_value = qdev_propinfo_set_default_value_enum,
631 /* --- BIOS CHS translation */
633 QEMU_BUILD_BUG_ON(sizeof(BiosAtaTranslation) != sizeof(int));
635 const PropertyInfo qdev_prop_bios_chs_trans = {
636 .name = "BiosAtaTranslation",
637 .description = "Logical CHS translation algorithm, "
638 "auto/none/lba/large/rechs",
639 .enum_table = &BiosAtaTranslation_lookup,
640 .get = qdev_propinfo_get_enum,
641 .set = qdev_propinfo_set_enum,
642 .set_default_value = qdev_propinfo_set_default_value_enum,
645 /* --- FDC default drive types */
647 const PropertyInfo qdev_prop_fdc_drive_type = {
648 .name = "FdcDriveType",
649 .description = "FDC drive type, "
650 "144/288/120/none/auto",
651 .enum_table = &FloppyDriveType_lookup,
652 .get = qdev_propinfo_get_enum,
653 .set = qdev_propinfo_set_enum,
654 .set_default_value = qdev_propinfo_set_default_value_enum,
657 /* --- MultiFDCompression --- */
659 const PropertyInfo qdev_prop_multifd_compression = {
660 .name = "MultiFDCompression",
661 .description = "multifd_compression values, "
662 "none/zlib/zstd/qpl/uadk/qatzip",
663 .enum_table = &MultiFDCompression_lookup,
664 .get = qdev_propinfo_get_enum,
665 .set = qdev_propinfo_set_enum,
666 .set_default_value = qdev_propinfo_set_default_value_enum,
669 /* --- MigMode --- */
671 QEMU_BUILD_BUG_ON(sizeof(MigMode) != sizeof(int));
673 const PropertyInfo qdev_prop_mig_mode = {
674 .name = "MigMode",
675 .description = "mig_mode values, "
676 "normal,cpr-reboot",
677 .enum_table = &MigMode_lookup,
678 .get = qdev_propinfo_get_enum,
679 .set = qdev_propinfo_set_enum,
680 .set_default_value = qdev_propinfo_set_default_value_enum,
683 /* --- GranuleMode --- */
685 QEMU_BUILD_BUG_ON(sizeof(GranuleMode) != sizeof(int));
687 const PropertyInfo qdev_prop_granule_mode = {
688 .name = "GranuleMode",
689 .description = "granule_mode values, "
690 "4k, 8k, 16k, 64k, host",
691 .enum_table = &GranuleMode_lookup,
692 .get = qdev_propinfo_get_enum,
693 .set = qdev_propinfo_set_enum,
694 .set_default_value = qdev_propinfo_set_default_value_enum,
697 const PropertyInfo qdev_prop_zero_page_detection = {
698 .name = "ZeroPageDetection",
699 .description = "zero_page_detection values, "
700 "none,legacy,multifd",
701 .enum_table = &ZeroPageDetection_lookup,
702 .get = qdev_propinfo_get_enum,
703 .set = qdev_propinfo_set_enum,
704 .set_default_value = qdev_propinfo_set_default_value_enum,
707 /* --- Reserved Region --- */
710 * Accepted syntax:
711 * <low address>:<high address>:<type>
712 * where low/high addresses are uint64_t in hexadecimal
713 * and type is a non-negative decimal integer
715 static void get_reserved_region(Object *obj, Visitor *v, const char *name,
716 void *opaque, Error **errp)
718 Property *prop = opaque;
719 ReservedRegion *rr = object_field_prop_ptr(obj, prop);
720 char buffer[64];
721 char *p = buffer;
722 int rc;
724 rc = snprintf(buffer, sizeof(buffer), "0x%"PRIx64":0x%"PRIx64":%u",
725 range_lob(&rr->range), range_upb(&rr->range), rr->type);
726 assert(rc < sizeof(buffer));
728 visit_type_str(v, name, &p, errp);
731 static void set_reserved_region(Object *obj, Visitor *v, const char *name,
732 void *opaque, Error **errp)
734 Property *prop = opaque;
735 ReservedRegion *rr = object_field_prop_ptr(obj, prop);
736 const char *endptr;
737 uint64_t lob, upb;
738 char *str;
739 int ret;
741 if (!visit_type_str(v, name, &str, errp)) {
742 return;
745 ret = qemu_strtou64(str, &endptr, 16, &lob);
746 if (ret) {
747 error_setg(errp, "start address of '%s'"
748 " must be a hexadecimal integer", name);
749 goto out;
751 if (*endptr != ':') {
752 goto separator_error;
755 ret = qemu_strtou64(endptr + 1, &endptr, 16, &upb);
756 if (ret) {
757 error_setg(errp, "end address of '%s'"
758 " must be a hexadecimal integer", name);
759 goto out;
761 if (*endptr != ':') {
762 goto separator_error;
765 range_set_bounds(&rr->range, lob, upb);
767 ret = qemu_strtoui(endptr + 1, &endptr, 10, &rr->type);
768 if (ret) {
769 error_setg(errp, "type of '%s'"
770 " must be a non-negative decimal integer", name);
772 goto out;
774 separator_error:
775 error_setg(errp, "reserved region fields must be separated with ':'");
776 out:
777 g_free(str);
778 return;
781 const PropertyInfo qdev_prop_reserved_region = {
782 .name = "reserved_region",
783 .description = "Reserved Region, example: 0xFEE00000:0xFEEFFFFF:0",
784 .get = get_reserved_region,
785 .set = set_reserved_region,
788 /* --- pci address --- */
791 * bus-local address, i.e. "$slot" or "$slot.$fn"
793 static void set_pci_devfn(Object *obj, Visitor *v, const char *name,
794 void *opaque, Error **errp)
796 Property *prop = opaque;
797 int32_t value, *ptr = object_field_prop_ptr(obj, prop);
798 unsigned int slot, fn, n;
799 char *str;
801 if (!visit_type_str(v, name, &str, NULL)) {
802 if (!visit_type_int32(v, name, &value, errp)) {
803 return;
805 if (value < -1 || value > 255) {
806 error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
807 name ? name : "null", "a value between -1 and 255");
808 return;
810 *ptr = value;
811 return;
814 if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
815 fn = 0;
816 if (sscanf(str, "%x%n", &slot, &n) != 1) {
817 goto invalid;
820 if (str[n] != '\0' || fn > 7 || slot > 31) {
821 goto invalid;
823 *ptr = slot << 3 | fn;
824 g_free(str);
825 return;
827 invalid:
828 error_set_from_qdev_prop_error(errp, EINVAL, obj, name, str);
829 g_free(str);
832 static int print_pci_devfn(Object *obj, Property *prop, char *dest,
833 size_t len)
835 int32_t *ptr = object_field_prop_ptr(obj, prop);
837 if (*ptr == -1) {
838 return snprintf(dest, len, "<unset>");
839 } else {
840 return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7);
844 const PropertyInfo qdev_prop_pci_devfn = {
845 .name = "int32",
846 .description = "Slot and optional function number, example: 06.0 or 06",
847 .print = print_pci_devfn,
848 .get = qdev_propinfo_get_int32,
849 .set = set_pci_devfn,
850 .set_default_value = qdev_propinfo_set_default_value_int,
853 /* --- pci host address --- */
855 static void get_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
856 void *opaque, Error **errp)
858 Property *prop = opaque;
859 PCIHostDeviceAddress *addr = object_field_prop_ptr(obj, prop);
860 char buffer[] = "ffff:ff:ff.f";
861 char *p = buffer;
862 int rc = 0;
865 * Catch "invalid" device reference from vfio-pci and allow the
866 * default buffer representing the non-existent device to be used.
868 if (~addr->domain || ~addr->bus || ~addr->slot || ~addr->function) {
869 rc = snprintf(buffer, sizeof(buffer), "%04x:%02x:%02x.%0d",
870 addr->domain, addr->bus, addr->slot, addr->function);
871 assert(rc == sizeof(buffer) - 1);
874 visit_type_str(v, name, &p, errp);
878 * Parse [<domain>:]<bus>:<slot>.<func>
879 * if <domain> is not supplied, it's assumed to be 0.
881 static void set_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
882 void *opaque, Error **errp)
884 Property *prop = opaque;
885 PCIHostDeviceAddress *addr = object_field_prop_ptr(obj, prop);
886 char *str, *p;
887 char *e;
888 unsigned long val;
889 unsigned long dom = 0, bus = 0;
890 unsigned int slot = 0, func = 0;
892 if (!visit_type_str(v, name, &str, errp)) {
893 return;
896 p = str;
897 val = strtoul(p, &e, 16);
898 if (e == p || *e != ':') {
899 goto inval;
901 bus = val;
903 p = e + 1;
904 val = strtoul(p, &e, 16);
905 if (e == p) {
906 goto inval;
908 if (*e == ':') {
909 dom = bus;
910 bus = val;
911 p = e + 1;
912 val = strtoul(p, &e, 16);
913 if (e == p) {
914 goto inval;
917 slot = val;
919 if (*e != '.') {
920 goto inval;
922 p = e + 1;
923 val = strtoul(p, &e, 10);
924 if (e == p) {
925 goto inval;
927 func = val;
929 if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) {
930 goto inval;
933 if (*e) {
934 goto inval;
937 addr->domain = dom;
938 addr->bus = bus;
939 addr->slot = slot;
940 addr->function = func;
942 g_free(str);
943 return;
945 inval:
946 error_set_from_qdev_prop_error(errp, EINVAL, obj, name, str);
947 g_free(str);
950 const PropertyInfo qdev_prop_pci_host_devaddr = {
951 .name = "str",
952 .description = "Address (bus/device/function) of "
953 "the host device, example: 04:10.0",
954 .get = get_pci_host_devaddr,
955 .set = set_pci_host_devaddr,
958 /* --- OffAutoPCIBAR off/auto/bar0/bar1/bar2/bar3/bar4/bar5 --- */
960 const PropertyInfo qdev_prop_off_auto_pcibar = {
961 .name = "OffAutoPCIBAR",
962 .description = "off/auto/bar0/bar1/bar2/bar3/bar4/bar5",
963 .enum_table = &OffAutoPCIBAR_lookup,
964 .get = qdev_propinfo_get_enum,
965 .set = qdev_propinfo_set_enum,
966 .set_default_value = qdev_propinfo_set_default_value_enum,
969 /* --- PCIELinkSpeed 2_5/5/8/16/32/64 -- */
971 static void get_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
972 void *opaque, Error **errp)
974 Property *prop = opaque;
975 PCIExpLinkSpeed *p = object_field_prop_ptr(obj, prop);
976 int speed;
978 switch (*p) {
979 case QEMU_PCI_EXP_LNK_2_5GT:
980 speed = PCIE_LINK_SPEED_2_5;
981 break;
982 case QEMU_PCI_EXP_LNK_5GT:
983 speed = PCIE_LINK_SPEED_5;
984 break;
985 case QEMU_PCI_EXP_LNK_8GT:
986 speed = PCIE_LINK_SPEED_8;
987 break;
988 case QEMU_PCI_EXP_LNK_16GT:
989 speed = PCIE_LINK_SPEED_16;
990 break;
991 case QEMU_PCI_EXP_LNK_32GT:
992 speed = PCIE_LINK_SPEED_32;
993 break;
994 case QEMU_PCI_EXP_LNK_64GT:
995 speed = PCIE_LINK_SPEED_64;
996 break;
997 default:
998 /* Unreachable */
999 abort();
1002 visit_type_enum(v, name, &speed, prop->info->enum_table, errp);
1005 static void set_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
1006 void *opaque, Error **errp)
1008 Property *prop = opaque;
1009 PCIExpLinkSpeed *p = object_field_prop_ptr(obj, prop);
1010 int speed;
1012 if (!visit_type_enum(v, name, &speed, prop->info->enum_table,
1013 errp)) {
1014 return;
1017 switch (speed) {
1018 case PCIE_LINK_SPEED_2_5:
1019 *p = QEMU_PCI_EXP_LNK_2_5GT;
1020 break;
1021 case PCIE_LINK_SPEED_5:
1022 *p = QEMU_PCI_EXP_LNK_5GT;
1023 break;
1024 case PCIE_LINK_SPEED_8:
1025 *p = QEMU_PCI_EXP_LNK_8GT;
1026 break;
1027 case PCIE_LINK_SPEED_16:
1028 *p = QEMU_PCI_EXP_LNK_16GT;
1029 break;
1030 case PCIE_LINK_SPEED_32:
1031 *p = QEMU_PCI_EXP_LNK_32GT;
1032 break;
1033 case PCIE_LINK_SPEED_64:
1034 *p = QEMU_PCI_EXP_LNK_64GT;
1035 break;
1036 default:
1037 /* Unreachable */
1038 abort();
1042 const PropertyInfo qdev_prop_pcie_link_speed = {
1043 .name = "PCIELinkSpeed",
1044 .description = "2_5/5/8/16/32/64",
1045 .enum_table = &PCIELinkSpeed_lookup,
1046 .get = get_prop_pcielinkspeed,
1047 .set = set_prop_pcielinkspeed,
1048 .set_default_value = qdev_propinfo_set_default_value_enum,
1051 /* --- PCIELinkWidth 1/2/4/8/12/16/32 -- */
1053 static void get_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
1054 void *opaque, Error **errp)
1056 Property *prop = opaque;
1057 PCIExpLinkWidth *p = object_field_prop_ptr(obj, prop);
1058 int width;
1060 switch (*p) {
1061 case QEMU_PCI_EXP_LNK_X1:
1062 width = PCIE_LINK_WIDTH_1;
1063 break;
1064 case QEMU_PCI_EXP_LNK_X2:
1065 width = PCIE_LINK_WIDTH_2;
1066 break;
1067 case QEMU_PCI_EXP_LNK_X4:
1068 width = PCIE_LINK_WIDTH_4;
1069 break;
1070 case QEMU_PCI_EXP_LNK_X8:
1071 width = PCIE_LINK_WIDTH_8;
1072 break;
1073 case QEMU_PCI_EXP_LNK_X12:
1074 width = PCIE_LINK_WIDTH_12;
1075 break;
1076 case QEMU_PCI_EXP_LNK_X16:
1077 width = PCIE_LINK_WIDTH_16;
1078 break;
1079 case QEMU_PCI_EXP_LNK_X32:
1080 width = PCIE_LINK_WIDTH_32;
1081 break;
1082 default:
1083 /* Unreachable */
1084 abort();
1087 visit_type_enum(v, name, &width, prop->info->enum_table, errp);
1090 static void set_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
1091 void *opaque, Error **errp)
1093 Property *prop = opaque;
1094 PCIExpLinkWidth *p = object_field_prop_ptr(obj, prop);
1095 int width;
1097 if (!visit_type_enum(v, name, &width, prop->info->enum_table,
1098 errp)) {
1099 return;
1102 switch (width) {
1103 case PCIE_LINK_WIDTH_1:
1104 *p = QEMU_PCI_EXP_LNK_X1;
1105 break;
1106 case PCIE_LINK_WIDTH_2:
1107 *p = QEMU_PCI_EXP_LNK_X2;
1108 break;
1109 case PCIE_LINK_WIDTH_4:
1110 *p = QEMU_PCI_EXP_LNK_X4;
1111 break;
1112 case PCIE_LINK_WIDTH_8:
1113 *p = QEMU_PCI_EXP_LNK_X8;
1114 break;
1115 case PCIE_LINK_WIDTH_12:
1116 *p = QEMU_PCI_EXP_LNK_X12;
1117 break;
1118 case PCIE_LINK_WIDTH_16:
1119 *p = QEMU_PCI_EXP_LNK_X16;
1120 break;
1121 case PCIE_LINK_WIDTH_32:
1122 *p = QEMU_PCI_EXP_LNK_X32;
1123 break;
1124 default:
1125 /* Unreachable */
1126 abort();
1130 const PropertyInfo qdev_prop_pcie_link_width = {
1131 .name = "PCIELinkWidth",
1132 .description = "1/2/4/8/12/16/32",
1133 .enum_table = &PCIELinkWidth_lookup,
1134 .get = get_prop_pcielinkwidth,
1135 .set = set_prop_pcielinkwidth,
1136 .set_default_value = qdev_propinfo_set_default_value_enum,
1139 /* --- UUID --- */
1141 static void get_uuid(Object *obj, Visitor *v, const char *name, void *opaque,
1142 Error **errp)
1144 Property *prop = opaque;
1145 QemuUUID *uuid = object_field_prop_ptr(obj, prop);
1146 char buffer[UUID_STR_LEN];
1147 char *p = buffer;
1149 qemu_uuid_unparse(uuid, buffer);
1151 visit_type_str(v, name, &p, errp);
1154 #define UUID_VALUE_AUTO "auto"
1156 static void set_uuid(Object *obj, Visitor *v, const char *name, void *opaque,
1157 Error **errp)
1159 Property *prop = opaque;
1160 QemuUUID *uuid = object_field_prop_ptr(obj, prop);
1161 char *str;
1163 if (!visit_type_str(v, name, &str, errp)) {
1164 return;
1167 if (!strcmp(str, UUID_VALUE_AUTO)) {
1168 qemu_uuid_generate(uuid);
1169 } else if (qemu_uuid_parse(str, uuid) < 0) {
1170 error_set_from_qdev_prop_error(errp, EINVAL, obj, name, str);
1172 g_free(str);
1175 static void set_default_uuid_auto(ObjectProperty *op, const Property *prop)
1177 object_property_set_default_str(op, UUID_VALUE_AUTO);
1180 const PropertyInfo qdev_prop_uuid = {
1181 .name = "str",
1182 .description = "UUID (aka GUID) or \"" UUID_VALUE_AUTO
1183 "\" for random value (default)",
1184 .get = get_uuid,
1185 .set = set_uuid,
1186 .set_default_value = set_default_uuid_auto,
1189 /* --- s390 cpu entitlement policy --- */
1191 QEMU_BUILD_BUG_ON(sizeof(S390CpuEntitlement) != sizeof(int));
1193 const PropertyInfo qdev_prop_cpus390entitlement = {
1194 .name = "S390CpuEntitlement",
1195 .description = "low/medium (default)/high",
1196 .enum_table = &S390CpuEntitlement_lookup,
1197 .get = qdev_propinfo_get_enum,
1198 .set = qdev_propinfo_set_enum,
1199 .set_default_value = qdev_propinfo_set_default_value_enum,
1202 /* --- IOThreadVirtQueueMappingList --- */
1204 static void get_iothread_vq_mapping_list(Object *obj, Visitor *v,
1205 const char *name, void *opaque, Error **errp)
1207 IOThreadVirtQueueMappingList **prop_ptr =
1208 object_field_prop_ptr(obj, opaque);
1210 visit_type_IOThreadVirtQueueMappingList(v, name, prop_ptr, errp);
1213 static void set_iothread_vq_mapping_list(Object *obj, Visitor *v,
1214 const char *name, void *opaque, Error **errp)
1216 IOThreadVirtQueueMappingList **prop_ptr =
1217 object_field_prop_ptr(obj, opaque);
1218 IOThreadVirtQueueMappingList *list;
1220 if (!visit_type_IOThreadVirtQueueMappingList(v, name, &list, errp)) {
1221 return;
1224 qapi_free_IOThreadVirtQueueMappingList(*prop_ptr);
1225 *prop_ptr = list;
1228 static void release_iothread_vq_mapping_list(Object *obj,
1229 const char *name, void *opaque)
1231 IOThreadVirtQueueMappingList **prop_ptr =
1232 object_field_prop_ptr(obj, opaque);
1234 qapi_free_IOThreadVirtQueueMappingList(*prop_ptr);
1235 *prop_ptr = NULL;
1238 const PropertyInfo qdev_prop_iothread_vq_mapping_list = {
1239 .name = "IOThreadVirtQueueMappingList",
1240 .description = "IOThread virtqueue mapping list [{\"iothread\":\"<id>\", "
1241 "\"vqs\":[1,2,3,...]},...]",
1242 .get = get_iothread_vq_mapping_list,
1243 .set = set_iothread_vq_mapping_list,
1244 .release = release_iothread_vq_mapping_list,