xref: /qemu/hw/core/qdev-properties-system.c (revision 440b2174)
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 /* --- Reserved Region --- */
683 
684 /*
685  * Accepted syntax:
686  *   <low address>:<high address>:<type>
687  *   where low/high addresses are uint64_t in hexadecimal
688  *   and type is a non-negative decimal integer
689  */
690 static void get_reserved_region(Object *obj, Visitor *v, const char *name,
691                                 void *opaque, Error **errp)
692 {
693     Property *prop = opaque;
694     ReservedRegion *rr = object_field_prop_ptr(obj, prop);
695     char buffer[64];
696     char *p = buffer;
697     int rc;
698 
699     rc = snprintf(buffer, sizeof(buffer), "0x%"PRIx64":0x%"PRIx64":%u",
700                   range_lob(&rr->range), range_upb(&rr->range), rr->type);
701     assert(rc < sizeof(buffer));
702 
703     visit_type_str(v, name, &p, errp);
704 }
705 
706 static void set_reserved_region(Object *obj, Visitor *v, const char *name,
707                                 void *opaque, Error **errp)
708 {
709     Property *prop = opaque;
710     ReservedRegion *rr = object_field_prop_ptr(obj, prop);
711     const char *endptr;
712     uint64_t lob, upb;
713     char *str;
714     int ret;
715 
716     if (!visit_type_str(v, name, &str, errp)) {
717         return;
718     }
719 
720     ret = qemu_strtou64(str, &endptr, 16, &lob);
721     if (ret) {
722         error_setg(errp, "start address of '%s'"
723                    " must be a hexadecimal integer", name);
724         goto out;
725     }
726     if (*endptr != ':') {
727         goto separator_error;
728     }
729 
730     ret = qemu_strtou64(endptr + 1, &endptr, 16, &upb);
731     if (ret) {
732         error_setg(errp, "end address of '%s'"
733                    " must be a hexadecimal integer", name);
734         goto out;
735     }
736     if (*endptr != ':') {
737         goto separator_error;
738     }
739 
740     range_set_bounds(&rr->range, lob, upb);
741 
742     ret = qemu_strtoui(endptr + 1, &endptr, 10, &rr->type);
743     if (ret) {
744         error_setg(errp, "type of '%s'"
745                    " must be a non-negative decimal integer", name);
746     }
747     goto out;
748 
749 separator_error:
750     error_setg(errp, "reserved region fields must be separated with ':'");
751 out:
752     g_free(str);
753     return;
754 }
755 
756 const PropertyInfo qdev_prop_reserved_region = {
757     .name  = "reserved_region",
758     .description = "Reserved Region, example: 0xFEE00000:0xFEEFFFFF:0",
759     .get   = get_reserved_region,
760     .set   = set_reserved_region,
761 };
762 
763 /* --- pci address --- */
764 
765 /*
766  * bus-local address, i.e. "$slot" or "$slot.$fn"
767  */
768 static void set_pci_devfn(Object *obj, Visitor *v, const char *name,
769                           void *opaque, Error **errp)
770 {
771     Property *prop = opaque;
772     int32_t value, *ptr = object_field_prop_ptr(obj, prop);
773     unsigned int slot, fn, n;
774     char *str;
775 
776     if (!visit_type_str(v, name, &str, NULL)) {
777         if (!visit_type_int32(v, name, &value, errp)) {
778             return;
779         }
780         if (value < -1 || value > 255) {
781             error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
782                        name ? name : "null", "a value between -1 and 255");
783             return;
784         }
785         *ptr = value;
786         return;
787     }
788 
789     if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
790         fn = 0;
791         if (sscanf(str, "%x%n", &slot, &n) != 1) {
792             goto invalid;
793         }
794     }
795     if (str[n] != '\0' || fn > 7 || slot > 31) {
796         goto invalid;
797     }
798     *ptr = slot << 3 | fn;
799     g_free(str);
800     return;
801 
802 invalid:
803     error_set_from_qdev_prop_error(errp, EINVAL, obj, name, str);
804     g_free(str);
805 }
806 
807 static int print_pci_devfn(Object *obj, Property *prop, char *dest,
808                            size_t len)
809 {
810     int32_t *ptr = object_field_prop_ptr(obj, prop);
811 
812     if (*ptr == -1) {
813         return snprintf(dest, len, "<unset>");
814     } else {
815         return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7);
816     }
817 }
818 
819 const PropertyInfo qdev_prop_pci_devfn = {
820     .name  = "int32",
821     .description = "Slot and optional function number, example: 06.0 or 06",
822     .print = print_pci_devfn,
823     .get   = qdev_propinfo_get_int32,
824     .set   = set_pci_devfn,
825     .set_default_value = qdev_propinfo_set_default_value_int,
826 };
827 
828 /* --- pci host address --- */
829 
830 static void get_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
831                                  void *opaque, Error **errp)
832 {
833     Property *prop = opaque;
834     PCIHostDeviceAddress *addr = object_field_prop_ptr(obj, prop);
835     char buffer[] = "ffff:ff:ff.f";
836     char *p = buffer;
837     int rc = 0;
838 
839     /*
840      * Catch "invalid" device reference from vfio-pci and allow the
841      * default buffer representing the non-existent device to be used.
842      */
843     if (~addr->domain || ~addr->bus || ~addr->slot || ~addr->function) {
844         rc = snprintf(buffer, sizeof(buffer), "%04x:%02x:%02x.%0d",
845                       addr->domain, addr->bus, addr->slot, addr->function);
846         assert(rc == sizeof(buffer) - 1);
847     }
848 
849     visit_type_str(v, name, &p, errp);
850 }
851 
852 /*
853  * Parse [<domain>:]<bus>:<slot>.<func>
854  *   if <domain> is not supplied, it's assumed to be 0.
855  */
856 static void set_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
857                                  void *opaque, Error **errp)
858 {
859     Property *prop = opaque;
860     PCIHostDeviceAddress *addr = object_field_prop_ptr(obj, prop);
861     char *str, *p;
862     char *e;
863     unsigned long val;
864     unsigned long dom = 0, bus = 0;
865     unsigned int slot = 0, func = 0;
866 
867     if (!visit_type_str(v, name, &str, errp)) {
868         return;
869     }
870 
871     p = str;
872     val = strtoul(p, &e, 16);
873     if (e == p || *e != ':') {
874         goto inval;
875     }
876     bus = val;
877 
878     p = e + 1;
879     val = strtoul(p, &e, 16);
880     if (e == p) {
881         goto inval;
882     }
883     if (*e == ':') {
884         dom = bus;
885         bus = val;
886         p = e + 1;
887         val = strtoul(p, &e, 16);
888         if (e == p) {
889             goto inval;
890         }
891     }
892     slot = val;
893 
894     if (*e != '.') {
895         goto inval;
896     }
897     p = e + 1;
898     val = strtoul(p, &e, 10);
899     if (e == p) {
900         goto inval;
901     }
902     func = val;
903 
904     if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) {
905         goto inval;
906     }
907 
908     if (*e) {
909         goto inval;
910     }
911 
912     addr->domain = dom;
913     addr->bus = bus;
914     addr->slot = slot;
915     addr->function = func;
916 
917     g_free(str);
918     return;
919 
920 inval:
921     error_set_from_qdev_prop_error(errp, EINVAL, obj, name, str);
922     g_free(str);
923 }
924 
925 const PropertyInfo qdev_prop_pci_host_devaddr = {
926     .name = "str",
927     .description = "Address (bus/device/function) of "
928                    "the host device, example: 04:10.0",
929     .get = get_pci_host_devaddr,
930     .set = set_pci_host_devaddr,
931 };
932 
933 /* --- OffAutoPCIBAR off/auto/bar0/bar1/bar2/bar3/bar4/bar5 --- */
934 
935 const PropertyInfo qdev_prop_off_auto_pcibar = {
936     .name = "OffAutoPCIBAR",
937     .description = "off/auto/bar0/bar1/bar2/bar3/bar4/bar5",
938     .enum_table = &OffAutoPCIBAR_lookup,
939     .get = qdev_propinfo_get_enum,
940     .set = qdev_propinfo_set_enum,
941     .set_default_value = qdev_propinfo_set_default_value_enum,
942 };
943 
944 /* --- PCIELinkSpeed 2_5/5/8/16 -- */
945 
946 static void get_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
947                                    void *opaque, Error **errp)
948 {
949     Property *prop = opaque;
950     PCIExpLinkSpeed *p = object_field_prop_ptr(obj, prop);
951     int speed;
952 
953     switch (*p) {
954     case QEMU_PCI_EXP_LNK_2_5GT:
955         speed = PCIE_LINK_SPEED_2_5;
956         break;
957     case QEMU_PCI_EXP_LNK_5GT:
958         speed = PCIE_LINK_SPEED_5;
959         break;
960     case QEMU_PCI_EXP_LNK_8GT:
961         speed = PCIE_LINK_SPEED_8;
962         break;
963     case QEMU_PCI_EXP_LNK_16GT:
964         speed = PCIE_LINK_SPEED_16;
965         break;
966     default:
967         /* Unreachable */
968         abort();
969     }
970 
971     visit_type_enum(v, name, &speed, prop->info->enum_table, errp);
972 }
973 
974 static void set_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
975                                    void *opaque, Error **errp)
976 {
977     Property *prop = opaque;
978     PCIExpLinkSpeed *p = object_field_prop_ptr(obj, prop);
979     int speed;
980 
981     if (!visit_type_enum(v, name, &speed, prop->info->enum_table,
982                          errp)) {
983         return;
984     }
985 
986     switch (speed) {
987     case PCIE_LINK_SPEED_2_5:
988         *p = QEMU_PCI_EXP_LNK_2_5GT;
989         break;
990     case PCIE_LINK_SPEED_5:
991         *p = QEMU_PCI_EXP_LNK_5GT;
992         break;
993     case PCIE_LINK_SPEED_8:
994         *p = QEMU_PCI_EXP_LNK_8GT;
995         break;
996     case PCIE_LINK_SPEED_16:
997         *p = QEMU_PCI_EXP_LNK_16GT;
998         break;
999     default:
1000         /* Unreachable */
1001         abort();
1002     }
1003 }
1004 
1005 const PropertyInfo qdev_prop_pcie_link_speed = {
1006     .name = "PCIELinkSpeed",
1007     .description = "2_5/5/8/16",
1008     .enum_table = &PCIELinkSpeed_lookup,
1009     .get = get_prop_pcielinkspeed,
1010     .set = set_prop_pcielinkspeed,
1011     .set_default_value = qdev_propinfo_set_default_value_enum,
1012 };
1013 
1014 /* --- PCIELinkWidth 1/2/4/8/12/16/32 -- */
1015 
1016 static void get_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
1017                                    void *opaque, Error **errp)
1018 {
1019     Property *prop = opaque;
1020     PCIExpLinkWidth *p = object_field_prop_ptr(obj, prop);
1021     int width;
1022 
1023     switch (*p) {
1024     case QEMU_PCI_EXP_LNK_X1:
1025         width = PCIE_LINK_WIDTH_1;
1026         break;
1027     case QEMU_PCI_EXP_LNK_X2:
1028         width = PCIE_LINK_WIDTH_2;
1029         break;
1030     case QEMU_PCI_EXP_LNK_X4:
1031         width = PCIE_LINK_WIDTH_4;
1032         break;
1033     case QEMU_PCI_EXP_LNK_X8:
1034         width = PCIE_LINK_WIDTH_8;
1035         break;
1036     case QEMU_PCI_EXP_LNK_X12:
1037         width = PCIE_LINK_WIDTH_12;
1038         break;
1039     case QEMU_PCI_EXP_LNK_X16:
1040         width = PCIE_LINK_WIDTH_16;
1041         break;
1042     case QEMU_PCI_EXP_LNK_X32:
1043         width = PCIE_LINK_WIDTH_32;
1044         break;
1045     default:
1046         /* Unreachable */
1047         abort();
1048     }
1049 
1050     visit_type_enum(v, name, &width, prop->info->enum_table, errp);
1051 }
1052 
1053 static void set_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
1054                                    void *opaque, Error **errp)
1055 {
1056     Property *prop = opaque;
1057     PCIExpLinkWidth *p = object_field_prop_ptr(obj, prop);
1058     int width;
1059 
1060     if (!visit_type_enum(v, name, &width, prop->info->enum_table,
1061                          errp)) {
1062         return;
1063     }
1064 
1065     switch (width) {
1066     case PCIE_LINK_WIDTH_1:
1067         *p = QEMU_PCI_EXP_LNK_X1;
1068         break;
1069     case PCIE_LINK_WIDTH_2:
1070         *p = QEMU_PCI_EXP_LNK_X2;
1071         break;
1072     case PCIE_LINK_WIDTH_4:
1073         *p = QEMU_PCI_EXP_LNK_X4;
1074         break;
1075     case PCIE_LINK_WIDTH_8:
1076         *p = QEMU_PCI_EXP_LNK_X8;
1077         break;
1078     case PCIE_LINK_WIDTH_12:
1079         *p = QEMU_PCI_EXP_LNK_X12;
1080         break;
1081     case PCIE_LINK_WIDTH_16:
1082         *p = QEMU_PCI_EXP_LNK_X16;
1083         break;
1084     case PCIE_LINK_WIDTH_32:
1085         *p = QEMU_PCI_EXP_LNK_X32;
1086         break;
1087     default:
1088         /* Unreachable */
1089         abort();
1090     }
1091 }
1092 
1093 const PropertyInfo qdev_prop_pcie_link_width = {
1094     .name = "PCIELinkWidth",
1095     .description = "1/2/4/8/12/16/32",
1096     .enum_table = &PCIELinkWidth_lookup,
1097     .get = get_prop_pcielinkwidth,
1098     .set = set_prop_pcielinkwidth,
1099     .set_default_value = qdev_propinfo_set_default_value_enum,
1100 };
1101 
1102 /* --- UUID --- */
1103 
1104 static void get_uuid(Object *obj, Visitor *v, const char *name, void *opaque,
1105                      Error **errp)
1106 {
1107     Property *prop = opaque;
1108     QemuUUID *uuid = object_field_prop_ptr(obj, prop);
1109     char buffer[UUID_STR_LEN];
1110     char *p = buffer;
1111 
1112     qemu_uuid_unparse(uuid, buffer);
1113 
1114     visit_type_str(v, name, &p, errp);
1115 }
1116 
1117 #define UUID_VALUE_AUTO        "auto"
1118 
1119 static void set_uuid(Object *obj, Visitor *v, const char *name, void *opaque,
1120                     Error **errp)
1121 {
1122     Property *prop = opaque;
1123     QemuUUID *uuid = object_field_prop_ptr(obj, prop);
1124     char *str;
1125 
1126     if (!visit_type_str(v, name, &str, errp)) {
1127         return;
1128     }
1129 
1130     if (!strcmp(str, UUID_VALUE_AUTO)) {
1131         qemu_uuid_generate(uuid);
1132     } else if (qemu_uuid_parse(str, uuid) < 0) {
1133         error_set_from_qdev_prop_error(errp, EINVAL, obj, name, str);
1134     }
1135     g_free(str);
1136 }
1137 
1138 static void set_default_uuid_auto(ObjectProperty *op, const Property *prop)
1139 {
1140     object_property_set_default_str(op, UUID_VALUE_AUTO);
1141 }
1142 
1143 const PropertyInfo qdev_prop_uuid = {
1144     .name  = "str",
1145     .description = "UUID (aka GUID) or \"" UUID_VALUE_AUTO
1146         "\" for random value (default)",
1147     .get   = get_uuid,
1148     .set   = set_uuid,
1149     .set_default_value = set_default_uuid_auto,
1150 };
1151 
1152 /* --- s390 cpu entitlement policy --- */
1153 
1154 QEMU_BUILD_BUG_ON(sizeof(CpuS390Entitlement) != sizeof(int));
1155 
1156 const PropertyInfo qdev_prop_cpus390entitlement = {
1157     .name  = "CpuS390Entitlement",
1158     .description = "low/medium (default)/high",
1159     .enum_table  = &CpuS390Entitlement_lookup,
1160     .get   = qdev_propinfo_get_enum,
1161     .set   = qdev_propinfo_set_enum,
1162     .set_default_value = qdev_propinfo_set_default_value_enum,
1163 };
1164 
1165 /* --- IOThreadVirtQueueMappingList --- */
1166 
1167 static void get_iothread_vq_mapping_list(Object *obj, Visitor *v,
1168         const char *name, void *opaque, Error **errp)
1169 {
1170     IOThreadVirtQueueMappingList **prop_ptr =
1171         object_field_prop_ptr(obj, opaque);
1172 
1173     visit_type_IOThreadVirtQueueMappingList(v, name, prop_ptr, errp);
1174 }
1175 
1176 static void set_iothread_vq_mapping_list(Object *obj, Visitor *v,
1177         const char *name, void *opaque, Error **errp)
1178 {
1179     IOThreadVirtQueueMappingList **prop_ptr =
1180         object_field_prop_ptr(obj, opaque);
1181     IOThreadVirtQueueMappingList *list;
1182 
1183     if (!visit_type_IOThreadVirtQueueMappingList(v, name, &list, errp)) {
1184         return;
1185     }
1186 
1187     qapi_free_IOThreadVirtQueueMappingList(*prop_ptr);
1188     *prop_ptr = list;
1189 }
1190 
1191 static void release_iothread_vq_mapping_list(Object *obj,
1192         const char *name, void *opaque)
1193 {
1194     IOThreadVirtQueueMappingList **prop_ptr =
1195         object_field_prop_ptr(obj, opaque);
1196 
1197     qapi_free_IOThreadVirtQueueMappingList(*prop_ptr);
1198     *prop_ptr = NULL;
1199 }
1200 
1201 const PropertyInfo qdev_prop_iothread_vq_mapping_list = {
1202     .name = "IOThreadVirtQueueMappingList",
1203     .description = "IOThread virtqueue mapping list [{\"iothread\":\"<id>\", "
1204                    "\"vqs\":[1,2,3,...]},...]",
1205     .get = get_iothread_vq_mapping_list,
1206     .set = set_iothread_vq_mapping_list,
1207     .release = release_iothread_vq_mapping_list,
1208 };
1209