qdev-properties.c 28.3 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
};

123 124 125 126 127 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
/* --- 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 = {
    .name  = "boolean",
    .get   = get_bool,
    .set   = set_bool,
};

J
Juan Quintela 已提交
156 157
/* --- 8bit integer --- */

158 159
static void get_uint8(Object *obj, Visitor *v, void *opaque,
                      const char *name, Error **errp)
160
{
161
    DeviceState *dev = DEVICE(obj);
162
    Property *prop = opaque;
163
    uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
164

165
    visit_type_uint8(v, ptr, name, errp);
166 167
}

168 169
static void set_uint8(Object *obj, Visitor *v, void *opaque,
                      const char *name, Error **errp)
170
{
171
    DeviceState *dev = DEVICE(obj);
172
    Property *prop = opaque;
173
    uint8_t *ptr = qdev_get_prop_ptr(dev, prop);
174

175
    if (dev->realized) {
176
        qdev_prop_set_after_realize(dev, name, errp);
177 178 179
        return;
    }

180
    visit_type_uint8(v, ptr, name, errp);
181 182
}

J
Juan Quintela 已提交
183 184
PropertyInfo qdev_prop_uint8 = {
    .name  = "uint8",
185 186
    .get   = get_uint8,
    .set   = set_uint8,
J
Juan Quintela 已提交
187 188
};

J
Jan Kiszka 已提交
189 190 191 192 193 194 195
/* --- 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;

196 197 198 199
    if (str[0] != '0' || str[1] != 'x') {
        return -EINVAL;
    }

J
Jan Kiszka 已提交
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
    *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 = {
215 216
    .name  = "uint8",
    .legacy_name  = "hex8",
J
Jan Kiszka 已提交
217 218
    .parse = parse_hex8,
    .print = print_hex8,
219 220
    .get   = get_uint8,
    .set   = set_uint8,
J
Jan Kiszka 已提交
221 222
};

G
Gerd Hoffmann 已提交
223 224
/* --- 16bit integer --- */

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

232
    visit_type_uint16(v, ptr, name, errp);
233 234
}

235 236
static void set_uint16(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
237
{
238
    DeviceState *dev = DEVICE(obj);
239
    Property *prop = opaque;
240
    uint16_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_uint16(v, ptr, name, errp);
248 249
}

G
Gerd Hoffmann 已提交
250 251
PropertyInfo qdev_prop_uint16 = {
    .name  = "uint16",
252 253
    .get   = get_uint16,
    .set   = set_uint16,
G
Gerd Hoffmann 已提交
254 255 256 257
};

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

258 259 260 261 262
static void get_uint32(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
{
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
263
    uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
264

265
    visit_type_uint32(v, ptr, name, errp);
266 267 268 269 270 271 272
}

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

275
    if (dev->realized) {
276
        qdev_prop_set_after_realize(dev, name, errp);
277 278 279
        return;
    }

280
    visit_type_uint32(v, ptr, name, errp);
281 282
}

283
static void get_int32(Object *obj, Visitor *v, void *opaque,
284 285
                      const char *name, Error **errp)
{
286
    DeviceState *dev = DEVICE(obj);
287 288 289
    Property *prop = opaque;
    int32_t *ptr = qdev_get_prop_ptr(dev, prop);

290
    visit_type_int32(v, ptr, name, errp);
291 292
}

293
static void set_int32(Object *obj, Visitor *v, void *opaque,
294 295
                      const char *name, Error **errp)
{
296
    DeviceState *dev = DEVICE(obj);
297
    Property *prop = opaque;
298
    int32_t *ptr = qdev_get_prop_ptr(dev, prop);
299

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

305
    visit_type_int32(v, ptr, name, errp);
306 307
}

G
Gerd Hoffmann 已提交
308 309
PropertyInfo qdev_prop_uint32 = {
    .name  = "uint32",
310 311
    .get   = get_uint32,
    .set   = set_uint32,
G
Gerd Hoffmann 已提交
312 313
};

314 315
PropertyInfo qdev_prop_int32 = {
    .name  = "int32",
316 317
    .get   = get_int32,
    .set   = set_int32,
318 319
};

G
Gerd Hoffmann 已提交
320 321 322 323 324
/* --- 32bit hex value --- */

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

327 328 329 330
    if (str[0] != '0' || str[1] != 'x') {
        return -EINVAL;
    }

331 332
    *ptr = strtoul(str, &end, 16);
    if ((*end != '\0') || (end == str)) {
333
        return -EINVAL;
334 335
    }

G
Gerd Hoffmann 已提交
336 337 338 339 340 341 342 343 344 345
    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 = {
346 347
    .name  = "uint32",
    .legacy_name  = "hex32",
G
Gerd Hoffmann 已提交
348 349
    .parse = parse_hex32,
    .print = print_hex32,
350 351
    .get   = get_uint32,
    .set   = set_uint32,
G
Gerd Hoffmann 已提交
352 353
};

B
Blue Swirl 已提交
354 355
/* --- 64bit integer --- */

356 357
static void get_uint64(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
358
{
359
    DeviceState *dev = DEVICE(obj);
360
    Property *prop = opaque;
361
    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
362

363
    visit_type_uint64(v, ptr, name, errp);
364 365
}

366 367
static void set_uint64(Object *obj, Visitor *v, void *opaque,
                       const char *name, Error **errp)
368
{
369
    DeviceState *dev = DEVICE(obj);
370
    Property *prop = opaque;
371
    uint64_t *ptr = qdev_get_prop_ptr(dev, prop);
372

373
    if (dev->realized) {
374
        qdev_prop_set_after_realize(dev, name, errp);
375 376 377
        return;
    }

378
    visit_type_uint64(v, ptr, name, errp);
379 380
}

B
Blue Swirl 已提交
381 382
PropertyInfo qdev_prop_uint64 = {
    .name  = "uint64",
383 384
    .get   = get_uint64,
    .set   = set_uint64,
B
Blue Swirl 已提交
385 386 387 388 389 390 391
};

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

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

394 395 396 397
    if (str[0] != '0' || str[1] != 'x') {
        return -EINVAL;
    }

398 399
    *ptr = strtoull(str, &end, 16);
    if ((*end != '\0') || (end == str)) {
400
        return -EINVAL;
401 402
    }

B
Blue Swirl 已提交
403 404 405 406 407 408 409 410 411 412
    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 = {
413 414
    .name  = "uint64",
    .legacy_name  = "hex64",
B
Blue Swirl 已提交
415 416
    .parse = parse_hex64,
    .print = print_hex64,
417 418
    .get   = get_uint64,
    .set   = set_uint64,
B
Blue Swirl 已提交
419 420
};

G
Gerd Hoffmann 已提交
421 422
/* --- string --- */

P
Paolo Bonzini 已提交
423
static void release_string(Object *obj, const char *name, void *opaque)
424
{
P
Paolo Bonzini 已提交
425 426
    Property *prop = opaque;
    g_free(*(char **)qdev_get_prop_ptr(DEVICE(obj), prop));
427 428
}

E
Eduardo Habkost 已提交
429 430
static int print_string(DeviceState *dev, Property *prop, char *dest,
                        size_t len)
G
Gerd Hoffmann 已提交
431 432
{
    char **ptr = qdev_get_prop_ptr(dev, prop);
E
Eduardo Habkost 已提交
433
    if (!*ptr) {
G
Gerd Hoffmann 已提交
434
        return snprintf(dest, len, "<null>");
E
Eduardo Habkost 已提交
435
    }
G
Gerd Hoffmann 已提交
436 437 438
    return snprintf(dest, len, "\"%s\"", *ptr);
}

439
static void get_string(Object *obj, Visitor *v, void *opaque,
440 441
                       const char *name, Error **errp)
{
442
    DeviceState *dev = DEVICE(obj);
443 444 445 446 447 448 449 450 451 452 453
    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);
    }
}

454
static void set_string(Object *obj, Visitor *v, void *opaque,
455 456
                       const char *name, Error **errp)
{
457
    DeviceState *dev = DEVICE(obj);
458 459 460 461 462
    Property *prop = opaque;
    char **ptr = qdev_get_prop_ptr(dev, prop);
    Error *local_err = NULL;
    char *str;

463
    if (dev->realized) {
464
        qdev_prop_set_after_realize(dev, name, errp);
465 466 467 468 469 470 471 472 473 474 475 476 477 478
        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 已提交
479 480 481
PropertyInfo qdev_prop_string = {
    .name  = "string",
    .print = print_string,
P
Paolo Bonzini 已提交
482
    .release = release_string,
483 484
    .get   = get_string,
    .set   = set_string,
G
Gerd Hoffmann 已提交
485 486
};

G
Gerd Hoffmann 已提交
487 488
/* --- pointer --- */

489
/* Not a proper property, just for dirty hacks.  TODO Remove it!  */
G
Gerd Hoffmann 已提交
490 491 492 493 494 495 496 497 498 499 500
PropertyInfo qdev_prop_ptr = {
    .name  = "ptr",
};

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

/*
 * accepted syntax versions:
 *   01:02:03:04:05:06
 *   01-02-03-04-05-06
 */
501 502
static void get_mac(Object *obj, Visitor *v, void *opaque,
                    const char *name, Error **errp)
G
Gerd Hoffmann 已提交
503
{
504 505
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
G
Gerd Hoffmann 已提交
506
    MACAddr *mac = qdev_get_prop_ptr(dev, prop);
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523
    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 已提交
524
    int i, pos;
525 526
    char *str, *p;

527
    if (dev->realized) {
528
        qdev_prop_set_after_realize(dev, name, errp);
529 530 531 532 533 534 535 536
        return;
    }

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

    for (i = 0, pos = 0; i < 6; i++, pos += 3) {
E
Eduardo Habkost 已提交
539
        if (!qemu_isxdigit(str[pos])) {
540
            goto inval;
E
Eduardo Habkost 已提交
541 542
        }
        if (!qemu_isxdigit(str[pos+1])) {
543
            goto inval;
E
Eduardo Habkost 已提交
544
        }
G
Gerd Hoffmann 已提交
545
        if (i == 5) {
E
Eduardo Habkost 已提交
546
            if (str[pos+2] != '\0') {
547
                goto inval;
E
Eduardo Habkost 已提交
548
            }
G
Gerd Hoffmann 已提交
549
        } else {
E
Eduardo Habkost 已提交
550
            if (str[pos+2] != ':' && str[pos+2] != '-') {
551
                goto inval;
E
Eduardo Habkost 已提交
552
            }
G
Gerd Hoffmann 已提交
553 554
        }
        mac->a[i] = strtol(str+pos, &p, 16);
G
Gerd Hoffmann 已提交
555
    }
D
dunrong huang 已提交
556
    g_free(str);
557
    return;
G
Gerd Hoffmann 已提交
558

559 560
inval:
    error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
D
dunrong huang 已提交
561
    g_free(str);
G
Gerd Hoffmann 已提交
562 563 564
}

PropertyInfo qdev_prop_macaddr = {
G
Gerd Hoffmann 已提交
565
    .name  = "macaddr",
566 567
    .get   = get_mac,
    .set   = set_mac,
G
Gerd Hoffmann 已提交
568 569
};

570 571
/* --- lost tick policy --- */

572 573 574 575 576 577
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,
578 579
};

580 581
QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int));

582
PropertyInfo qdev_prop_losttickpolicy = {
583 584 585 586
    .name  = "LostTickPolicy",
    .enum_table  = lost_tick_policy_table,
    .get   = get_enum,
    .set   = set_enum,
587 588
};

589 590 591 592 593 594 595 596 597 598 599 600 601 602 603
/* --- 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,
};

604 605 606 607 608
/* --- pci address --- */

/*
 * bus-local address, i.e. "$slot" or "$slot.$fn"
 */
609 610
static void set_pci_devfn(Object *obj, Visitor *v, void *opaque,
                          const char *name, Error **errp)
611
{
612 613
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
614
    int32_t value, *ptr = qdev_get_prop_ptr(dev, prop);
615
    unsigned int slot, fn, n;
616
    Error *local_err = NULL;
D
dunrong huang 已提交
617
    char *str;
618

619
    if (dev->realized) {
620
        qdev_prop_set_after_realize(dev, name, errp);
621 622 623 624 625
        return;
    }

    visit_type_str(v, &str, name, &local_err);
    if (local_err) {
626
        error_free(local_err);
627 628 629 630 631 632 633 634 635 636 637
        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;
638
    }
639 640 641 642

    if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
        fn = 0;
        if (sscanf(str, "%x%n", &slot, &n) != 1) {
643
            goto invalid;
644 645
        }
    }
646 647 648
    if (str[n] != '\0' || fn > 7 || slot > 31) {
        goto invalid;
    }
649
    *ptr = slot << 3 | fn;
D
dunrong huang 已提交
650
    g_free(str);
651 652 653 654
    return;

invalid:
    error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
D
dunrong huang 已提交
655
    g_free(str);
656 657
}

E
Eduardo Habkost 已提交
658 659
static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest,
                           size_t len)
660
{
661
    int32_t *ptr = qdev_get_prop_ptr(dev, prop);
662

B
Blue Swirl 已提交
663
    if (*ptr == -1) {
664 665 666 667 668 669 670
        return snprintf(dest, len, "<unset>");
    } else {
        return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7);
    }
}

PropertyInfo qdev_prop_pci_devfn = {
671 672
    .name  = "int32",
    .legacy_name  = "pci-devfn",
673
    .print = print_pci_devfn,
674
    .get   = get_int32,
675
    .set   = set_pci_devfn,
676 677
};

678 679 680 681 682 683 684
/* --- blocksize --- */

static void set_blocksize(Object *obj, Visitor *v, void *opaque,
                          const char *name, Error **errp)
{
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
685
    uint16_t value, *ptr = qdev_get_prop_ptr(dev, prop);
686
    Error *local_err = NULL;
687 688
    const int64_t min = 512;
    const int64_t max = 32768;
689

690
    if (dev->realized) {
691
        qdev_prop_set_after_realize(dev, name, errp);
692 693 694
        return;
    }

695
    visit_type_uint16(v, &value, name, &local_err);
696 697 698 699
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }
700
    if (value < min || value > max) {
701
        error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
702
                  dev->id?:"", name, (int64_t)value, min, max);
703 704 705 706 707 708
        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,
709
                  dev->id?:"", name, (int64_t)value);
710 711 712 713 714 715 716 717
        return;
    }

    *ptr = value;
}

PropertyInfo qdev_prop_blocksize = {
    .name  = "blocksize",
718
    .get   = get_uint16,
719 720 721
    .set   = set_blocksize,
};

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

758
    if (dev->realized) {
759
        qdev_prop_set_after_realize(dev, name, errp);
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 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828
        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,
};

829 830 831 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 868 869 870 871 872 873
/* --- 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) {
874
        qdev_prop_set_after_realize(dev, name, errp);
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 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932
        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 已提交
933 934 935 936
/* --- public helpers --- */

static Property *qdev_prop_walk(Property *props, const char *name)
{
E
Eduardo Habkost 已提交
937
    if (!props) {
G
Gerd Hoffmann 已提交
938
        return NULL;
E
Eduardo Habkost 已提交
939
    }
G
Gerd Hoffmann 已提交
940
    while (props->name) {
E
Eduardo Habkost 已提交
941
        if (strcmp(props->name, name) == 0) {
G
Gerd Hoffmann 已提交
942
            return props;
E
Eduardo Habkost 已提交
943
        }
G
Gerd Hoffmann 已提交
944 945 946 947 948 949 950
        props++;
    }
    return NULL;
}

static Property *qdev_prop_find(DeviceState *dev, const char *name)
{
951
    ObjectClass *class;
G
Gerd Hoffmann 已提交
952 953 954
    Property *prop;

    /* device properties */
955 956 957 958 959 960 961 962
    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 已提交
963 964 965 966

    return NULL;
}

967 968 969 970 971 972
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,
973
                  object_get_typename(OBJECT(dev)), prop->name, value);
974 975 976 977
        break;
    default:
    case -EINVAL:
        error_set(errp, QERR_PROPERTY_VALUE_BAD,
978
                  object_get_typename(OBJECT(dev)), prop->name, value);
979 980 981
        break;
    case -ENOENT:
        error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND,
982
                  object_get_typename(OBJECT(dev)), prop->name, value);
983 984 985 986 987 988
        break;
    case 0:
        break;
    }
}

989 990
void qdev_prop_parse(DeviceState *dev, const char *name, const char *value,
                     Error **errp)
G
Gerd Hoffmann 已提交
991
{
992
    char *legacy_name;
G
Gerd Hoffmann 已提交
993

994 995
    legacy_name = g_strdup_printf("legacy-%s", name);
    if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) {
996
        object_property_parse(OBJECT(dev), value, legacy_name, errp);
997
    } else {
998
        object_property_parse(OBJECT(dev), value, name, errp);
G
Gerd Hoffmann 已提交
999
    }
1000
    g_free(legacy_name);
G
Gerd Hoffmann 已提交
1001 1002
}

1003 1004
void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value)
{
P
Paolo Bonzini 已提交
1005 1006
    Error *errp = NULL;
    object_property_set_bool(OBJECT(dev), value, name, &errp);
1007
    assert_no_error(errp);
1008 1009
}

J
Juan Quintela 已提交
1010 1011
void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value)
{
P
Paolo Bonzini 已提交
1012 1013
    Error *errp = NULL;
    object_property_set_int(OBJECT(dev), value, name, &errp);
1014
    assert_no_error(errp);
J
Juan Quintela 已提交
1015 1016
}

G
Gerd Hoffmann 已提交
1017 1018
void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value)
{
P
Paolo Bonzini 已提交
1019 1020
    Error *errp = NULL;
    object_property_set_int(OBJECT(dev), value, name, &errp);
1021
    assert_no_error(errp);
G
Gerd Hoffmann 已提交
1022 1023 1024 1025
}

void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value)
{
P
Paolo Bonzini 已提交
1026 1027
    Error *errp = NULL;
    object_property_set_int(OBJECT(dev), value, name, &errp);
1028
    assert_no_error(errp);
G
Gerd Hoffmann 已提交
1029 1030
}

1031 1032
void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value)
{
P
Paolo Bonzini 已提交
1033 1034
    Error *errp = NULL;
    object_property_set_int(OBJECT(dev), value, name, &errp);
1035
    assert_no_error(errp);
1036 1037
}

B
Blue Swirl 已提交
1038 1039
void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value)
{
P
Paolo Bonzini 已提交
1040 1041
    Error *errp = NULL;
    object_property_set_int(OBJECT(dev), value, name, &errp);
1042
    assert_no_error(errp);
B
Blue Swirl 已提交
1043 1044
}

1045
void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value)
1046
{
P
Paolo Bonzini 已提交
1047 1048
    Error *errp = NULL;
    object_property_set_str(OBJECT(dev), value, name, &errp);
1049
    assert_no_error(errp);
1050 1051
}

G
Gerd Hoffmann 已提交
1052 1053
void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value)
{
P
Paolo Bonzini 已提交
1054 1055 1056 1057 1058 1059
    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);
1060
    assert_no_error(errp);
G
Gerd Hoffmann 已提交
1061 1062
}

P
Paolo Bonzini 已提交
1063
void qdev_prop_set_enum(DeviceState *dev, const char *name, int value)
1064
{
P
Paolo Bonzini 已提交
1065 1066 1067 1068 1069 1070
    Property *prop;
    Error *errp = NULL;

    prop = qdev_prop_find(dev, name);
    object_property_set_str(OBJECT(dev), prop->info->enum_table[value],
                            name, &errp);
1071
    assert_no_error(errp);
1072 1073
}

G
Gerd Hoffmann 已提交
1074 1075
void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
{
1076 1077 1078 1079 1080 1081 1082
    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 已提交
1083 1084
}

E
Eduardo Habkost 已提交
1085 1086
static QTAILQ_HEAD(, GlobalProperty) global_props =
        QTAILQ_HEAD_INITIALIZER(global_props);
1087

1088
void qdev_prop_register_global(GlobalProperty *prop)
1089
{
1090
    QTAILQ_INSERT_TAIL(&global_props, prop, next);
1091 1092
}

1093
void qdev_prop_register_global_list(GlobalProperty *props)
1094
{
1095
    int i;
1096

1097 1098
    for (i = 0; props[i].driver != NULL; i++) {
        qdev_prop_register_global(props+i);
1099
    }
1100 1101
}

1102
void qdev_prop_set_globals(DeviceState *dev, Error **errp)
1103
{
1104 1105 1106 1107 1108
    ObjectClass *class = object_get_class(OBJECT(dev));

    do {
        GlobalProperty *prop;
        QTAILQ_FOREACH(prop, &global_props, next) {
1109 1110
            Error *err = NULL;

1111 1112 1113
            if (strcmp(object_class_get_name(class), prop->driver) != 0) {
                continue;
            }
1114 1115 1116 1117
            qdev_prop_parse(dev, prop->property, prop->value, &err);
            if (err != NULL) {
                error_propagate(errp, err);
                return;
1118
            }
1119
        }
1120 1121
        class = object_class_get_parent(class);
    } while (class);
1122
}