machine + QOM queue, 2020-10-06

* QOM documentation fixes and cleanups (Eduardo Habkost)
 * user-mode: Prune build dependencies (Philippe Mathieu-Daudé)
 * qom: Improve error message (Philippe Mathieu-Daudé)
 * numa: hmat: require parent cache description before the next
   level one (Igor Mammedov)
 -----BEGIN PGP SIGNATURE-----
 
 iQJIBAABCAAyFiEEWjIv1avE09usz9GqKAeTb5hNxaYFAl986v8UHGVoYWJrb3N0
 QHJlZGhhdC5jb20ACgkQKAeTb5hNxaaiAQ//Q81DvgnT6HkW4VleY6Qx3q8TfKfp
 m1H71YA1SKa1cuTbzDkb/7J5SYwrL/tWaLlcWwVIRs5LYoexAbGo2sOJnt85L/We
 WNUdPHyFUWuX/pXsX8F5du6x4xvXnd3I8HqSrjZf1LCUkdbfvQUK1yDG6gZJAfsC
 BCs4uJG2d3NE44mAqhhy3fl+qFs8p0FwBOFZ7M3UZXU5vgWhgZKpT8svUH4GuuXQ
 +0YHpJjvXHcug4cD2LpUuQ49j40BvXZFdoGDMpY6RJai/50kIw78PBenG6DX/QKR
 I0B03Qz7TMl8d5XAuDU2vfyMLW2Ow5rlxO56/fXkRYDEngb7pWwiH6KXENzY2jkm
 gfif8di8i/Kt9WKNJ8Eba7ulFmhRlybEFLSNCxUPJpq8LS0anRxHsuDS4GwgChWw
 Pe9sw1qSlf5iKqo1Erj9U3kWmFbZ7WvqApE3OCKEGbmxCe6beTcX4+1IaQ+01RYO
 or38ZGznCjiEmHaQBESzjV72TD+2gKDjYbcMMt5AWytBdtV3pY8JYXe/C0YeovT7
 X8KCZpizyyDWSmPq/+3Z2KVCCkX4+TjRaRyxkJ0ECCrCXsrCGt0F5rogV6Y58Rmh
 hBEW0ydpY3TjUIZG1rpaeeJSNMr+9O0Ut76OAowd86SYLsu6+jgG9pyzQ1S0pD24
 gP/2kKSr2xG1T9Q=
 =hTTy
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/ehabkost/tags/machine-next-pull-request' into staging

machine + QOM queue, 2020-10-06

* QOM documentation fixes and cleanups (Eduardo Habkost)
* user-mode: Prune build dependencies (Philippe Mathieu-Daudé)
* qom: Improve error message (Philippe Mathieu-Daudé)
* numa: hmat: require parent cache description before the next
  level one (Igor Mammedov)

# gpg: Signature made Tue 06 Oct 2020 23:09:03 BST
# gpg:                using RSA key 5A322FD5ABC4D3DBACCFD1AA2807936F984DC5A6
# gpg:                issuer "ehabkost@redhat.com"
# gpg: Good signature from "Eduardo Habkost <ehabkost@redhat.com>" [full]
# Primary key fingerprint: 5A32 2FD5 ABC4 D3DB ACCF  D1AA 2807 936F 984D C5A6

* remotes/ehabkost/tags/machine-next-pull-request: (21 commits)
  numa: hmat: require parent cache description before the next level one
  kernel-doc: Remove $decl_type='type name' hack
  memory: Explicitly tag doc comments for structs
  qom: Explicitly tag doc comments for typedefs and structs
  kernel-doc: Handle function typedefs without asterisks
  kernel-doc: Handle function typedefs that return pointers
  docs/devel/qom: Avoid long lines
  docs/devel/qom: Remove usage of <code>
  docs/devel/qom: Use *emphasis* for emphasis
  docs/devel/qom: Fix indentation of code blocks
  docs/devel/qom: Fix indentation of bulleted list
  qom: Fix DECLARE_*CHECKER documentation
  qom: Improve error message displayed with missing object properties
  hw/core/cpu: Add missing 'exec/cpu-common.h' include
  hw/core/qdev-properties: Extract system-mode specific properties
  hw/core/qdev-properties: Export some integer-related functions
  hw/core/qdev-properties: Export qdev_prop_enum
  hw/core/qdev-properties: Export enum-related functions
  hw/core/qdev-properties: Fix code style
  hw/core/qdev-properties: Use qemu_strtoul() in set_pci_host_devaddr()
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2020-10-08 11:32:54 +01:00
commit a1d22c668a
11 changed files with 829 additions and 783 deletions

View File

@ -8,9 +8,9 @@ The QEMU Object Model provides a framework for registering user creatable
types and instantiating objects from those types. QOM provides the following
features:
- System for dynamically registering types
- Support for single-inheritance of types
- Multiple inheritance of stateless interfaces
- System for dynamically registering types
- Support for single-inheritance of types
- Multiple inheritance of stateless interfaces
.. code-block:: c
:caption: Creating a minimal type
@ -174,17 +174,17 @@ dynamically cast it to an object that implements the interface.
Methods
=======
A <emphasis>method</emphasis> is a function within the namespace scope of
A *method* is a function within the namespace scope of
a class. It usually operates on the object instance by passing it as a
strongly-typed first argument.
If it does not operate on an object instance, it is dubbed
<emphasis>class method</emphasis>.
*class method*.
Methods cannot be overloaded. That is, the #ObjectClass and method name
uniquely identity the function to be called; the signature does not vary
except for trailing varargs.
Methods are always <emphasis>virtual</emphasis>. Overriding a method in
Methods are always *virtual*. Overriding a method in
#TypeInfo.class_init of a subclass leads to any user of the class obtained
via OBJECT_GET_CLASS() accessing the overridden function.
The original function is not automatically invoked. It is the responsibility
@ -284,28 +284,29 @@ in the header file:
.. code-block:: c
:caption: Declaring a simple type
OBJECT_DECLARE_SIMPLE_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE)
OBJECT_DECLARE_SIMPLE_TYPE(MyDevice, my_device,
MY_DEVICE, DEVICE)
This is equivalent to the following:
.. code-block:: c
:caption: Expansion from declaring a simple type
typedef struct MyDevice MyDevice;
typedef struct MyDeviceClass MyDeviceClass;
typedef struct MyDevice MyDevice;
typedef struct MyDeviceClass MyDeviceClass;
G_DEFINE_AUTOPTR_CLEANUP_FUNC(MyDeviceClass, object_unref)
G_DEFINE_AUTOPTR_CLEANUP_FUNC(MyDeviceClass, object_unref)
#define MY_DEVICE_GET_CLASS(void *obj) \
OBJECT_GET_CLASS(MyDeviceClass, obj, TYPE_MY_DEVICE)
#define MY_DEVICE_CLASS(void *klass) \
OBJECT_CLASS_CHECK(MyDeviceClass, klass, TYPE_MY_DEVICE)
#define MY_DEVICE(void *obj)
OBJECT_CHECK(MyDevice, obj, TYPE_MY_DEVICE)
#define MY_DEVICE_GET_CLASS(void *obj) \
OBJECT_GET_CLASS(MyDeviceClass, obj, TYPE_MY_DEVICE)
#define MY_DEVICE_CLASS(void *klass) \
OBJECT_CLASS_CHECK(MyDeviceClass, klass, TYPE_MY_DEVICE)
#define MY_DEVICE(void *obj)
OBJECT_CHECK(MyDevice, obj, TYPE_MY_DEVICE)
struct MyDeviceClass {
DeviceClass parent_class;
};
struct MyDeviceClass {
DeviceClass parent_class;
};
The 'struct MyDevice' needs to be declared separately.
If the type requires virtual functions to be declared in the class
@ -319,33 +320,33 @@ In the simple case the OBJECT_DEFINE_TYPE macro is suitable:
.. code-block:: c
:caption: Defining a simple type
OBJECT_DEFINE_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE)
OBJECT_DEFINE_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE)
This is equivalent to the following:
.. code-block:: c
:caption: Expansion from defining a simple type
static void my_device_finalize(Object *obj);
static void my_device_class_init(ObjectClass *oc, void *data);
static void my_device_init(Object *obj);
static void my_device_finalize(Object *obj);
static void my_device_class_init(ObjectClass *oc, void *data);
static void my_device_init(Object *obj);
static const TypeInfo my_device_info = {
.parent = TYPE_DEVICE,
.name = TYPE_MY_DEVICE,
.instance_size = sizeof(MyDevice),
.instance_init = my_device_init,
.instance_finalize = my_device_finalize,
.class_size = sizeof(MyDeviceClass),
.class_init = my_device_class_init,
};
static const TypeInfo my_device_info = {
.parent = TYPE_DEVICE,
.name = TYPE_MY_DEVICE,
.instance_size = sizeof(MyDevice),
.instance_init = my_device_init,
.instance_finalize = my_device_finalize,
.class_size = sizeof(MyDeviceClass),
.class_init = my_device_class_init,
};
static void
my_device_register_types(void)
{
type_register_static(&my_device_info);
}
type_init(my_device_register_types);
static void
my_device_register_types(void)
{
type_register_static(&my_device_info);
}
type_init(my_device_register_types);
This is sufficient to get the type registered with the type
system, and the three standard methods now need to be implemented
@ -358,9 +359,10 @@ This accepts an array of interface type names.
.. code-block:: c
:caption: Defining a simple type implementing interfaces
OBJECT_DEFINE_TYPE_WITH_INTERFACES(MyDevice, my_device,
MY_DEVICE, DEVICE,
{ TYPE_USER_CREATABLE }, { NULL })
OBJECT_DEFINE_TYPE_WITH_INTERFACES(MyDevice, my_device,
MY_DEVICE, DEVICE,
{ TYPE_USER_CREATABLE },
{ NULL })
If the type is not intended to be instantiated, then then
the OBJECT_DEFINE_ABSTRACT_TYPE() macro can be used instead:
@ -368,7 +370,8 @@ the OBJECT_DEFINE_ABSTRACT_TYPE() macro can be used instead:
.. code-block:: c
:caption: Defining a simple abstract type
OBJECT_DEFINE_ABSTRACT_TYPE(MyDevice, my_device, MY_DEVICE, DEVICE)
OBJECT_DEFINE_ABSTRACT_TYPE(MyDevice, my_device,
MY_DEVICE, DEVICE)

View File

@ -26,6 +26,7 @@
#include "qemu/log.h"
#include "qemu/main-loop.h"
#include "exec/log.h"
#include "exec/cpu-common.h"
#include "qemu/error-report.h"
#include "qemu/qemu-print.h"
#include "sysemu/tcg.h"

View File

@ -424,7 +424,13 @@ void parse_numa_hmat_cache(MachineState *ms, NumaHmatCacheOptions *node,
}
if ((node->level > 1) &&
ms->numa_state->hmat_cache[node->node_id][node->level - 1] &&
ms->numa_state->hmat_cache[node->node_id][node->level - 1] == NULL) {
error_setg(errp, "Cache level=%u shall be defined first",
node->level - 1);
return;
}
if ((node->level > 1) &&
(node->size <=
ms->numa_state->hmat_cache[node->node_id][node->level - 1]->size)) {
error_setg(errp, "Invalid size=%" PRIu64 ", the size of level=%" PRIu8

View File

@ -0,0 +1,30 @@
/*
* qdev property parsing
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef HW_CORE_QDEV_PROP_INTERNAL_H
#define HW_CORE_QDEV_PROP_INTERNAL_H
void qdev_propinfo_get_enum(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp);
void qdev_propinfo_set_enum(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp);
void qdev_propinfo_set_default_value_enum(ObjectProperty *op,
const Property *prop);
void qdev_propinfo_set_default_value_int(ObjectProperty *op,
const Property *prop);
void qdev_propinfo_set_default_value_uint(ObjectProperty *op,
const Property *prop);
void qdev_propinfo_get_uint16(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp);
void qdev_propinfo_get_int32(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp);
void qdev_propinfo_get_size32(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp);
#endif

View File

@ -11,19 +11,25 @@
*/
#include "qemu/osdep.h"
#include "audio/audio.h"
#include "net/net.h"
#include "hw/qdev-properties.h"
#include "qapi/error.h"
#include "qapi/visitor.h"
#include "qapi/qapi-types-block.h"
#include "qapi/qapi-types-machine.h"
#include "qapi/qapi-types-migration.h"
#include "qapi/qmp/qerror.h"
#include "qemu/ctype.h"
#include "qemu/cutils.h"
#include "qemu/units.h"
#include "qemu/error-report.h"
#include "qdev-prop-internal.h"
#include "audio/audio.h"
#include "chardev/char-fe.h"
#include "sysemu/block-backend.h"
#include "sysemu/blockdev.h"
#include "hw/block/block.h"
#include "net/hub.h"
#include "qapi/visitor.h"
#include "chardev/char-fe.h"
#include "sysemu/iothread.h"
#include "sysemu/tpm_backend.h"
#include "net/net.h"
#include "hw/pci/pci.h"
static bool check_prop_still_unset(DeviceState *dev, const char *name,
const void *old_val, const char *new_val,
@ -280,6 +286,96 @@ const PropertyInfo qdev_prop_chr = {
.release = release_chr,
};
/* --- mac address --- */
/*
* accepted syntax versions:
* 01:02:03:04:05:06
* 01-02-03-04-05-06
*/
static void get_mac(Object *obj, Visitor *v, const char *name, void *opaque,
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, name, &p, errp);
}
static void set_mac(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
MACAddr *mac = qdev_get_prop_ptr(dev, prop);
int i, pos;
char *str;
const char *p;
if (dev->realized) {
qdev_prop_set_after_realize(dev, name, errp);
return;
}
if (!visit_type_str(v, name, &str, errp)) {
return;
}
for (i = 0, pos = 0; i < 6; i++, pos += 3) {
long val;
if (!qemu_isxdigit(str[pos])) {
goto inval;
}
if (!qemu_isxdigit(str[pos + 1])) {
goto inval;
}
if (i == 5) {
if (str[pos + 2] != '\0') {
goto inval;
}
} else {
if (str[pos + 2] != ':' && str[pos + 2] != '-') {
goto inval;
}
}
if (qemu_strtol(str + pos, &p, 16, &val) < 0 || val > 0xff) {
goto inval;
}
mac->a[i] = val;
}
g_free(str);
return;
inval:
error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
g_free(str);
}
const PropertyInfo qdev_prop_macaddr = {
.name = "str",
.description = "Ethernet 6-byte MAC Address, example: 52:54:00:12:34:56",
.get = get_mac,
.set = set_mac,
};
void qdev_prop_set_macaddr(DeviceState *dev, const char *name,
const uint8_t *value)
{
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), name, str, &error_abort);
}
/* --- netdev device --- */
static void get_netdev(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
@ -465,3 +561,578 @@ void qdev_set_nic_properties(DeviceState *dev, NICInfo *nd)
}
nd->instantiated = 1;
}
/* --- lost tick policy --- */
QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int));
const PropertyInfo qdev_prop_losttickpolicy = {
.name = "LostTickPolicy",
.enum_table = &LostTickPolicy_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
.set_default_value = qdev_propinfo_set_default_value_enum,
};
/* --- blocksize --- */
/* lower limit is sector size */
#define MIN_BLOCK_SIZE 512
#define MIN_BLOCK_SIZE_STR "512 B"
/*
* upper limit is arbitrary, 2 MiB looks sufficient for all sensible uses, and
* matches qcow2 cluster size limit
*/
#define MAX_BLOCK_SIZE (2 * MiB)
#define MAX_BLOCK_SIZE_STR "2 MiB"
static void set_blocksize(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
uint64_t value;
if (dev->realized) {
qdev_prop_set_after_realize(dev, name, errp);
return;
}
if (!visit_type_size(v, name, &value, errp)) {
return;
}
/* value of 0 means "unset" */
if (value && (value < MIN_BLOCK_SIZE || value > MAX_BLOCK_SIZE)) {
error_setg(errp,
"Property %s.%s doesn't take value %" PRIu64
" (minimum: " MIN_BLOCK_SIZE_STR
", maximum: " MAX_BLOCK_SIZE_STR ")",
dev->id ? : "", name, value);
return;
}
/* We rely on power-of-2 blocksizes for bitmasks */
if ((value & (value - 1)) != 0) {
error_setg(errp,
"Property %s.%s doesn't take value '%" PRId64 "', "
"it's not a power of 2", dev->id ?: "", name, (int64_t)value);
return;
}
*ptr = value;
}
const PropertyInfo qdev_prop_blocksize = {
.name = "size",
.description = "A power of two between " MIN_BLOCK_SIZE_STR
" and " MAX_BLOCK_SIZE_STR,
.get = qdev_propinfo_get_size32,
.set = set_blocksize,
.set_default_value = qdev_propinfo_set_default_value_uint,
};
/* --- Block device error handling policy --- */
QEMU_BUILD_BUG_ON(sizeof(BlockdevOnError) != sizeof(int));
const PropertyInfo qdev_prop_blockdev_on_error = {
.name = "BlockdevOnError",
.description = "Error handling policy, "
"report/ignore/enospc/stop/auto",
.enum_table = &BlockdevOnError_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
.set_default_value = qdev_propinfo_set_default_value_enum,
};
/* --- BIOS CHS translation */
QEMU_BUILD_BUG_ON(sizeof(BiosAtaTranslation) != sizeof(int));
const PropertyInfo qdev_prop_bios_chs_trans = {
.name = "BiosAtaTranslation",
.description = "Logical CHS translation algorithm, "
"auto/none/lba/large/rechs",
.enum_table = &BiosAtaTranslation_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
.set_default_value = qdev_propinfo_set_default_value_enum,
};
/* --- FDC default drive types */
const PropertyInfo qdev_prop_fdc_drive_type = {
.name = "FdcDriveType",
.description = "FDC drive type, "
"144/288/120/none/auto",
.enum_table = &FloppyDriveType_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
.set_default_value = qdev_propinfo_set_default_value_enum,
};
/* --- MultiFDCompression --- */
const PropertyInfo qdev_prop_multifd_compression = {
.name = "MultiFDCompression",
.description = "multifd_compression values, "
"none/zlib/zstd",
.enum_table = &MultiFDCompression_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
.set_default_value = qdev_propinfo_set_default_value_enum,
};
/* --- Reserved Region --- */
/*
* Accepted syntax:
* <low address>:<high address>:<type>
* where low/high addresses are uint64_t in hexadecimal
* and type is a non-negative decimal integer
*/
static void get_reserved_region(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
ReservedRegion *rr = qdev_get_prop_ptr(dev, prop);
char buffer[64];
char *p = buffer;
int rc;
rc = snprintf(buffer, sizeof(buffer), "0x%"PRIx64":0x%"PRIx64":%u",
rr->low, rr->high, rr->type);
assert(rc < sizeof(buffer));
visit_type_str(v, name, &p, errp);
}
static void set_reserved_region(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
ReservedRegion *rr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
const char *endptr;
char *str;
int ret;
if (dev->realized) {
qdev_prop_set_after_realize(dev, name, errp);
return;
}
visit_type_str(v, name, &str, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
ret = qemu_strtou64(str, &endptr, 16, &rr->low);
if (ret) {
error_setg(errp, "start address of '%s'"
" must be a hexadecimal integer", name);
goto out;
}
if (*endptr != ':') {
goto separator_error;
}
ret = qemu_strtou64(endptr + 1, &endptr, 16, &rr->high);
if (ret) {
error_setg(errp, "end address of '%s'"
" must be a hexadecimal integer", name);
goto out;
}
if (*endptr != ':') {
goto separator_error;
}
ret = qemu_strtoui(endptr + 1, &endptr, 10, &rr->type);
if (ret) {
error_setg(errp, "type of '%s'"
" must be a non-negative decimal integer", name);
}
goto out;
separator_error:
error_setg(errp, "reserved region fields must be separated with ':'");
out:
g_free(str);
return;
}
const PropertyInfo qdev_prop_reserved_region = {
.name = "reserved_region",
.description = "Reserved Region, example: 0xFEE00000:0xFEEFFFFF:0",
.get = get_reserved_region,
.set = set_reserved_region,
};
/* --- pci address --- */
/*
* bus-local address, i.e. "$slot" or "$slot.$fn"
*/
static void set_pci_devfn(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int32_t value, *ptr = qdev_get_prop_ptr(dev, prop);
unsigned int slot, fn, n;
char *str;
if (dev->realized) {
qdev_prop_set_after_realize(dev, name, errp);
return;
}
if (!visit_type_str(v, name, &str, NULL)) {
if (!visit_type_int32(v, name, &value, errp)) {
return;
}
if (value < -1 || value > 255) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
name ? name : "null", "pci_devfn");
return;
}
*ptr = value;
return;
}
if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
fn = 0;
if (sscanf(str, "%x%n", &slot, &n) != 1) {
goto invalid;
}
}
if (str[n] != '\0' || fn > 7 || slot > 31) {
goto invalid;
}
*ptr = slot << 3 | fn;
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)
{
int32_t *ptr = qdev_get_prop_ptr(dev, prop);
if (*ptr == -1) {
return snprintf(dest, len, "<unset>");
} else {
return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7);
}
}
const PropertyInfo qdev_prop_pci_devfn = {
.name = "int32",
.description = "Slot and optional function number, example: 06.0 or 06",
.print = print_pci_devfn,
.get = qdev_propinfo_get_int32,
.set = set_pci_devfn,
.set_default_value = qdev_propinfo_set_default_value_int,
};
/* --- pci host address --- */
static void get_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop);
char buffer[] = "ffff:ff:ff.f";
char *p = buffer;
int rc = 0;
/*
* Catch "invalid" device reference from vfio-pci and allow the
* default buffer representing the non-existent device to be used.
*/
if (~addr->domain || ~addr->bus || ~addr->slot || ~addr->function) {
rc = snprintf(buffer, sizeof(buffer), "%04x:%02x:%02x.%0d",
addr->domain, addr->bus, addr->slot, addr->function);
assert(rc == sizeof(buffer) - 1);
}
visit_type_str(v, name, &p, 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, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop);
char *str, *p;
const char *e;
unsigned long val;
unsigned long dom = 0, bus = 0;
unsigned int slot = 0, func = 0;
if (dev->realized) {
qdev_prop_set_after_realize(dev, name, errp);
return;
}
if (!visit_type_str(v, name, &str, errp)) {
return;
}
p = str;
if (qemu_strtoul(p, &e, 16, &val) < 0 || val > 0xffff || e == p) {
goto inval;
}
if (*e != ':') {
goto inval;
}
bus = val;
p = (char *)e + 1;
if (qemu_strtoul(p, &e, 16, &val) < 0 || val > 0x1f || e == p) {
goto inval;
}
if (*e == ':') {
dom = bus;
bus = val;
p = (char *)e + 1;
if (qemu_strtoul(p, &e, 16, &val) < 0 || val > 0x1f || e == p) {
goto inval;
}
}
slot = val;
if (*e != '.') {
goto inval;
}
p = (char *)e + 1;
if (qemu_strtoul(p, &e, 10, &val) < 0 || val > 7 || e == p) {
goto inval;
}
func = val;
if (bus > 0xff) {
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);
}
const PropertyInfo qdev_prop_pci_host_devaddr = {
.name = "str",
.description = "Address (bus/device/function) of "
"the host device, example: 04:10.0",
.get = get_pci_host_devaddr,
.set = set_pci_host_devaddr,
};
/* --- OffAutoPCIBAR off/auto/bar0/bar1/bar2/bar3/bar4/bar5 --- */
const PropertyInfo qdev_prop_off_auto_pcibar = {
.name = "OffAutoPCIBAR",
.description = "off/auto/bar0/bar1/bar2/bar3/bar4/bar5",
.enum_table = &OffAutoPCIBAR_lookup,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
.set_default_value = qdev_propinfo_set_default_value_enum,
};
/* --- PCIELinkSpeed 2_5/5/8/16 -- */
static void get_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
PCIExpLinkSpeed *p = qdev_get_prop_ptr(dev, prop);
int speed;
switch (*p) {
case QEMU_PCI_EXP_LNK_2_5GT:
speed = PCIE_LINK_SPEED_2_5;
break;
case QEMU_PCI_EXP_LNK_5GT:
speed = PCIE_LINK_SPEED_5;
break;
case QEMU_PCI_EXP_LNK_8GT:
speed = PCIE_LINK_SPEED_8;
break;
case QEMU_PCI_EXP_LNK_16GT:
speed = PCIE_LINK_SPEED_16;
break;
default:
/* Unreachable */
abort();
}
visit_type_enum(v, prop->name, &speed, prop->info->enum_table, errp);
}
static void set_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
PCIExpLinkSpeed *p = qdev_get_prop_ptr(dev, prop);
int speed;
if (dev->realized) {
qdev_prop_set_after_realize(dev, name, errp);
return;
}
if (!visit_type_enum(v, prop->name, &speed, prop->info->enum_table,
errp)) {
return;
}
switch (speed) {
case PCIE_LINK_SPEED_2_5:
*p = QEMU_PCI_EXP_LNK_2_5GT;
break;
case PCIE_LINK_SPEED_5:
*p = QEMU_PCI_EXP_LNK_5GT;
break;
case PCIE_LINK_SPEED_8:
*p = QEMU_PCI_EXP_LNK_8GT;
break;
case PCIE_LINK_SPEED_16:
*p = QEMU_PCI_EXP_LNK_16GT;
break;
default:
/* Unreachable */
abort();
}
}
const PropertyInfo qdev_prop_pcie_link_speed = {
.name = "PCIELinkSpeed",
.description = "2_5/5/8/16",
.enum_table = &PCIELinkSpeed_lookup,
.get = get_prop_pcielinkspeed,
.set = set_prop_pcielinkspeed,
.set_default_value = qdev_propinfo_set_default_value_enum,
};
/* --- PCIELinkWidth 1/2/4/8/12/16/32 -- */
static void get_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
PCIExpLinkWidth *p = qdev_get_prop_ptr(dev, prop);
int width;
switch (*p) {
case QEMU_PCI_EXP_LNK_X1:
width = PCIE_LINK_WIDTH_1;
break;
case QEMU_PCI_EXP_LNK_X2:
width = PCIE_LINK_WIDTH_2;
break;
case QEMU_PCI_EXP_LNK_X4:
width = PCIE_LINK_WIDTH_4;
break;
case QEMU_PCI_EXP_LNK_X8:
width = PCIE_LINK_WIDTH_8;
break;
case QEMU_PCI_EXP_LNK_X12:
width = PCIE_LINK_WIDTH_12;
break;
case QEMU_PCI_EXP_LNK_X16:
width = PCIE_LINK_WIDTH_16;
break;
case QEMU_PCI_EXP_LNK_X32:
width = PCIE_LINK_WIDTH_32;
break;
default:
/* Unreachable */
abort();
}
visit_type_enum(v, prop->name, &width, prop->info->enum_table, errp);
}
static void set_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
PCIExpLinkWidth *p = qdev_get_prop_ptr(dev, prop);
int width;
if (dev->realized) {
qdev_prop_set_after_realize(dev, name, errp);
return;
}
if (!visit_type_enum(v, prop->name, &width, prop->info->enum_table,
errp)) {
return;
}
switch (width) {
case PCIE_LINK_WIDTH_1:
*p = QEMU_PCI_EXP_LNK_X1;
break;
case PCIE_LINK_WIDTH_2:
*p = QEMU_PCI_EXP_LNK_X2;
break;
case PCIE_LINK_WIDTH_4:
*p = QEMU_PCI_EXP_LNK_X4;
break;
case PCIE_LINK_WIDTH_8:
*p = QEMU_PCI_EXP_LNK_X8;
break;
case PCIE_LINK_WIDTH_12:
*p = QEMU_PCI_EXP_LNK_X12;
break;
case PCIE_LINK_WIDTH_16:
*p = QEMU_PCI_EXP_LNK_X16;
break;
case PCIE_LINK_WIDTH_32:
*p = QEMU_PCI_EXP_LNK_X32;
break;
default:
/* Unreachable */
abort();
}
}
const PropertyInfo qdev_prop_pcie_link_width = {
.name = "PCIELinkWidth",
.description = "1/2/4/8/12/16/32",
.enum_table = &PCIELinkWidth_lookup,
.get = get_prop_pcielinkwidth,
.set = set_prop_pcielinkwidth,
.set_default_value = qdev_propinfo_set_default_value_enum,
};

View File

@ -1,22 +1,15 @@
#include "qemu/osdep.h"
#include "net/net.h"
#include "hw/qdev-properties.h"
#include "qapi/error.h"
#include "hw/pci/pci.h"
#include "qapi/qapi-types-block.h"
#include "qapi/qapi-types-machine.h"
#include "qapi/qapi-types-misc.h"
#include "qapi/qmp/qerror.h"
#include "qemu/ctype.h"
#include "qemu/error-report.h"
#include "qapi/qapi-types-migration.h"
#include "hw/block/block.h"
#include "net/hub.h"
#include "qapi/visitor.h"
#include "chardev/char.h"
#include "qemu/uuid.h"
#include "qemu/units.h"
#include "qemu/cutils.h"
#include "qdev-prop-internal.h"
void qdev_prop_set_after_realize(DeviceState *dev, const char *name,
Error **errp)
@ -52,8 +45,8 @@ void *qdev_get_prop_ptr(DeviceState *dev, Property *prop)
return ptr;
}
static void get_enum(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
void qdev_propinfo_get_enum(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
@ -62,8 +55,8 @@ static void get_enum(Object *obj, Visitor *v, const char *name, void *opaque,
visit_type_enum(v, prop->name, ptr, prop->info->enum_table, errp);
}
static void set_enum(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
void qdev_propinfo_set_enum(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
@ -77,12 +70,20 @@ static void set_enum(Object *obj, Visitor *v, const char *name, void *opaque,
visit_type_enum(v, prop->name, ptr, prop->info->enum_table, errp);
}
static void set_default_value_enum(ObjectProperty *op, const Property *prop)
void qdev_propinfo_set_default_value_enum(ObjectProperty *op,
const Property *prop)
{
object_property_set_default_str(op,
qapi_enum_lookup(prop->info->enum_table, prop->defval.i));
}
const PropertyInfo qdev_prop_enum = {
.name = "enum",
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
.set_default_value = qdev_propinfo_set_default_value_enum,
};
/* Bit */
static uint32_t qdev_get_prop_mask(Property *prop)
@ -261,12 +262,14 @@ static void set_uint8(Object *obj, Visitor *v, const char *name, void *opaque,
visit_type_uint8(v, name, ptr, errp);
}
static void set_default_value_int(ObjectProperty *op, const Property *prop)
void qdev_propinfo_set_default_value_int(ObjectProperty *op,
const Property *prop)
{
object_property_set_default_int(op, prop->defval.i);
}
static void set_default_value_uint(ObjectProperty *op, const Property *prop)
void qdev_propinfo_set_default_value_uint(ObjectProperty *op,
const Property *prop)
{
object_property_set_default_uint(op, prop->defval.u);
}
@ -275,13 +278,13 @@ const PropertyInfo qdev_prop_uint8 = {
.name = "uint8",
.get = get_uint8,
.set = set_uint8,
.set_default_value = set_default_value_uint,
.set_default_value = qdev_propinfo_set_default_value_uint,
};
/* --- 16bit integer --- */
static void get_uint16(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
void qdev_propinfo_get_uint16(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
@ -307,9 +310,9 @@ static void set_uint16(Object *obj, Visitor *v, const char *name,
const PropertyInfo qdev_prop_uint16 = {
.name = "uint16",
.get = get_uint16,
.get = qdev_propinfo_get_uint16,
.set = set_uint16,
.set_default_value = set_default_value_uint,
.set_default_value = qdev_propinfo_set_default_value_uint,
};
/* --- 32bit integer --- */
@ -339,8 +342,8 @@ static void set_uint32(Object *obj, Visitor *v, const char *name,
visit_type_uint32(v, name, ptr, errp);
}
static void get_int32(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
void qdev_propinfo_get_int32(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
@ -368,14 +371,14 @@ const PropertyInfo qdev_prop_uint32 = {
.name = "uint32",
.get = get_uint32,
.set = set_uint32,
.set_default_value = set_default_value_uint,
.set_default_value = qdev_propinfo_set_default_value_uint,
};
const PropertyInfo qdev_prop_int32 = {
.name = "int32",
.get = get_int32,
.get = qdev_propinfo_get_int32,
.set = set_int32,
.set_default_value = set_default_value_int,
.set_default_value = qdev_propinfo_set_default_value_int,
};
/* --- 64bit integer --- */
@ -434,14 +437,14 @@ const PropertyInfo qdev_prop_uint64 = {
.name = "uint64",
.get = get_uint64,
.set = set_uint64,
.set_default_value = set_default_value_uint,
.set_default_value = qdev_propinfo_set_default_value_uint,
};
const PropertyInfo qdev_prop_int64 = {
.name = "int64",
.get = get_int64,
.set = set_int64,
.set_default_value = set_default_value_int,
.set_default_value = qdev_propinfo_set_default_value_int,
};
/* --- string --- */
@ -494,318 +497,21 @@ const PropertyInfo qdev_prop_string = {
.set = set_string,
};
/* --- mac address --- */
/*
* accepted syntax versions:
* 01:02:03:04:05:06
* 01-02-03-04-05-06
*/
static void get_mac(Object *obj, Visitor *v, const char *name, void *opaque,
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, name, &p, errp);
}
static void set_mac(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
MACAddr *mac = qdev_get_prop_ptr(dev, prop);
int i, pos;
char *str, *p;
if (dev->realized) {
qdev_prop_set_after_realize(dev, name, errp);
return;
}
if (!visit_type_str(v, name, &str, errp)) {
return;
}
for (i = 0, pos = 0; i < 6; i++, pos += 3) {
if (!qemu_isxdigit(str[pos])) {
goto inval;
}
if (!qemu_isxdigit(str[pos+1])) {
goto inval;
}
if (i == 5) {
if (str[pos+2] != '\0') {
goto inval;
}
} else {
if (str[pos+2] != ':' && str[pos+2] != '-') {
goto inval;
}
}
mac->a[i] = strtol(str+pos, &p, 16);
}
g_free(str);
return;
inval:
error_set_from_qdev_prop_error(errp, EINVAL, dev, prop, str);
g_free(str);
}
const PropertyInfo qdev_prop_macaddr = {
.name = "str",
.description = "Ethernet 6-byte MAC Address, example: 52:54:00:12:34:56",
.get = get_mac,
.set = set_mac,
};
/* --- Reserved Region --- */
/*
* Accepted syntax:
* <low address>:<high address>:<type>
* where low/high addresses are uint64_t in hexadecimal
* and type is a non-negative decimal integer
*/
static void get_reserved_region(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
ReservedRegion *rr = qdev_get_prop_ptr(dev, prop);
char buffer[64];
char *p = buffer;
int rc;
rc = snprintf(buffer, sizeof(buffer), "0x%"PRIx64":0x%"PRIx64":%u",
rr->low, rr->high, rr->type);
assert(rc < sizeof(buffer));
visit_type_str(v, name, &p, errp);
}
static void set_reserved_region(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
ReservedRegion *rr = qdev_get_prop_ptr(dev, prop);
Error *local_err = NULL;
const char *endptr;
char *str;
int ret;
if (dev->realized) {
qdev_prop_set_after_realize(dev, name, errp);
return;
}
visit_type_str(v, name, &str, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
}
ret = qemu_strtou64(str, &endptr, 16, &rr->low);
if (ret) {
error_setg(errp, "start address of '%s'"
" must be a hexadecimal integer", name);
goto out;
}
if (*endptr != ':') {
goto separator_error;
}
ret = qemu_strtou64(endptr + 1, &endptr, 16, &rr->high);
if (ret) {
error_setg(errp, "end address of '%s'"
" must be a hexadecimal integer", name);
goto out;
}
if (*endptr != ':') {
goto separator_error;
}
ret = qemu_strtoui(endptr + 1, &endptr, 10, &rr->type);
if (ret) {
error_setg(errp, "type of '%s'"
" must be a non-negative decimal integer", name);
}
goto out;
separator_error:
error_setg(errp, "reserved region fields must be separated with ':'");
out:
g_free(str);
return;
}
const PropertyInfo qdev_prop_reserved_region = {
.name = "reserved_region",
.description = "Reserved Region, example: 0xFEE00000:0xFEEFFFFF:0",
.get = get_reserved_region,
.set = set_reserved_region,
};
/* --- on/off/auto --- */
const PropertyInfo qdev_prop_on_off_auto = {
.name = "OnOffAuto",
.description = "on/off/auto",
.enum_table = &OnOffAuto_lookup,
.get = get_enum,
.set = set_enum,
.set_default_value = set_default_value_enum,
};
/* --- lost tick policy --- */
QEMU_BUILD_BUG_ON(sizeof(LostTickPolicy) != sizeof(int));
const PropertyInfo qdev_prop_losttickpolicy = {
.name = "LostTickPolicy",
.enum_table = &LostTickPolicy_lookup,
.get = get_enum,
.set = set_enum,
.set_default_value = set_default_value_enum,
};
/* --- Block device error handling policy --- */
QEMU_BUILD_BUG_ON(sizeof(BlockdevOnError) != sizeof(int));
const PropertyInfo qdev_prop_blockdev_on_error = {
.name = "BlockdevOnError",
.description = "Error handling policy, "
"report/ignore/enospc/stop/auto",
.enum_table = &BlockdevOnError_lookup,
.get = get_enum,
.set = set_enum,
.set_default_value = set_default_value_enum,
};
/* --- BIOS CHS translation */
QEMU_BUILD_BUG_ON(sizeof(BiosAtaTranslation) != sizeof(int));
const PropertyInfo qdev_prop_bios_chs_trans = {
.name = "BiosAtaTranslation",
.description = "Logical CHS translation algorithm, "
"auto/none/lba/large/rechs",
.enum_table = &BiosAtaTranslation_lookup,
.get = get_enum,
.set = set_enum,
.set_default_value = set_default_value_enum,
};
/* --- FDC default drive types */
const 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,
.set_default_value = set_default_value_enum,
};
/* --- MultiFDCompression --- */
const PropertyInfo qdev_prop_multifd_compression = {
.name = "MultiFDCompression",
.description = "multifd_compression values, "
"none/zlib/zstd",
.enum_table = &MultiFDCompression_lookup,
.get = get_enum,
.set = set_enum,
.set_default_value = set_default_value_enum,
};
/* --- pci address --- */
/*
* bus-local address, i.e. "$slot" or "$slot.$fn"
*/
static void set_pci_devfn(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
int32_t value, *ptr = qdev_get_prop_ptr(dev, prop);
unsigned int slot, fn, n;
char *str;
if (dev->realized) {
qdev_prop_set_after_realize(dev, name, errp);
return;
}
if (!visit_type_str(v, name, &str, NULL)) {
if (!visit_type_int32(v, name, &value, errp)) {
return;
}
if (value < -1 || value > 255) {
error_setg(errp, QERR_INVALID_PARAMETER_VALUE,
name ? name : "null", "pci_devfn");
return;
}
*ptr = value;
return;
}
if (sscanf(str, "%x.%x%n", &slot, &fn, &n) != 2) {
fn = 0;
if (sscanf(str, "%x%n", &slot, &n) != 1) {
goto invalid;
}
}
if (str[n] != '\0' || fn > 7 || slot > 31) {
goto invalid;
}
*ptr = slot << 3 | fn;
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)
{
int32_t *ptr = qdev_get_prop_ptr(dev, prop);
if (*ptr == -1) {
return snprintf(dest, len, "<unset>");
} else {
return snprintf(dest, len, "%02x.%x", *ptr >> 3, *ptr & 7);
}
}
const PropertyInfo qdev_prop_pci_devfn = {
.name = "int32",
.description = "Slot and optional function number, example: 06.0 or 06",
.print = print_pci_devfn,
.get = get_int32,
.set = set_pci_devfn,
.set_default_value = set_default_value_int,
.get = qdev_propinfo_get_enum,
.set = qdev_propinfo_set_enum,
.set_default_value = qdev_propinfo_set_default_value_enum,
};
/* --- 32bit unsigned int 'size' type --- */
static void get_size32(Object *obj, Visitor *v, const char *name, void *opaque,
Error **errp)
void qdev_propinfo_get_size32(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
@ -845,179 +551,9 @@ static void set_size32(Object *obj, Visitor *v, const char *name, void *opaque,
const PropertyInfo qdev_prop_size32 = {
.name = "size",
.get = get_size32,
.get = qdev_propinfo_get_size32,
.set = set_size32,
.set_default_value = set_default_value_uint,
};
/* --- blocksize --- */
/* lower limit is sector size */
#define MIN_BLOCK_SIZE 512
#define MIN_BLOCK_SIZE_STR "512 B"
/*
* upper limit is arbitrary, 2 MiB looks sufficient for all sensible uses, and
* matches qcow2 cluster size limit
*/
#define MAX_BLOCK_SIZE (2 * MiB)
#define MAX_BLOCK_SIZE_STR "2 MiB"
static void set_blocksize(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
uint32_t *ptr = qdev_get_prop_ptr(dev, prop);
uint64_t value;
if (dev->realized) {
qdev_prop_set_after_realize(dev, name, errp);
return;
}
if (!visit_type_size(v, name, &value, errp)) {
return;
}
/* value of 0 means "unset" */
if (value && (value < MIN_BLOCK_SIZE || value > MAX_BLOCK_SIZE)) {
error_setg(errp,
"Property %s.%s doesn't take value %" PRIu64
" (minimum: " MIN_BLOCK_SIZE_STR
", maximum: " MAX_BLOCK_SIZE_STR ")",
dev->id ? : "", name, value);
return;
}
/* We rely on power-of-2 blocksizes for bitmasks */
if ((value & (value - 1)) != 0) {
error_setg(errp,
"Property %s.%s doesn't take value '%" PRId64 "', it's not a power of 2",
dev->id ?: "", name, (int64_t)value);
return;
}
*ptr = value;
}
const PropertyInfo qdev_prop_blocksize = {
.name = "size",
.description = "A power of two between " MIN_BLOCK_SIZE_STR
" and " MAX_BLOCK_SIZE_STR,
.get = get_size32,
.set = set_blocksize,
.set_default_value = set_default_value_uint,
};
/* --- pci host address --- */
static void get_pci_host_devaddr(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop);
char buffer[] = "ffff:ff:ff.f";
char *p = buffer;
int rc = 0;
/*
* Catch "invalid" device reference from vfio-pci and allow the
* default buffer representing the non-existent device to be used.
*/
if (~addr->domain || ~addr->bus || ~addr->slot || ~addr->function) {
rc = snprintf(buffer, sizeof(buffer), "%04x:%02x:%02x.%0d",
addr->domain, addr->bus, addr->slot, addr->function);
assert(rc == sizeof(buffer) - 1);
}
visit_type_str(v, name, &p, 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, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
PCIHostDeviceAddress *addr = qdev_get_prop_ptr(dev, prop);
char *str, *p;
char *e;
unsigned long val;
unsigned long dom = 0, bus = 0;
unsigned int slot = 0, func = 0;
if (dev->realized) {
qdev_prop_set_after_realize(dev, name, errp);
return;
}
if (!visit_type_str(v, name, &str, errp)) {
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);
}
const PropertyInfo qdev_prop_pci_host_devaddr = {
.name = "str",
.description = "Address (bus/device/function) of "
"the host device, example: 04:10.0",
.get = get_pci_host_devaddr,
.set = set_pci_host_devaddr,
.set_default_value = qdev_propinfo_set_default_value_uint,
};
/* --- UUID --- */
@ -1175,7 +711,7 @@ const PropertyInfo qdev_prop_arraylen = {
.name = "uint32",
.get = get_uint32,
.set = set_prop_arraylen,
.set_default_value = set_default_value_uint,
.set_default_value = qdev_propinfo_set_default_value_uint,
};
/* --- public helpers --- */
@ -1269,16 +805,6 @@ void qdev_prop_set_string(DeviceState *dev, const char *name, const char *value)
object_property_set_str(OBJECT(dev), name, value, &error_abort);
}
void qdev_prop_set_macaddr(DeviceState *dev, const char *name,
const uint8_t *value)
{
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), name, str, &error_abort);
}
void qdev_prop_set_enum(DeviceState *dev, const char *name, int value)
{
Property *prop;
@ -1386,7 +912,7 @@ const PropertyInfo qdev_prop_size = {
.name = "size",
.get = get_size,
.set = set_size,
.set_default_value = set_default_value_uint,
.set_default_value = qdev_propinfo_set_default_value_uint,
};
/* --- object link property --- */
@ -1403,186 +929,3 @@ const PropertyInfo qdev_prop_link = {
.name = "link",
.create = create_link_property,
};
/* --- OffAutoPCIBAR off/auto/bar0/bar1/bar2/bar3/bar4/bar5 --- */
const PropertyInfo qdev_prop_off_auto_pcibar = {
.name = "OffAutoPCIBAR",
.description = "off/auto/bar0/bar1/bar2/bar3/bar4/bar5",
.enum_table = &OffAutoPCIBAR_lookup,
.get = get_enum,
.set = set_enum,
.set_default_value = set_default_value_enum,
};
/* --- PCIELinkSpeed 2_5/5/8/16 -- */
static void get_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
PCIExpLinkSpeed *p = qdev_get_prop_ptr(dev, prop);
int speed;
switch (*p) {
case QEMU_PCI_EXP_LNK_2_5GT:
speed = PCIE_LINK_SPEED_2_5;
break;
case QEMU_PCI_EXP_LNK_5GT:
speed = PCIE_LINK_SPEED_5;
break;
case QEMU_PCI_EXP_LNK_8GT:
speed = PCIE_LINK_SPEED_8;
break;
case QEMU_PCI_EXP_LNK_16GT:
speed = PCIE_LINK_SPEED_16;
break;
default:
/* Unreachable */
abort();
}
visit_type_enum(v, prop->name, &speed, prop->info->enum_table, errp);
}
static void set_prop_pcielinkspeed(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
PCIExpLinkSpeed *p = qdev_get_prop_ptr(dev, prop);
int speed;
if (dev->realized) {
qdev_prop_set_after_realize(dev, name, errp);
return;
}
if (!visit_type_enum(v, prop->name, &speed, prop->info->enum_table,
errp)) {
return;
}
switch (speed) {
case PCIE_LINK_SPEED_2_5:
*p = QEMU_PCI_EXP_LNK_2_5GT;
break;
case PCIE_LINK_SPEED_5:
*p = QEMU_PCI_EXP_LNK_5GT;
break;
case PCIE_LINK_SPEED_8:
*p = QEMU_PCI_EXP_LNK_8GT;
break;
case PCIE_LINK_SPEED_16:
*p = QEMU_PCI_EXP_LNK_16GT;
break;
default:
/* Unreachable */
abort();
}
}
const PropertyInfo qdev_prop_pcie_link_speed = {
.name = "PCIELinkSpeed",
.description = "2_5/5/8/16",
.enum_table = &PCIELinkSpeed_lookup,
.get = get_prop_pcielinkspeed,
.set = set_prop_pcielinkspeed,
.set_default_value = set_default_value_enum,
};
/* --- PCIELinkWidth 1/2/4/8/12/16/32 -- */
static void get_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
PCIExpLinkWidth *p = qdev_get_prop_ptr(dev, prop);
int width;
switch (*p) {
case QEMU_PCI_EXP_LNK_X1:
width = PCIE_LINK_WIDTH_1;
break;
case QEMU_PCI_EXP_LNK_X2:
width = PCIE_LINK_WIDTH_2;
break;
case QEMU_PCI_EXP_LNK_X4:
width = PCIE_LINK_WIDTH_4;
break;
case QEMU_PCI_EXP_LNK_X8:
width = PCIE_LINK_WIDTH_8;
break;
case QEMU_PCI_EXP_LNK_X12:
width = PCIE_LINK_WIDTH_12;
break;
case QEMU_PCI_EXP_LNK_X16:
width = PCIE_LINK_WIDTH_16;
break;
case QEMU_PCI_EXP_LNK_X32:
width = PCIE_LINK_WIDTH_32;
break;
default:
/* Unreachable */
abort();
}
visit_type_enum(v, prop->name, &width, prop->info->enum_table, errp);
}
static void set_prop_pcielinkwidth(Object *obj, Visitor *v, const char *name,
void *opaque, Error **errp)
{
DeviceState *dev = DEVICE(obj);
Property *prop = opaque;
PCIExpLinkWidth *p = qdev_get_prop_ptr(dev, prop);
int width;
if (dev->realized) {
qdev_prop_set_after_realize(dev, name, errp);
return;
}
if (!visit_type_enum(v, prop->name, &width, prop->info->enum_table,
errp)) {
return;
}
switch (width) {
case PCIE_LINK_WIDTH_1:
*p = QEMU_PCI_EXP_LNK_X1;
break;
case PCIE_LINK_WIDTH_2:
*p = QEMU_PCI_EXP_LNK_X2;
break;
case PCIE_LINK_WIDTH_4:
*p = QEMU_PCI_EXP_LNK_X4;
break;
case PCIE_LINK_WIDTH_8:
*p = QEMU_PCI_EXP_LNK_X8;
break;
case PCIE_LINK_WIDTH_12:
*p = QEMU_PCI_EXP_LNK_X12;
break;
case PCIE_LINK_WIDTH_16:
*p = QEMU_PCI_EXP_LNK_X16;
break;
case PCIE_LINK_WIDTH_32:
*p = QEMU_PCI_EXP_LNK_X32;
break;
default:
/* Unreachable */
abort();
}
}
const PropertyInfo qdev_prop_pcie_link_width = {
.name = "PCIELinkWidth",
.description = "1/2/4/8/12/16/32",
.enum_table = &PCIELinkWidth_lookup,
.get = get_prop_pcielinkwidth,
.set = set_prop_pcielinkwidth,
.set_default_value = set_default_value_enum,
};

View File

@ -443,7 +443,7 @@ struct IOMMUMemoryRegion {
QLIST_FOREACH((n), &(mr)->iommu_notify, node)
/**
* MemoryListener: callbacks structure for updates to the physical memory map
* struct MemoryListener: callbacks structure for updates to the physical memory map
*
* Allows a component to adjust to changes in the guest-visible memory map.
* Use with memory_listener_register() and memory_listener_unregister().
@ -681,7 +681,7 @@ struct MemoryListener {
};
/**
* AddressSpace: describes a mapping of addresses to #MemoryRegion objects
* struct AddressSpace: describes a mapping of addresses to #MemoryRegion objects
*/
struct AddressSpace {
/* private: */
@ -721,7 +721,7 @@ static inline FlatView *address_space_to_flatview(AddressSpace *as)
/**
* MemoryRegionSection: describes a fragment of a #MemoryRegion
* struct MemoryRegionSection: describes a fragment of a #MemoryRegion
*
* @mr: the region, or %NULL if empty
* @fv: the flat view of the address space the region is mapped in

View File

@ -8,6 +8,7 @@
extern const PropertyInfo qdev_prop_bit;
extern const PropertyInfo qdev_prop_bit64;
extern const PropertyInfo qdev_prop_bool;
extern const PropertyInfo qdev_prop_enum;
extern const PropertyInfo qdev_prop_uint8;
extern const PropertyInfo qdev_prop_uint16;
extern const PropertyInfo qdev_prop_uint32;

View File

@ -31,7 +31,7 @@ typedef struct InterfaceInfo InterfaceInfo;
typedef struct ObjectProperty ObjectProperty;
/**
* ObjectPropertyAccessor:
* typedef ObjectPropertyAccessor:
* @obj: the object that owns the property
* @v: the visitor that contains the property data
* @name: the name of the property
@ -47,7 +47,7 @@ typedef void (ObjectPropertyAccessor)(Object *obj,
Error **errp);
/**
* ObjectPropertyResolve:
* typedef ObjectPropertyResolve:
* @obj: the object that owns the property
* @opaque: the opaque registered with the property
* @part: the name of the property
@ -66,7 +66,7 @@ typedef Object *(ObjectPropertyResolve)(Object *obj,
const char *part);
/**
* ObjectPropertyRelease:
* typedef ObjectPropertyRelease:
* @obj: the object that owns the property
* @name: the name of the property
* @opaque: the opaque registered with the property
@ -78,7 +78,7 @@ typedef void (ObjectPropertyRelease)(Object *obj,
void *opaque);
/**
* ObjectPropertyInit:
* typedef ObjectPropertyInit:
* @obj: the object that owns the property
* @prop: the property to set
*
@ -101,7 +101,7 @@ struct ObjectProperty
};
/**
* ObjectUnparent:
* typedef ObjectUnparent:
* @obj: the object that is being removed from the composition tree
*
* Called when an object is being removed from the QOM composition tree.
@ -110,7 +110,7 @@ struct ObjectProperty
typedef void (ObjectUnparent)(Object *obj);
/**
* ObjectFree:
* typedef ObjectFree:
* @obj: the object being freed
*
* Called when an object's last reference is removed.
@ -120,7 +120,7 @@ typedef void (ObjectFree)(void *obj);
#define OBJECT_CLASS_CAST_CACHE 4
/**
* ObjectClass:
* struct ObjectClass:
*
* The base for all classes. The only thing that #ObjectClass contains is an
* integer type handle.
@ -140,7 +140,7 @@ struct ObjectClass
};
/**
* Object:
* struct Object:
*
* The base for all objects. The first member of this object is a pointer to
* a #ObjectClass. Since C guarantees that the first member of a structure
@ -170,7 +170,7 @@ struct Object
* Direct usage of this macro should be avoided, and the complete
* OBJECT_DECLARE_TYPE macro is recommended instead.
*
* This macro will provide the three standard type cast functions for a
* This macro will provide the instance type cast functions for a
* QOM type.
*/
#define DECLARE_INSTANCE_CHECKER(InstanceType, OBJ_NAME, TYPENAME) \
@ -187,7 +187,7 @@ struct Object
* Direct usage of this macro should be avoided, and the complete
* OBJECT_DECLARE_TYPE macro is recommended instead.
*
* This macro will provide the three standard type cast functions for a
* This macro will provide the class type cast functions for a
* QOM type.
*/
#define DECLARE_CLASS_CHECKERS(ClassType, OBJ_NAME, TYPENAME) \
@ -370,7 +370,7 @@ struct Object
true, { NULL })
/**
* TypeInfo:
* struct TypeInfo:
* @name: The name of the type.
* @parent: The name of the parent type.
* @instance_size: The size of the object (derivative of #Object). If
@ -496,7 +496,7 @@ struct TypeInfo
OBJECT_CLASS_CHECK(class, object_get_class(OBJECT(obj)), name)
/**
* InterfaceInfo:
* struct InterfaceInfo:
* @type: The name of the interface.
*
* The information associated with an interface.
@ -506,7 +506,7 @@ struct InterfaceInfo {
};
/**
* InterfaceClass:
* struct InterfaceClass:
* @parent_class: the base class
*
* The class for all interfaces. Subclasses of this class should only add
@ -1256,7 +1256,7 @@ char *object_property_get_str(Object *obj, const char *name,
* Writes an object's canonical path to a property.
*
* If the link property was created with
* <code>OBJ_PROP_LINK_STRONG</code> bit, the old target object is
* %OBJ_PROP_LINK_STRONG bit, the old target object is
* unreferenced, and a reference is added to the new target object.
*
* Returns: %true on success, %false on failure.
@ -1603,16 +1603,16 @@ void object_property_allow_set_link(const Object *obj, const char *name,
*
* Links form the graph in the object model.
*
* The <code>@check()</code> callback is invoked when
* The @check() callback is invoked when
* object_property_set_link() is called and can raise an error to prevent the
* link being set. If <code>@check</code> is NULL, the property is read-only
* link being set. If @check is NULL, the property is read-only
* and cannot be set.
*
* Ownership of the pointer that @child points to is transferred to the
* link property. The reference count for <code>*@child</code> is
* link property. The reference count for *@child is
* managed by the property from after the function returns till the
* property is deleted with object_property_del(). If the
* <code>@flags</code> <code>OBJ_PROP_LINK_STRONG</code> bit is set,
* @flags %OBJ_PROP_LINK_STRONG bit is set,
* the reference count is decremented when the property is deleted or
* modified.
*
@ -1823,7 +1823,7 @@ ObjectProperty *object_class_property_add_uint64_ptr(ObjectClass *klass,
* Add an alias for a property on an object. This function will add a property
* of the same type as the forwarded property.
*
* The caller must ensure that <code>@target_obj</code> stays alive as long as
* The caller must ensure that @target_obj stays alive as long as
* this property exists. In the case of a child object or an alias on the same
* object this will be the case. For aliases to other objects the caller is
* responsible for taking a reference.

View File

@ -1291,7 +1291,8 @@ ObjectProperty *object_property_find_err(Object *obj, const char *name,
{
ObjectProperty *prop = object_property_find(obj, name);
if (!prop) {
error_setg(errp, "Property '.%s' not found", name);
error_setg(errp, "Property '%s.%s' not found",
object_get_typename(obj), name);
}
return prop;
}

View File

@ -1064,14 +1064,6 @@ sub output_blockhead {
sub dump_declaration($$) {
no strict 'refs';
my ($prototype, $file) = @_;
if ($decl_type eq 'type name') {
if ($prototype =~ /^(enum|struct|union)\s+/) {
$decl_type = $1;
} else {
return;
}
}
my $func = "dump_" . $decl_type;
&$func(@_);
}
@ -1318,8 +1310,8 @@ sub dump_typedef($$) {
$x =~ s@/\*.*?\*/@@gos; # strip comments.
# Parse function prototypes
if ($x =~ /typedef\s+(\w+)\s*\(\*\s*(\w\S+)\s*\)\s*\((.*)\);/ ||
$x =~ /typedef\s+(\w+)\s*(\w\S+)\s*\s*\((.*)\);/) {
if ($x =~ /typedef\s+(\w+\s*\**)\s*\(\*?\s*(\w\S+)\s*\)\s*\((.*)\);/ ||
$x =~ /typedef\s+(\w+\s*\**)\s*(\w\S+)\s*\s*\((.*)\);/) {
# Function typedefs
$return_type = $1;
@ -1928,9 +1920,7 @@ sub process_name($$) {
++$warnings;
}
if ($identifier =~ m/^[A-Z]/) {
$decl_type = 'type name';
} elsif ($identifier =~ m/^struct\b/) {
if ($identifier =~ m/^struct\b/) {
$decl_type = 'struct';
} elsif ($identifier =~ m/^union\b/) {
$decl_type = 'union';