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

10 11 12 13 14 15 16 17 18 19 20 21 22 23
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)));
    }
}

24 25 26 27 28 29 30 31 32 33 34 35
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 已提交
36 37 38 39 40 41 42
void *qdev_get_prop_ptr(DeviceState *dev, Property *prop)
{
    void *ptr = dev;
    ptr += prop->offset;
    return ptr;
}

43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
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);

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

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

/* Bit */

M
Michael S. Tsirkin 已提交
72 73
static uint32_t qdev_get_prop_mask(Property *prop)
{
74
    assert(prop->info == &qdev_prop_bit);
M
Michael S. Tsirkin 已提交
75 76 77 78 79 80 81
    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 已提交
82
    if (val) {
83
        *p |= mask;
E
Eduardo Habkost 已提交
84
    } else {
M
Michael S. Tsirkin 已提交
85
        *p &= ~mask;
E
Eduardo Habkost 已提交
86
    }
M
Michael S. Tsirkin 已提交
87 88
}

89
static void prop_get_bit(Object *obj, Visitor *v, void *opaque,
90 91
                    const char *name, Error **errp)
{
92
    DeviceState *dev = DEVICE(obj);
93 94 95 96 97 98 99
    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);
}

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

108
    if (dev->realized) {
109
        qdev_prop_set_after_realize(dev, name, errp);
110 111 112 113 114 115 116 117 118 119 120
        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 已提交
121
PropertyInfo qdev_prop_bit = {
122
    .name  = "bool",
123
    .description = "on/off",
124 125
    .get   = prop_get_bit,
    .set   = prop_set_bit,
M
Michael S. Tsirkin 已提交
126 127
};

G
Gerd Hoffmann 已提交
128 129 130 131 132 133 134 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
/* Bit64 */

static uint64_t qdev_get_prop_mask64(Property *prop)
{
    assert(prop->info == &qdev_prop_bit);
    return 0x1 << prop->bitnr;
}

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,
};

186 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
/* --- 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 = {
214
    .name  = "bool",
215 216 217 218
    .get   = get_bool,
    .set   = set_bool,
};

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

390
static void get_string(Object *obj, Visitor *v, void *opaque,
391 392
                       const char *name, Error **errp)
{
393
    DeviceState *dev = DEVICE(obj);
394 395 396 397 398 399 400 401 402 403 404
    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);
    }
}

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

414
    if (dev->realized) {
415
        qdev_prop_set_after_realize(dev, name, errp);
416 417 418 419 420 421 422 423 424 425 426 427 428 429
        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 已提交
430
PropertyInfo qdev_prop_string = {
431
    .name  = "str",
P
Paolo Bonzini 已提交
432
    .release = release_string,
433 434
    .get   = get_string,
    .set   = set_string,
G
Gerd Hoffmann 已提交
435 436
};

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

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

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

/*
 * accepted syntax versions:
 *   01:02:03:04:05:06
 *   01-02-03-04-05-06
 */
451 452
static void get_mac(Object *obj, Visitor *v, void *opaque,
                    const char *name, Error **errp)
G
Gerd Hoffmann 已提交
453
{
454 455
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
G
Gerd Hoffmann 已提交
456
    MACAddr *mac = qdev_get_prop_ptr(dev, prop);
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473
    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 已提交
474
    int i, pos;
475 476
    char *str, *p;

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

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

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

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

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

521 522
/* --- lost tick policy --- */

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

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

532 533
/* --- BIOS CHS translation */

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

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

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

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

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

    visit_type_str(v, &str, name, &local_err);
    if (local_err) {
567
        error_free(local_err);
568 569 570 571 572 573 574 575 576 577 578
        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) {
            error_set(errp, QERR_INVALID_PARAMETER_VALUE, name ? name : "null",
                      "pci_devfn");
        } else {
            *ptr = value;
        }
        return;
579
    }
580 581 582 583

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

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

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

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

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

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

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

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

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

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

    *ptr = value;
}

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

666 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
/* --- 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;

702
    if (dev->realized) {
703
        qdev_prop_set_after_realize(dev, name, errp);
704 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
        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 = {
768
    .name = "str",
769 770
    .description = "Address (bus/device/function) of "
                   "the host device, example: 04:10.0",
771 772 773 774
    .get = get_pci_host_devaddr,
    .set = set_pci_host_devaddr,
};

775 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
/* --- 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;
815
    Error *local_err = NULL;
816 817 818 819 820
    void *eltptr;
    const char *arrayname;
    int i;

    if (dev->realized) {
821
        qdev_prop_set_after_realize(dev, name, errp);
822 823 824 825 826 827 828
        return;
    }
    if (*alenptr) {
        error_setg(errp, "array size property %s may not be set more than once",
                   name);
        return;
    }
829 830 831
    visit_type_uint32(v, alenptr, name, &local_err);
    if (local_err) {
        error_propagate(errp, local_err);
832 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
        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,
868 869 870
                            arrayprop, &local_err);
        if (local_err) {
            error_propagate(errp, local_err);
871 872 873 874 875 876 877 878 879 880 881
            return;
        }
    }
}

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

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

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

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

    /* device properties */
904 905 906 907 908 909 910 911
    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 已提交
912 913 914 915

    return NULL;
}

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

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

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

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

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

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

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

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

G
Gerd Hoffmann 已提交
973 974
void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value)
{
P
Paolo Bonzini 已提交
975 976 977 978
    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]);

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

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

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

G
Gerd Hoffmann 已提交
991 992
void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
{
993 994 995 996 997 998 999
    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 已提交
1000 1001
}

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

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

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

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

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

    QTAILQ_FOREACH(prop, &global_props, next) {
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045
        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;
1046 1047 1048 1049 1050 1051
            continue;
        }
    }
    return ret;
}

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

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

        if (strcmp(typename, prop->driver) != 0) {
            continue;
        }
1063
        prop->used = true;
P
Paolo Bonzini 已提交
1064
        object_property_parse(OBJECT(dev), prop->value, prop->property, &err);
1065
        if (err != NULL) {
1066 1067 1068 1069 1070
            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);
1071 1072 1073 1074 1075
            return;
        }
    }
}

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

    do {
1081
        qdev_prop_set_globals_for_type(dev, object_class_get_name(class));
1082 1083
        class = object_class_get_parent(class);
    } while (class);
1084
}
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

/* --- 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,
};