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

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

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

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

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

45 46 47 48 49 50 51
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);

52 53
    visit_type_enum(v, prop->name, ptr, prop->info->enum_table,
                    prop->info->name, errp);
54 55 56 57 58 59 60 61 62
}

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);

63
    if (dev->realized) {
64
        qdev_prop_set_after_realize(dev, name, errp);
65 66 67
        return;
    }

68 69
    visit_type_enum(v, prop->name, ptr, prop->info->enum_table,
                    prop->info->name, errp);
70 71 72 73
}

/* Bit */

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

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

99
    visit_type_bool(v, name, &value, errp);
100 101
}

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

110
    if (dev->realized) {
111
        qdev_prop_set_after_realize(dev, name, errp);
112 113 114
        return;
    }

115
    visit_type_bool(v, name, &value, &local_err);
116 117 118 119 120 121 122
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }
    bit_prop_set(dev, prop, value);
}

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

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

static uint64_t qdev_get_prop_mask64(Property *prop)
{
C
Cornelia Huck 已提交
134
    assert(prop->info == &qdev_prop_bit64);
G
Gonglei 已提交
135
    return 0x1ull << prop->bitnr;
G
Gerd Hoffmann 已提交
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
}

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

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

157
    visit_type_bool(v, name, &value, errp);
G
Gerd Hoffmann 已提交
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
}

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

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

173
    visit_type_bool(v, name, &value, &local_err);
G
Gerd Hoffmann 已提交
174 175 176 177 178 179 180 181 182 183 184 185 186 187
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }
    bit64_prop_set(dev, prop, value);
}

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

188 189 190 191 192 193 194 195 196
/* --- 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);

197
    visit_type_bool(v, name, ptr, errp);
198 199 200 201 202 203 204 205 206 207 208 209 210 211
}

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

212
    visit_type_bool(v, name, ptr, errp);
213 214 215
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    if (!*ptr) {
        char *str = (char *)"";
401
        visit_type_str(v, name, &str, errp);
402
    } else {
403
        visit_type_str(v, name, ptr, errp);
404 405 406
    }
}

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

416
    if (dev->realized) {
417
        qdev_prop_set_after_realize(dev, name, errp);
418 419 420
        return;
    }

421
    visit_type_str(v, name, &str, &local_err);
422 423 424 425
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }
426
    g_free(*ptr);
427 428 429
    *ptr = str;
}

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

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

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

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

/*
 * accepted syntax versions:
 *   01:02:03:04:05:06
 *   01-02-03-04-05-06
 */
451 452
static void get_mac(Object *obj, Visitor *v, void *opaque,
                    const char *name, Error **errp)
G
Gerd Hoffmann 已提交
453
{
454 455
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
G
Gerd Hoffmann 已提交
456
    MACAddr *mac = qdev_get_prop_ptr(dev, prop);
457 458 459 460 461 462 463
    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]);

464
    visit_type_str(v, name, &p, errp);
465 466 467 468 469 470 471 472 473
}

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

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

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

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

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

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

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

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

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

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

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

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

J
John Snow 已提交
545 546 547 548 549 550 551 552 553 554 555
/* --- FDC default drive types */

PropertyInfo qdev_prop_fdc_drive_type = {
    .name = "FdcDriveType",
    .description = "FDC drive type, "
                   "144/288/120/none/auto",
    .enum_table = FloppyDriveType_lookup,
    .get = get_enum,
    .set = set_enum
};

556 557 558 559 560
/* --- pci address --- */

/*
 * bus-local address, i.e. "$slot" or "$slot.$fn"
 */
561 562
static void set_pci_devfn(Object *obj, Visitor *v, void *opaque,
                          const char *name, Error **errp)
563
{
564 565
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
566
    int32_t value, *ptr = qdev_get_prop_ptr(dev, prop);
567
    unsigned int slot, fn, n;
568
    Error *local_err = NULL;
D
dunrong huang 已提交
569
    char *str;
570

571
    if (dev->realized) {
572
        qdev_prop_set_after_realize(dev, name, errp);
573 574 575
        return;
    }

576
    visit_type_str(v, name, &str, &local_err);
577
    if (local_err) {
578
        error_free(local_err);
579
        local_err = NULL;
580
        visit_type_int32(v, name, &value, &local_err);
581 582 583
        if (local_err) {
            error_propagate(errp, local_err);
        } else if (value < -1 || value > 255) {
584 585
            error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
                       name ? name : "null", "pci_devfn");
586 587 588 589
        } else {
            *ptr = value;
        }
        return;
590
    }
591 592 593 594

    if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
        fn = 0;
        if (sscanf(str, "%x%n", &slot, &n) != 1) {
595
            goto invalid;
596 597
        }
    }
598 599 600
    if (str[n] != '\0' || fn > 7 || slot > 31) {
        goto invalid;
    }
601
    *ptr = slot << 3 | fn;
D
dunrong huang 已提交
602
    g_free(str);
603 604 605 606
    return;

invalid:
    error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
D
dunrong huang 已提交
607
    g_free(str);
608 609
}

E
Eduardo Habkost 已提交
610 611
static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest,
                           size_t len)
612
{
613
    int32_t *ptr = qdev_get_prop_ptr(dev, prop);
614

B
Blue Swirl 已提交
615
    if (*ptr == -1) {
616 617 618 619 620 621 622
        return snprintf(dest, len, "<unset>");
    } else {
        return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7);
    }
}

PropertyInfo qdev_prop_pci_devfn = {
623
    .name  = "int32",
624
    .description = "Slot and optional function number, example: 06.0 or 06",
625
    .print = print_pci_devfn,
626
    .get   = get_int32,
627
    .set   = set_pci_devfn,
628 629
};

630 631 632 633 634 635 636
/* --- blocksize --- */

static void set_blocksize(Object *obj, Visitor *v, void *opaque,
                          const char *name, Error **errp)
{
    DeviceState *dev = DEVICE(obj);
    Property *prop = opaque;
637
    uint16_t value, *ptr = qdev_get_prop_ptr(dev, prop);
638
    Error *local_err = NULL;
639 640
    const int64_t min = 512;
    const int64_t max = 32768;
641

642
    if (dev->realized) {
643
        qdev_prop_set_after_realize(dev, name, errp);
644 645 646
        return;
    }

647
    visit_type_uint16(v, name, &value, &local_err);
648 649 650 651
    if (local_err) {
        error_propagate(errp, local_err);
        return;
    }
652 653
    /* value of 0 means "unset" */
    if (value && (value < min || value > max)) {
654 655
        error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE,
                   dev->id ? : "", name, (int64_t)value, min, max);
656 657 658 659 660
        return;
    }

    /* We rely on power-of-2 blocksizes for bitmasks */
    if ((value & (value - 1)) != 0) {
661 662 663
        error_setg(errp,
                  "Property %s.%s doesn't take value '%" PRId64 "', it's not a power of 2",
                  dev->id ?: "", name, (int64_t)value);
664 665 666 667 668 669 670
        return;
    }

    *ptr = value;
}

PropertyInfo qdev_prop_blocksize = {
671
    .name  = "uint16",
672
    .description = "A power of two between 512 and 32768",
673
    .get   = get_uint16,
674 675 676
    .set   = set_blocksize,
};

677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692
/* --- 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);

693
    visit_type_str(v, name, &p, errp);
694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
}

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

713
    if (dev->realized) {
714
        qdev_prop_set_after_realize(dev, name, errp);
715 716 717
        return;
    }

718
    visit_type_str(v, name, &str, &local_err);
719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778
    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 = {
779
    .name = "str",
780 781
    .description = "Address (bus/device/function) of "
                   "the host device, example: 04:10.0",
782 783 784 785
    .get = get_pci_host_devaddr,
    .set = set_pci_host_devaddr,
};

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
/* --- 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;
826
    Error *local_err = NULL;
827 828 829 830 831
    void *eltptr;
    const char *arrayname;
    int i;

    if (dev->realized) {
832
        qdev_prop_set_after_realize(dev, name, errp);
833 834 835 836 837 838 839
        return;
    }
    if (*alenptr) {
        error_setg(errp, "array size property %s may not be set more than once",
                   name);
        return;
    }
840
    visit_type_uint32(v, name, alenptr, &local_err);
841 842
    if (local_err) {
        error_propagate(errp, local_err);
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
        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,
879 880 881
                            arrayprop, &local_err);
        if (local_err) {
            error_propagate(errp, local_err);
882 883 884 885 886 887 888 889 890 891 892
            return;
        }
    }
}

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

G
Gerd Hoffmann 已提交
893 894 895 896
/* --- public helpers --- */

static Property *qdev_prop_walk(Property *props, const char *name)
{
E
Eduardo Habkost 已提交
897
    if (!props) {
G
Gerd Hoffmann 已提交
898
        return NULL;
E
Eduardo Habkost 已提交
899
    }
G
Gerd Hoffmann 已提交
900
    while (props->name) {
E
Eduardo Habkost 已提交
901
        if (strcmp(props->name, name) == 0) {
G
Gerd Hoffmann 已提交
902
            return props;
E
Eduardo Habkost 已提交
903
        }
G
Gerd Hoffmann 已提交
904 905 906 907 908 909 910
        props++;
    }
    return NULL;
}

static Property *qdev_prop_find(DeviceState *dev, const char *name)
{
911
    ObjectClass *class;
G
Gerd Hoffmann 已提交
912 913 914
    Property *prop;

    /* device properties */
915 916 917 918 919 920 921 922
    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 已提交
923 924 925 926

    return NULL;
}

927 928 929 930 931
void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev,
                                    Property *prop, const char *value)
{
    switch (ret) {
    case -EEXIST:
932
        error_setg(errp, "Property '%s.%s' can't take value '%s', it's in use",
933
                  object_get_typename(OBJECT(dev)), prop->name, value);
934 935 936
        break;
    default:
    case -EINVAL:
937 938
        error_setg(errp, QERR_PROPERTY_VALUE_BAD,
                   object_get_typename(OBJECT(dev)), prop->name, value);
939 940
        break;
    case -ENOENT:
941
        error_setg(errp, "Property '%s.%s' can't find value '%s'",
942
                  object_get_typename(OBJECT(dev)), prop->name, value);
943 944 945 946 947 948
        break;
    case 0:
        break;
    }
}

949 950
void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value)
{
951
    object_property_set_bool(OBJECT(dev), value, name, &error_abort);
952 953
}

J
Juan Quintela 已提交
954 955
void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value)
{
956
    object_property_set_int(OBJECT(dev), value, name, &error_abort);
J
Juan Quintela 已提交
957 958
}

G
Gerd Hoffmann 已提交
959 960
void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value)
{
961
    object_property_set_int(OBJECT(dev), value, name, &error_abort);
G
Gerd Hoffmann 已提交
962 963 964 965
}

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

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

B
Blue Swirl 已提交
974 975
void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value)
{
976
    object_property_set_int(OBJECT(dev), value, name, &error_abort);
B
Blue Swirl 已提交
977 978
}

979
void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value)
980
{
981
    object_property_set_str(OBJECT(dev), value, name, &error_abort);
982 983
}

G
Gerd Hoffmann 已提交
984 985
void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value)
{
P
Paolo Bonzini 已提交
986 987 988 989
    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]);

990
    object_property_set_str(OBJECT(dev), str, name, &error_abort);
G
Gerd Hoffmann 已提交
991 992
}

P
Paolo Bonzini 已提交
993
void qdev_prop_set_enum(DeviceState *dev, const char *name, int value)
994
{
P
Paolo Bonzini 已提交
995 996 997 998
    Property *prop;

    prop = qdev_prop_find(dev, name);
    object_property_set_str(OBJECT(dev), prop->info->enum_table[value],
999
                            name, &error_abort);
1000 1001
}

G
Gerd Hoffmann 已提交
1002 1003
void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value)
{
1004 1005 1006 1007 1008 1009 1010
    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 已提交
1011 1012
}

E
Eduardo Habkost 已提交
1013 1014
static QTAILQ_HEAD(, GlobalProperty) global_props =
        QTAILQ_HEAD_INITIALIZER(global_props);
1015

1016
void qdev_prop_register_global(GlobalProperty *prop)
1017
{
1018
    QTAILQ_INSERT_TAIL(&global_props, prop, next);
1019 1020
}

1021
void qdev_prop_register_global_list(GlobalProperty *props)
1022
{
1023
    int i;
1024

1025 1026
    for (i = 0; props[i].driver != NULL; i++) {
        qdev_prop_register_global(props+i);
1027
    }
1028 1029
}

1030
int qdev_prop_check_globals(void)
1031 1032 1033 1034 1035
{
    GlobalProperty *prop;
    int ret = 0;

    QTAILQ_FOREACH(prop, &global_props, next) {
1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
        ObjectClass *oc;
        DeviceClass *dc;
        if (prop->used) {
            continue;
        }
        if (!prop->user_provided) {
            continue;
        }
        oc = object_class_by_name(prop->driver);
        oc = object_class_dynamic_cast(oc, TYPE_DEVICE);
        if (!oc) {
            error_report("Warning: global %s.%s has invalid class name",
                       prop->driver, prop->property);
            ret = 1;
            continue;
        }
        dc = DEVICE_CLASS(oc);
        if (!dc->hotpluggable && !prop->used) {
            error_report("Warning: global %s.%s=%s not used",
                       prop->driver, prop->property, prop->value);
            ret = 1;
1057 1058 1059 1060 1061 1062
            continue;
        }
    }
    return ret;
}

1063 1064
static void qdev_prop_set_globals_for_type(DeviceState *dev,
                                const char *typename)
1065 1066 1067 1068 1069 1070 1071 1072 1073
{
    GlobalProperty *prop;

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

        if (strcmp(typename, prop->driver) != 0) {
            continue;
        }
1074
        prop->used = true;
P
Paolo Bonzini 已提交
1075
        object_property_parse(OBJECT(dev), prop->value, prop->property, &err);
1076
        if (err != NULL) {
1077
            assert(prop->user_provided);
1078 1079
            error_reportf_err(err, "Warning: global %s.%s=%s ignored: ",
                              prop->driver, prop->property, prop->value);
1080 1081 1082 1083 1084
            return;
        }
    }
}

1085
void qdev_prop_set_globals(DeviceState *dev)
1086
{
1087 1088 1089
    ObjectClass *class = object_get_class(OBJECT(dev));

    do {
1090
        qdev_prop_set_globals_for_type(dev, object_class_get_name(class));
1091 1092
        class = object_class_get_parent(class);
    } while (class);
1093
}
1094 1095 1096 1097 1098 1099 1100 1101 1102 1103

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

1104
    visit_type_size(v, name, ptr, errp);
1105 1106 1107 1108 1109 1110 1111 1112 1113
}

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);

1114
    visit_type_size(v, name, ptr, errp);
1115 1116 1117 1118 1119 1120 1121
}

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