qdev-properties.c 25.5 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/blockdev.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)));
    }
}

G
Gerd Hoffmann 已提交
24 25 26 27 28 29 30
void *qdev_get_prop_ptr(DeviceState *dev, Property *prop)
{
    void *ptr = dev;
    ptr += prop->offset;
    return ptr;
}

31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
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);

49
    if (dev->realized) {
50
        qdev_prop_set_after_realize(dev, name, errp);
51 52 53 54 55 56 57 58 59
        return;
    }

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

/* Bit */

M
Michael S. Tsirkin 已提交
60 61
static uint32_t qdev_get_prop_mask(Property *prop)
{
62
    assert(prop->info == &qdev_prop_bit);
M
Michael S. Tsirkin 已提交
63 64 65 66 67 68 69
    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 已提交
70
    if (val) {
71
        *p |= mask;
E
Eduardo Habkost 已提交
72
    } else {
M
Michael S. Tsirkin 已提交
73
        *p &= ~mask;
E
Eduardo Habkost 已提交
74
    }
M
Michael S. Tsirkin 已提交
75 76
}

77
static void prop_get_bit(Object *obj, Visitor *v, void *opaque,
78 79
                    const char *name, Error **errp)
{
80
    DeviceState *dev = DEVICE(obj);
81 82 83 84 85 86 87
    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);
}

88
static void prop_set_bit(Object *obj, Visitor *v, void *opaque,
89 90
                    const char *name, Error **errp)
{
91
    DeviceState *dev = DEVICE(obj);
92 93 94 95
    Property *prop = opaque;
    Error *local_err = NULL;
    bool value;

96
    if (dev->realized) {
97
        qdev_prop_set_after_realize(dev, name, errp);
98 99 100 101 102 103 104 105 106 107 108
        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 已提交
109
PropertyInfo qdev_prop_bit = {
110
    .name  = "bool",
111
    .legacy_name  = "on/off",
112 113
    .get   = prop_get_bit,
    .set   = prop_set_bit,
M
Michael S. Tsirkin 已提交
114 115
};

116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
/* --- 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 = {
144
    .name  = "bool",
145 146 147 148
    .get   = get_bool,
    .set   = set_bool,
};

J
Juan Quintela 已提交
149 150
/* --- 8bit integer --- */

151 152
static void get_uint8(Object *obj, Visitor *v, void *opaque,
                      const char *name, Error **errp)
153
{
154
    DeviceState *dev = DEVICE(obj);
155
    Property *prop = opaque;
156
    uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
157

158
    visit_type_uint8(v, ptr, name, errp);
159 160
}

161 162
static void set_uint8(Object *obj, Visitor *v, void *opaque,
                      const char *name, Error **errp)
163
{
164
    DeviceState *dev = DEVICE(obj);
165
    Property *prop = opaque;
166
    uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
167

168
    if (dev->realized) {
169
        qdev_prop_set_after_realize(dev, name, errp);
170 171 172
        return;
    }

173
    visit_type_uint8(v, ptr, name, errp);
174 175
}

J
Juan Quintela 已提交
176 177
PropertyInfo qdev_prop_uint8 = {
    .name  = "uint8",
178 179
    .get   = get_uint8,
    .set   = set_uint8,
J
Juan Quintela 已提交
180 181
};

G
Gerd Hoffmann 已提交
182 183
/* --- 16bit integer --- */

184 185
static void get_uint16(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
186
{
187
    DeviceState *dev = DEVICE(obj);
188
    Property *prop = opaque;
189
    uint16_t *ptr = qdev_get_prop_ptr(dev, prop);
190

191
    visit_type_uint16(v, ptr, name, errp);
192 193
}

194 195
static void set_uint16(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
196
{
197
    DeviceState *dev = DEVICE(obj);
198
    Property *prop = opaque;
199
    uint16_t *ptr = qdev_get_prop_ptr(dev, prop);
200

201
    if (dev->realized) {
202
        qdev_prop_set_after_realize(dev, name, errp);
203 204 205
        return;
    }

206
    visit_type_uint16(v, ptr, name, errp);
207 208
}

G
Gerd Hoffmann 已提交
209 210
PropertyInfo qdev_prop_uint16 = {
    .name  = "uint16",
211 212
    .get   = get_uint16,
    .set   = set_uint16,
G
Gerd Hoffmann 已提交
213 214 215 216
};

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

217 218 219 220 221
static void get_uint32(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
{
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
222
    uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
223

224
    visit_type_uint32(v, ptr, name, errp);
225 226 227 228 229 230 231
}

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

234
    if (dev->realized) {
235
        qdev_prop_set_after_realize(dev, name, errp);
236 237 238
        return;
    }

239
    visit_type_uint32(v, ptr, name, errp);
240 241
}

242
static void get_int32(Object *obj, Visitor *v, void *opaque,
243 244
                      const char *name, Error **errp)
{
245
    DeviceState *dev = DEVICE(obj);
246 247 248
    Property *prop = opaque;
    int32_t *ptr = qdev_get_prop_ptr(dev, prop);

249
    visit_type_int32(v, ptr, name, errp);
250 251
}

252
static void set_int32(Object *obj, Visitor *v, void *opaque,
253 254
                      const char *name, Error **errp)
{
255
    DeviceState *dev = DEVICE(obj);
256
    Property *prop = opaque;
257
    int32_t *ptr = qdev_get_prop_ptr(dev, prop);
258

259
    if (dev->realized) {
260
        qdev_prop_set_after_realize(dev, name, errp);
261 262 263
        return;
    }

264
    visit_type_int32(v, ptr, name, errp);
265 266
}

G
Gerd Hoffmann 已提交
267 268
PropertyInfo qdev_prop_uint32 = {
    .name  = "uint32",
269 270
    .get   = get_uint32,
    .set   = set_uint32,
G
Gerd Hoffmann 已提交
271 272
};

273 274
PropertyInfo qdev_prop_int32 = {
    .name  = "int32",
275 276
    .get   = get_int32,
    .set   = set_int32,
277 278
};

B
Blue Swirl 已提交
279 280
/* --- 64bit integer --- */

281 282
static void get_uint64(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
283
{
284
    DeviceState *dev = DEVICE(obj);
285
    Property *prop = opaque;
286
    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
287

288
    visit_type_uint64(v, ptr, name, errp);
289 290
}

291 292
static void set_uint64(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
293
{
294
    DeviceState *dev = DEVICE(obj);
295
    Property *prop = opaque;
296
    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
297

298
    if (dev->realized) {
299
        qdev_prop_set_after_realize(dev, name, errp);
300 301 302
        return;
    }

303
    visit_type_uint64(v, ptr, name, errp);
304 305
}

B
Blue Swirl 已提交
306 307
PropertyInfo qdev_prop_uint64 = {
    .name  = "uint64",
308 309
    .get   = get_uint64,
    .set   = set_uint64,
B
Blue Swirl 已提交
310 311
};

G
Gerd Hoffmann 已提交
312 313
/* --- string --- */

P
Paolo Bonzini 已提交
314
static void release_string(Object *obj, const char *name, void *opaque)
315
{
P
Paolo Bonzini 已提交
316 317
    Property *prop = opaque;
    g_free(*(char **)qdev_get_prop_ptr(DEVICE(obj), prop));
318 319
}

320
static void get_string(Object *obj, Visitor *v, void *opaque,
321 322
                       const char *name, Error **errp)
{
323
    DeviceState *dev = DEVICE(obj);
324 325 326 327 328 329 330 331 332 333 334
    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);
    }
}

335
static void set_string(Object *obj, Visitor *v, void *opaque,
336 337
                       const char *name, Error **errp)
{
338
    DeviceState *dev = DEVICE(obj);
339 340 341 342 343
    Property *prop = opaque;
    char **ptr = qdev_get_prop_ptr(dev, prop);
    Error *local_err = NULL;
    char *str;

344
    if (dev->realized) {
345
        qdev_prop_set_after_realize(dev, name, errp);
346 347 348 349 350 351 352 353 354 355 356 357 358 359
        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 已提交
360
PropertyInfo qdev_prop_string = {
361
    .name  = "str",
P
Paolo Bonzini 已提交
362
    .release = release_string,
363 364
    .get   = get_string,
    .set   = set_string,
G
Gerd Hoffmann 已提交
365 366
};

G
Gerd Hoffmann 已提交
367 368
/* --- pointer --- */

369
/* Not a proper property, just for dirty hacks.  TODO Remove it!  */
G
Gerd Hoffmann 已提交
370 371 372 373 374 375 376 377 378 379 380
PropertyInfo qdev_prop_ptr = {
    .name  = "ptr",
};

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

/*
 * accepted syntax versions:
 *   01:02:03:04:05:06
 *   01-02-03-04-05-06
 */
381 382
static void get_mac(Object *obj, Visitor *v, void *opaque,
                    const char *name, Error **errp)
G
Gerd Hoffmann 已提交
383
{
384 385
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
G
Gerd Hoffmann 已提交
386
    MACAddr *mac = qdev_get_prop_ptr(dev, prop);
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
    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 已提交
404
    int i, pos;
405 406
    char *str, *p;

407
    if (dev->realized) {
408
        qdev_prop_set_after_realize(dev, name, errp);
409 410 411 412 413 414 415 416
        return;
    }

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

    for (i = 0, pos = 0; i < 6; i++, pos += 3) {
E
Eduardo Habkost 已提交
419
        if (!qemu_isxdigit(str[pos])) {
420
            goto inval;
E
Eduardo Habkost 已提交
421 422
        }
        if (!qemu_isxdigit(str[pos+1])) {
423
            goto inval;
E
Eduardo Habkost 已提交
424
        }
G
Gerd Hoffmann 已提交
425
        if (i == 5) {
E
Eduardo Habkost 已提交
426
            if (str[pos+2] != '\0') {
427
                goto inval;
E
Eduardo Habkost 已提交
428
            }
G
Gerd Hoffmann 已提交
429
        } else {
E
Eduardo Habkost 已提交
430
            if (str[pos+2] != ':' && str[pos+2] != '-') {
431
                goto inval;
E
Eduardo Habkost 已提交
432
            }
G
Gerd Hoffmann 已提交
433 434
        }
        mac->a[i] = strtol(str+pos, &p, 16);
G
Gerd Hoffmann 已提交
435
    }
D
dunrong huang 已提交
436
    g_free(str);
437
    return;
G
Gerd Hoffmann 已提交
438

439 440
inval:
    error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
D
dunrong huang 已提交
441
    g_free(str);
G
Gerd Hoffmann 已提交
442 443 444
}

PropertyInfo qdev_prop_macaddr = {
445 446
    .name  = "str",
    .legacy_name  = "macaddr",
447 448
    .get   = get_mac,
    .set   = set_mac,
G
Gerd Hoffmann 已提交
449 450
};

451 452
/* --- lost tick policy --- */

453 454
QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int));

455
PropertyInfo qdev_prop_losttickpolicy = {
456
    .name  = "LostTickPolicy",
457
    .enum_table  = LostTickPolicy_lookup,
458 459
    .get   = get_enum,
    .set   = set_enum,
460 461
};

462 463
/* --- BIOS CHS translation */

464
QEMU_BUILD_BUG_ON(sizeof(BiosAtaTranslation) != sizeof(int));
465 466

PropertyInfo qdev_prop_bios_chs_trans = {
467 468
    .name = "BiosAtaTranslation",
    .legacy_name = "bios-chs-trans",
469
    .enum_table = BiosAtaTranslation_lookup,
470 471 472 473
    .get = get_enum,
    .set = set_enum,
};

474 475 476 477 478
/* --- pci address --- */

/*
 * bus-local address, i.e. "$slot" or "$slot.$fn"
 */
479 480
static void set_pci_devfn(Object *obj, Visitor *v, void *opaque,
                          const char *name, Error **errp)
481
{
482 483
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
484
    int32_t value, *ptr = qdev_get_prop_ptr(dev, prop);
485
    unsigned int slot, fn, n;
486
    Error *local_err = NULL;
D
dunrong huang 已提交
487
    char *str;
488

489
    if (dev->realized) {
490
        qdev_prop_set_after_realize(dev, name, errp);
491 492 493 494 495
        return;
    }

    visit_type_str(v, &str, name, &local_err);
    if (local_err) {
496
        error_free(local_err);
497 498 499 500 501 502 503 504 505 506 507
        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;
508
    }
509 510 511 512

    if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
        fn = 0;
        if (sscanf(str, "%x%n", &slot, &n) != 1) {
513
            goto invalid;
514 515
        }
    }
516 517 518
    if (str[n] != '\0' || fn > 7 || slot > 31) {
        goto invalid;
    }
519
    *ptr = slot << 3 | fn;
D
dunrong huang 已提交
520
    g_free(str);
521 522 523 524
    return;

invalid:
    error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
D
dunrong huang 已提交
525
    g_free(str);
526 527
}

E
Eduardo Habkost 已提交
528 529
static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest,
                           size_t len)
530
{
531
    int32_t *ptr = qdev_get_prop_ptr(dev, prop);
532

B
Blue Swirl 已提交
533
    if (*ptr == -1) {
534 535 536 537 538 539 540
        return snprintf(dest, len, "<unset>");
    } else {
        return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7);
    }
}

PropertyInfo qdev_prop_pci_devfn = {
541 542
    .name  = "int32",
    .legacy_name  = "pci-devfn",
543
    .print = print_pci_devfn,
544
    .get   = get_int32,
545
    .set   = set_pci_devfn,
546 547
};

548 549 550 551 552 553 554
/* --- blocksize --- */

static void set_blocksize(Object *obj, Visitor *v, void *opaque,
                          const char *name, Error **errp)
{
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
555
    uint16_t value, *ptr = qdev_get_prop_ptr(dev, prop);
556
    Error *local_err = NULL;
557 558
    const int64_t min = 512;
    const int64_t max = 32768;
559

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

565
    visit_type_uint16(v, &value, name, &local_err);
566 567 568 569
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }
570
    if (value < min || value > max) {
571
        error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
572
                  dev->id?:"", name, (int64_t)value, min, max);
573 574 575 576 577 578
        return;
    }

    /* We rely on power-of-2 blocksizes for bitmasks */
    if ((value & (value - 1)) != 0) {
        error_set(errp, QERR_PROPERTY_VALUE_NOT_POWER_OF_2,
579
                  dev->id?:"", name, (int64_t)value);
580 581 582 583 584 585 586
        return;
    }

    *ptr = value;
}

PropertyInfo qdev_prop_blocksize = {
587 588
    .name  = "uint16",
    .legacy_name  = "blocksize",
589
    .get   = get_uint16,
590 591 592
    .set   = set_blocksize,
};

593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
/* --- 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;

629
    if (dev->realized) {
630
        qdev_prop_set_after_realize(dev, name, errp);
631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 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
        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 = {
695 696
    .name = "str",
    .legacy_name = "pci-host-devaddr",
697 698 699 700
    .get = get_pci_host_devaddr,
    .set = set_pci_host_devaddr,
};

701 702 703 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
/* --- 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;
    void *eltptr;
    const char *arrayname;
    int i;

    if (dev->realized) {
746
        qdev_prop_set_after_realize(dev, name, errp);
747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 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
        return;
    }
    if (*alenptr) {
        error_setg(errp, "array size property %s may not be set more than once",
                   name);
        return;
    }
    visit_type_uint32(v, alenptr, name, errp);
    if (error_is_set(errp)) {
        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,
                            arrayprop, errp);
        if (error_is_set(errp)) {
            return;
        }
    }
}

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

G
Gerd Hoffmann 已提交
805 806 807 808
/* --- public helpers --- */

static Property *qdev_prop_walk(Property *props, const char *name)
{
E
Eduardo Habkost 已提交
809
    if (!props) {
G
Gerd Hoffmann 已提交
810
        return NULL;
E
Eduardo Habkost 已提交
811
    }
G
Gerd Hoffmann 已提交
812
    while (props->name) {
E
Eduardo Habkost 已提交
813
        if (strcmp(props->name, name) == 0) {
G
Gerd Hoffmann 已提交
814
            return props;
E
Eduardo Habkost 已提交
815
        }
G
Gerd Hoffmann 已提交
816 817 818 819 820 821 822
        props++;
    }
    return NULL;
}

static Property *qdev_prop_find(DeviceState *dev, const char *name)
{
823
    ObjectClass *class;
G
Gerd Hoffmann 已提交
824 825 826
    Property *prop;

    /* device properties */
827 828 829 830 831 832 833 834
    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 已提交
835 836 837 838

    return NULL;
}

839 840 841 842 843 844
void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
                                    Property *prop, const char *value)
{
    switch (ret) {
    case -EEXIST:
        error_set(errp, QERR_PROPERTY_VALUE_IN_USE,
845
                  object_get_typename(OBJECT(dev)), prop->name, value);
846 847 848 849
        break;
    default:
    case -EINVAL:
        error_set(errp, QERR_PROPERTY_VALUE_BAD,
850
                  object_get_typename(OBJECT(dev)), prop->name, value);
851 852 853
        break;
    case -ENOENT:
        error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND,
854
                  object_get_typename(OBJECT(dev)), prop->name, value);
855 856 857 858 859 860
        break;
    case 0:
        break;
    }
}

861 862
void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value)
{
863
    object_property_set_bool(OBJECT(dev), value, name, &error_abort);
864 865
}

J
Juan Quintela 已提交
866 867
void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value)
{
868
    object_property_set_int(OBJECT(dev), value, name, &error_abort);
J
Juan Quintela 已提交
869 870
}

G
Gerd Hoffmann 已提交
871 872
void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value)
{
873
    object_property_set_int(OBJECT(dev), value, name, &error_abort);
G
Gerd Hoffmann 已提交
874 875 876 877
}

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

881 882
void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value)
{
883
    object_property_set_int(OBJECT(dev), value, name, &error_abort);
884 885
}

B
Blue Swirl 已提交
886 887
void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value)
{
888
    object_property_set_int(OBJECT(dev), value, name, &error_abort);
B
Blue Swirl 已提交
889 890
}

891
void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value)
892
{
893
    object_property_set_str(OBJECT(dev), value, name, &error_abort);
894 895
}

G
Gerd Hoffmann 已提交
896 897
void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value)
{
P
Paolo Bonzini 已提交
898 899 900 901
    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]);

902
    object_property_set_str(OBJECT(dev), str, name, &error_abort);
G
Gerd Hoffmann 已提交
903 904
}

P
Paolo Bonzini 已提交
905
void qdev_prop_set_enum(DeviceState *dev, const char *name, int value)
906
{
P
Paolo Bonzini 已提交
907 908 909 910
    Property *prop;

    prop = qdev_prop_find(dev, name);
    object_property_set_str(OBJECT(dev), prop->info->enum_table[value],
911
                            name, &error_abort);
912 913
}

G
Gerd Hoffmann 已提交
914 915
void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
{
916 917 918 919 920 921 922
    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 已提交
923 924
}

E
Eduardo Habkost 已提交
925 926
static QTAILQ_HEAD(, GlobalProperty) global_props =
        QTAILQ_HEAD_INITIALIZER(global_props);
927

928
void qdev_prop_register_global(GlobalProperty *prop)
929
{
930
    QTAILQ_INSERT_TAIL(&global_props, prop, next);
931 932
}

933
void qdev_prop_register_global_list(GlobalProperty *props)
934
{
935
    int i;
936

937 938
    for (i = 0; props[i].driver != NULL; i++) {
        qdev_prop_register_global(props+i);
939
    }
940 941
}

942 943 944 945 946 947 948 949 950 951 952
void qdev_prop_set_globals_for_type(DeviceState *dev, const char *typename,
                                    Error **errp)
{
    GlobalProperty *prop;

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

        if (strcmp(typename, prop->driver) != 0) {
            continue;
        }
P
Paolo Bonzini 已提交
953
        object_property_parse(OBJECT(dev), prop->value, prop->property, &err);
954 955 956 957 958 959 960
        if (err != NULL) {
            error_propagate(errp, err);
            return;
        }
    }
}

961
void qdev_prop_set_globals(DeviceState *dev, Error **errp)
962
{
963 964 965
    ObjectClass *class = object_get_class(OBJECT(dev));

    do {
966
        Error *err = NULL;
967

968 969 970 971 972
        qdev_prop_set_globals_for_type(dev, object_class_get_name(class),
                                       &err);
        if (err != NULL) {
            error_propagate(errp, err);
            return;
973
        }
974 975
        class = object_class_get_parent(class);
    } while (class);
976
}
977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004

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