qdev-properties.c 27.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 78
}

static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len)
{
79
    uint32_t *p = qdev_get_prop_ptr(dev, prop);
M
Michael S. Tsirkin 已提交
80 81 82
    return snprintf(dest, len, (*p & qdev_get_prop_mask(prop)) ? "on" : "off");
}

83
static void get_bit(Object *obj, Visitor *v, void *opaque,
84 85
                    const char *name, Error **errp)
{
86
    DeviceState *dev = DEVICE(obj);
87 88 89 90 91 92 93
    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);
}

94
static void set_bit(Object *obj, Visitor *v, void *opaque,
95 96
                    const char *name, Error **errp)
{
97
    DeviceState *dev = DEVICE(obj);
98 99 100 101
    Property *prop = opaque;
    Error *local_err = NULL;
    bool value;

102
    if (dev->realized) {
103
        qdev_prop_set_after_realize(dev, name, errp);
104 105 106 107 108 109 110 111 112 113 114
        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 已提交
115
PropertyInfo qdev_prop_bit = {
116 117
    .name  = "boolean",
    .legacy_name  = "on/off",
M
Michael S. Tsirkin 已提交
118
    .print = print_bit,
119 120
    .get   = get_bit,
    .set   = set_bit,
M
Michael S. Tsirkin 已提交
121 122
};

J
Juan Quintela 已提交
123 124
/* --- 8bit integer --- */

125 126
static void get_uint8(Object *obj, Visitor *v, void *opaque,
                      const char *name, Error **errp)
127
{
128
    DeviceState *dev = DEVICE(obj);
129
    Property *prop = opaque;
130
    uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
131

132
    visit_type_uint8(v, ptr, name, errp);
133 134
}

135 136
static void set_uint8(Object *obj, Visitor *v, void *opaque,
                      const char *name, Error **errp)
137
{
138
    DeviceState *dev = DEVICE(obj);
139
    Property *prop = opaque;
140
    uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
141

142
    if (dev->realized) {
143
        qdev_prop_set_after_realize(dev, name, errp);
144 145 146
        return;
    }

147
    visit_type_uint8(v, ptr, name, errp);
148 149
}

J
Juan Quintela 已提交
150 151
PropertyInfo qdev_prop_uint8 = {
    .name  = "uint8",
152 153
    .get   = get_uint8,
    .set   = set_uint8,
J
Juan Quintela 已提交
154 155
};

J
Jan Kiszka 已提交
156 157 158 159 160 161 162
/* --- 8bit hex value --- */

static int parse_hex8(DeviceState *dev, Property *prop, const char *str)
{
    uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
    char *end;

163 164 165 166
    if (str[0] != '0' || str[1] != 'x') {
        return -EINVAL;
    }

J
Jan Kiszka 已提交
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
    *ptr = strtoul(str, &end, 16);
    if ((*end != '\0') || (end == str)) {
        return -EINVAL;
    }

    return 0;
}

static int print_hex8(DeviceState *dev, Property *prop, char *dest, size_t len)
{
    uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
    return snprintf(dest, len, "0x%" PRIx8, *ptr);
}

PropertyInfo qdev_prop_hex8 = {
182 183
    .name  = "uint8",
    .legacy_name  = "hex8",
J
Jan Kiszka 已提交
184 185
    .parse = parse_hex8,
    .print = print_hex8,
186 187
    .get   = get_uint8,
    .set   = set_uint8,
J
Jan Kiszka 已提交
188 189
};

G
Gerd Hoffmann 已提交
190 191
/* --- 16bit integer --- */

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

199
    visit_type_uint16(v, ptr, name, errp);
200 201
}

202 203
static void set_uint16(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
204
{
205
    DeviceState *dev = DEVICE(obj);
206
    Property *prop = opaque;
207
    uint16_t *ptr = qdev_get_prop_ptr(dev, prop);
208

209
    if (dev->realized) {
210
        qdev_prop_set_after_realize(dev, name, errp);
211 212 213
        return;
    }

214
    visit_type_uint16(v, ptr, name, errp);
215 216
}

G
Gerd Hoffmann 已提交
217 218
PropertyInfo qdev_prop_uint16 = {
    .name  = "uint16",
219 220
    .get   = get_uint16,
    .set   = set_uint16,
G
Gerd Hoffmann 已提交
221 222 223 224
};

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

225 226 227 228 229
static void get_uint32(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
{
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
230
    uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
231

232
    visit_type_uint32(v, ptr, name, errp);
233 234 235 236 237 238 239
}

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

242
    if (dev->realized) {
243
        qdev_prop_set_after_realize(dev, name, errp);
244 245 246
        return;
    }

247
    visit_type_uint32(v, ptr, name, errp);
248 249
}

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

257
    visit_type_int32(v, ptr, name, errp);
258 259
}

260
static void set_int32(Object *obj, Visitor *v, void *opaque,
261 262
                      const char *name, Error **errp)
{
263
    DeviceState *dev = DEVICE(obj);
264
    Property *prop = opaque;
265
    int32_t *ptr = qdev_get_prop_ptr(dev, prop);
266

267
    if (dev->realized) {
268
        qdev_prop_set_after_realize(dev, name, errp);
269 270 271
        return;
    }

272
    visit_type_int32(v, ptr, name, errp);
273 274
}

G
Gerd Hoffmann 已提交
275 276
PropertyInfo qdev_prop_uint32 = {
    .name  = "uint32",
277 278
    .get   = get_uint32,
    .set   = set_uint32,
G
Gerd Hoffmann 已提交
279 280
};

281 282
PropertyInfo qdev_prop_int32 = {
    .name  = "int32",
283 284
    .get   = get_int32,
    .set   = set_int32,
285 286
};

G
Gerd Hoffmann 已提交
287 288 289 290 291
/* --- 32bit hex value --- */

static int parse_hex32(DeviceState *dev, Property *prop, const char *str)
{
    uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
292
    char *end;
G
Gerd Hoffmann 已提交
293

294 295 296 297
    if (str[0] != '0' || str[1] != 'x') {
        return -EINVAL;
    }

298 299
    *ptr = strtoul(str, &end, 16);
    if ((*end != '\0') || (end == str)) {
300
        return -EINVAL;
301 302
    }

G
Gerd Hoffmann 已提交
303 304 305 306 307 308 309 310 311 312
    return 0;
}

static int print_hex32(DeviceState *dev, Property *prop, char *dest, size_t len)
{
    uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
    return snprintf(dest, len, "0x%" PRIx32, *ptr);
}

PropertyInfo qdev_prop_hex32 = {
313 314
    .name  = "uint32",
    .legacy_name  = "hex32",
G
Gerd Hoffmann 已提交
315 316
    .parse = parse_hex32,
    .print = print_hex32,
317 318
    .get   = get_uint32,
    .set   = set_uint32,
G
Gerd Hoffmann 已提交
319 320
};

B
Blue Swirl 已提交
321 322
/* --- 64bit integer --- */

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

330
    visit_type_uint64(v, ptr, name, errp);
331 332
}

333 334
static void set_uint64(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
335
{
336
    DeviceState *dev = DEVICE(obj);
337
    Property *prop = opaque;
338
    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
339

340
    if (dev->realized) {
341
        qdev_prop_set_after_realize(dev, name, errp);
342 343 344
        return;
    }

345
    visit_type_uint64(v, ptr, name, errp);
346 347
}

B
Blue Swirl 已提交
348 349
PropertyInfo qdev_prop_uint64 = {
    .name  = "uint64",
350 351
    .get   = get_uint64,
    .set   = set_uint64,
B
Blue Swirl 已提交
352 353 354 355 356 357 358
};

/* --- 64bit hex value --- */

static int parse_hex64(DeviceState *dev, Property *prop, const char *str)
{
    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
359
    char *end;
B
Blue Swirl 已提交
360

361 362 363 364
    if (str[0] != '0' || str[1] != 'x') {
        return -EINVAL;
    }

365 366
    *ptr = strtoull(str, &end, 16);
    if ((*end != '\0') || (end == str)) {
367
        return -EINVAL;
368 369
    }

B
Blue Swirl 已提交
370 371 372 373 374 375 376 377 378 379
    return 0;
}

static int print_hex64(DeviceState *dev, Property *prop, char *dest, size_t len)
{
    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
    return snprintf(dest, len, "0x%" PRIx64, *ptr);
}

PropertyInfo qdev_prop_hex64 = {
380 381
    .name  = "uint64",
    .legacy_name  = "hex64",
B
Blue Swirl 已提交
382 383
    .parse = parse_hex64,
    .print = print_hex64,
384 385
    .get   = get_uint64,
    .set   = set_uint64,
B
Blue Swirl 已提交
386 387
};

G
Gerd Hoffmann 已提交
388 389
/* --- string --- */

P
Paolo Bonzini 已提交
390
static void release_string(Object *obj, const char *name, void *opaque)
391
{
P
Paolo Bonzini 已提交
392 393
    Property *prop = opaque;
    g_free(*(char **)qdev_get_prop_ptr(DEVICE(obj), prop));
394 395
}

E
Eduardo Habkost 已提交
396 397
static int print_string(DeviceState *dev, Property *prop, char *dest,
                        size_t len)
G
Gerd Hoffmann 已提交
398 399
{
    char **ptr = qdev_get_prop_ptr(dev, prop);
E
Eduardo Habkost 已提交
400
    if (!*ptr) {
G
Gerd Hoffmann 已提交
401
        return snprintf(dest, len, "<null>");
E
Eduardo Habkost 已提交
402
    }
G
Gerd Hoffmann 已提交
403 404 405
    return snprintf(dest, len, "\"%s\"", *ptr);
}

406
static void get_string(Object *obj, Visitor *v, void *opaque,
407 408
                       const char *name, Error **errp)
{
409
    DeviceState *dev = DEVICE(obj);
410 411 412 413 414 415 416 417 418 419 420
    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);
    }
}

421
static void set_string(Object *obj, Visitor *v, void *opaque,
422 423
                       const char *name, Error **errp)
{
424
    DeviceState *dev = DEVICE(obj);
425 426 427 428 429
    Property *prop = opaque;
    char **ptr = qdev_get_prop_ptr(dev, prop);
    Error *local_err = NULL;
    char *str;

430
    if (dev->realized) {
431
        qdev_prop_set_after_realize(dev, name, errp);
432 433 434 435 436 437 438 439 440 441 442 443 444 445
        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 已提交
446 447 448
PropertyInfo qdev_prop_string = {
    .name  = "string",
    .print = print_string,
P
Paolo Bonzini 已提交
449
    .release = release_string,
450 451
    .get   = get_string,
    .set   = set_string,
G
Gerd Hoffmann 已提交
452 453
};

G
Gerd Hoffmann 已提交
454 455
/* --- pointer --- */

456
/* Not a proper property, just for dirty hacks.  TODO Remove it!  */
G
Gerd Hoffmann 已提交
457 458 459 460 461 462 463 464 465 466 467
PropertyInfo qdev_prop_ptr = {
    .name  = "ptr",
};

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

/*
 * accepted syntax versions:
 *   01:02:03:04:05:06
 *   01-02-03-04-05-06
 */
468 469
static void get_mac(Object *obj, Visitor *v, void *opaque,
                    const char *name, Error **errp)
G
Gerd Hoffmann 已提交
470
{
471 472
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
G
Gerd Hoffmann 已提交
473
    MACAddr *mac = qdev_get_prop_ptr(dev, prop);
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490
    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 已提交
491
    int i, pos;
492 493
    char *str, *p;

494
    if (dev->realized) {
495
        qdev_prop_set_after_realize(dev, name, errp);
496 497 498 499 500 501 502 503
        return;
    }

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

    for (i = 0, pos = 0; i < 6; i++, pos += 3) {
E
Eduardo Habkost 已提交
506
        if (!qemu_isxdigit(str[pos])) {
507
            goto inval;
E
Eduardo Habkost 已提交
508 509
        }
        if (!qemu_isxdigit(str[pos+1])) {
510
            goto inval;
E
Eduardo Habkost 已提交
511
        }
G
Gerd Hoffmann 已提交
512
        if (i == 5) {
E
Eduardo Habkost 已提交
513
            if (str[pos+2] != '\0') {
514
                goto inval;
E
Eduardo Habkost 已提交
515
            }
G
Gerd Hoffmann 已提交
516
        } else {
E
Eduardo Habkost 已提交
517
            if (str[pos+2] != ':' && str[pos+2] != '-') {
518
                goto inval;
E
Eduardo Habkost 已提交
519
            }
G
Gerd Hoffmann 已提交
520 521
        }
        mac->a[i] = strtol(str+pos, &p, 16);
G
Gerd Hoffmann 已提交
522
    }
D
dunrong huang 已提交
523
    g_free(str);
524
    return;
G
Gerd Hoffmann 已提交
525

526 527
inval:
    error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
D
dunrong huang 已提交
528
    g_free(str);
G
Gerd Hoffmann 已提交
529 530 531
}

PropertyInfo qdev_prop_macaddr = {
G
Gerd Hoffmann 已提交
532
    .name  = "macaddr",
533 534
    .get   = get_mac,
    .set   = set_mac,
G
Gerd Hoffmann 已提交
535 536
};

537 538
/* --- lost tick policy --- */

539 540 541 542 543 544
static const char *lost_tick_policy_table[LOST_TICK_MAX+1] = {
    [LOST_TICK_DISCARD] = "discard",
    [LOST_TICK_DELAY] = "delay",
    [LOST_TICK_MERGE] = "merge",
    [LOST_TICK_SLEW] = "slew",
    [LOST_TICK_MAX] = NULL,
545 546
};

547 548
QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int));

549
PropertyInfo qdev_prop_losttickpolicy = {
550 551 552 553
    .name  = "LostTickPolicy",
    .enum_table  = lost_tick_policy_table,
    .get   = get_enum,
    .set   = set_enum,
554 555
};

556 557 558 559 560 561 562 563 564 565 566 567 568 569 570
/* --- BIOS CHS translation */

static const char *bios_chs_trans_table[] = {
    [BIOS_ATA_TRANSLATION_AUTO] = "auto",
    [BIOS_ATA_TRANSLATION_NONE] = "none",
    [BIOS_ATA_TRANSLATION_LBA]  = "lba",
};

PropertyInfo qdev_prop_bios_chs_trans = {
    .name = "bios-chs-trans",
    .enum_table = bios_chs_trans_table,
    .get = get_enum,
    .set = set_enum,
};

571 572 573 574 575
/* --- pci address --- */

/*
 * bus-local address, i.e. "$slot" or "$slot.$fn"
 */
576 577
static void set_pci_devfn(Object *obj, Visitor *v, void *opaque,
                          const char *name, Error **errp)
578
{
579 580
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
581
    int32_t value, *ptr = qdev_get_prop_ptr(dev, prop);
582
    unsigned int slot, fn, n;
583
    Error *local_err = NULL;
D
dunrong huang 已提交
584
    char *str;
585

586
    if (dev->realized) {
587
        qdev_prop_set_after_realize(dev, name, errp);
588 589 590 591 592
        return;
    }

    visit_type_str(v, &str, name, &local_err);
    if (local_err) {
593
        error_free(local_err);
594 595 596 597 598 599 600 601 602 603 604
        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;
605
    }
606 607 608 609

    if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
        fn = 0;
        if (sscanf(str, "%x%n", &slot, &n) != 1) {
610
            goto invalid;
611 612
        }
    }
613 614 615
    if (str[n] != '\0' || fn > 7 || slot > 31) {
        goto invalid;
    }
616
    *ptr = slot << 3 | fn;
D
dunrong huang 已提交
617
    g_free(str);
618 619 620 621
    return;

invalid:
    error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
D
dunrong huang 已提交
622
    g_free(str);
623 624
}

E
Eduardo Habkost 已提交
625 626
static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest,
                           size_t len)
627
{
628
    int32_t *ptr = qdev_get_prop_ptr(dev, prop);
629

B
Blue Swirl 已提交
630
    if (*ptr == -1) {
631 632 633 634 635 636 637
        return snprintf(dest, len, "<unset>");
    } else {
        return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7);
    }
}

PropertyInfo qdev_prop_pci_devfn = {
638 639
    .name  = "int32",
    .legacy_name  = "pci-devfn",
640
    .print = print_pci_devfn,
641
    .get   = get_int32,
642
    .set   = set_pci_devfn,
643 644
};

645 646 647 648 649 650 651
/* --- blocksize --- */

static void set_blocksize(Object *obj, Visitor *v, void *opaque,
                          const char *name, Error **errp)
{
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
652
    uint16_t value, *ptr = qdev_get_prop_ptr(dev, prop);
653
    Error *local_err = NULL;
654 655
    const int64_t min = 512;
    const int64_t max = 32768;
656

657
    if (dev->realized) {
658
        qdev_prop_set_after_realize(dev, name, errp);
659 660 661
        return;
    }

662
    visit_type_uint16(v, &value, name, &local_err);
663 664 665 666
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }
667
    if (value < min || value > max) {
668
        error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
669
                  dev->id?:"", name, (int64_t)value, min, max);
670 671 672 673 674 675
        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,
676
                  dev->id?:"", name, (int64_t)value);
677 678 679 680 681 682 683 684
        return;
    }

    *ptr = value;
}

PropertyInfo qdev_prop_blocksize = {
    .name  = "blocksize",
685
    .get   = get_uint16,
686 687 688
    .set   = set_blocksize,
};

689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724
/* --- 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;

725
    if (dev->realized) {
726
        qdev_prop_set_after_realize(dev, name, errp);
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 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
        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 = {
    .name = "pci-host-devaddr",
    .get = get_pci_host_devaddr,
    .set = set_pci_host_devaddr,
};

796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840
/* --- 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) {
841
        qdev_prop_set_after_realize(dev, name, errp);
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 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899
        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 已提交
900 901 902 903
/* --- public helpers --- */

static Property *qdev_prop_walk(Property *props, const char *name)
{
E
Eduardo Habkost 已提交
904
    if (!props) {
G
Gerd Hoffmann 已提交
905
        return NULL;
E
Eduardo Habkost 已提交
906
    }
G
Gerd Hoffmann 已提交
907
    while (props->name) {
E
Eduardo Habkost 已提交
908
        if (strcmp(props->name, name) == 0) {
G
Gerd Hoffmann 已提交
909
            return props;
E
Eduardo Habkost 已提交
910
        }
G
Gerd Hoffmann 已提交
911 912 913 914 915 916 917
        props++;
    }
    return NULL;
}

static Property *qdev_prop_find(DeviceState *dev, const char *name)
{
918
    ObjectClass *class;
G
Gerd Hoffmann 已提交
919 920 921
    Property *prop;

    /* device properties */
922 923 924 925 926 927 928 929
    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 已提交
930 931 932 933

    return NULL;
}

934 935 936 937 938 939
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,
940
                  object_get_typename(OBJECT(dev)), prop->name, value);
941 942 943 944
        break;
    default:
    case -EINVAL:
        error_set(errp, QERR_PROPERTY_VALUE_BAD,
945
                  object_get_typename(OBJECT(dev)), prop->name, value);
946 947 948
        break;
    case -ENOENT:
        error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND,
949
                  object_get_typename(OBJECT(dev)), prop->name, value);
950 951 952 953 954 955
        break;
    case 0:
        break;
    }
}

G
Gerd Hoffmann 已提交
956 957
int qdev_prop_parse(DeviceState *dev, const char *name, const char *value)
{
958 959
    char *legacy_name;
    Error *err = NULL;
G
Gerd Hoffmann 已提交
960

961 962
    legacy_name = g_strdup_printf("legacy-%s", name);
    if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) {
963
        object_property_parse(OBJECT(dev), value, legacy_name, &err);
964
    } else {
965
        object_property_parse(OBJECT(dev), value, name, &err);
G
Gerd Hoffmann 已提交
966
    }
967 968 969
    g_free(legacy_name);

    if (err) {
970 971
        qerror_report_err(err);
        error_free(err);
972 973 974
        return -1;
    }
    return 0;
G
Gerd Hoffmann 已提交
975 976
}

977 978
void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value)
{
P
Paolo Bonzini 已提交
979 980
    Error *errp = NULL;
    object_property_set_bool(OBJECT(dev), value, name, &errp);
981
    assert_no_error(errp);
982 983
}

J
Juan Quintela 已提交
984 985
void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value)
{
P
Paolo Bonzini 已提交
986 987
    Error *errp = NULL;
    object_property_set_int(OBJECT(dev), value, name, &errp);
988
    assert_no_error(errp);
J
Juan Quintela 已提交
989 990
}

G
Gerd Hoffmann 已提交
991 992
void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value)
{
P
Paolo Bonzini 已提交
993 994
    Error *errp = NULL;
    object_property_set_int(OBJECT(dev), value, name, &errp);
995
    assert_no_error(errp);
G
Gerd Hoffmann 已提交
996 997 998 999
}

void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value)
{
P
Paolo Bonzini 已提交
1000 1001
    Error *errp = NULL;
    object_property_set_int(OBJECT(dev), value, name, &errp);
1002
    assert_no_error(errp);
G
Gerd Hoffmann 已提交
1003 1004
}

1005 1006
void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value)
{
P
Paolo Bonzini 已提交
1007 1008
    Error *errp = NULL;
    object_property_set_int(OBJECT(dev), value, name, &errp);
1009
    assert_no_error(errp);
1010 1011
}

B
Blue Swirl 已提交
1012 1013
void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value)
{
P
Paolo Bonzini 已提交
1014 1015
    Error *errp = NULL;
    object_property_set_int(OBJECT(dev), value, name, &errp);
1016
    assert_no_error(errp);
B
Blue Swirl 已提交
1017 1018
}

1019
void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value)
1020
{
P
Paolo Bonzini 已提交
1021 1022
    Error *errp = NULL;
    object_property_set_str(OBJECT(dev), value, name, &errp);
1023
    assert_no_error(errp);
1024 1025
}

G
Gerd Hoffmann 已提交
1026 1027
void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value)
{
P
Paolo Bonzini 已提交
1028 1029 1030 1031 1032 1033
    Error *errp = NULL;
    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]);

    object_property_set_str(OBJECT(dev), str, name, &errp);
1034
    assert_no_error(errp);
G
Gerd Hoffmann 已提交
1035 1036
}

P
Paolo Bonzini 已提交
1037
void qdev_prop_set_enum(DeviceState *dev, const char *name, int value)
1038
{
P
Paolo Bonzini 已提交
1039 1040 1041 1042 1043 1044
    Property *prop;
    Error *errp = NULL;

    prop = qdev_prop_find(dev, name);
    object_property_set_str(OBJECT(dev), prop->info->enum_table[value],
                            name, &errp);
1045
    assert_no_error(errp);
1046 1047
}

G
Gerd Hoffmann 已提交
1048 1049
void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
{
1050 1051 1052 1053 1054 1055 1056
    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 已提交
1057 1058
}

E
Eduardo Habkost 已提交
1059 1060
static QTAILQ_HEAD(, GlobalProperty) global_props =
        QTAILQ_HEAD_INITIALIZER(global_props);
1061

1062
void qdev_prop_register_global(GlobalProperty *prop)
1063
{
1064
    QTAILQ_INSERT_TAIL(&global_props, prop, next);
1065 1066
}

1067
void qdev_prop_register_global_list(GlobalProperty *props)
1068
{
1069
    int i;
1070

1071 1072
    for (i = 0; props[i].driver != NULL; i++) {
        qdev_prop_register_global(props+i);
1073
    }
1074 1075 1076 1077
}

void qdev_prop_set_globals(DeviceState *dev)
{
1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088
    ObjectClass *class = object_get_class(OBJECT(dev));

    do {
        GlobalProperty *prop;
        QTAILQ_FOREACH(prop, &global_props, next) {
            if (strcmp(object_class_get_name(class), prop->driver) != 0) {
                continue;
            }
            if (qdev_prop_parse(dev, prop->property, prop->value) != 0) {
                exit(1);
            }
1089
        }
1090 1091
        class = object_class_get_parent(class);
    } while (class);
1092
}