xref: /qemu/hw/core/qdev-properties-system.c (revision d884e272)
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/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"
29 
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"
39 
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)
43 {
44     const GlobalProperty *prop = qdev_find_global_prop(obj, name);
45 
46     if (!old_val || (!prop && allow_override)) {
47         return true;
48     }
49 
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);
57     }
58     return false;
59 }
60 
61 
62 /* --- drive --- */
63 
64 static void get_drive(Object *obj, Visitor *v, const char *name, void *opaque,
65                       Error **errp)
66 {
67     Property *prop = opaque;
68     void **ptr = object_field_prop_ptr(obj, prop);
69     const char *value;
70     char *p;
71 
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);
78             }
79         }
80     } else {
81         value = "";
82     }
83 
84     p = g_strdup(value);
85     visit_type_str(v, name, &p, errp);
86     g_free(p);
87 }
88 
89 static void set_drive_helper(Object *obj, Visitor *v, const char *name,
90                              void *opaque, bool iothread, Error **errp)
91 {
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;
101 
102     if (!visit_type_str(v, name, &str, errp)) {
103         return;
104     }
105 
106     if (!check_prop_still_unset(obj, name, *ptr, str, true, errp)) {
107         return;
108     }
109 
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;
117         }
118 
119         if (ctx != bdrv_get_aio_context(bs)) {
120             error_setg(errp, "Different aio context is not supported for new "
121                        "node");
122         }
123 
124         blk_replace_bs(blk, bs, errp);
125         return;
126     }
127 
128     if (!*str) {
129         g_free(str);
130         *ptr = NULL;
131         return;
132     }
133 
134     blk = blk_by_name(str);
135     if (!blk) {
136         bs = bdrv_lookup_bs(NULL, str, NULL);
137         if (bs) {
138             /*
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.
144              */
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;
149 
150             ret = blk_insert_bs(blk, bs, errp);
151             if (ret < 0) {
152                 goto fail;
153             }
154         }
155     }
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;
160     }
161     if (blk_attach_dev(blk, dev) < 0) {
162         DriveInfo *dinfo = blk_legacy_dinfo(blk);
163 
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);
172         }
173         goto fail;
174     }
175 
176     *ptr = blk;
177 
178 fail:
179     if (blk_created) {
180         /* If we need to keep a reference, blk_attach_dev() took it */
181         blk_unref(blk);
182     }
183 
184     g_free(str);
185 }
186 
187 static void set_drive(Object *obj, Visitor *v, const char *name, void *opaque,
188                       Error **errp)
189 {
190     set_drive_helper(obj, v, name, opaque, false, errp);
191 }
192 
193 static void set_drive_iothread(Object *obj, Visitor *v, const char *name,
194                                void *opaque, Error **errp)
195 {
196     set_drive_helper(obj, v, name, opaque, true, errp);
197 }
198 
199 static void release_drive(Object *obj, const char *name, void *opaque)
200 {
201     DeviceState *dev = DEVICE(obj);
202     Property *prop = opaque;
203     BlockBackend **ptr = object_field_prop_ptr(obj, prop);
204 
205     if (*ptr) {
206         blockdev_auto_del(*ptr);
207         blk_detach_dev(*ptr, dev);
208     }
209 }
210 
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,
218 };
219 
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,
227 };
228 
229 /* --- character device --- */
230 
231 static void get_chr(Object *obj, Visitor *v, const char *name, void *opaque,
232                     Error **errp)
233 {
234     CharBackend *be = object_field_prop_ptr(obj, opaque);
235     char *p;
236 
237     p = g_strdup(be->chr && be->chr->label ? be->chr->label : "");
238     visit_type_str(v, name, &p, errp);
239     g_free(p);
240 }
241 
242 static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque,
243                     Error **errp)
244 {
245     Property *prop = opaque;
246     CharBackend *be = object_field_prop_ptr(obj, prop);
247     Chardev *s;
248     char *str;
249 
250     if (!visit_type_str(v, name, &str, errp)) {
251         return;
252     }
253 
254     /*
255      * TODO Should this really be an error?  If no, the old value
256      * needs to be released before we store the new one.
257      */
258     if (!check_prop_still_unset(obj, name, be->chr, str, false, errp)) {
259         return;
260     }
261 
262     if (!*str) {
263         g_free(str);
264         be->chr = NULL;
265         return;
266     }
267 
268     s = qemu_chr_find(str);
269     if (s == NULL) {
270         error_setg(errp, "Property '%s.%s' can't find value '%s'",
271                    object_get_typename(obj), name, str);
272     } else if (!qemu_chr_fe_init(be, s, errp)) {
273         error_prepend(errp, "Property '%s.%s' can't take value '%s': ",
274                       object_get_typename(obj), name, str);
275     }
276     g_free(str);
277 }
278 
279 static void release_chr(Object *obj, const char *name, void *opaque)
280 {
281     Property *prop = opaque;
282     CharBackend *be = object_field_prop_ptr(obj, prop);
283 
284     qemu_chr_fe_deinit(be, false);
285 }
286 
287 const PropertyInfo qdev_prop_chr = {
288     .name  = "str",
289     .description = "ID of a chardev to use as a backend",
290     .get   = get_chr,
291     .set   = set_chr,
292     .release = release_chr,
293 };
294 
295 /* --- mac address --- */
296 
297 /*
298  * accepted syntax versions:
299  *   01:02:03:04:05:06
300  *   01-02-03-04-05-06
301  */
302 static void get_mac(Object *obj, Visitor *v, const char *name, void *opaque,
303                     Error **errp)
304 {
305     Property *prop = opaque;
306     MACAddr *mac = object_field_prop_ptr(obj, prop);
307     char buffer[2 * 6 + 5 + 1];
308     char *p = buffer;
309 
310     snprintf(buffer, sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x",
311              mac->a[0], mac->a[1], mac->a[2],
312              mac->a[3], mac->a[4], mac->a[5]);
313 
314     visit_type_str(v, name, &p, errp);
315 }
316 
317 static void set_mac(Object *obj, Visitor *v, const char *name, void *opaque,
318                     Error **errp)
319 {
320     Property *prop = opaque;
321     MACAddr *mac = object_field_prop_ptr(obj, prop);
322     int i, pos;
323     char *str;
324     const char *p;
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, name, 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 = object_field_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     Property *prop = opaque;
394     NICPeers *peers_ptr = object_field_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 (!visit_type_str(v, name, &str, errp)) {
401         return;
402     }
403 
404     queues = qemu_find_net_clients_except(str, peers,
405                                           NET_CLIENT_DRIVER_NIC,
406                                           MAX_QUEUE_NUM);
407     if (queues == 0) {
408         err = -ENOENT;
409         goto out;
410     }
411 
412     if (queues > MAX_QUEUE_NUM) {
413         error_setg(errp, "queues of backend '%s'(%d) exceeds QEMU limitation(%d)",
414                    str, queues, MAX_QUEUE_NUM);
415         goto out;
416     }
417 
418     for (i = 0; i < queues; i++) {
419         if (peers[i]->peer) {
420             err = -EEXIST;
421             goto out;
422         }
423 
424         /*
425          * TODO Should this really be an error?  If no, the old value
426          * needs to be released before we store the new one.
427          */
428         if (!check_prop_still_unset(obj, name, ncs[i], str, false, errp)) {
429             goto out;
430         }
431 
432         if (peers[i]->info->check_peer_type) {
433             if (!peers[i]->info->check_peer_type(peers[i], obj->class, errp)) {
434                 goto out;
435             }
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->name, 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 = object_field_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     Property *prop = opaque;
473     QEMUSoundCard *card = object_field_prop_ptr(obj, prop);
474     AudioState *state;
475     g_autofree char *str = NULL;
476 
477     if (!visit_type_str(v, name, &str, errp)) {
478         return;
479     }
480 
481     state = audio_state_by_name(str, errp);
482     if (state) {
483         card->state = state;
484     }
485 }
486 
487 const PropertyInfo qdev_prop_audiodev = {
488     .name = "str",
489     .description = "ID of an audiodev to use as a backend",
490     /* release done on shutdown */
491     .get = get_audiodev,
492     .set = set_audiodev,
493 };
494 
495 bool qdev_prop_set_drive_err(DeviceState *dev, const char *name,
496                              BlockBackend *value, Error **errp)
497 {
498     const char *ref = "";
499 
500     if (value) {
501         ref = blk_name(value);
502         if (!*ref) {
503             const BlockDriverState *bs = blk_bs(value);
504             if (bs) {
505                 ref = bdrv_get_node_name(bs);
506             }
507         }
508     }
509 
510     return object_property_set_str(OBJECT(dev), name, ref, errp);
511 }
512 
513 void qdev_prop_set_drive(DeviceState *dev, const char *name,
514                          BlockBackend *value)
515 {
516     qdev_prop_set_drive_err(dev, name, value, &error_abort);
517 }
518 
519 void qdev_prop_set_chr(DeviceState *dev, const char *name,
520                        Chardev *value)
521 {
522     assert(!value || value->label);
523     object_property_set_str(OBJECT(dev), name, value ? value->label : "",
524                             &error_abort);
525 }
526 
527 void qdev_prop_set_netdev(DeviceState *dev, const char *name,
528                           NetClientState *value)
529 {
530     assert(!value || value->name);
531     object_property_set_str(OBJECT(dev), name, value ? value->name : "",
532                             &error_abort);
533 }
534 
535 void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
536 {
537     qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
538     if (nd->netdev) {
539         qdev_prop_set_netdev(dev, "netdev", nd->netdev);
540     }
541     if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
542         object_property_find(OBJECT(dev), "vectors")) {
543         qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
544     }
545     nd->instantiated = 1;
546 }
547 
548 /* --- lost tick policy --- */
549 
550 static void qdev_propinfo_set_losttickpolicy(Object *obj, Visitor *v,
551                                              const char *name, void *opaque,
552                                              Error **errp)
553 {
554     Property *prop = opaque;
555     int *ptr = object_field_prop_ptr(obj, prop);
556     int value;
557 
558     if (!visit_type_enum(v, name, &value, prop->info->enum_table, errp)) {
559         return;
560     }
561 
562     if (value == LOST_TICK_POLICY_SLEW) {
563         MachineState *ms = MACHINE(qdev_get_machine());
564 
565         if (!object_dynamic_cast(OBJECT(ms), TYPE_X86_MACHINE)) {
566             error_setg(errp,
567                        "the 'slew' policy is only available for x86 machines");
568             return;
569         }
570     }
571 
572     *ptr = value;
573 }
574 
575 QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int));
576 
577 const PropertyInfo qdev_prop_losttickpolicy = {
578     .name  = "LostTickPolicy",
579     .enum_table  = &LostTickPolicy_lookup,
580     .get   = qdev_propinfo_get_enum,
581     .set   = qdev_propinfo_set_losttickpolicy,
582     .set_default_value = qdev_propinfo_set_default_value_enum,
583 };
584 
585 /* --- blocksize --- */
586 
587 static void set_blocksize(Object *obj, Visitor *v, const char *name,
588                           void *opaque, Error **errp)
589 {
590     DeviceState *dev = DEVICE(obj);
591     Property *prop = opaque;
592     uint32_t *ptr = object_field_prop_ptr(obj, prop);
593     uint64_t value;
594     Error *local_err = NULL;
595 
596     if (!visit_type_size(v, name, &value, errp)) {
597         return;
598     }
599     check_block_size(dev->id ? : "", name, value, &local_err);
600     if (local_err) {
601         error_propagate(errp, local_err);
602         return;
603     }
604     *ptr = value;
605 }
606 
607 const PropertyInfo qdev_prop_blocksize = {
608     .name  = "size",
609     .description = "A power of two between " MIN_BLOCK_SIZE_STR
610                    " and " MAX_BLOCK_SIZE_STR,
611     .get   = qdev_propinfo_get_size32,
612     .set   = set_blocksize,
613     .set_default_value = qdev_propinfo_set_default_value_uint,
614 };
615 
616 /* --- Block device error handling policy --- */
617 
618 QEMU_BUILD_BUG_ON(sizeof(BlockdevOnError) != sizeof(int));
619 
620 const PropertyInfo qdev_prop_blockdev_on_error = {
621     .name = "BlockdevOnError",
622     .description = "Error handling policy, "
623                    "report/ignore/enospc/stop/auto",
624     .enum_table = &BlockdevOnError_lookup,
625     .get = qdev_propinfo_get_enum,
626     .set = qdev_propinfo_set_enum,
627     .set_default_value = qdev_propinfo_set_default_value_enum,
628 };
629 
630 /* --- BIOS CHS translation */
631 
632 QEMU_BUILD_BUG_ON(sizeof(BiosAtaTranslation) != sizeof(int));
633 
634 const PropertyInfo qdev_prop_bios_chs_trans = {
635     .name = "BiosAtaTranslation",
636     .description = "Logical CHS translation algorithm, "
637                    "auto/none/lba/large/rechs",
638     .enum_table = &BiosAtaTranslation_lookup,
639     .get = qdev_propinfo_get_enum,
640     .set = qdev_propinfo_set_enum,
641     .set_default_value = qdev_propinfo_set_default_value_enum,
642 };
643 
644 /* --- FDC default drive types */
645 
646 const PropertyInfo qdev_prop_fdc_drive_type = {
647     .name = "FdcDriveType",
648     .description = "FDC drive type, "
649                    "144/288/120/none/auto",
650     .enum_table = &FloppyDriveType_lookup,
651     .get = qdev_propinfo_get_enum,
652     .set = qdev_propinfo_set_enum,
653     .set_default_value = qdev_propinfo_set_default_value_enum,
654 };
655 
656 /* --- MultiFDCompression --- */
657 
658 const PropertyInfo qdev_prop_multifd_compression = {
659     .name = "MultiFDCompression",
660     .description = "multifd_compression values, "
661                    "none/zlib/zstd",
662     .enum_table = &MultiFDCompression_lookup,
663     .get = qdev_propinfo_get_enum,
664     .set = qdev_propinfo_set_enum,
665     .set_default_value = qdev_propinfo_set_default_value_enum,
666 };
667 
668 /* --- MigMode --- */
669 
670 QEMU_BUILD_BUG_ON(sizeof(MigMode) != sizeof(int));
671 
672 const PropertyInfo qdev_prop_mig_mode = {
673     .name = "MigMode",
674     .description = "mig_mode values, "
675                    "normal,cpr-reboot",
676     .enum_table = &MigMode_lookup,
677     .get = qdev_propinfo_get_enum,
678     .set = qdev_propinfo_set_enum,
679     .set_default_value = qdev_propinfo_set_default_value_enum,
680 };
681 
682 /* --- GranuleMode --- */
683 
684 QEMU_BUILD_BUG_ON(sizeof(GranuleMode) != sizeof(int));
685 
686 const PropertyInfo qdev_prop_granule_mode = {
687     .name = "GranuleMode",
688     .description = "granule_mode values, "
689                    "4k, 8k, 16k, 64k, host",
690     .enum_table = &GranuleMode_lookup,
691     .get = qdev_propinfo_get_enum,
692     .set = qdev_propinfo_set_enum,
693     .set_default_value = qdev_propinfo_set_default_value_enum,
694 };
695 
696 /* --- Reserved Region --- */
697 
698 /*
699  * Accepted syntax:
700  *   <low address>:<high address>:<type>
701  *   where low/high addresses are uint64_t in hexadecimal
702  *   and type is a non-negative decimal integer
703  */
704 static void get_reserved_region(Object *obj, Visitor *v, const char *name,
705                                 void *opaque, Error **errp)
706 {
707     Property *prop = opaque;
708     ReservedRegion *rr = object_field_prop_ptr(obj, prop);
709     char buffer[64];
710     char *p = buffer;
711     int rc;
712 
713     rc = snprintf(buffer, sizeof(buffer), "0x%"PRIx64":0x%"PRIx64":%u",
714                   range_lob(&rr->range), range_upb(&rr->range), rr->type);
715     assert(rc < sizeof(buffer));
716 
717     visit_type_str(v, name, &p, errp);
718 }
719 
720 static void set_reserved_region(Object *obj, Visitor *v, const char *name,
721                                 void *opaque, Error **errp)
722 {
723     Property *prop = opaque;
724     ReservedRegion *rr = object_field_prop_ptr(obj, prop);
725     const char *endptr;
726     uint64_t lob, upb;
727     char *str;
728     int ret;
729 
730     if (!visit_type_str(v, name, &str, errp)) {
731         return;
732     }
733 
734     ret = qemu_strtou64(str, &endptr, 16, &lob);
735     if (ret) {
736         error_setg(errp, "start address of '%s'"
737                    " must be a hexadecimal integer", name);
738         goto out;
739     }
740     if (*endptr != ':') {
741         goto separator_error;
742     }
743 
744     ret = qemu_strtou64(endptr + 1, &endptr, 16, &upb);
745     if (ret) {
746         error_setg(errp, "end address of '%s'"
747                    " must be a hexadecimal integer", name);
748         goto out;
749     }
750     if (*endptr != ':') {
751         goto separator_error;
752     }
753 
754     range_set_bounds(&rr->range, lob, upb);
755 
756     ret = qemu_strtoui(endptr + 1, &endptr, 10, &rr->type);
757     if (ret) {
758         error_setg(errp, "type of '%s'"
759                    " must be a non-negative decimal integer", name);
760     }
761     goto out;
762 
763 separator_error:
764     error_setg(errp, "reserved region fields must be separated with ':'");
765 out:
766     g_free(str);
767     return;
768 }
769 
770 const PropertyInfo qdev_prop_reserved_region = {
771     .name  = "reserved_region",
772     .description = "Reserved Region, example: 0xFEE00000:0xFEEFFFFF:0",
773     .get   = get_reserved_region,
774     .set   = set_reserved_region,
775 };
776 
777 /* --- pci address --- */
778 
779 /*
780  * bus-local address, i.e. "$slot" or "$slot.$fn"
781  */
782 static void set_pci_devfn(Object *obj, Visitor *v, const char *name,
783                           void *opaque, Error **errp)
784 {
785     Property *prop = opaque;
786     int32_t value, *ptr = object_field_prop_ptr(obj, prop);
787     unsigned int slot, fn, n;
788     char *str;
789 
790     if (!visit_type_str(v, name, &str, NULL)) {
791         if (!visit_type_int32(v, name, &value, errp)) {
792             return;
793         }
794         if (value < -1 || value > 255) {
795             error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
796                        name ? name : "null", "a value between -1 and 255");
797             return;
798         }
799         *ptr = value;
800         return;
801     }
802 
803     if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
804         fn = 0;
805         if (sscanf(str, "%x%n", &slot, &n) != 1) {
806             goto invalid;
807         }
808     }
809     if (str[n] != '\0' || fn > 7 || slot > 31) {
810         goto invalid;
811     }
812     *ptr = slot << 3 | fn;
813     g_free(str);
814     return;
815 
816 invalid:
817     error_set_from_qdev_prop_error(errp, EINVAL, obj, name, str);
818     g_free(str);
819 }
820 
821 static int print_pci_devfn(Object *obj, Property *prop, char *dest,
822                            size_t len)
823 {
824     int32_t *ptr = object_field_prop_ptr(obj, prop);
825 
826     if (*ptr == -1) {
827         return snprintf(dest, len, "<unset>");
828     } else {
829         return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7);
830     }
831 }
832 
833 const PropertyInfo qdev_prop_pci_devfn = {
834     .name  = "int32",
835     .description = "Slot and optional function number, example: 06.0 or 06",
836     .print = print_pci_devfn,
837     .get   = qdev_propinfo_get_int32,
838     .set   = set_pci_devfn,
839     .set_default_value = qdev_propinfo_set_default_value_int,
840 };
841 
842 /* --- pci host address --- */
843 
844 static void get_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
845                                  void *opaque, Error **errp)
846 {
847     Property *prop = opaque;
848     PCIHostDeviceAddress *addr = object_field_prop_ptr(obj, prop);
849     char buffer[] = "ffff:ff:ff.f";
850     char *p = buffer;
851     int rc = 0;
852 
853     /*
854      * Catch "invalid" device reference from vfio-pci and allow the
855      * default buffer representing the non-existent device to be used.
856      */
857     if (~addr->domain || ~addr->bus || ~addr->slot || ~addr->function) {
858         rc = snprintf(buffer, sizeof(buffer), "%04x:%02x:%02x.%0d",
859                       addr->domain, addr->bus, addr->slot, addr->function);
860         assert(rc == sizeof(buffer) - 1);
861     }
862 
863     visit_type_str(v, name, &p, errp);
864 }
865 
866 /*
867  * Parse [<domain>:]<bus>:<slot>.<func>
868  *   if <domain> is not supplied, it's assumed to be 0.
869  */
870 static void set_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
871                                  void *opaque, Error **errp)
872 {
873     Property *prop = opaque;
874     PCIHostDeviceAddress *addr = object_field_prop_ptr(obj, prop);
875     char *str, *p;
876     char *e;
877     unsigned long val;
878     unsigned long dom = 0, bus = 0;
879     unsigned int slot = 0, func = 0;
880 
881     if (!visit_type_str(v, name, &str, errp)) {
882         return;
883     }
884 
885     p = str;
886     val = strtoul(p, &e, 16);
887     if (e == p || *e != ':') {
888         goto inval;
889     }
890     bus = val;
891 
892     p = e + 1;
893     val = strtoul(p, &e, 16);
894     if (e == p) {
895         goto inval;
896     }
897     if (*e == ':') {
898         dom = bus;
899         bus = val;
900         p = e + 1;
901         val = strtoul(p, &e, 16);
902         if (e == p) {
903             goto inval;
904         }
905     }
906     slot = val;
907 
908     if (*e != '.') {
909         goto inval;
910     }
911     p = e + 1;
912     val = strtoul(p, &e, 10);
913     if (e == p) {
914         goto inval;
915     }
916     func = val;
917 
918     if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) {
919         goto inval;
920     }
921 
922     if (*e) {
923         goto inval;
924     }
925 
926     addr->domain = dom;
927     addr->bus = bus;
928     addr->slot = slot;
929     addr->function = func;
930 
931     g_free(str);
932     return;
933 
934 inval:
935     error_set_from_qdev_prop_error(errp, EINVAL, obj, name, str);
936     g_free(str);
937 }
938 
939 const PropertyInfo qdev_prop_pci_host_devaddr = {
940     .name = "str",
941     .description = "Address (bus/device/function) of "
942                    "the host device, example: 04:10.0",
943     .get = get_pci_host_devaddr,
944     .set = set_pci_host_devaddr,
945 };
946 
947 /* --- OffAutoPCIBAR off/auto/bar0/bar1/bar2/bar3/bar4/bar5 --- */
948 
949 const PropertyInfo qdev_prop_off_auto_pcibar = {
950     .name = "OffAutoPCIBAR",
951     .description = "off/auto/bar0/bar1/bar2/bar3/bar4/bar5",
952     .enum_table = &OffAutoPCIBAR_lookup,
953     .get = qdev_propinfo_get_enum,
954     .set = qdev_propinfo_set_enum,
955     .set_default_value = qdev_propinfo_set_default_value_enum,
956 };
957 
958 /* --- PCIELinkSpeed 2_5/5/8/16 -- */
959 
960 static void get_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
961                                    void *opaque, Error **errp)
962 {
963     Property *prop = opaque;
964     PCIExpLinkSpeed *p = object_field_prop_ptr(obj, prop);
965     int speed;
966 
967     switch (*p) {
968     case QEMU_PCI_EXP_LNK_2_5GT:
969         speed = PCIE_LINK_SPEED_2_5;
970         break;
971     case QEMU_PCI_EXP_LNK_5GT:
972         speed = PCIE_LINK_SPEED_5;
973         break;
974     case QEMU_PCI_EXP_LNK_8GT:
975         speed = PCIE_LINK_SPEED_8;
976         break;
977     case QEMU_PCI_EXP_LNK_16GT:
978         speed = PCIE_LINK_SPEED_16;
979         break;
980     default:
981         /* Unreachable */
982         abort();
983     }
984 
985     visit_type_enum(v, name, &speed, prop->info->enum_table, errp);
986 }
987 
988 static void set_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
989                                    void *opaque, Error **errp)
990 {
991     Property *prop = opaque;
992     PCIExpLinkSpeed *p = object_field_prop_ptr(obj, prop);
993     int speed;
994 
995     if (!visit_type_enum(v, name, &speed, prop->info->enum_table,
996                          errp)) {
997         return;
998     }
999 
1000     switch (speed) {
1001     case PCIE_LINK_SPEED_2_5:
1002         *p = QEMU_PCI_EXP_LNK_2_5GT;
1003         break;
1004     case PCIE_LINK_SPEED_5:
1005         *p = QEMU_PCI_EXP_LNK_5GT;
1006         break;
1007     case PCIE_LINK_SPEED_8:
1008         *p = QEMU_PCI_EXP_LNK_8GT;
1009         break;
1010     case PCIE_LINK_SPEED_16:
1011         *p = QEMU_PCI_EXP_LNK_16GT;
1012         break;
1013     default:
1014         /* Unreachable */
1015         abort();
1016     }
1017 }
1018 
1019 const PropertyInfo qdev_prop_pcie_link_speed = {
1020     .name = "PCIELinkSpeed",
1021     .description = "2_5/5/8/16",
1022     .enum_table = &PCIELinkSpeed_lookup,
1023     .get = get_prop_pcielinkspeed,
1024     .set = set_prop_pcielinkspeed,
1025     .set_default_value = qdev_propinfo_set_default_value_enum,
1026 };
1027 
1028 /* --- PCIELinkWidth 1/2/4/8/12/16/32 -- */
1029 
1030 static void get_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
1031                                    void *opaque, Error **errp)
1032 {
1033     Property *prop = opaque;
1034     PCIExpLinkWidth *p = object_field_prop_ptr(obj, prop);
1035     int width;
1036 
1037     switch (*p) {
1038     case QEMU_PCI_EXP_LNK_X1:
1039         width = PCIE_LINK_WIDTH_1;
1040         break;
1041     case QEMU_PCI_EXP_LNK_X2:
1042         width = PCIE_LINK_WIDTH_2;
1043         break;
1044     case QEMU_PCI_EXP_LNK_X4:
1045         width = PCIE_LINK_WIDTH_4;
1046         break;
1047     case QEMU_PCI_EXP_LNK_X8:
1048         width = PCIE_LINK_WIDTH_8;
1049         break;
1050     case QEMU_PCI_EXP_LNK_X12:
1051         width = PCIE_LINK_WIDTH_12;
1052         break;
1053     case QEMU_PCI_EXP_LNK_X16:
1054         width = PCIE_LINK_WIDTH_16;
1055         break;
1056     case QEMU_PCI_EXP_LNK_X32:
1057         width = PCIE_LINK_WIDTH_32;
1058         break;
1059     default:
1060         /* Unreachable */
1061         abort();
1062     }
1063 
1064     visit_type_enum(v, name, &width, prop->info->enum_table, errp);
1065 }
1066 
1067 static void set_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
1068                                    void *opaque, Error **errp)
1069 {
1070     Property *prop = opaque;
1071     PCIExpLinkWidth *p = object_field_prop_ptr(obj, prop);
1072     int width;
1073 
1074     if (!visit_type_enum(v, name, &width, prop->info->enum_table,
1075                          errp)) {
1076         return;
1077     }
1078 
1079     switch (width) {
1080     case PCIE_LINK_WIDTH_1:
1081         *p = QEMU_PCI_EXP_LNK_X1;
1082         break;
1083     case PCIE_LINK_WIDTH_2:
1084         *p = QEMU_PCI_EXP_LNK_X2;
1085         break;
1086     case PCIE_LINK_WIDTH_4:
1087         *p = QEMU_PCI_EXP_LNK_X4;
1088         break;
1089     case PCIE_LINK_WIDTH_8:
1090         *p = QEMU_PCI_EXP_LNK_X8;
1091         break;
1092     case PCIE_LINK_WIDTH_12:
1093         *p = QEMU_PCI_EXP_LNK_X12;
1094         break;
1095     case PCIE_LINK_WIDTH_16:
1096         *p = QEMU_PCI_EXP_LNK_X16;
1097         break;
1098     case PCIE_LINK_WIDTH_32:
1099         *p = QEMU_PCI_EXP_LNK_X32;
1100         break;
1101     default:
1102         /* Unreachable */
1103         abort();
1104     }
1105 }
1106 
1107 const PropertyInfo qdev_prop_pcie_link_width = {
1108     .name = "PCIELinkWidth",
1109     .description = "1/2/4/8/12/16/32",
1110     .enum_table = &PCIELinkWidth_lookup,
1111     .get = get_prop_pcielinkwidth,
1112     .set = set_prop_pcielinkwidth,
1113     .set_default_value = qdev_propinfo_set_default_value_enum,
1114 };
1115 
1116 /* --- UUID --- */
1117 
1118 static void get_uuid(Object *obj, Visitor *v, const char *name, void *opaque,
1119                      Error **errp)
1120 {
1121     Property *prop = opaque;
1122     QemuUUID *uuid = object_field_prop_ptr(obj, prop);
1123     char buffer[UUID_STR_LEN];
1124     char *p = buffer;
1125 
1126     qemu_uuid_unparse(uuid, buffer);
1127 
1128     visit_type_str(v, name, &p, errp);
1129 }
1130 
1131 #define UUID_VALUE_AUTO        "auto"
1132 
1133 static void set_uuid(Object *obj, Visitor *v, const char *name, void *opaque,
1134                     Error **errp)
1135 {
1136     Property *prop = opaque;
1137     QemuUUID *uuid = object_field_prop_ptr(obj, prop);
1138     char *str;
1139 
1140     if (!visit_type_str(v, name, &str, errp)) {
1141         return;
1142     }
1143 
1144     if (!strcmp(str, UUID_VALUE_AUTO)) {
1145         qemu_uuid_generate(uuid);
1146     } else if (qemu_uuid_parse(str, uuid) < 0) {
1147         error_set_from_qdev_prop_error(errp, EINVAL, obj, name, str);
1148     }
1149     g_free(str);
1150 }
1151 
1152 static void set_default_uuid_auto(ObjectProperty *op, const Property *prop)
1153 {
1154     object_property_set_default_str(op, UUID_VALUE_AUTO);
1155 }
1156 
1157 const PropertyInfo qdev_prop_uuid = {
1158     .name  = "str",
1159     .description = "UUID (aka GUID) or \"" UUID_VALUE_AUTO
1160         "\" for random value (default)",
1161     .get   = get_uuid,
1162     .set   = set_uuid,
1163     .set_default_value = set_default_uuid_auto,
1164 };
1165 
1166 /* --- s390 cpu entitlement policy --- */
1167 
1168 QEMU_BUILD_BUG_ON(sizeof(CpuS390Entitlement) != sizeof(int));
1169 
1170 const PropertyInfo qdev_prop_cpus390entitlement = {
1171     .name  = "CpuS390Entitlement",
1172     .description = "low/medium (default)/high",
1173     .enum_table  = &CpuS390Entitlement_lookup,
1174     .get   = qdev_propinfo_get_enum,
1175     .set   = qdev_propinfo_set_enum,
1176     .set_default_value = qdev_propinfo_set_default_value_enum,
1177 };
1178 
1179 /* --- IOThreadVirtQueueMappingList --- */
1180 
1181 static void get_iothread_vq_mapping_list(Object *obj, Visitor *v,
1182         const char *name, void *opaque, Error **errp)
1183 {
1184     IOThreadVirtQueueMappingList **prop_ptr =
1185         object_field_prop_ptr(obj, opaque);
1186 
1187     visit_type_IOThreadVirtQueueMappingList(v, name, prop_ptr, errp);
1188 }
1189 
1190 static void set_iothread_vq_mapping_list(Object *obj, Visitor *v,
1191         const char *name, void *opaque, Error **errp)
1192 {
1193     IOThreadVirtQueueMappingList **prop_ptr =
1194         object_field_prop_ptr(obj, opaque);
1195     IOThreadVirtQueueMappingList *list;
1196 
1197     if (!visit_type_IOThreadVirtQueueMappingList(v, name, &list, errp)) {
1198         return;
1199     }
1200 
1201     qapi_free_IOThreadVirtQueueMappingList(*prop_ptr);
1202     *prop_ptr = list;
1203 }
1204 
1205 static void release_iothread_vq_mapping_list(Object *obj,
1206         const char *name, void *opaque)
1207 {
1208     IOThreadVirtQueueMappingList **prop_ptr =
1209         object_field_prop_ptr(obj, opaque);
1210 
1211     qapi_free_IOThreadVirtQueueMappingList(*prop_ptr);
1212     *prop_ptr = NULL;
1213 }
1214 
1215 const PropertyInfo qdev_prop_iothread_vq_mapping_list = {
1216     .name = "IOThreadVirtQueueMappingList",
1217     .description = "IOThread virtqueue mapping list [{\"iothread\":\"<id>\", "
1218                    "\"vqs\":[1,2,3,...]},...]",
1219     .get = get_iothread_vq_mapping_list,
1220     .set = set_iothread_vq_mapping_list,
1221     .release = release_iothread_vq_mapping_list,
1222 };
1223