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