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