cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

qdev-properties-system.c (30188B)


      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
     37static 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
     61static 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
     86static 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
    176fail:
    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
    185static 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
    191static 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
    197static 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
    213const 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
    222const 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
    233static 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
    244static 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
    281static 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
    289const 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 */
    304static 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
    319static 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
    358inval:
    359    error_set_from_qdev_prop_error(errp, EINVAL, obj, name, str);
    360    g_free(str);
    361}
    362
    363const 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
    370void 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 --- */
    381static 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
    392static 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        ncs[i] = peers[i];
    435        ncs[i]->queue_index = i;
    436    }
    437
    438    peers_ptr->queues = queues;
    439
    440out:
    441    error_set_from_qdev_prop_error(errp, err, obj, name, str);
    442    g_free(str);
    443}
    444
    445const PropertyInfo qdev_prop_netdev = {
    446    .name  = "str",
    447    .description = "ID of a netdev to use as a backend",
    448    .get   = get_netdev,
    449    .set   = set_netdev,
    450};
    451
    452
    453/* --- audiodev --- */
    454static void get_audiodev(Object *obj, Visitor *v, const char* name,
    455                         void *opaque, Error **errp)
    456{
    457    Property *prop = opaque;
    458    QEMUSoundCard *card = object_field_prop_ptr(obj, prop);
    459    char *p = g_strdup(audio_get_id(card));
    460
    461    visit_type_str(v, name, &p, errp);
    462    g_free(p);
    463}
    464
    465static void set_audiodev(Object *obj, Visitor *v, const char* name,
    466                         void *opaque, Error **errp)
    467{
    468    Property *prop = opaque;
    469    QEMUSoundCard *card = object_field_prop_ptr(obj, prop);
    470    AudioState *state;
    471    int err = 0;
    472    char *str;
    473
    474    if (!visit_type_str(v, name, &str, errp)) {
    475        return;
    476    }
    477
    478    state = audio_state_by_name(str);
    479
    480    if (!state) {
    481        err = -ENOENT;
    482        goto out;
    483    }
    484    card->state = state;
    485
    486out:
    487    error_set_from_qdev_prop_error(errp, err, obj, name, str);
    488    g_free(str);
    489}
    490
    491const PropertyInfo qdev_prop_audiodev = {
    492    .name = "str",
    493    .description = "ID of an audiodev to use as a backend",
    494    /* release done on shutdown */
    495    .get = get_audiodev,
    496    .set = set_audiodev,
    497};
    498
    499bool qdev_prop_set_drive_err(DeviceState *dev, const char *name,
    500                             BlockBackend *value, Error **errp)
    501{
    502    const char *ref = "";
    503
    504    if (value) {
    505        ref = blk_name(value);
    506        if (!*ref) {
    507            const BlockDriverState *bs = blk_bs(value);
    508            if (bs) {
    509                ref = bdrv_get_node_name(bs);
    510            }
    511        }
    512    }
    513
    514    return object_property_set_str(OBJECT(dev), name, ref, errp);
    515}
    516
    517void qdev_prop_set_drive(DeviceState *dev, const char *name,
    518                         BlockBackend *value)
    519{
    520    qdev_prop_set_drive_err(dev, name, value, &error_abort);
    521}
    522
    523void qdev_prop_set_chr(DeviceState *dev, const char *name,
    524                       Chardev *value)
    525{
    526    assert(!value || value->label);
    527    object_property_set_str(OBJECT(dev), name, value ? value->label : "",
    528                            &error_abort);
    529}
    530
    531void qdev_prop_set_netdev(DeviceState *dev, const char *name,
    532                          NetClientState *value)
    533{
    534    assert(!value || value->name);
    535    object_property_set_str(OBJECT(dev), name, value ? value->name : "",
    536                            &error_abort);
    537}
    538
    539void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
    540{
    541    qdev_prop_set_macaddr(dev, "mac", nd->macaddr.a);
    542    if (nd->netdev) {
    543        qdev_prop_set_netdev(dev, "netdev", nd->netdev);
    544    }
    545    if (nd->nvectors != DEV_NVECTORS_UNSPECIFIED &&
    546        object_property_find(OBJECT(dev), "vectors")) {
    547        qdev_prop_set_uint32(dev, "vectors", nd->nvectors);
    548    }
    549    nd->instantiated = 1;
    550}
    551
    552/* --- lost tick policy --- */
    553
    554QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int));
    555
    556const PropertyInfo qdev_prop_losttickpolicy = {
    557    .name  = "LostTickPolicy",
    558    .enum_table  = &LostTickPolicy_lookup,
    559    .get   = qdev_propinfo_get_enum,
    560    .set   = qdev_propinfo_set_enum,
    561    .set_default_value = qdev_propinfo_set_default_value_enum,
    562};
    563
    564/* --- blocksize --- */
    565
    566static void set_blocksize(Object *obj, Visitor *v, const char *name,
    567                          void *opaque, Error **errp)
    568{
    569    DeviceState *dev = DEVICE(obj);
    570    Property *prop = opaque;
    571    uint32_t *ptr = object_field_prop_ptr(obj, prop);
    572    uint64_t value;
    573    Error *local_err = NULL;
    574
    575    if (!visit_type_size(v, name, &value, errp)) {
    576        return;
    577    }
    578    check_block_size(dev->id ? : "", name, value, &local_err);
    579    if (local_err) {
    580        error_propagate(errp, local_err);
    581        return;
    582    }
    583    *ptr = value;
    584}
    585
    586const PropertyInfo qdev_prop_blocksize = {
    587    .name  = "size",
    588    .description = "A power of two between " MIN_BLOCK_SIZE_STR
    589                   " and " MAX_BLOCK_SIZE_STR,
    590    .get   = qdev_propinfo_get_size32,
    591    .set   = set_blocksize,
    592    .set_default_value = qdev_propinfo_set_default_value_uint,
    593};
    594
    595/* --- Block device error handling policy --- */
    596
    597QEMU_BUILD_BUG_ON(sizeof(BlockdevOnError) != sizeof(int));
    598
    599const PropertyInfo qdev_prop_blockdev_on_error = {
    600    .name = "BlockdevOnError",
    601    .description = "Error handling policy, "
    602                   "report/ignore/enospc/stop/auto",
    603    .enum_table = &BlockdevOnError_lookup,
    604    .get = qdev_propinfo_get_enum,
    605    .set = qdev_propinfo_set_enum,
    606    .set_default_value = qdev_propinfo_set_default_value_enum,
    607};
    608
    609/* --- BIOS CHS translation */
    610
    611QEMU_BUILD_BUG_ON(sizeof(BiosAtaTranslation) != sizeof(int));
    612
    613const PropertyInfo qdev_prop_bios_chs_trans = {
    614    .name = "BiosAtaTranslation",
    615    .description = "Logical CHS translation algorithm, "
    616                   "auto/none/lba/large/rechs",
    617    .enum_table = &BiosAtaTranslation_lookup,
    618    .get = qdev_propinfo_get_enum,
    619    .set = qdev_propinfo_set_enum,
    620    .set_default_value = qdev_propinfo_set_default_value_enum,
    621};
    622
    623/* --- FDC default drive types */
    624
    625const PropertyInfo qdev_prop_fdc_drive_type = {
    626    .name = "FdcDriveType",
    627    .description = "FDC drive type, "
    628                   "144/288/120/none/auto",
    629    .enum_table = &FloppyDriveType_lookup,
    630    .get = qdev_propinfo_get_enum,
    631    .set = qdev_propinfo_set_enum,
    632    .set_default_value = qdev_propinfo_set_default_value_enum,
    633};
    634
    635/* --- MultiFDCompression --- */
    636
    637const PropertyInfo qdev_prop_multifd_compression = {
    638    .name = "MultiFDCompression",
    639    .description = "multifd_compression values, "
    640                   "none/zlib/zstd",
    641    .enum_table = &MultiFDCompression_lookup,
    642    .get = qdev_propinfo_get_enum,
    643    .set = qdev_propinfo_set_enum,
    644    .set_default_value = qdev_propinfo_set_default_value_enum,
    645};
    646
    647/* --- Reserved Region --- */
    648
    649/*
    650 * Accepted syntax:
    651 *   <low address>:<high address>:<type>
    652 *   where low/high addresses are uint64_t in hexadecimal
    653 *   and type is a non-negative decimal integer
    654 */
    655static void get_reserved_region(Object *obj, Visitor *v, const char *name,
    656                                void *opaque, Error **errp)
    657{
    658    Property *prop = opaque;
    659    ReservedRegion *rr = object_field_prop_ptr(obj, prop);
    660    char buffer[64];
    661    char *p = buffer;
    662    int rc;
    663
    664    rc = snprintf(buffer, sizeof(buffer), "0x%"PRIx64":0x%"PRIx64":%u",
    665                  rr->low, rr->high, rr->type);
    666    assert(rc < sizeof(buffer));
    667
    668    visit_type_str(v, name, &p, errp);
    669}
    670
    671static void set_reserved_region(Object *obj, Visitor *v, const char *name,
    672                                void *opaque, Error **errp)
    673{
    674    Property *prop = opaque;
    675    ReservedRegion *rr = object_field_prop_ptr(obj, prop);
    676    Error *local_err = NULL;
    677    const char *endptr;
    678    char *str;
    679    int ret;
    680
    681    visit_type_str(v, name, &str, &local_err);
    682    if (local_err) {
    683        error_propagate(errp, local_err);
    684        return;
    685    }
    686
    687    ret = qemu_strtou64(str, &endptr, 16, &rr->low);
    688    if (ret) {
    689        error_setg(errp, "start address of '%s'"
    690                   " must be a hexadecimal integer", name);
    691        goto out;
    692    }
    693    if (*endptr != ':') {
    694        goto separator_error;
    695    }
    696
    697    ret = qemu_strtou64(endptr + 1, &endptr, 16, &rr->high);
    698    if (ret) {
    699        error_setg(errp, "end address of '%s'"
    700                   " must be a hexadecimal integer", name);
    701        goto out;
    702    }
    703    if (*endptr != ':') {
    704        goto separator_error;
    705    }
    706
    707    ret = qemu_strtoui(endptr + 1, &endptr, 10, &rr->type);
    708    if (ret) {
    709        error_setg(errp, "type of '%s'"
    710                   " must be a non-negative decimal integer", name);
    711    }
    712    goto out;
    713
    714separator_error:
    715    error_setg(errp, "reserved region fields must be separated with ':'");
    716out:
    717    g_free(str);
    718    return;
    719}
    720
    721const PropertyInfo qdev_prop_reserved_region = {
    722    .name  = "reserved_region",
    723    .description = "Reserved Region, example: 0xFEE00000:0xFEEFFFFF:0",
    724    .get   = get_reserved_region,
    725    .set   = set_reserved_region,
    726};
    727
    728/* --- pci address --- */
    729
    730/*
    731 * bus-local address, i.e. "$slot" or "$slot.$fn"
    732 */
    733static void set_pci_devfn(Object *obj, Visitor *v, const char *name,
    734                          void *opaque, Error **errp)
    735{
    736    Property *prop = opaque;
    737    int32_t value, *ptr = object_field_prop_ptr(obj, prop);
    738    unsigned int slot, fn, n;
    739    char *str;
    740
    741    if (!visit_type_str(v, name, &str, NULL)) {
    742        if (!visit_type_int32(v, name, &value, errp)) {
    743            return;
    744        }
    745        if (value < -1 || value > 255) {
    746            error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
    747                       name ? name : "null", "a value between -1 and 255");
    748            return;
    749        }
    750        *ptr = value;
    751        return;
    752    }
    753
    754    if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
    755        fn = 0;
    756        if (sscanf(str, "%x%n", &slot, &n) != 1) {
    757            goto invalid;
    758        }
    759    }
    760    if (str[n] != '\0' || fn > 7 || slot > 31) {
    761        goto invalid;
    762    }
    763    *ptr = slot << 3 | fn;
    764    g_free(str);
    765    return;
    766
    767invalid:
    768    error_set_from_qdev_prop_error(errp, EINVAL, obj, name, str);
    769    g_free(str);
    770}
    771
    772static int print_pci_devfn(Object *obj, Property *prop, char *dest,
    773                           size_t len)
    774{
    775    int32_t *ptr = object_field_prop_ptr(obj, prop);
    776
    777    if (*ptr == -1) {
    778        return snprintf(dest, len, "<unset>");
    779    } else {
    780        return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7);
    781    }
    782}
    783
    784const PropertyInfo qdev_prop_pci_devfn = {
    785    .name  = "int32",
    786    .description = "Slot and optional function number, example: 06.0 or 06",
    787    .print = print_pci_devfn,
    788    .get   = qdev_propinfo_get_int32,
    789    .set   = set_pci_devfn,
    790    .set_default_value = qdev_propinfo_set_default_value_int,
    791};
    792
    793/* --- pci host address --- */
    794
    795static void get_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
    796                                 void *opaque, Error **errp)
    797{
    798    Property *prop = opaque;
    799    PCIHostDeviceAddress *addr = object_field_prop_ptr(obj, prop);
    800    char buffer[] = "ffff:ff:ff.f";
    801    char *p = buffer;
    802    int rc = 0;
    803
    804    /*
    805     * Catch "invalid" device reference from vfio-pci and allow the
    806     * default buffer representing the non-existent device to be used.
    807     */
    808    if (~addr->domain || ~addr->bus || ~addr->slot || ~addr->function) {
    809        rc = snprintf(buffer, sizeof(buffer), "%04x:%02x:%02x.%0d",
    810                      addr->domain, addr->bus, addr->slot, addr->function);
    811        assert(rc == sizeof(buffer) - 1);
    812    }
    813
    814    visit_type_str(v, name, &p, errp);
    815}
    816
    817/*
    818 * Parse [<domain>:]<bus>:<slot>.<func>
    819 *   if <domain> is not supplied, it's assumed to be 0.
    820 */
    821static void set_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
    822                                 void *opaque, Error **errp)
    823{
    824    Property *prop = opaque;
    825    PCIHostDeviceAddress *addr = object_field_prop_ptr(obj, prop);
    826    char *str, *p;
    827    char *e;
    828    unsigned long val;
    829    unsigned long dom = 0, bus = 0;
    830    unsigned int slot = 0, func = 0;
    831
    832    if (!visit_type_str(v, name, &str, errp)) {
    833        return;
    834    }
    835
    836    p = str;
    837    val = strtoul(p, &e, 16);
    838    if (e == p || *e != ':') {
    839        goto inval;
    840    }
    841    bus = val;
    842
    843    p = e + 1;
    844    val = strtoul(p, &e, 16);
    845    if (e == p) {
    846        goto inval;
    847    }
    848    if (*e == ':') {
    849        dom = bus;
    850        bus = val;
    851        p = e + 1;
    852        val = strtoul(p, &e, 16);
    853        if (e == p) {
    854            goto inval;
    855        }
    856    }
    857    slot = val;
    858
    859    if (*e != '.') {
    860        goto inval;
    861    }
    862    p = e + 1;
    863    val = strtoul(p, &e, 10);
    864    if (e == p) {
    865        goto inval;
    866    }
    867    func = val;
    868
    869    if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) {
    870        goto inval;
    871    }
    872
    873    if (*e) {
    874        goto inval;
    875    }
    876
    877    addr->domain = dom;
    878    addr->bus = bus;
    879    addr->slot = slot;
    880    addr->function = func;
    881
    882    g_free(str);
    883    return;
    884
    885inval:
    886    error_set_from_qdev_prop_error(errp, EINVAL, obj, name, str);
    887    g_free(str);
    888}
    889
    890const PropertyInfo qdev_prop_pci_host_devaddr = {
    891    .name = "str",
    892    .description = "Address (bus/device/function) of "
    893                   "the host device, example: 04:10.0",
    894    .get = get_pci_host_devaddr,
    895    .set = set_pci_host_devaddr,
    896};
    897
    898/* --- OffAutoPCIBAR off/auto/bar0/bar1/bar2/bar3/bar4/bar5 --- */
    899
    900const PropertyInfo qdev_prop_off_auto_pcibar = {
    901    .name = "OffAutoPCIBAR",
    902    .description = "off/auto/bar0/bar1/bar2/bar3/bar4/bar5",
    903    .enum_table = &OffAutoPCIBAR_lookup,
    904    .get = qdev_propinfo_get_enum,
    905    .set = qdev_propinfo_set_enum,
    906    .set_default_value = qdev_propinfo_set_default_value_enum,
    907};
    908
    909/* --- PCIELinkSpeed 2_5/5/8/16 -- */
    910
    911static void get_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
    912                                   void *opaque, Error **errp)
    913{
    914    Property *prop = opaque;
    915    PCIExpLinkSpeed *p = object_field_prop_ptr(obj, prop);
    916    int speed;
    917
    918    switch (*p) {
    919    case QEMU_PCI_EXP_LNK_2_5GT:
    920        speed = PCIE_LINK_SPEED_2_5;
    921        break;
    922    case QEMU_PCI_EXP_LNK_5GT:
    923        speed = PCIE_LINK_SPEED_5;
    924        break;
    925    case QEMU_PCI_EXP_LNK_8GT:
    926        speed = PCIE_LINK_SPEED_8;
    927        break;
    928    case QEMU_PCI_EXP_LNK_16GT:
    929        speed = PCIE_LINK_SPEED_16;
    930        break;
    931    default:
    932        /* Unreachable */
    933        abort();
    934    }
    935
    936    visit_type_enum(v, name, &speed, prop->info->enum_table, errp);
    937}
    938
    939static void set_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
    940                                   void *opaque, Error **errp)
    941{
    942    Property *prop = opaque;
    943    PCIExpLinkSpeed *p = object_field_prop_ptr(obj, prop);
    944    int speed;
    945
    946    if (!visit_type_enum(v, name, &speed, prop->info->enum_table,
    947                         errp)) {
    948        return;
    949    }
    950
    951    switch (speed) {
    952    case PCIE_LINK_SPEED_2_5:
    953        *p = QEMU_PCI_EXP_LNK_2_5GT;
    954        break;
    955    case PCIE_LINK_SPEED_5:
    956        *p = QEMU_PCI_EXP_LNK_5GT;
    957        break;
    958    case PCIE_LINK_SPEED_8:
    959        *p = QEMU_PCI_EXP_LNK_8GT;
    960        break;
    961    case PCIE_LINK_SPEED_16:
    962        *p = QEMU_PCI_EXP_LNK_16GT;
    963        break;
    964    default:
    965        /* Unreachable */
    966        abort();
    967    }
    968}
    969
    970const PropertyInfo qdev_prop_pcie_link_speed = {
    971    .name = "PCIELinkSpeed",
    972    .description = "2_5/5/8/16",
    973    .enum_table = &PCIELinkSpeed_lookup,
    974    .get = get_prop_pcielinkspeed,
    975    .set = set_prop_pcielinkspeed,
    976    .set_default_value = qdev_propinfo_set_default_value_enum,
    977};
    978
    979/* --- PCIELinkWidth 1/2/4/8/12/16/32 -- */
    980
    981static void get_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
    982                                   void *opaque, Error **errp)
    983{
    984    Property *prop = opaque;
    985    PCIExpLinkWidth *p = object_field_prop_ptr(obj, prop);
    986    int width;
    987
    988    switch (*p) {
    989    case QEMU_PCI_EXP_LNK_X1:
    990        width = PCIE_LINK_WIDTH_1;
    991        break;
    992    case QEMU_PCI_EXP_LNK_X2:
    993        width = PCIE_LINK_WIDTH_2;
    994        break;
    995    case QEMU_PCI_EXP_LNK_X4:
    996        width = PCIE_LINK_WIDTH_4;
    997        break;
    998    case QEMU_PCI_EXP_LNK_X8:
    999        width = PCIE_LINK_WIDTH_8;
   1000        break;
   1001    case QEMU_PCI_EXP_LNK_X12:
   1002        width = PCIE_LINK_WIDTH_12;
   1003        break;
   1004    case QEMU_PCI_EXP_LNK_X16:
   1005        width = PCIE_LINK_WIDTH_16;
   1006        break;
   1007    case QEMU_PCI_EXP_LNK_X32:
   1008        width = PCIE_LINK_WIDTH_32;
   1009        break;
   1010    default:
   1011        /* Unreachable */
   1012        abort();
   1013    }
   1014
   1015    visit_type_enum(v, name, &width, prop->info->enum_table, errp);
   1016}
   1017
   1018static void set_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
   1019                                   void *opaque, Error **errp)
   1020{
   1021    Property *prop = opaque;
   1022    PCIExpLinkWidth *p = object_field_prop_ptr(obj, prop);
   1023    int width;
   1024
   1025    if (!visit_type_enum(v, name, &width, prop->info->enum_table,
   1026                         errp)) {
   1027        return;
   1028    }
   1029
   1030    switch (width) {
   1031    case PCIE_LINK_WIDTH_1:
   1032        *p = QEMU_PCI_EXP_LNK_X1;
   1033        break;
   1034    case PCIE_LINK_WIDTH_2:
   1035        *p = QEMU_PCI_EXP_LNK_X2;
   1036        break;
   1037    case PCIE_LINK_WIDTH_4:
   1038        *p = QEMU_PCI_EXP_LNK_X4;
   1039        break;
   1040    case PCIE_LINK_WIDTH_8:
   1041        *p = QEMU_PCI_EXP_LNK_X8;
   1042        break;
   1043    case PCIE_LINK_WIDTH_12:
   1044        *p = QEMU_PCI_EXP_LNK_X12;
   1045        break;
   1046    case PCIE_LINK_WIDTH_16:
   1047        *p = QEMU_PCI_EXP_LNK_X16;
   1048        break;
   1049    case PCIE_LINK_WIDTH_32:
   1050        *p = QEMU_PCI_EXP_LNK_X32;
   1051        break;
   1052    default:
   1053        /* Unreachable */
   1054        abort();
   1055    }
   1056}
   1057
   1058const PropertyInfo qdev_prop_pcie_link_width = {
   1059    .name = "PCIELinkWidth",
   1060    .description = "1/2/4/8/12/16/32",
   1061    .enum_table = &PCIELinkWidth_lookup,
   1062    .get = get_prop_pcielinkwidth,
   1063    .set = set_prop_pcielinkwidth,
   1064    .set_default_value = qdev_propinfo_set_default_value_enum,
   1065};
   1066
   1067/* --- UUID --- */
   1068
   1069static void get_uuid(Object *obj, Visitor *v, const char *name, void *opaque,
   1070                     Error **errp)
   1071{
   1072    Property *prop = opaque;
   1073    QemuUUID *uuid = object_field_prop_ptr(obj, prop);
   1074    char buffer[UUID_FMT_LEN + 1];
   1075    char *p = buffer;
   1076
   1077    qemu_uuid_unparse(uuid, buffer);
   1078
   1079    visit_type_str(v, name, &p, errp);
   1080}
   1081
   1082#define UUID_VALUE_AUTO        "auto"
   1083
   1084static void set_uuid(Object *obj, Visitor *v, const char *name, void *opaque,
   1085                    Error **errp)
   1086{
   1087    Property *prop = opaque;
   1088    QemuUUID *uuid = object_field_prop_ptr(obj, prop);
   1089    char *str;
   1090
   1091    if (!visit_type_str(v, name, &str, errp)) {
   1092        return;
   1093    }
   1094
   1095    if (!strcmp(str, UUID_VALUE_AUTO)) {
   1096        qemu_uuid_generate(uuid);
   1097    } else if (qemu_uuid_parse(str, uuid) < 0) {
   1098        error_set_from_qdev_prop_error(errp, EINVAL, obj, name, str);
   1099    }
   1100    g_free(str);
   1101}
   1102
   1103static void set_default_uuid_auto(ObjectProperty *op, const Property *prop)
   1104{
   1105    object_property_set_default_str(op, UUID_VALUE_AUTO);
   1106}
   1107
   1108const PropertyInfo qdev_prop_uuid = {
   1109    .name  = "str",
   1110    .description = "UUID (aka GUID) or \"" UUID_VALUE_AUTO
   1111        "\" for random value (default)",
   1112    .get   = get_uuid,
   1113    .set   = set_uuid,
   1114    .set_default_value = set_default_uuid_auto,
   1115};