X-Git-Url: https://repo.jachan.dev/qemu.git/blobdiff_plain/0e9a2ea2e4c27d0a122a74b96f38a5c0c4c3c2a9..2b584959ed300ddff4acba0d7554becad5f274fd:/hw/qdev-properties.c diff --git a/hw/qdev-properties.c b/hw/qdev-properties.c index f0b811c806..01c378f534 100644 --- a/hw/qdev-properties.c +++ b/hw/qdev-properties.c @@ -2,6 +2,7 @@ #include "qdev.h" #include "qerror.h" #include "blockdev.h" +#include "hw/block-common.h" void *qdev_get_prop_ptr(DeviceState *dev, Property *prop) { @@ -10,9 +11,81 @@ void *qdev_get_prop_ptr(DeviceState *dev, Property *prop) return ptr; } +static void get_pointer(Object *obj, Visitor *v, Property *prop, + const char *(*print)(void *ptr), + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + void **ptr = qdev_get_prop_ptr(dev, prop); + char *p; + + p = (char *) (*ptr ? print(*ptr) : ""); + visit_type_str(v, &p, name, errp); +} + +static void set_pointer(Object *obj, Visitor *v, Property *prop, + int (*parse)(DeviceState *dev, const char *str, + void **ptr), + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Error *local_err = NULL; + void **ptr = qdev_get_prop_ptr(dev, prop); + char *str; + int ret; + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_str(v, &str, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + if (!*str) { + g_free(str); + *ptr = NULL; + return; + } + ret = parse(dev, str, ptr); + error_set_from_qdev_prop_error(errp, ret, dev, prop, str); + g_free(str); +} + +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); + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_enum(v, ptr, prop->info->enum_table, + prop->info->name, prop->name, errp); +} + +/* Bit */ + static uint32_t qdev_get_prop_mask(Property *prop) { - assert(prop->info->type == PROP_TYPE_BIT); + assert(prop->info == &qdev_prop_bit); return 0x1 << prop->bitnr; } @@ -26,71 +99,83 @@ static void bit_prop_set(DeviceState *dev, Property *props, bool val) *p &= ~mask; } -static void qdev_prop_cpy(DeviceState *dev, Property *props, void *src) +static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len) { - if (props->info->type == PROP_TYPE_BIT) { - bool *defval = src; - bit_prop_set(dev, props, *defval); - } else { - char *dst = qdev_get_prop_ptr(dev, props); - memcpy(dst, src, props->info->size); - } + uint32_t *p = qdev_get_prop_ptr(dev, prop); + return snprintf(dest, len, (*p & qdev_get_prop_mask(prop)) ? "on" : "off"); } -/* Bit */ -static int parse_bit(DeviceState *dev, Property *prop, const char *str) +static void get_bit(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { - if (!strncasecmp(str, "on", 2)) - bit_prop_set(dev, prop, true); - else if (!strncasecmp(str, "off", 3)) - bit_prop_set(dev, prop, false); - else - return -EINVAL; - return 0; + DeviceState *dev = DEVICE(obj); + 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); } -static int print_bit(DeviceState *dev, Property *prop, char *dest, size_t len) +static void set_bit(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { - uint32_t *p = qdev_get_prop_ptr(dev, prop); - return snprintf(dest, len, (*p & qdev_get_prop_mask(prop)) ? "on" : "off"); + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + Error *local_err = NULL; + bool value; + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_bool(v, &value, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + bit_prop_set(dev, prop, value); } PropertyInfo qdev_prop_bit = { - .name = "on/off", - .type = PROP_TYPE_BIT, - .size = sizeof(uint32_t), - .parse = parse_bit, + .name = "boolean", + .legacy_name = "on/off", .print = print_bit, + .get = get_bit, + .set = set_bit, }; /* --- 8bit integer --- */ -static int parse_uint8(DeviceState *dev, Property *prop, const char *str) +static void get_uint8(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; uint8_t *ptr = qdev_get_prop_ptr(dev, prop); - char *end; - - /* accept both hex and decimal */ - *ptr = strtoul(str, &end, 0); - if ((*end != '\0') || (end == str)) { - return -EINVAL; - } - return 0; + visit_type_uint8(v, ptr, name, errp); } -static int print_uint8(DeviceState *dev, Property *prop, char *dest, size_t len) +static void set_uint8(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; uint8_t *ptr = qdev_get_prop_ptr(dev, prop); - return snprintf(dest, len, "%" PRIu8, *ptr); + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_uint8(v, ptr, name, errp); } PropertyInfo qdev_prop_uint8 = { .name = "uint8", - .type = PROP_TYPE_UINT8, - .size = sizeof(uint8_t), - .parse = parse_uint8, - .print = print_uint8, + .get = get_uint8, + .set = set_uint8, }; /* --- 8bit hex value --- */ @@ -100,6 +185,10 @@ static int parse_hex8(DeviceState *dev, Property *prop, const char *str) uint8_t *ptr = qdev_get_prop_ptr(dev, prop); char *end; + if (str[0] != '0' || str[1] != 'x') { + return -EINVAL; + } + *ptr = strtoul(str, &end, 16); if ((*end != '\0') || (end == str)) { return -EINVAL; @@ -115,98 +204,109 @@ static int print_hex8(DeviceState *dev, Property *prop, char *dest, size_t len) } PropertyInfo qdev_prop_hex8 = { - .name = "hex8", - .type = PROP_TYPE_UINT8, - .size = sizeof(uint8_t), + .name = "uint8", + .legacy_name = "hex8", .parse = parse_hex8, .print = print_hex8, + .get = get_uint8, + .set = set_uint8, }; /* --- 16bit integer --- */ -static int parse_uint16(DeviceState *dev, Property *prop, const char *str) +static void get_uint16(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; uint16_t *ptr = qdev_get_prop_ptr(dev, prop); - char *end; - /* accept both hex and decimal */ - *ptr = strtoul(str, &end, 0); - if ((*end != '\0') || (end == str)) { - return -EINVAL; - } - - return 0; + visit_type_uint16(v, ptr, name, errp); } -static int print_uint16(DeviceState *dev, Property *prop, char *dest, size_t len) +static void set_uint16(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; uint16_t *ptr = qdev_get_prop_ptr(dev, prop); - return snprintf(dest, len, "%" PRIu16, *ptr); + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_uint16(v, ptr, name, errp); } PropertyInfo qdev_prop_uint16 = { .name = "uint16", - .type = PROP_TYPE_UINT16, - .size = sizeof(uint16_t), - .parse = parse_uint16, - .print = print_uint16, + .get = get_uint16, + .set = set_uint16, }; /* --- 32bit integer --- */ -static int parse_uint32(DeviceState *dev, Property *prop, const char *str) +static void get_uint32(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; uint32_t *ptr = qdev_get_prop_ptr(dev, prop); - char *end; - /* accept both hex and decimal */ - *ptr = strtoul(str, &end, 0); - if ((*end != '\0') || (end == str)) { - return -EINVAL; - } - - return 0; + visit_type_uint32(v, ptr, name, errp); } -static int print_uint32(DeviceState *dev, Property *prop, char *dest, size_t len) +static void set_uint32(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; uint32_t *ptr = qdev_get_prop_ptr(dev, prop); - return snprintf(dest, len, "%" PRIu32, *ptr); -} -PropertyInfo qdev_prop_uint32 = { - .name = "uint32", - .type = PROP_TYPE_UINT32, - .size = sizeof(uint32_t), - .parse = parse_uint32, - .print = print_uint32, -}; + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } -static int parse_int32(DeviceState *dev, Property *prop, const char *str) + visit_type_uint32(v, ptr, name, errp); +} + +static void get_int32(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; int32_t *ptr = qdev_get_prop_ptr(dev, prop); - char *end; - *ptr = strtol(str, &end, 10); - if ((*end != '\0') || (end == str)) { - return -EINVAL; - } - - return 0; + visit_type_int32(v, ptr, name, errp); } -static int print_int32(DeviceState *dev, Property *prop, char *dest, size_t len) +static void set_int32(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; int32_t *ptr = qdev_get_prop_ptr(dev, prop); - return snprintf(dest, len, "%" PRId32, *ptr); + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_int32(v, ptr, name, errp); } +PropertyInfo qdev_prop_uint32 = { + .name = "uint32", + .get = get_uint32, + .set = set_uint32, +}; + PropertyInfo qdev_prop_int32 = { .name = "int32", - .type = PROP_TYPE_INT32, - .size = sizeof(int32_t), - .parse = parse_int32, - .print = print_int32, + .get = get_int32, + .set = set_int32, }; /* --- 32bit hex value --- */ @@ -216,6 +316,10 @@ static int parse_hex32(DeviceState *dev, Property *prop, const char *str) uint32_t *ptr = qdev_get_prop_ptr(dev, prop); char *end; + if (str[0] != '0' || str[1] != 'x') { + return -EINVAL; + } + *ptr = strtoul(str, &end, 16); if ((*end != '\0') || (end == str)) { return -EINVAL; @@ -231,41 +335,45 @@ static int print_hex32(DeviceState *dev, Property *prop, char *dest, size_t len) } PropertyInfo qdev_prop_hex32 = { - .name = "hex32", - .type = PROP_TYPE_UINT32, - .size = sizeof(uint32_t), + .name = "uint32", + .legacy_name = "hex32", .parse = parse_hex32, .print = print_hex32, + .get = get_uint32, + .set = set_uint32, }; /* --- 64bit integer --- */ -static int parse_uint64(DeviceState *dev, Property *prop, const char *str) +static void get_uint64(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); - char *end; - /* accept both hex and decimal */ - *ptr = strtoull(str, &end, 0); - if ((*end != '\0') || (end == str)) { - return -EINVAL; - } - - return 0; + visit_type_uint64(v, ptr, name, errp); } -static int print_uint64(DeviceState *dev, Property *prop, char *dest, size_t len) +static void set_uint64(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); - return snprintf(dest, len, "%" PRIu64, *ptr); + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_uint64(v, ptr, name, errp); } PropertyInfo qdev_prop_uint64 = { .name = "uint64", - .type = PROP_TYPE_UINT64, - .size = sizeof(uint64_t), - .parse = parse_uint64, - .print = print_uint64, + .get = get_uint64, + .set = set_uint64, }; /* --- 64bit hex value --- */ @@ -275,6 +383,10 @@ static int parse_hex64(DeviceState *dev, Property *prop, const char *str) uint64_t *ptr = qdev_get_prop_ptr(dev, prop); char *end; + if (str[0] != '0' || str[1] != 'x') { + return -EINVAL; + } + *ptr = strtoull(str, &end, 16); if ((*end != '\0') || (end == str)) { return -EINVAL; @@ -290,28 +402,20 @@ static int print_hex64(DeviceState *dev, Property *prop, char *dest, size_t len) } PropertyInfo qdev_prop_hex64 = { - .name = "hex64", - .type = PROP_TYPE_UINT64, - .size = sizeof(uint64_t), + .name = "uint64", + .legacy_name = "hex64", .parse = parse_hex64, .print = print_hex64, + .get = get_uint64, + .set = set_uint64, }; /* --- string --- */ -static int parse_string(DeviceState *dev, Property *prop, const char *str) -{ - char **ptr = qdev_get_prop_ptr(dev, prop); - - if (*ptr) - g_free(*ptr); - *ptr = g_strdup(str); - return 0; -} - -static void free_string(DeviceState *dev, Property *prop) +static void release_string(Object *obj, const char *name, void *opaque) { - g_free(*(char **)qdev_get_prop_ptr(dev, prop)); + Property *prop = opaque; + g_free(*(char **)qdev_get_prop_ptr(DEVICE(obj), prop)); } static int print_string(DeviceState *dev, Property *prop, char *dest, size_t len) @@ -322,20 +426,58 @@ static int print_string(DeviceState *dev, Property *prop, char *dest, size_t len return snprintf(dest, len, "\"%s\"", *ptr); } +static void get_string(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + 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); + } +} + +static void set_string(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + char **ptr = qdev_get_prop_ptr(dev, prop); + Error *local_err = NULL; + char *str; + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + 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; +} + PropertyInfo qdev_prop_string = { .name = "string", - .type = PROP_TYPE_STRING, - .size = sizeof(char*), - .parse = parse_string, .print = print_string, - .free = free_string, + .release = release_string, + .get = get_string, + .set = set_string, }; /* --- drive --- */ -static int parse_drive(DeviceState *dev, Property *prop, const char *str) +static int parse_drive(DeviceState *dev, const char *str, void **ptr) { - BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop); BlockDriverState *bs; bs = bdrv_find(str); @@ -347,8 +489,10 @@ static int parse_drive(DeviceState *dev, Property *prop, const char *str) return 0; } -static void free_drive(DeviceState *dev, Property *prop) +static void release_drive(Object *obj, const char *name, void *opaque) { + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop); if (*ptr) { @@ -357,107 +501,127 @@ static void free_drive(DeviceState *dev, Property *prop) } } -static int print_drive(DeviceState *dev, Property *prop, char *dest, size_t len) +static const char *print_drive(void *ptr) { - BlockDriverState **ptr = qdev_get_prop_ptr(dev, prop); - return snprintf(dest, len, "%s", - *ptr ? bdrv_get_device_name(*ptr) : ""); + return bdrv_get_device_name(ptr); +} + +static void get_drive(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + get_pointer(obj, v, opaque, print_drive, name, errp); +} + +static void set_drive(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + set_pointer(obj, v, opaque, parse_drive, name, errp); } PropertyInfo qdev_prop_drive = { .name = "drive", - .type = PROP_TYPE_DRIVE, - .size = sizeof(BlockDriverState *), - .parse = parse_drive, - .print = print_drive, - .free = free_drive, + .get = get_drive, + .set = set_drive, + .release = release_drive, }; /* --- character device --- */ -static int parse_chr(DeviceState *dev, Property *prop, const char *str) +static int parse_chr(DeviceState *dev, const char *str, void **ptr) { - CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); - - *ptr = qemu_chr_find(str); - if (*ptr == NULL) { + CharDriverState *chr = qemu_chr_find(str); + if (chr == NULL) { return -ENOENT; } - if ((*ptr)->avail_connections < 1) { + if (chr->avail_connections < 1) { return -EEXIST; } - --(*ptr)->avail_connections; + *ptr = chr; + --chr->avail_connections; return 0; } -static int print_chr(DeviceState *dev, Property *prop, char *dest, size_t len) +static void release_chr(Object *obj, const char *name, void *opaque) { + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; CharDriverState **ptr = qdev_get_prop_ptr(dev, prop); - if (*ptr && (*ptr)->label) { - return snprintf(dest, len, "%s", (*ptr)->label); - } else { - return snprintf(dest, len, ""); + if (*ptr) { + qemu_chr_add_handlers(*ptr, NULL, NULL, NULL, NULL); } } + +static const char *print_chr(void *ptr) +{ + CharDriverState *chr = ptr; + + return chr->label ? chr->label : ""; +} + +static void get_chr(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + get_pointer(obj, v, opaque, print_chr, name, errp); +} + +static void set_chr(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + set_pointer(obj, v, opaque, parse_chr, name, errp); +} + PropertyInfo qdev_prop_chr = { .name = "chr", - .type = PROP_TYPE_CHR, - .size = sizeof(CharDriverState*), - .parse = parse_chr, - .print = print_chr, + .get = get_chr, + .set = set_chr, + .release = release_chr, }; /* --- netdev device --- */ -static int parse_netdev(DeviceState *dev, Property *prop, const char *str) +static int parse_netdev(DeviceState *dev, const char *str, void **ptr) { - VLANClientState **ptr = qdev_get_prop_ptr(dev, prop); + VLANClientState *netdev = qemu_find_netdev(str); - *ptr = qemu_find_netdev(str); - if (*ptr == NULL) + if (netdev == NULL) { return -ENOENT; - if ((*ptr)->peer) { + } + if (netdev->peer) { return -EEXIST; } + *ptr = netdev; return 0; } -static int print_netdev(DeviceState *dev, Property *prop, char *dest, size_t len) +static const char *print_netdev(void *ptr) { - VLANClientState **ptr = qdev_get_prop_ptr(dev, prop); + VLANClientState *netdev = ptr; - if (*ptr && (*ptr)->name) { - return snprintf(dest, len, "%s", (*ptr)->name); - } else { - return snprintf(dest, len, ""); - } + return netdev->name ? netdev->name : ""; +} + +static void get_netdev(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + get_pointer(obj, v, opaque, print_netdev, name, errp); +} + +static void set_netdev(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + set_pointer(obj, v, opaque, parse_netdev, name, errp); } PropertyInfo qdev_prop_netdev = { .name = "netdev", - .type = PROP_TYPE_NETDEV, - .size = sizeof(VLANClientState*), - .parse = parse_netdev, - .print = print_netdev, + .get = get_netdev, + .set = set_netdev, }; /* --- vlan --- */ -static int parse_vlan(DeviceState *dev, Property *prop, const char *str) -{ - VLANState **ptr = qdev_get_prop_ptr(dev, prop); - int id; - - if (sscanf(str, "%d", &id) != 1) - return -EINVAL; - *ptr = qemu_find_vlan(id, 1); - if (*ptr == NULL) - return -ENOENT; - return 0; -} - static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len) { VLANState **ptr = qdev_get_prop_ptr(dev, prop); @@ -469,12 +633,56 @@ static int print_vlan(DeviceState *dev, Property *prop, char *dest, size_t len) } } +static void get_vlan(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + VLANState **ptr = qdev_get_prop_ptr(dev, prop); + int64_t id; + + id = *ptr ? (*ptr)->id : -1; + visit_type_int64(v, &id, name, errp); +} + +static void set_vlan(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + VLANState **ptr = qdev_get_prop_ptr(dev, prop); + Error *local_err = NULL; + int64_t id; + VLANState *vlan; + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_int64(v, &id, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + if (id == -1) { + *ptr = NULL; + return; + } + vlan = qemu_find_vlan(id, 1); + if (!vlan) { + error_set(errp, QERR_INVALID_PARAMETER_VALUE, + name, prop->info->name); + return; + } + *ptr = vlan; +} + PropertyInfo qdev_prop_vlan = { .name = "vlan", - .type = PROP_TYPE_VLAN, - .size = sizeof(VLANClientState*), - .parse = parse_vlan, .print = print_vlan, + .get = get_vlan, + .set = set_vlan, }; /* --- pointer --- */ @@ -482,8 +690,6 @@ PropertyInfo qdev_prop_vlan = { /* Not a proper property, just for dirty hacks. TODO Remove it! */ PropertyInfo qdev_prop_ptr = { .name = "ptr", - .type = PROP_TYPE_PTR, - .size = sizeof(void*), }; /* --- mac address --- */ @@ -493,44 +699,103 @@ PropertyInfo qdev_prop_ptr = { * 01:02:03:04:05:06 * 01-02-03-04-05-06 */ -static int parse_mac(DeviceState *dev, Property *prop, const char *str) +static void get_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); + 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; int i, pos; - char *p; + char *str, *p; + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_str(v, &str, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } for (i = 0, pos = 0; i < 6; i++, pos += 3) { if (!qemu_isxdigit(str[pos])) - return -EINVAL; + goto inval; if (!qemu_isxdigit(str[pos+1])) - return -EINVAL; + goto inval; if (i == 5) { if (str[pos+2] != '\0') - return -EINVAL; + goto inval; } else { if (str[pos+2] != ':' && str[pos+2] != '-') - return -EINVAL; + goto inval; } mac->a[i] = strtol(str+pos, &p, 16); } - return 0; -} + g_free(str); + return; -static int print_mac(DeviceState *dev, Property *prop, char *dest, size_t len) -{ - MACAddr *mac = qdev_get_prop_ptr(dev, prop); - - return snprintf(dest, len, "%02x:%02x:%02x:%02x:%02x:%02x", - mac->a[0], mac->a[1], mac->a[2], - mac->a[3], mac->a[4], mac->a[5]); +inval: + error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); + g_free(str); } PropertyInfo qdev_prop_macaddr = { .name = "macaddr", - .type = PROP_TYPE_MACADDR, - .size = sizeof(MACAddr), - .parse = parse_mac, - .print = print_mac, + .get = get_mac, + .set = set_mac, +}; + +/* --- lost tick policy --- */ + +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, +}; + +QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int)); + +PropertyInfo qdev_prop_losttickpolicy = { + .name = "LostTickPolicy", + .enum_table = lost_tick_policy_table, + .get = get_enum, + .set = set_enum, +}; + +/* --- 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, }; /* --- pci address --- */ @@ -538,30 +803,58 @@ PropertyInfo qdev_prop_macaddr = { /* * bus-local address, i.e. "$slot" or "$slot.$fn" */ -static int parse_pci_devfn(DeviceState *dev, Property *prop, const char *str) +static void set_pci_devfn(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) { - uint32_t *ptr = qdev_get_prop_ptr(dev, prop); + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + int32_t value, *ptr = qdev_get_prop_ptr(dev, prop); unsigned int slot, fn, n; + Error *local_err = NULL; + char *str; + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_str(v, &str, name, &local_err); + if (local_err) { + error_free(local_err); + 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; + } if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) { fn = 0; if (sscanf(str, "%x%n", &slot, &n) != 1) { - return -EINVAL; + goto invalid; } } - if (str[n] != '\0') - return -EINVAL; - if (fn > 7) - return -EINVAL; - if (slot > 31) - return -EINVAL; + if (str[n] != '\0' || fn > 7 || slot > 31) { + goto invalid; + } *ptr = slot << 3 | fn; - return 0; + g_free(str); + return; + +invalid: + error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str); + g_free(str); } static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t len) { - uint32_t *ptr = qdev_get_prop_ptr(dev, prop); + int32_t *ptr = qdev_get_prop_ptr(dev, prop); if (*ptr == -1) { return snprintf(dest, len, ""); @@ -571,11 +864,162 @@ static int print_pci_devfn(DeviceState *dev, Property *prop, char *dest, size_t } PropertyInfo qdev_prop_pci_devfn = { - .name = "pci-devfn", - .type = PROP_TYPE_UINT32, - .size = sizeof(uint32_t), - .parse = parse_pci_devfn, + .name = "int32", + .legacy_name = "pci-devfn", .print = print_pci_devfn, + .get = get_int32, + .set = set_pci_devfn, +}; + +/* --- blocksize --- */ + +static void set_blocksize(Object *obj, Visitor *v, void *opaque, + const char *name, Error **errp) +{ + DeviceState *dev = DEVICE(obj); + Property *prop = opaque; + uint16_t value, *ptr = qdev_get_prop_ptr(dev, prop); + Error *local_err = NULL; + const int64_t min = 512; + const int64_t max = 32768; + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + return; + } + + visit_type_uint16(v, &value, name, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } + if (value < min || value > max) { + error_set(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, + dev->id?:"", name, (int64_t)value, min, max); + 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, + dev->id?:"", name, (int64_t)value); + return; + } + + *ptr = value; +} + +PropertyInfo qdev_prop_blocksize = { + .name = "blocksize", + .get = get_uint16, + .set = set_blocksize, +}; + +/* --- 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 [:]:. + * if 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; + + if (dev->state != DEV_STATE_CREATED) { + error_set(errp, QERR_PERMISSION_DENIED); + 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, }; /* --- public helpers --- */ @@ -594,130 +1038,125 @@ static Property *qdev_prop_walk(Property *props, const char *name) static Property *qdev_prop_find(DeviceState *dev, const char *name) { + ObjectClass *class; Property *prop; /* device properties */ - prop = qdev_prop_walk(dev->info->props, name); - if (prop) - return prop; - - /* bus properties */ - prop = qdev_prop_walk(dev->parent_bus->info->props, name); - if (prop) - return prop; + 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)); return NULL; } -int qdev_prop_exists(DeviceState *dev, const char *name) +void error_set_from_qdev_prop_error(Error **errp, int ret, DeviceState *dev, + Property *prop, const char *value) { - return qdev_prop_find(dev, name) ? true : false; + switch (ret) { + case -EEXIST: + error_set(errp, QERR_PROPERTY_VALUE_IN_USE, + object_get_typename(OBJECT(dev)), prop->name, value); + break; + default: + case -EINVAL: + error_set(errp, QERR_PROPERTY_VALUE_BAD, + object_get_typename(OBJECT(dev)), prop->name, value); + break; + case -ENOENT: + error_set(errp, QERR_PROPERTY_VALUE_NOT_FOUND, + object_get_typename(OBJECT(dev)), prop->name, value); + break; + case 0: + break; + } } int qdev_prop_parse(DeviceState *dev, const char *name, const char *value) { - Property *prop; - int ret; + char *legacy_name; + Error *err = NULL; - prop = qdev_prop_find(dev, name); - /* - * TODO Properties without a parse method are just for dirty - * hacks. qdev_prop_ptr is the only such PropertyInfo. It's - * marked for removal. The test !prop->info->parse should be - * removed along with it. - */ - if (!prop || !prop->info->parse) { - qerror_report(QERR_PROPERTY_NOT_FOUND, dev->info->name, name); - return -1; + legacy_name = g_strdup_printf("legacy-%s", name); + if (object_property_get_type(OBJECT(dev), legacy_name, NULL)) { + object_property_parse(OBJECT(dev), value, legacy_name, &err); + } else { + object_property_parse(OBJECT(dev), value, name, &err); } - ret = prop->info->parse(dev, prop, value); - if (ret < 0) { - switch (ret) { - case -EEXIST: - qerror_report(QERR_PROPERTY_VALUE_IN_USE, - dev->info->name, name, value); - break; - default: - case -EINVAL: - qerror_report(QERR_PROPERTY_VALUE_BAD, - dev->info->name, name, value); - break; - case -ENOENT: - qerror_report(QERR_PROPERTY_VALUE_NOT_FOUND, - dev->info->name, name, value); - break; - } + g_free(legacy_name); + + if (err) { + qerror_report_err(err); + error_free(err); return -1; } return 0; } -void qdev_prop_set(DeviceState *dev, const char *name, void *src, enum PropertyType type) -{ - Property *prop; - - prop = qdev_prop_find(dev, name); - if (!prop) { - fprintf(stderr, "%s: property \"%s.%s\" not found\n", - __FUNCTION__, dev->info->name, name); - abort(); - } - if (prop->info->type != type) { - fprintf(stderr, "%s: property \"%s.%s\" type mismatch\n", - __FUNCTION__, dev->info->name, name); - abort(); - } - qdev_prop_cpy(dev, prop, src); -} - void qdev_prop_set_bit(DeviceState *dev, const char *name, bool value) { - qdev_prop_set(dev, name, &value, PROP_TYPE_BIT); + Error *errp = NULL; + object_property_set_bool(OBJECT(dev), value, name, &errp); + assert_no_error(errp); } void qdev_prop_set_uint8(DeviceState *dev, const char *name, uint8_t value) { - qdev_prop_set(dev, name, &value, PROP_TYPE_UINT8); + Error *errp = NULL; + object_property_set_int(OBJECT(dev), value, name, &errp); + assert_no_error(errp); } void qdev_prop_set_uint16(DeviceState *dev, const char *name, uint16_t value) { - qdev_prop_set(dev, name, &value, PROP_TYPE_UINT16); + Error *errp = NULL; + object_property_set_int(OBJECT(dev), value, name, &errp); + assert_no_error(errp); } void qdev_prop_set_uint32(DeviceState *dev, const char *name, uint32_t value) { - qdev_prop_set(dev, name, &value, PROP_TYPE_UINT32); + Error *errp = NULL; + object_property_set_int(OBJECT(dev), value, name, &errp); + assert_no_error(errp); } void qdev_prop_set_int32(DeviceState *dev, const char *name, int32_t value) { - qdev_prop_set(dev, name, &value, PROP_TYPE_INT32); + Error *errp = NULL; + object_property_set_int(OBJECT(dev), value, name, &errp); + assert_no_error(errp); } void qdev_prop_set_uint64(DeviceState *dev, const char *name, uint64_t value) { - qdev_prop_set(dev, name, &value, PROP_TYPE_UINT64); + Error *errp = NULL; + object_property_set_int(OBJECT(dev), value, name, &errp); + assert_no_error(errp); } void qdev_prop_set_string(DeviceState *dev, const char *name, char *value) { - qdev_prop_set(dev, name, &value, PROP_TYPE_STRING); + Error *errp = NULL; + object_property_set_str(OBJECT(dev), value, name, &errp); + assert_no_error(errp); } int qdev_prop_set_drive(DeviceState *dev, const char *name, BlockDriverState *value) { - int res; - - res = bdrv_attach_dev(value, dev); - if (res < 0) { - error_report("Can't attach drive %s to %s.%s: %s", - bdrv_get_device_name(value), - dev->id ? dev->id : dev->info->name, - name, strerror(-res)); + Error *errp = NULL; + const char *bdrv_name = value ? bdrv_get_device_name(value) : ""; + object_property_set_str(OBJECT(dev), bdrv_name, + name, &errp); + if (errp) { + qerror_report_err(errp); + error_free(errp); return -1; } - qdev_prop_set(dev, name, &value, PROP_TYPE_DRIVE); return 0; } @@ -729,39 +1168,60 @@ void qdev_prop_set_drive_nofail(DeviceState *dev, const char *name, BlockDriverS } void qdev_prop_set_chr(DeviceState *dev, const char *name, CharDriverState *value) { - qdev_prop_set(dev, name, &value, PROP_TYPE_CHR); + Error *errp = NULL; + assert(!value || value->label); + object_property_set_str(OBJECT(dev), + value ? value->label : "", name, &errp); + assert_no_error(errp); } void qdev_prop_set_netdev(DeviceState *dev, const char *name, VLANClientState *value) { - qdev_prop_set(dev, name, &value, PROP_TYPE_NETDEV); + Error *errp = NULL; + assert(!value || value->name); + object_property_set_str(OBJECT(dev), + value ? value->name : "", name, &errp); + assert_no_error(errp); } void qdev_prop_set_vlan(DeviceState *dev, const char *name, VLANState *value) { - qdev_prop_set(dev, name, &value, PROP_TYPE_VLAN); + Error *errp = NULL; + object_property_set_int(OBJECT(dev), value ? value->id : -1, name, &errp); + assert_no_error(errp); } void qdev_prop_set_macaddr(DeviceState *dev, const char *name, uint8_t *value) { - qdev_prop_set(dev, name, value, PROP_TYPE_MACADDR); + 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); + assert_no_error(errp); } -void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value) +void qdev_prop_set_enum(DeviceState *dev, const char *name, int value) { - qdev_prop_set(dev, name, &value, PROP_TYPE_PTR); + Property *prop; + Error *errp = NULL; + + prop = qdev_prop_find(dev, name); + object_property_set_str(OBJECT(dev), prop->info->enum_table[value], + name, &errp); + assert_no_error(errp); } -void qdev_prop_set_defaults(DeviceState *dev, Property *props) +void qdev_prop_set_ptr(DeviceState *dev, const char *name, void *value) { - if (!props) - return; - while (props->name) { - if (props->defval) { - qdev_prop_cpy(dev, props, props->defval); - } - props++; - } + 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; } static QTAILQ_HEAD(, GlobalProperty) global_props = QTAILQ_HEAD_INITIALIZER(global_props); @@ -782,17 +1242,20 @@ void qdev_prop_register_global_list(GlobalProperty *props) void qdev_prop_set_globals(DeviceState *dev) { - GlobalProperty *prop; - - QTAILQ_FOREACH(prop, &global_props, next) { - if (strcmp(dev->info->name, prop->driver) != 0 && - strcmp(dev->info->bus_info->name, prop->driver) != 0) { - continue; + 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); + } } - if (qdev_prop_parse(dev, prop->property, prop->value) != 0) { - exit(1); - } - } + class = object_class_get_parent(class); + } while (class); } static int qdev_add_one_global(QemuOpts *opts, void *opaque)