]> git.proxmox.com Git - mirror_qemu.git/blame - hw/core/qdev-properties-system.c
Merge tag 'net-pull-request' of https://github.com/jasowang/qemu into staging
[mirror_qemu.git] / hw / core / qdev-properties-system.c
CommitLineData
a404b612 1/*
8d76bfe8 2 * qdev property parsing
a404b612
EH
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
18c86e2b 13#include "qemu/osdep.h"
a27bd6c7 14#include "hw/qdev-properties.h"
ce35e229 15#include "hw/qdev-properties-system.h"
da34e65c 16#include "qapi/error.h"
aa1859cc
PMD
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"
501a7ce7 21#include "qapi/qmp/qerror.h"
aa1859cc
PMD
22#include "qemu/ctype.h"
23#include "qemu/cutils.h"
24#include "qemu/units.h"
38255eff 25#include "qemu/uuid.h"
aa1859cc
PMD
26#include "qemu/error-report.h"
27#include "qdev-prop-internal.h"
28
29#include "audio/audio.h"
30#include "chardev/char-fe.h"
4be74634 31#include "sysemu/block-backend.h"
501a7ce7 32#include "sysemu/blockdev.h"
aa1859cc
PMD
33#include "net/net.h"
34#include "hw/pci/pci.h"
edf5ca5d 35#include "hw/pci/pcie.h"
aae16721 36#include "hw/i386/x86.h"
5937835a 37#include "util/block-helpers.h"
a404b612 38
38148159 39static bool check_prop_still_unset(Object *obj, const char *name,
1bc13336 40 const void *old_val, const char *new_val,
d1a58c17 41 bool allow_override, Error **errp)
1bc13336 42{
38148159 43 const GlobalProperty *prop = qdev_find_global_prop(obj, name);
1bc13336 44
d1a58c17 45 if (!old_val || (!prop && allow_override)) {
1bc13336
MA
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
466c2983
MA
61/* --- drive --- */
62
63static void get_drive(Object *obj, Visitor *v, const char *name, void *opaque,
64 Error **errp)
a404b612 65{
466c2983 66 Property *prop = opaque;
1e198715 67 void **ptr = object_field_prop_ptr(obj, prop);
466c2983 68 const char *value;
a404b612
EH
69 char *p;
70
466c2983
MA
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);
51e72bc1 84 visit_type_str(v, name, &p, errp);
7d1de464 85 g_free(p);
a404b612
EH
86}
87
466c2983
MA
88static void set_drive_helper(Object *obj, Visitor *v, const char *name,
89 void *opaque, bool iothread, Error **errp)
a404b612
EH
90{
91 DeviceState *dev = DEVICE(obj);
466c2983 92 Property *prop = opaque;
1e198715 93 void **ptr = object_field_prop_ptr(obj, prop);
a404b612 94 char *str;
466c2983
MA
95 BlockBackend *blk;
96 bool blk_created = false;
97 int ret;
d1a58c17
VSO
98 BlockDriverState *bs;
99 AioContext *ctx;
a404b612 100
668f62ec 101 if (!visit_type_str(v, name, &str, errp)) {
a404b612
EH
102 return;
103 }
466c2983 104
d1a58c17
VSO
105 if (!check_prop_still_unset(obj, name, *ptr, str, true, errp)) {
106 return;
107 }
108
109 if (*ptr) {
9b4b4e51 110 /* BlockBackend already exists. So, we want to change attached node */
d1a58c17
VSO
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);
84b0475c
MA
126 return;
127 }
128
a404b612
EH
129 if (!*str) {
130 g_free(str);
131 *ptr = NULL;
132 return;
133 }
a404b612 134
4be74634 135 blk = blk_by_name(str);
8daea510 136 if (!blk) {
d1a58c17 137 bs = bdrv_lookup_bs(NULL, str, NULL);
8daea510 138 if (bs) {
307a5f60
KW
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 */
415275ae
KW
146 ctx = bdrv_get_aio_context(bs);
147 blk = blk_new(iothread ? ctx : qemu_get_aio_context(),
148 0, BLK_PERM_ALL);
8daea510 149 blk_created = true;
d7086422 150
415275ae 151 aio_context_acquire(ctx);
d7086422 152 ret = blk_insert_bs(blk, bs, errp);
415275ae
KW
153 aio_context_release(ctx);
154
d7086422
KW
155 if (ret < 0) {
156 goto fail;
157 }
8daea510
KW
158 }
159 }
4be74634 160 if (!blk) {
f1fb9f0d 161 error_setg(errp, "Property '%s.%s' can't find value '%s'",
991f0ac9 162 object_get_typename(OBJECT(dev)), name, str);
8daea510 163 goto fail;
a404b612 164 }
4be74634 165 if (blk_attach_dev(blk, dev) < 0) {
62f7dbde
PM
166 DriveInfo *dinfo = blk_legacy_dinfo(blk);
167
a9d52a75 168 if (dinfo && dinfo->type != IF_NONE) {
62f7dbde
PM
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 }
8daea510 177 goto fail;
a404b612 178 }
8daea510 179
4be74634 180 *ptr = blk;
8daea510
KW
181
182fail:
183 if (blk_created) {
184 /* If we need to keep a reference, blk_attach_dev() took it */
185 blk_unref(blk);
186 }
466c2983
MA
187
188 g_free(str);
a404b612
EH
189}
190
466c2983
MA
191static void set_drive(Object *obj, Visitor *v, const char *name, void *opaque,
192 Error **errp)
307a5f60 193{
466c2983 194 set_drive_helper(obj, v, name, opaque, false, errp);
307a5f60
KW
195}
196
466c2983
MA
197static void set_drive_iothread(Object *obj, Visitor *v, const char *name,
198 void *opaque, Error **errp)
307a5f60 199{
466c2983 200 set_drive_helper(obj, v, name, opaque, true, errp);
307a5f60
KW
201}
202
a404b612
EH
203static void release_drive(Object *obj, const char *name, void *opaque)
204{
205 DeviceState *dev = DEVICE(obj);
206 Property *prop = opaque;
1e198715 207 BlockBackend **ptr = object_field_prop_ptr(obj, prop);
a404b612
EH
208
209 if (*ptr) {
9588c589
DL
210 AioContext *ctx = blk_get_aio_context(*ptr);
211
212 aio_context_acquire(ctx);
a404b612 213 blockdev_auto_del(*ptr);
8daea510 214 blk_detach_dev(*ptr, dev);
9588c589 215 aio_context_release(ctx);
a404b612
EH
216 }
217}
218
1b6b7d10 219const PropertyInfo qdev_prop_drive = {
85ca1202 220 .name = "str",
8daea510 221 .description = "Node name or ID of a block device to use as a backend",
d1a58c17 222 .realized_set_allowed = true,
a404b612
EH
223 .get = get_drive,
224 .set = set_drive,
225 .release = release_drive,
226};
227
307a5f60
KW
228const PropertyInfo qdev_prop_drive_iothread = {
229 .name = "str",
230 .description = "Node name or ID of a block device to use as a backend",
d1a58c17 231 .realized_set_allowed = true,
307a5f60
KW
232 .get = get_drive,
233 .set = set_drive_iothread,
234 .release = release_drive,
235};
236
a404b612
EH
237/* --- character device --- */
238
becdfa00
MAL
239static void get_chr(Object *obj, Visitor *v, const char *name, void *opaque,
240 Error **errp)
a404b612 241{
1e198715 242 CharBackend *be = object_field_prop_ptr(obj, opaque);
becdfa00
MAL
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);
a404b612
EH
248}
249
becdfa00
MAL
250static void set_chr(Object *obj, Visitor *v, const char *name, void *opaque,
251 Error **errp)
a404b612 252{
a404b612 253 Property *prop = opaque;
1e198715 254 CharBackend *be = object_field_prop_ptr(obj, prop);
0ec7b3e7 255 Chardev *s;
becdfa00 256 char *str;
a404b612 257
668f62ec 258 if (!visit_type_str(v, name, &str, errp)) {
becdfa00
MAL
259 return;
260 }
a404b612 261
9572a787
MA
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 */
d1a58c17 266 if (!check_prop_still_unset(obj, name, be->chr, str, false, errp)) {
9572a787
MA
267 return;
268 }
269
becdfa00
MAL
270 if (!*str) {
271 g_free(str);
272 be->chr = NULL;
273 return;
274 }
a404b612 275
becdfa00 276 s = qemu_chr_find(str);
becdfa00
MAL
277 if (s == NULL) {
278 error_setg(errp, "Property '%s.%s' can't find value '%s'",
991f0ac9 279 object_get_typename(obj), name, str);
2209401f 280 } else if (!qemu_chr_fe_init(be, s, errp)) {
c39860e6 281 error_prepend(errp, "Property '%s.%s' can't take value '%s': ",
991f0ac9 282 object_get_typename(obj), name, str);
becdfa00 283 }
2209401f 284 g_free(str);
a404b612
EH
285}
286
becdfa00 287static void release_chr(Object *obj, const char *name, void *opaque)
a404b612 288{
becdfa00 289 Property *prop = opaque;
1e198715 290 CharBackend *be = object_field_prop_ptr(obj, prop);
becdfa00 291
1ce2610c 292 qemu_chr_fe_deinit(be, false);
a404b612
EH
293}
294
1b6b7d10 295const PropertyInfo qdev_prop_chr = {
85ca1202 296 .name = "str",
51b2e8c3 297 .description = "ID of a chardev to use as a backend",
a404b612
EH
298 .get = get_chr,
299 .set = set_chr,
300 .release = release_chr,
301};
302
aa1859cc
PMD
303/* --- mac address --- */
304
305/*
306 * accepted syntax versions:
307 * 01:02:03:04:05:06
308 * 01-02-03-04-05-06
309 */
310static void get_mac(Object *obj, Visitor *v, const char *name, void *opaque,
311 Error **errp)
312{
aa1859cc 313 Property *prop = opaque;
1e198715 314 MACAddr *mac = object_field_prop_ptr(obj, prop);
aa1859cc
PMD
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
325static void set_mac(Object *obj, Visitor *v, const char *name, void *opaque,
326 Error **errp)
327{
aa1859cc 328 Property *prop = opaque;
1e198715 329 MACAddr *mac = object_field_prop_ptr(obj, prop);
aa1859cc
PMD
330 int i, pos;
331 char *str;
332 const char *p;
333
aa1859cc
PMD
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
364inval:
e68c2cb7 365 error_set_from_qdev_prop_error(errp, EINVAL, obj, name, str);
aa1859cc
PMD
366 g_free(str);
367}
368
369const 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
376void 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
a404b612 386/* --- netdev device --- */
d7bce999
EB
387static void get_netdev(Object *obj, Visitor *v, const char *name,
388 void *opaque, Error **errp)
23120b13 389{
23120b13 390 Property *prop = opaque;
1e198715 391 NICPeers *peers_ptr = object_field_prop_ptr(obj, prop);
23120b13
JW
392 char *p = g_strdup(peers_ptr->ncs[0] ? peers_ptr->ncs[0]->name : "");
393
51e72bc1 394 visit_type_str(v, name, &p, errp);
23120b13
JW
395 g_free(p);
396}
a404b612 397
d7bce999
EB
398static void set_netdev(Object *obj, Visitor *v, const char *name,
399 void *opaque, Error **errp)
a404b612 400{
23120b13 401 Property *prop = opaque;
1e198715 402 NICPeers *peers_ptr = object_field_prop_ptr(obj, prop);
1ceef9f2
JW
403 NetClientState **ncs = peers_ptr->ncs;
404 NetClientState *peers[MAX_QUEUE_NUM];
23120b13
JW
405 int queues, err = 0, i = 0;
406 char *str;
407
668f62ec 408 if (!visit_type_str(v, name, &str, errp)) {
23120b13
JW
409 return;
410 }
a404b612 411
1ceef9f2 412 queues = qemu_find_net_clients_except(str, peers,
f394b2e2 413 NET_CLIENT_DRIVER_NIC,
1ceef9f2
JW
414 MAX_QUEUE_NUM);
415 if (queues == 0) {
23120b13
JW
416 err = -ENOENT;
417 goto out;
a404b612 418 }
1ceef9f2
JW
419
420 if (queues > MAX_QUEUE_NUM) {
23120b13
JW
421 error_setg(errp, "queues of backend '%s'(%d) exceeds QEMU limitation(%d)",
422 str, queues, MAX_QUEUE_NUM);
423 goto out;
1ceef9f2
JW
424 }
425
426 for (i = 0; i < queues; i++) {
1ceef9f2 427 if (peers[i]->peer) {
23120b13
JW
428 err = -EEXIST;
429 goto out;
1ceef9f2
JW
430 }
431
1bc13336
MA
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 */
d1a58c17 436 if (!check_prop_still_unset(obj, name, ncs[i], str, false, errp)) {
23120b13 437 goto out;
30c367ed
VY
438 }
439
e287bf7b
KW
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
1ceef9f2
JW
446 ncs[i] = peers[i];
447 ncs[i]->queue_index = i;
a404b612 448 }
1ceef9f2 449
575a1c0e 450 peers_ptr->queues = queues;
1ceef9f2 451
23120b13 452out:
3257b854 453 error_set_from_qdev_prop_error(errp, err, obj, prop->name, str);
23120b13 454 g_free(str);
a404b612
EH
455}
456
1b6b7d10 457const PropertyInfo qdev_prop_netdev = {
85ca1202 458 .name = "str",
51b2e8c3 459 .description = "ID of a netdev to use as a backend",
a404b612
EH
460 .get = get_netdev,
461 .set = set_netdev,
462};
463
a404b612 464
88e47b9a
KZ
465/* --- audiodev --- */
466static void get_audiodev(Object *obj, Visitor *v, const char* name,
467 void *opaque, Error **errp)
468{
88e47b9a 469 Property *prop = opaque;
1e198715 470 QEMUSoundCard *card = object_field_prop_ptr(obj, prop);
88e47b9a
KZ
471 char *p = g_strdup(audio_get_id(card));
472
473 visit_type_str(v, name, &p, errp);
474 g_free(p);
475}
476
477static void set_audiodev(Object *obj, Visitor *v, const char* name,
478 void *opaque, Error **errp)
479{
88e47b9a 480 Property *prop = opaque;
1e198715 481 QEMUSoundCard *card = object_field_prop_ptr(obj, prop);
88e47b9a 482 AudioState *state;
176adafc 483 g_autofree char *str = NULL;
88e47b9a 484
668f62ec 485 if (!visit_type_str(v, name, &str, errp)) {
88e47b9a
KZ
486 return;
487 }
488
176adafc
PB
489 state = audio_state_by_name(str, errp);
490 if (state) {
491 card->state = state;
88e47b9a 492 }
88e47b9a
KZ
493}
494
495const 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
73ac1aac 503bool qdev_prop_set_drive_err(DeviceState *dev, const char *name,
934df912 504 BlockBackend *value, Error **errp)
a404b612 505{
8daea510
KW
506 const char *ref = "";
507
508 if (value) {
509 ref = blk_name(value);
510 if (!*ref) {
be9721f4 511 const BlockDriverState *bs = blk_bs(value);
8daea510
KW
512 if (bs) {
513 ref = bdrv_get_node_name(bs);
514 }
515 }
516 }
517
73ac1aac 518 return object_property_set_str(OBJECT(dev), name, ref, errp);
a404b612
EH
519}
520
934df912
MA
521void 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
a404b612 527void qdev_prop_set_chr(DeviceState *dev, const char *name,
0ec7b3e7 528 Chardev *value)
a404b612 529{
a404b612 530 assert(!value || value->label);
5325cc34
MA
531 object_property_set_str(OBJECT(dev), name, value ? value->label : "",
532 &error_abort);
a404b612
EH
533}
534
535void qdev_prop_set_netdev(DeviceState *dev, const char *name,
536 NetClientState *value)
537{
a404b612 538 assert(!value || value->name);
5325cc34
MA
539 object_property_set_str(OBJECT(dev), name, value ? value->name : "",
540 &error_abort);
a404b612
EH
541}
542
543void 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 &&
efba1595 550 object_property_find(OBJECT(dev), "vectors")) {
a404b612
EH
551 qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
552 }
553 nd->instantiated = 1;
554}
aa1859cc
PMD
555
556/* --- lost tick policy --- */
557
aae16721
TH
558static 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
aa1859cc
PMD
583QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int));
584
585const PropertyInfo qdev_prop_losttickpolicy = {
586 .name = "LostTickPolicy",
587 .enum_table = &LostTickPolicy_lookup,
588 .get = qdev_propinfo_get_enum,
aae16721 589 .set = qdev_propinfo_set_losttickpolicy,
aa1859cc
PMD
590 .set_default_value = qdev_propinfo_set_default_value_enum,
591};
592
593/* --- blocksize --- */
594
aa1859cc
PMD
595static 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;
1e198715 600 uint32_t *ptr = object_field_prop_ptr(obj, prop);
aa1859cc 601 uint64_t value;
5937835a 602 Error *local_err = NULL;
aa1859cc 603
aa1859cc
PMD
604 if (!visit_type_size(v, name, &value, errp)) {
605 return;
606 }
5937835a
CX
607 check_block_size(dev->id ? : "", name, value, &local_err);
608 if (local_err) {
609 error_propagate(errp, local_err);
aa1859cc
PMD
610 return;
611 }
aa1859cc
PMD
612 *ptr = value;
613}
614
615const 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
626QEMU_BUILD_BUG_ON(sizeof(BlockdevOnError) != sizeof(int));
627
628const 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
640QEMU_BUILD_BUG_ON(sizeof(BiosAtaTranslation) != sizeof(int));
641
642const 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
654const 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
666const 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
eea1e5c9
SS
676/* --- MigMode --- */
677
678QEMU_BUILD_BUG_ON(sizeof(MigMode) != sizeof(int));
679
680const PropertyInfo qdev_prop_mig_mode = {
681 .name = "MigMode",
682 .description = "mig_mode values, "
a87e6451 683 "normal,cpr-reboot",
eea1e5c9
SS
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
aa1859cc
PMD
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 */
698static void get_reserved_region(Object *obj, Visitor *v, const char *name,
699 void *opaque, Error **errp)
700{
aa1859cc 701 Property *prop = opaque;
1e198715 702 ReservedRegion *rr = object_field_prop_ptr(obj, prop);
aa1859cc
PMD
703 char buffer[64];
704 char *p = buffer;
705 int rc;
706
707 rc = snprintf(buffer, sizeof(buffer), "0x%"PRIx64":0x%"PRIx64":%u",
e8f433f8 708 range_lob(&rr->range), range_upb(&rr->range), rr->type);
aa1859cc
PMD
709 assert(rc < sizeof(buffer));
710
711 visit_type_str(v, name, &p, errp);
712}
713
714static void set_reserved_region(Object *obj, Visitor *v, const char *name,
715 void *opaque, Error **errp)
716{
aa1859cc 717 Property *prop = opaque;
1e198715 718 ReservedRegion *rr = object_field_prop_ptr(obj, prop);
aa1859cc 719 const char *endptr;
e8f433f8 720 uint64_t lob, upb;
aa1859cc
PMD
721 char *str;
722 int ret;
723
d1c81c34 724 if (!visit_type_str(v, name, &str, errp)) {
aa1859cc
PMD
725 return;
726 }
727
e8f433f8 728 ret = qemu_strtou64(str, &endptr, 16, &lob);
aa1859cc
PMD
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
e8f433f8 738 ret = qemu_strtou64(endptr + 1, &endptr, 16, &upb);
aa1859cc
PMD
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
e8f433f8
EA
748 range_set_bounds(&rr->range, lob, upb);
749
aa1859cc
PMD
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
757separator_error:
758 error_setg(errp, "reserved region fields must be separated with ':'");
759out:
760 g_free(str);
761 return;
762}
763
764const 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 */
776static void set_pci_devfn(Object *obj, Visitor *v, const char *name,
777 void *opaque, Error **errp)
778{
aa1859cc 779 Property *prop = opaque;
1e198715 780 int32_t value, *ptr = object_field_prop_ptr(obj, prop);
aa1859cc
PMD
781 unsigned int slot, fn, n;
782 char *str;
783
aa1859cc
PMD
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,
6cc0667d 790 name ? name : "null", "a value between -1 and 255");
aa1859cc
PMD
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
810invalid:
e68c2cb7 811 error_set_from_qdev_prop_error(errp, EINVAL, obj, name, str);
aa1859cc
PMD
812 g_free(str);
813}
814
40ea00b0 815static int print_pci_devfn(Object *obj, Property *prop, char *dest,
aa1859cc
PMD
816 size_t len)
817{
1e198715 818 int32_t *ptr = object_field_prop_ptr(obj, prop);
aa1859cc
PMD
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
827const 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
838static void get_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
839 void *opaque, Error **errp)
840{
aa1859cc 841 Property *prop = opaque;
1e198715 842 PCIHostDeviceAddress *addr = object_field_prop_ptr(obj, prop);
aa1859cc
PMD
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 */
864static void set_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
865 void *opaque, Error **errp)
866{
aa1859cc 867 Property *prop = opaque;
1e198715 868 PCIHostDeviceAddress *addr = object_field_prop_ptr(obj, prop);
aa1859cc 869 char *str, *p;
28afbc1f 870 char *e;
aa1859cc
PMD
871 unsigned long val;
872 unsigned long dom = 0, bus = 0;
873 unsigned int slot = 0, func = 0;
874
aa1859cc
PMD
875 if (!visit_type_str(v, name, &str, errp)) {
876 return;
877 }
878
879 p = str;
28afbc1f
MT
880 val = strtoul(p, &e, 16);
881 if (e == p || *e != ':') {
aa1859cc
PMD
882 goto inval;
883 }
884 bus = val;
885
28afbc1f
MT
886 p = e + 1;
887 val = strtoul(p, &e, 16);
888 if (e == p) {
aa1859cc
PMD
889 goto inval;
890 }
891 if (*e == ':') {
892 dom = bus;
893 bus = val;
28afbc1f
MT
894 p = e + 1;
895 val = strtoul(p, &e, 16);
896 if (e == p) {
aa1859cc
PMD
897 goto inval;
898 }
899 }
900 slot = val;
901
902 if (*e != '.') {
903 goto inval;
904 }
28afbc1f
MT
905 p = e + 1;
906 val = strtoul(p, &e, 10);
907 if (e == p) {
aa1859cc
PMD
908 goto inval;
909 }
910 func = val;
911
28afbc1f 912 if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) {
aa1859cc
PMD
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
928inval:
e68c2cb7 929 error_set_from_qdev_prop_error(errp, EINVAL, obj, name, str);
aa1859cc
PMD
930 g_free(str);
931}
932
933const 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
943const 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
954static void get_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
955 void *opaque, Error **errp)
956{
aa1859cc 957 Property *prop = opaque;
1e198715 958 PCIExpLinkSpeed *p = object_field_prop_ptr(obj, prop);
aa1859cc
PMD
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
991f0ac9 979 visit_type_enum(v, name, &speed, prop->info->enum_table, errp);
aa1859cc
PMD
980}
981
982static void set_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
983 void *opaque, Error **errp)
984{
aa1859cc 985 Property *prop = opaque;
1e198715 986 PCIExpLinkSpeed *p = object_field_prop_ptr(obj, prop);
aa1859cc
PMD
987 int speed;
988
991f0ac9 989 if (!visit_type_enum(v, name, &speed, prop->info->enum_table,
aa1859cc
PMD
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
1013const 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
1024static void get_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
1025 void *opaque, Error **errp)
1026{
aa1859cc 1027 Property *prop = opaque;
1e198715 1028 PCIExpLinkWidth *p = object_field_prop_ptr(obj, prop);
aa1859cc
PMD
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
991f0ac9 1058 visit_type_enum(v, name, &width, prop->info->enum_table, errp);
aa1859cc
PMD
1059}
1060
1061static void set_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
1062 void *opaque, Error **errp)
1063{
aa1859cc 1064 Property *prop = opaque;
1e198715 1065 PCIExpLinkWidth *p = object_field_prop_ptr(obj, prop);
aa1859cc
PMD
1066 int width;
1067
991f0ac9 1068 if (!visit_type_enum(v, name, &width, prop->info->enum_table,
aa1859cc
PMD
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
1101const 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};
38255eff
EH
1109
1110/* --- UUID --- */
1111
1112static void get_uuid(Object *obj, Visitor *v, const char *name, void *opaque,
1113 Error **errp)
1114{
1115 Property *prop = opaque;
1e198715 1116 QemuUUID *uuid = object_field_prop_ptr(obj, prop);
721da039 1117 char buffer[UUID_STR_LEN];
38255eff
EH
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
1127static void set_uuid(Object *obj, Visitor *v, const char *name, void *opaque,
1128 Error **errp)
1129{
38255eff 1130 Property *prop = opaque;
1e198715 1131 QemuUUID *uuid = object_field_prop_ptr(obj, prop);
38255eff
EH
1132 char *str;
1133
38255eff
EH
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) {
e68c2cb7 1141 error_set_from_qdev_prop_error(errp, EINVAL, obj, name, str);
38255eff
EH
1142 }
1143 g_free(str);
1144}
1145
1146static void set_default_uuid_auto(ObjectProperty *op, const Property *prop)
1147{
1148 object_property_set_default_str(op, UUID_VALUE_AUTO);
1149}
1150
1151const 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};
5de1aff2
PM
1159
1160/* --- s390 cpu entitlement policy --- */
1161
1162QEMU_BUILD_BUG_ON(sizeof(CpuS390Entitlement) != sizeof(int));
1163
1164const 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};