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