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