qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

qdev-properties-system.c (30366B)


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