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