qdev-properties.c 28.8 KB
Newer Older
P
Paolo Bonzini 已提交
1
#include "net/net.h"
2
#include "hw/qdev.h"
3
#include "qapi/qmp/qerror.h"
4
#include "qemu/error-report.h"
5
#include "sysemu/block-backend.h"
P
Paolo Bonzini 已提交
6
#include "hw/block/block.h"
7
#include "net/hub.h"
8
#include "qapi/visitor.h"
9
#include "sysemu/char.h"
G
Gerd Hoffmann 已提交
10

11 12 13 14 15 16 17 18 19 20 21 22 23 24
void qdev_prop_set_after_realize(DeviceState *dev, const char *name,
                                  Error **errp)
{
    if (dev->id) {
        error_setg(errp, "Attempt to set property '%s' on device '%s' "
                   "(type '%s') after it was realized", name, dev->id,
                   object_get_typename(OBJECT(dev)));
    } else {
        error_setg(errp, "Attempt to set property '%s' on anonymous device "
                   "(type '%s') after it was realized", name,
                   object_get_typename(OBJECT(dev)));
    }
}

25 26 27 28 29 30 31 32 33 34 35 36
void qdev_prop_allow_set_link_before_realize(Object *obj, const char *name,
                                             Object *val, Error **errp)
{
    DeviceState *dev = DEVICE(obj);

    if (dev->realized) {
        error_setg(errp, "Attempt to set link property '%s' on device '%s' "
                   "(type '%s') after it was realized",
                   name, dev->id, object_get_typename(obj));
    }
}

G
Gerd Hoffmann 已提交
37 38 39 40 41 42 43
void *qdev_get_prop_ptr(DeviceState *dev, Property *prop)
{
    void *ptr = dev;
    ptr += prop->offset;
    return ptr;
}

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
static void get_enum(Object *obj, Visitor *v, void *opaque,
                     const char *name, Error **errp)
{
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
    int *ptr = qdev_get_prop_ptr(dev, prop);

    visit_type_enum(v, ptr, prop->info->enum_table,
                    prop->info->name, prop->name, errp);
}

static void set_enum(Object *obj, Visitor *v, void *opaque,
                     const char *name, Error **errp)
{
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
    int *ptr = qdev_get_prop_ptr(dev, prop);

62
    if (dev->realized) {
63
        qdev_prop_set_after_realize(dev, name, errp);
64 65 66 67 68 69 70 71 72
        return;
    }

    visit_type_enum(v, ptr, prop->info->enum_table,
                    prop->info->name, prop->name, errp);
}

/* Bit */

M
Michael S. Tsirkin 已提交
73 74
static uint32_t qdev_get_prop_mask(Property *prop)
{
75
    assert(prop->info == &qdev_prop_bit);
M
Michael S. Tsirkin 已提交
76 77 78 79 80 81 82
    return 0x1 << prop->bitnr;
}

static void bit_prop_set(DeviceState *dev, Property *props, bool val)
{
    uint32_t *p = qdev_get_prop_ptr(dev, props);
    uint32_t mask = qdev_get_prop_mask(props);
E
Eduardo Habkost 已提交
83
    if (val) {
84
        *p |= mask;
E
Eduardo Habkost 已提交
85
    } else {
M
Michael S. Tsirkin 已提交
86
        *p &= ~mask;
E
Eduardo Habkost 已提交
87
    }
M
Michael S. Tsirkin 已提交
88 89
}

90
static void prop_get_bit(Object *obj, Visitor *v, void *opaque,
91 92
                    const char *name, Error **errp)
{
93
    DeviceState *dev = DEVICE(obj);
94 95 96 97 98 99 100
    Property *prop = opaque;
    uint32_t *p = qdev_get_prop_ptr(dev, prop);
    bool value = (*p & qdev_get_prop_mask(prop)) != 0;

    visit_type_bool(v, &value, name, errp);
}

101
static void prop_set_bit(Object *obj, Visitor *v, void *opaque,
102 103
                    const char *name, Error **errp)
{
104
    DeviceState *dev = DEVICE(obj);
105 106 107 108
    Property *prop = opaque;
    Error *local_err = NULL;
    bool value;

109
    if (dev->realized) {
110
        qdev_prop_set_after_realize(dev, name, errp);
111 112 113 114 115 116 117 118 119 120 121
        return;
    }

    visit_type_bool(v, &value, name, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }
    bit_prop_set(dev, prop, value);
}

M
Michael S. Tsirkin 已提交
122
PropertyInfo qdev_prop_bit = {
123
    .name  = "bool",
124
    .description = "on/off",
125 126
    .get   = prop_get_bit,
    .set   = prop_set_bit,
M
Michael S. Tsirkin 已提交
127 128
};

G
Gerd Hoffmann 已提交
129 130 131 132
/* Bit64 */

static uint64_t qdev_get_prop_mask64(Property *prop)
{
C
Cornelia Huck 已提交
133
    assert(prop->info == &qdev_prop_bit64);
G
Gonglei 已提交
134
    return 0x1ull << prop->bitnr;
G
Gerd Hoffmann 已提交
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
}

static void bit64_prop_set(DeviceState *dev, Property *props, bool val)
{
    uint64_t *p = qdev_get_prop_ptr(dev, props);
    uint64_t mask = qdev_get_prop_mask64(props);
    if (val) {
        *p |= mask;
    } else {
        *p &= ~mask;
    }
}

static void prop_get_bit64(Object *obj, Visitor *v, void *opaque,
                           const char *name, Error **errp)
{
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
    uint64_t *p = qdev_get_prop_ptr(dev, prop);
    bool value = (*p & qdev_get_prop_mask64(prop)) != 0;

    visit_type_bool(v, &value, name, errp);
}

static void prop_set_bit64(Object *obj, Visitor *v, void *opaque,
                           const char *name, Error **errp)
{
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
    Error *local_err = NULL;
    bool value;

    if (dev->realized) {
        qdev_prop_set_after_realize(dev, name, errp);
        return;
    }

    visit_type_bool(v, &value, name, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }
    bit64_prop_set(dev, prop, value);
}

PropertyInfo qdev_prop_bit64 = {
    .name  = "bool",
    .description = "on/off",
    .get   = prop_get_bit64,
    .set   = prop_set_bit64,
};

187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
/* --- bool --- */

static void get_bool(Object *obj, Visitor *v, void *opaque,
                     const char *name, Error **errp)
{
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
    bool *ptr = qdev_get_prop_ptr(dev, prop);

    visit_type_bool(v, ptr, name, errp);
}

static void set_bool(Object *obj, Visitor *v, void *opaque,
                     const char *name, Error **errp)
{
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
    bool *ptr = qdev_get_prop_ptr(dev, prop);

    if (dev->realized) {
        qdev_prop_set_after_realize(dev, name, errp);
        return;
    }

    visit_type_bool(v, ptr, name, errp);
}

PropertyInfo qdev_prop_bool = {
215
    .name  = "bool",
216 217 218 219
    .get   = get_bool,
    .set   = set_bool,
};

J
Juan Quintela 已提交
220 221
/* --- 8bit integer --- */

222 223
static void get_uint8(Object *obj, Visitor *v, void *opaque,
                      const char *name, Error **errp)
224
{
225
    DeviceState *dev = DEVICE(obj);
226
    Property *prop = opaque;
227
    uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
228

229
    visit_type_uint8(v, ptr, name, errp);
230 231
}

232 233
static void set_uint8(Object *obj, Visitor *v, void *opaque,
                      const char *name, Error **errp)
234
{
235
    DeviceState *dev = DEVICE(obj);
236
    Property *prop = opaque;
237
    uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
238

239
    if (dev->realized) {
240
        qdev_prop_set_after_realize(dev, name, errp);
241 242 243
        return;
    }

244
    visit_type_uint8(v, ptr, name, errp);
245 246
}

J
Juan Quintela 已提交
247 248
PropertyInfo qdev_prop_uint8 = {
    .name  = "uint8",
249 250
    .get   = get_uint8,
    .set   = set_uint8,
J
Juan Quintela 已提交
251 252
};

G
Gerd Hoffmann 已提交
253 254
/* --- 16bit integer --- */

255 256
static void get_uint16(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
257
{
258
    DeviceState *dev = DEVICE(obj);
259
    Property *prop = opaque;
260
    uint16_t *ptr = qdev_get_prop_ptr(dev, prop);
261

262
    visit_type_uint16(v, ptr, name, errp);
263 264
}

265 266
static void set_uint16(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
267
{
268
    DeviceState *dev = DEVICE(obj);
269
    Property *prop = opaque;
270
    uint16_t *ptr = qdev_get_prop_ptr(dev, prop);
271

272
    if (dev->realized) {
273
        qdev_prop_set_after_realize(dev, name, errp);
274 275 276
        return;
    }

277
    visit_type_uint16(v, ptr, name, errp);
278 279
}

G
Gerd Hoffmann 已提交
280 281
PropertyInfo qdev_prop_uint16 = {
    .name  = "uint16",
282 283
    .get   = get_uint16,
    .set   = set_uint16,
G
Gerd Hoffmann 已提交
284 285 286 287
};

/* --- 32bit integer --- */

288 289 290 291 292
static void get_uint32(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
{
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
293
    uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
294

295
    visit_type_uint32(v, ptr, name, errp);
296 297 298 299 300 301 302
}

static void set_uint32(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
{
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
303
    uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
304

305
    if (dev->realized) {
306
        qdev_prop_set_after_realize(dev, name, errp);
307 308 309
        return;
    }

310
    visit_type_uint32(v, ptr, name, errp);
311 312
}

313
static void get_int32(Object *obj, Visitor *v, void *opaque,
314 315
                      const char *name, Error **errp)
{
316
    DeviceState *dev = DEVICE(obj);
317 318 319
    Property *prop = opaque;
    int32_t *ptr = qdev_get_prop_ptr(dev, prop);

320
    visit_type_int32(v, ptr, name, errp);
321 322
}

323
static void set_int32(Object *obj, Visitor *v, void *opaque,
324 325
                      const char *name, Error **errp)
{
326
    DeviceState *dev = DEVICE(obj);
327
    Property *prop = opaque;
328
    int32_t *ptr = qdev_get_prop_ptr(dev, prop);
329

330
    if (dev->realized) {
331
        qdev_prop_set_after_realize(dev, name, errp);
332 333 334
        return;
    }

335
    visit_type_int32(v, ptr, name, errp);
336 337
}

G
Gerd Hoffmann 已提交
338 339
PropertyInfo qdev_prop_uint32 = {
    .name  = "uint32",
340 341
    .get   = get_uint32,
    .set   = set_uint32,
G
Gerd Hoffmann 已提交
342 343
};

344 345
PropertyInfo qdev_prop_int32 = {
    .name  = "int32",
346 347
    .get   = get_int32,
    .set   = set_int32,
348 349
};

B
Blue Swirl 已提交
350 351
/* --- 64bit integer --- */

352 353
static void get_uint64(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
354
{
355
    DeviceState *dev = DEVICE(obj);
356
    Property *prop = opaque;
357
    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
358

359
    visit_type_uint64(v, ptr, name, errp);
360 361
}

362 363
static void set_uint64(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
364
{
365
    DeviceState *dev = DEVICE(obj);
366
    Property *prop = opaque;
367
    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
368

369
    if (dev->realized) {
370
        qdev_prop_set_after_realize(dev, name, errp);
371 372 373
        return;
    }

374
    visit_type_uint64(v, ptr, name, errp);
375 376
}

B
Blue Swirl 已提交
377 378
PropertyInfo qdev_prop_uint64 = {
    .name  = "uint64",
379 380
    .get   = get_uint64,
    .set   = set_uint64,
B
Blue Swirl 已提交
381 382
};

G
Gerd Hoffmann 已提交
383 384
/* --- string --- */

P
Paolo Bonzini 已提交
385
static void release_string(Object *obj, const char *name, void *opaque)
386
{
P
Paolo Bonzini 已提交
387 388
    Property *prop = opaque;
    g_free(*(char **)qdev_get_prop_ptr(DEVICE(obj), prop));
389 390
}

391
static void get_string(Object *obj, Visitor *v, void *opaque,
392 393
                       const char *name, Error **errp)
{
394
    DeviceState *dev = DEVICE(obj);
395 396 397 398 399 400 401 402 403 404 405
    Property *prop = opaque;
    char **ptr = qdev_get_prop_ptr(dev, prop);

    if (!*ptr) {
        char *str = (char *)"";
        visit_type_str(v, &str, name, errp);
    } else {
        visit_type_str(v, ptr, name, errp);
    }
}

406
static void set_string(Object *obj, Visitor *v, void *opaque,
407 408
                       const char *name, Error **errp)
{
409
    DeviceState *dev = DEVICE(obj);
410 411 412 413 414
    Property *prop = opaque;
    char **ptr = qdev_get_prop_ptr(dev, prop);
    Error *local_err = NULL;
    char *str;

415
    if (dev->realized) {
416
        qdev_prop_set_after_realize(dev, name, errp);
417 418 419 420 421 422 423 424 425 426 427 428 429 430
        return;
    }

    visit_type_str(v, &str, name, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }
    if (*ptr) {
        g_free(*ptr);
    }
    *ptr = str;
}

G
Gerd Hoffmann 已提交
431
PropertyInfo qdev_prop_string = {
432
    .name  = "str",
P
Paolo Bonzini 已提交
433
    .release = release_string,
434 435
    .get   = get_string,
    .set   = set_string,
G
Gerd Hoffmann 已提交
436 437
};

G
Gerd Hoffmann 已提交
438 439
/* --- pointer --- */

440
/* Not a proper property, just for dirty hacks.  TODO Remove it!  */
G
Gerd Hoffmann 已提交
441 442 443 444 445 446 447 448 449 450 451
PropertyInfo qdev_prop_ptr = {
    .name  = "ptr",
};

/* --- mac address --- */

/*
 * accepted syntax versions:
 *   01:02:03:04:05:06
 *   01-02-03-04-05-06
 */
452 453
static void get_mac(Object *obj, Visitor *v, void *opaque,
                    const char *name, Error **errp)
G
Gerd Hoffmann 已提交
454
{
455 456
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
G
Gerd Hoffmann 已提交
457
    MACAddr *mac = qdev_get_prop_ptr(dev, prop);
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474
    char buffer[2 * 6 + 5 + 1];
    char *p = buffer;

    snprintf(buffer, sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x",
             mac->a[0], mac->a[1], mac->a[2],
             mac->a[3], mac->a[4], mac->a[5]);

    visit_type_str(v, &p, name, errp);
}

static void set_mac(Object *obj, Visitor *v, void *opaque,
                    const char *name, Error **errp)
{
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
    MACAddr *mac = qdev_get_prop_ptr(dev, prop);
    Error *local_err = NULL;
G
Gerd Hoffmann 已提交
475
    int i, pos;
476 477
    char *str, *p;

478
    if (dev->realized) {
479
        qdev_prop_set_after_realize(dev, name, errp);
480 481 482 483 484 485 486 487
        return;
    }

    visit_type_str(v, &str, name, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }
G
Gerd Hoffmann 已提交
488 489

    for (i = 0, pos = 0; i < 6; i++, pos += 3) {
E
Eduardo Habkost 已提交
490
        if (!qemu_isxdigit(str[pos])) {
491
            goto inval;
E
Eduardo Habkost 已提交
492 493
        }
        if (!qemu_isxdigit(str[pos+1])) {
494
            goto inval;
E
Eduardo Habkost 已提交
495
        }
G
Gerd Hoffmann 已提交
496
        if (i == 5) {
E
Eduardo Habkost 已提交
497
            if (str[pos+2] != '\0') {
498
                goto inval;
E
Eduardo Habkost 已提交
499
            }
G
Gerd Hoffmann 已提交
500
        } else {
E
Eduardo Habkost 已提交
501
            if (str[pos+2] != ':' && str[pos+2] != '-') {
502
                goto inval;
E
Eduardo Habkost 已提交
503
            }
G
Gerd Hoffmann 已提交
504 505
        }
        mac->a[i] = strtol(str+pos, &p, 16);
G
Gerd Hoffmann 已提交
506
    }
D
dunrong huang 已提交
507
    g_free(str);
508
    return;
G
Gerd Hoffmann 已提交
509

510 511
inval:
    error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
D
dunrong huang 已提交
512
    g_free(str);
G
Gerd Hoffmann 已提交
513 514 515
}

PropertyInfo qdev_prop_macaddr = {
516
    .name  = "str",
517
    .description = "Ethernet 6-byte MAC Address, example: 52:54:00:12:34:56",
518 519
    .get   = get_mac,
    .set   = set_mac,
G
Gerd Hoffmann 已提交
520 521
};

522 523
/* --- lost tick policy --- */

524 525
QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int));

526
PropertyInfo qdev_prop_losttickpolicy = {
527
    .name  = "LostTickPolicy",
528
    .enum_table  = LostTickPolicy_lookup,
529 530
    .get   = get_enum,
    .set   = set_enum,
531 532
};

533 534
/* --- BIOS CHS translation */

535
QEMU_BUILD_BUG_ON(sizeof(BiosAtaTranslation) != sizeof(int));
536 537

PropertyInfo qdev_prop_bios_chs_trans = {
538
    .name = "BiosAtaTranslation",
539 540
    .description = "Logical CHS translation algorithm, "
                   "auto/none/lba/large/rechs",
541
    .enum_table = BiosAtaTranslation_lookup,
542 543 544 545
    .get = get_enum,
    .set = set_enum,
};

546 547 548 549 550
/* --- pci address --- */

/*
 * bus-local address, i.e. "$slot" or "$slot.$fn"
 */
551 552
static void set_pci_devfn(Object *obj, Visitor *v, void *opaque,
                          const char *name, Error **errp)
553
{
554 555
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
556
    int32_t value, *ptr = qdev_get_prop_ptr(dev, prop);
557
    unsigned int slot, fn, n;
558
    Error *local_err = NULL;
D
dunrong huang 已提交
559
    char *str;
560

561
    if (dev->realized) {
562
        qdev_prop_set_after_realize(dev, name, errp);
563 564 565 566 567
        return;
    }

    visit_type_str(v, &str, name, &local_err);
    if (local_err) {
568
        error_free(local_err);
569 570 571 572 573
        local_err = NULL;
        visit_type_int32(v, &value, name, &local_err);
        if (local_err) {
            error_propagate(errp, local_err);
        } else if (value < -1 || value > 255) {
574 575
            error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                       name ? name : "null", "pci_devfn");
576 577 578 579
        } else {
            *ptr = value;
        }
        return;
580
    }
581 582 583 584

    if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
        fn = 0;
        if (sscanf(str, "%x%n", &slot, &n) != 1) {
585
            goto invalid;
586 587
        }
    }
588 589 590
    if (str[n] != '\0' || fn > 7 || slot > 31) {
        goto invalid;
    }
591
    *ptr = slot << 3 | fn;
D
dunrong huang 已提交
592
    g_free(str);
593 594 595 596
    return;

invalid:
    error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
D
dunrong huang 已提交
597
    g_free(str);
598 599
}

E
Eduardo Habkost 已提交
600 601
static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest,
                           size_t len)
602
{
603
    int32_t *ptr = qdev_get_prop_ptr(dev, prop);
604

B
Blue Swirl 已提交
605
    if (*ptr == -1) {
606 607 608 609 610 611 612
        return snprintf(dest, len, "<unset>");
    } else {
        return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7);
    }
}

PropertyInfo qdev_prop_pci_devfn = {
613
    .name  = "int32",
614
    .description = "Slot and optional function number, example: 06.0 or 06",
615
    .print = print_pci_devfn,
616
    .get   = get_int32,
617
    .set   = set_pci_devfn,
618 619
};

620 621 622 623 624 625 626
/* --- blocksize --- */

static void set_blocksize(Object *obj, Visitor *v, void *opaque,
                          const char *name, Error **errp)
{
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
627
    uint16_t value, *ptr = qdev_get_prop_ptr(dev, prop);
628
    Error *local_err = NULL;
629 630
    const int64_t min = 512;
    const int64_t max = 32768;
631

632
    if (dev->realized) {
633
        qdev_prop_set_after_realize(dev, name, errp);
634 635 636
        return;
    }

637
    visit_type_uint16(v, &value, name, &local_err);
638 639 640 641
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }
642 643
    /* value of 0 means "unset" */
    if (value && (value < min || value > max)) {
644 645
        error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
                   dev->id ? : "", name, (int64_t)value, min, max);
646 647 648 649 650
        return;
    }

    /* We rely on power-of-2 blocksizes for bitmasks */
    if ((value & (value - 1)) != 0) {
651 652 653
        error_setg(errp,
                  "Property %s.%s doesn't take value '%" PRId64 "', it's not a power of 2",
                  dev->id ?: "", name, (int64_t)value);
654 655 656 657 658 659 660
        return;
    }

    *ptr = value;
}

PropertyInfo qdev_prop_blocksize = {
661
    .name  = "uint16",
662
    .description = "A power of two between 512 and 32768",
663
    .get   = get_uint16,
664 665 666
    .set   = set_blocksize,
};

667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702
/* --- pci host address --- */

static void get_pci_host_devaddr(Object *obj, Visitor *v, void *opaque,
                                 const char *name, Error **errp)
{
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
    PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop);
    char buffer[] = "xxxx:xx:xx.x";
    char *p = buffer;
    int rc = 0;

    rc = snprintf(buffer, sizeof(buffer), "%04x:%02x:%02x.%d",
                  addr->domain, addr->bus, addr->slot, addr->function);
    assert(rc == sizeof(buffer) - 1);

    visit_type_str(v, &p, name, errp);
}

/*
 * Parse [<domain>:]<bus>:<slot>.<func>
 *   if <domain> is not supplied, it's assumed to be 0.
 */
static void set_pci_host_devaddr(Object *obj, Visitor *v, void *opaque,
                                 const char *name, Error **errp)
{
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
    PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop);
    Error *local_err = NULL;
    char *str, *p;
    char *e;
    unsigned long val;
    unsigned long dom = 0, bus = 0;
    unsigned int slot = 0, func = 0;

703
    if (dev->realized) {
704
        qdev_prop_set_after_realize(dev, name, errp);
705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768
        return;
    }

    visit_type_str(v, &str, name, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }

    p = str;
    val = strtoul(p, &e, 16);
    if (e == p || *e != ':') {
        goto inval;
    }
    bus = val;

    p = e + 1;
    val = strtoul(p, &e, 16);
    if (e == p) {
        goto inval;
    }
    if (*e == ':') {
        dom = bus;
        bus = val;
        p = e + 1;
        val = strtoul(p, &e, 16);
        if (e == p) {
            goto inval;
        }
    }
    slot = val;

    if (*e != '.') {
        goto inval;
    }
    p = e + 1;
    val = strtoul(p, &e, 10);
    if (e == p) {
        goto inval;
    }
    func = val;

    if (dom > 0xffff || bus > 0xff || slot > 0x1f || func > 7) {
        goto inval;
    }

    if (*e) {
        goto inval;
    }

    addr->domain = dom;
    addr->bus = bus;
    addr->slot = slot;
    addr->function = func;

    g_free(str);
    return;

inval:
    error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
    g_free(str);
}

PropertyInfo qdev_prop_pci_host_devaddr = {
769
    .name = "str",
770 771
    .description = "Address (bus/device/function) of "
                   "the host device, example: 04:10.0",
772 773 774 775
    .get = get_pci_host_devaddr,
    .set = set_pci_host_devaddr,
};

776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815
/* --- support for array properties --- */

/* Used as an opaque for the object properties we add for each
 * array element. Note that the struct Property must be first
 * in the struct so that a pointer to this works as the opaque
 * for the underlying element's property hooks as well as for
 * our own release callback.
 */
typedef struct {
    struct Property prop;
    char *propname;
    ObjectPropertyRelease *release;
} ArrayElementProperty;

/* object property release callback for array element properties:
 * we call the underlying element's property release hook, and
 * then free the memory we allocated when we added the property.
 */
static void array_element_release(Object *obj, const char *name, void *opaque)
{
    ArrayElementProperty *p = opaque;
    if (p->release) {
        p->release(obj, name, opaque);
    }
    g_free(p->propname);
    g_free(p);
}

static void set_prop_arraylen(Object *obj, Visitor *v, void *opaque,
                              const char *name, Error **errp)
{
    /* Setter for the property which defines the length of a
     * variable-sized property array. As well as actually setting the
     * array-length field in the device struct, we have to create the
     * array itself and dynamically add the corresponding properties.
     */
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
    uint32_t *alenptr = qdev_get_prop_ptr(dev, prop);
    void **arrayptr = (void *)dev + prop->arrayoffset;
816
    Error *local_err = NULL;
817 818 819 820 821
    void *eltptr;
    const char *arrayname;
    int i;

    if (dev->realized) {
822
        qdev_prop_set_after_realize(dev, name, errp);
823 824 825 826 827 828 829
        return;
    }
    if (*alenptr) {
        error_setg(errp, "array size property %s may not be set more than once",
                   name);
        return;
    }
830 831 832
    visit_type_uint32(v, alenptr, name, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868
        return;
    }
    if (!*alenptr) {
        return;
    }

    /* DEFINE_PROP_ARRAY guarantees that name should start with this prefix;
     * strip it off so we can get the name of the array itself.
     */
    assert(strncmp(name, PROP_ARRAY_LEN_PREFIX,
                   strlen(PROP_ARRAY_LEN_PREFIX)) == 0);
    arrayname = name + strlen(PROP_ARRAY_LEN_PREFIX);

    /* Note that it is the responsibility of the individual device's deinit
     * to free the array proper.
     */
    *arrayptr = eltptr = g_malloc0(*alenptr * prop->arrayfieldsize);
    for (i = 0; i < *alenptr; i++, eltptr += prop->arrayfieldsize) {
        char *propname = g_strdup_printf("%s[%d]", arrayname, i);
        ArrayElementProperty *arrayprop = g_new0(ArrayElementProperty, 1);
        arrayprop->release = prop->arrayinfo->release;
        arrayprop->propname = propname;
        arrayprop->prop.info = prop->arrayinfo;
        arrayprop->prop.name = propname;
        /* This ugly piece of pointer arithmetic sets up the offset so
         * that when the underlying get/set hooks call qdev_get_prop_ptr
         * they get the right answer despite the array element not actually
         * being inside the device struct.
         */
        arrayprop->prop.offset = eltptr - (void *)dev;
        assert(qdev_get_prop_ptr(dev, &arrayprop->prop) == eltptr);
        object_property_add(obj, propname,
                            arrayprop->prop.info->name,
                            arrayprop->prop.info->get,
                            arrayprop->prop.info->set,
                            array_element_release,
869 870 871
                            arrayprop, &local_err);
        if (local_err) {
            error_propagate(errp, local_err);
872 873 874 875 876 877 878 879 880 881 882
            return;
        }
    }
}

PropertyInfo qdev_prop_arraylen = {
    .name = "uint32",
    .get = get_uint32,
    .set = set_prop_arraylen,
};

G
Gerd Hoffmann 已提交
883 884 885 886
/* --- public helpers --- */

static Property *qdev_prop_walk(Property *props, const char *name)
{
E
Eduardo Habkost 已提交
887
    if (!props) {
G
Gerd Hoffmann 已提交
888
        return NULL;
E
Eduardo Habkost 已提交
889
    }
G
Gerd Hoffmann 已提交
890
    while (props->name) {
E
Eduardo Habkost 已提交
891
        if (strcmp(props->name, name) == 0) {
G
Gerd Hoffmann 已提交
892
            return props;
E
Eduardo Habkost 已提交
893
        }
G
Gerd Hoffmann 已提交
894 895 896 897 898 899 900
        props++;
    }
    return NULL;
}

static Property *qdev_prop_find(DeviceState *dev, const char *name)
{
901
    ObjectClass *class;
G
Gerd Hoffmann 已提交
902 903 904
    Property *prop;

    /* device properties */
905 906 907 908 909 910 911 912
    class = object_get_class(OBJECT(dev));
    do {
        prop = qdev_prop_walk(DEVICE_CLASS(class)->props, name);
        if (prop) {
            return prop;
        }
        class = object_class_get_parent(class);
    } while (class != object_class_by_name(TYPE_DEVICE));
G
Gerd Hoffmann 已提交
913 914 915 916

    return NULL;
}

917 918 919 920 921
void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
                                    Property *prop, const char *value)
{
    switch (ret) {
    case -EEXIST:
922
        error_setg(errp, "Property '%s.%s' can't take value '%s', it's in use",
923
                  object_get_typename(OBJECT(dev)), prop->name, value);
924 925 926
        break;
    default:
    case -EINVAL:
927 928
        error_setg(errp, QERR_PROPERTY_VALUE_BAD,
                   object_get_typename(OBJECT(dev)), prop->name, value);
929 930
        break;
    case -ENOENT:
931
        error_setg(errp, "Property '%s.%s' can't find value '%s'",
932
                  object_get_typename(OBJECT(dev)), prop->name, value);
933 934 935 936 937 938
        break;
    case 0:
        break;
    }
}

939 940
void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value)
{
941
    object_property_set_bool(OBJECT(dev), value, name, &error_abort);
942 943
}

J
Juan Quintela 已提交
944 945
void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value)
{
946
    object_property_set_int(OBJECT(dev), value, name, &error_abort);
J
Juan Quintela 已提交
947 948
}

G
Gerd Hoffmann 已提交
949 950
void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value)
{
951
    object_property_set_int(OBJECT(dev), value, name, &error_abort);
G
Gerd Hoffmann 已提交
952 953 954 955
}

void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value)
{
956
    object_property_set_int(OBJECT(dev), value, name, &error_abort);
G
Gerd Hoffmann 已提交
957 958
}

959 960
void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value)
{
961
    object_property_set_int(OBJECT(dev), value, name, &error_abort);
962 963
}

B
Blue Swirl 已提交
964 965
void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value)
{
966
    object_property_set_int(OBJECT(dev), value, name, &error_abort);
B
Blue Swirl 已提交
967 968
}

969
void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value)
970
{
971
    object_property_set_str(OBJECT(dev), value, name, &error_abort);
972 973
}

G
Gerd Hoffmann 已提交
974 975
void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value)
{
P
Paolo Bonzini 已提交
976 977 978 979
    char str[2 * 6 + 5 + 1];
    snprintf(str, sizeof(str), "%02x:%02x:%02x:%02x:%02x:%02x",
             value[0], value[1], value[2], value[3], value[4], value[5]);

980
    object_property_set_str(OBJECT(dev), str, name, &error_abort);
G
Gerd Hoffmann 已提交
981 982
}

P
Paolo Bonzini 已提交
983
void qdev_prop_set_enum(DeviceState *dev, const char *name, int value)
984
{
P
Paolo Bonzini 已提交
985 986 987 988
    Property *prop;

    prop = qdev_prop_find(dev, name);
    object_property_set_str(OBJECT(dev), prop->info->enum_table[value],
989
                            name, &error_abort);
990 991
}

G
Gerd Hoffmann 已提交
992 993
void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
{
994 995 996 997 998 999 1000
    Property *prop;
    void **ptr;

    prop = qdev_prop_find(dev, name);
    assert(prop && prop->info == &qdev_prop_ptr);
    ptr = qdev_get_prop_ptr(dev, prop);
    *ptr = value;
G
Gerd Hoffmann 已提交
1001 1002
}

E
Eduardo Habkost 已提交
1003 1004
static QTAILQ_HEAD(, GlobalProperty) global_props =
        QTAILQ_HEAD_INITIALIZER(global_props);
1005

1006
void qdev_prop_register_global(GlobalProperty *prop)
1007
{
1008
    QTAILQ_INSERT_TAIL(&global_props, prop, next);
1009 1010
}

1011
void qdev_prop_register_global_list(GlobalProperty *props)
1012
{
1013
    int i;
1014

1015 1016
    for (i = 0; props[i].driver != NULL; i++) {
        qdev_prop_register_global(props+i);
1017
    }
1018 1019
}

1020
int qdev_prop_check_globals(void)
1021 1022 1023 1024 1025
{
    GlobalProperty *prop;
    int ret = 0;

    QTAILQ_FOREACH(prop, &global_props, next) {
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046
        ObjectClass *oc;
        DeviceClass *dc;
        if (prop->used) {
            continue;
        }
        if (!prop->user_provided) {
            continue;
        }
        oc = object_class_by_name(prop->driver);
        oc = object_class_dynamic_cast(oc, TYPE_DEVICE);
        if (!oc) {
            error_report("Warning: global %s.%s has invalid class name",
                       prop->driver, prop->property);
            ret = 1;
            continue;
        }
        dc = DEVICE_CLASS(oc);
        if (!dc->hotpluggable && !prop->used) {
            error_report("Warning: global %s.%s=%s not used",
                       prop->driver, prop->property, prop->value);
            ret = 1;
1047 1048 1049 1050 1051 1052
            continue;
        }
    }
    return ret;
}

1053 1054
static void qdev_prop_set_globals_for_type(DeviceState *dev,
                                const char *typename)
1055 1056 1057 1058 1059 1060 1061 1062 1063
{
    GlobalProperty *prop;

    QTAILQ_FOREACH(prop, &global_props, next) {
        Error *err = NULL;

        if (strcmp(typename, prop->driver) != 0) {
            continue;
        }
1064
        prop->used = true;
P
Paolo Bonzini 已提交
1065
        object_property_parse(OBJECT(dev), prop->value, prop->property, &err);
1066
        if (err != NULL) {
1067 1068 1069 1070 1071
            assert(prop->user_provided);
            error_report("Warning: global %s.%s=%s ignored (%s)",
                         prop->driver, prop->property, prop->value,
                         error_get_pretty(err));
            error_free(err);
1072 1073 1074 1075 1076
            return;
        }
    }
}

1077
void qdev_prop_set_globals(DeviceState *dev)
1078
{
1079 1080 1081
    ObjectClass *class = object_get_class(OBJECT(dev));

    do {
1082
        qdev_prop_set_globals_for_type(dev, object_class_get_name(class));
1083 1084
        class = object_class_get_parent(class);
    } while (class);
1085
}
1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113

/* --- 64bit unsigned int 'size' type --- */

static void get_size(Object *obj, Visitor *v, void *opaque,
                     const char *name, Error **errp)
{
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);

    visit_type_size(v, ptr, name, errp);
}

static void set_size(Object *obj, Visitor *v, void *opaque,
                     const char *name, Error **errp)
{
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);

    visit_type_size(v, ptr, name, errp);
}

PropertyInfo qdev_prop_size = {
    .name  = "size",
    .get = get_size,
    .set = set_size,
};