x86 and machine queue, 2017-07-17

-----BEGIN PGP SIGNATURE-----
 
 iQIcBAABCAAGBQJZbQX2AAoJECgHk2+YTcWmVVgP/jJ+ctRt2PL8KMZQffcF8j+G
 ij5ZVa6C/8dwA+KwYa9HEVVPe/R7SyGw51BQidk/5u5L/w+ROx9teH/KX6phG1q1
 Zq8BxL1lIlSElneUEULm+tsxc+CDhXoH45XU8/7252VnzHN8w4B/og86osWwjtYA
 ShBNM6uhFTGrCl7fwrQldw3b33dznUpp4oI8lmLKFgyeUb6gjNk5ws1wDyPsO6ns
 pBYAoKvrdz6mJ/LCxufmHcexd7BMUoPmvp8SKqViK3ZrBFs0R0Ys6FFc0SIUuKzd
 Vc0FOTQPVnMfqi6EhzK6XW0I2odZ4n7MukoRnEYCU37WwYB0cpA+aVZuw/ZUj/cP
 sXrwi8O2QCSXUIa5ZQ/yBOsA6ZYkD90rALQEsJgzDiHqSG77tKkG8lZtEaAdPuFl
 eVTME0c7khA0aO9PXORAUqfJ8Av9+S8fWJ80A6duGkCxokqO0edLGAVFIFF5P1v7
 4DtvV45U3q0FQ/L21L08TlgXW0tlpOIEwc3UFeDoo+c+kZRkIlWhca47OLWozyus
 N24ku4cDZVmNYCJbKBWX6CECP7EfN8cFwVR7dCy22p1mwPWdQyQxx0pz3LQVJIab
 ccmluZmPX9zqQj/ecKMWY5GMvLw51c5hkP7r5hPwSHgMBNkt0uF2C4aZYBk/n6A1
 hj+EEKcaUJCnqO3EW5La
 =Vt6Z
 -----END PGP SIGNATURE-----

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

x86 and machine queue, 2017-07-17

# gpg: Signature made Mon 17 Jul 2017 19:46:14 BST
# gpg:                using RSA key 0x2807936F984DC5A6
# gpg: Good signature from "Eduardo Habkost <ehabkost@redhat.com>"
# Primary key fingerprint: 5A32 2FD5 ABC4 D3DB ACCF  D1AA 2807 936F 984D C5A6

* remotes/ehabkost/tags/x86-and-machine-pull-request:
  qmp: Include parent type on 'qom-list-types' output
  qmp: Include 'abstract' field on 'qom-list-types' output
  tests: Simplify abstract-interfaces check with a helper
  i386: add Skylake-Server cpu model
  i386: Update comment about XSAVES on Skylake-Client
  i386: expose "TCGTCGTCGTCG" in the 0x40000000 CPUID leaf
  fw_cfg: move QOM type defines and fw_cfg types into fw_cfg.h
  fw_cfg: move qdev_init_nofail() from fw_cfg_init1() to callers
  fw_cfg: switch fw_cfg_find() to locate the fw_cfg device by type rather than path
  qom: Fix ambiguous path detection when ambiguous=NULL
  Revert "machine: Convert abstract typename on compat_props to subclass names"
  test-qdev-global-props: Test global property ordering
  qdev: fix the order compat and global properties are applied
  tests: Test case for object_resolve_path*()
  device-crash-test: Fix regexp on whitelist

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2017-07-18 15:24:11 +01:00
commit 368e708b4c
15 changed files with 379 additions and 135 deletions

View File

@ -770,18 +770,11 @@ static void machine_class_finalize(ObjectClass *klass, void *data)
g_free(mc->name);
}
static void machine_register_compat_for_subclass(ObjectClass *oc, void *opaque)
{
GlobalProperty *p = opaque;
register_compat_prop(object_class_get_name(oc), p->property, p->value);
}
void machine_register_compat_props(MachineState *machine)
{
MachineClass *mc = MACHINE_GET_CLASS(machine);
int i;
GlobalProperty *p;
ObjectClass *oc;
if (!mc->compat_props) {
return;
@ -789,22 +782,9 @@ void machine_register_compat_props(MachineState *machine)
for (i = 0; i < mc->compat_props->len; i++) {
p = g_array_index(mc->compat_props, GlobalProperty *, i);
oc = object_class_by_name(p->driver);
if (oc && object_class_is_abstract(oc)) {
/* temporary hack to make sure we do not override
* globals set explicitly on -global: if an abstract class
* is on compat_props, register globals for all its
* non-abstract subtypes instead.
*
* This doesn't solve the problem for cases where
* a non-abstract typename mentioned on compat_props
* has subclasses, like spapr-pci-host-bridge.
*/
object_class_foreach(machine_register_compat_for_subclass,
p->driver, false, p);
} else {
register_compat_prop(p->driver, p->property, p->value);
}
/* Machine compat_props must never cause errors: */
p->errp = &error_abort;
qdev_prop_register_global(p);
}
}

View File

@ -1149,8 +1149,7 @@ int qdev_prop_check_globals(void)
return ret;
}
static void qdev_prop_set_globals_for_type(DeviceState *dev,
const char *typename)
void qdev_prop_set_globals(DeviceState *dev)
{
GList *l;
@ -1158,7 +1157,7 @@ static void qdev_prop_set_globals_for_type(DeviceState *dev,
GlobalProperty *prop = l->data;
Error *err = NULL;
if (strcmp(typename, prop->driver) != 0) {
if (object_dynamic_cast(OBJECT(dev), prop->driver) == NULL) {
continue;
}
prop->used = true;
@ -1176,16 +1175,6 @@ static void qdev_prop_set_globals_for_type(DeviceState *dev,
}
}
void qdev_prop_set_globals(DeviceState *dev)
{
ObjectClass *class = object_get_class(OBJECT(dev));
do {
qdev_prop_set_globals_for_type(dev, object_class_get_name(class));
class = object_class_get_parent(class);
} while (class);
}
/* --- 64bit unsigned int 'size' type --- */
static void get_size(Object *obj, Visitor *v, const char *name, void *opaque,

View File

@ -37,17 +37,6 @@
#define FW_CFG_FILE_SLOTS_DFLT 0x20
#define FW_CFG_NAME "fw_cfg"
#define FW_CFG_PATH "/machine/" FW_CFG_NAME
#define TYPE_FW_CFG "fw_cfg"
#define TYPE_FW_CFG_IO "fw_cfg_io"
#define TYPE_FW_CFG_MEM "fw_cfg_mem"
#define FW_CFG(obj) OBJECT_CHECK(FWCfgState, (obj), TYPE_FW_CFG)
#define FW_CFG_IO(obj) OBJECT_CHECK(FWCfgIoState, (obj), TYPE_FW_CFG_IO)
#define FW_CFG_MEM(obj) OBJECT_CHECK(FWCfgMemState, (obj), TYPE_FW_CFG_MEM)
/* FW_CFG_VERSION bits */
#define FW_CFG_VERSION 0x01
#define FW_CFG_VERSION_DMA 0x02
@ -61,51 +50,12 @@
#define FW_CFG_DMA_SIGNATURE 0x51454d5520434647ULL /* "QEMU CFG" */
typedef struct FWCfgEntry {
struct FWCfgEntry {
uint32_t len;
bool allow_write;
uint8_t *data;
void *callback_opaque;
FWCfgReadCallback read_callback;
} FWCfgEntry;
struct FWCfgState {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
uint16_t file_slots;
FWCfgEntry *entries[2];
int *entry_order;
FWCfgFiles *files;
uint16_t cur_entry;
uint32_t cur_offset;
Notifier machine_ready;
int fw_cfg_order_override;
bool dma_enabled;
dma_addr_t dma_addr;
AddressSpace *dma_as;
MemoryRegion dma_iomem;
};
struct FWCfgIoState {
/*< private >*/
FWCfgState parent_obj;
/*< public >*/
MemoryRegion comb_iomem;
};
struct FWCfgMemState {
/*< private >*/
FWCfgState parent_obj;
/*< public >*/
MemoryRegion ctl_iomem, data_iomem;
uint32_t data_width;
MemoryRegionOps wide_data_ops;
};
#define JPG_FILE 0
@ -909,17 +859,16 @@ static void fw_cfg_machine_ready(struct Notifier *n, void *data)
static void fw_cfg_init1(DeviceState *dev)
static void fw_cfg_common_realize(DeviceState *dev, Error **errp)
{
FWCfgState *s = FW_CFG(dev);
MachineState *machine = MACHINE(qdev_get_machine());
uint32_t version = FW_CFG_VERSION;
assert(!object_resolve_path(FW_CFG_PATH, NULL));
object_property_add_child(OBJECT(machine), FW_CFG_NAME, OBJECT(s), NULL);
qdev_init_nofail(dev);
if (!fw_cfg_find()) {
error_setg(errp, "at most one %s device is permitted", TYPE_FW_CFG);
return;
}
fw_cfg_add_bytes(s, FW_CFG_SIGNATURE, (char *)"QEMU", 4);
fw_cfg_add_bytes(s, FW_CFG_UUID, &qemu_uuid, 16);
@ -952,7 +901,9 @@ FWCfgState *fw_cfg_init_io_dma(uint32_t iobase, uint32_t dma_iobase,
qdev_prop_set_bit(dev, "dma_enabled", false);
}
fw_cfg_init1(dev);
object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG,
OBJECT(dev), NULL);
qdev_init_nofail(dev);
sbd = SYS_BUS_DEVICE(dev);
ios = FW_CFG_IO(dev);
@ -990,7 +941,9 @@ FWCfgState *fw_cfg_init_mem_wide(hwaddr ctl_addr,
qdev_prop_set_bit(dev, "dma_enabled", false);
}
fw_cfg_init1(dev);
object_property_add_child(OBJECT(qdev_get_machine()), TYPE_FW_CFG,
OBJECT(dev), NULL);
qdev_init_nofail(dev);
sbd = SYS_BUS_DEVICE(dev);
sysbus_mmio_map(sbd, 0, ctl_addr);
@ -1017,9 +970,11 @@ FWCfgState *fw_cfg_init_mem(hwaddr ctl_addr, hwaddr data_addr)
FWCfgState *fw_cfg_find(void)
{
return FW_CFG(object_resolve_path(FW_CFG_PATH, NULL));
/* Returns NULL unless there is exactly one fw_cfg device */
return FW_CFG(object_resolve_path_type("", TYPE_FW_CFG, NULL));
}
static void fw_cfg_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
@ -1091,6 +1046,8 @@ static void fw_cfg_io_realize(DeviceState *dev, Error **errp)
&fw_cfg_dma_mem_ops, FW_CFG(s), "fwcfg.dma",
sizeof(dma_addr_t));
}
fw_cfg_common_realize(dev, errp);
}
static void fw_cfg_io_class_init(ObjectClass *klass, void *data)
@ -1157,6 +1114,8 @@ static void fw_cfg_mem_realize(DeviceState *dev, Error **errp)
sizeof(dma_addr_t));
sysbus_init_mmio(sbd, &FW_CFG(s)->dma_iomem);
}
fw_cfg_common_realize(dev, errp);
}
static void fw_cfg_mem_class_init(ObjectClass *klass, void *data)

View File

@ -379,6 +379,11 @@ bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
#define PC_COMPAT_2_8 \
HW_COMPAT_2_8 \
{\
.driver = TYPE_X86_CPU,\
.property = "tcg-cpuid",\
.value = "off",\
},\
{\
.driver = "kvmclock",\
.property = "x-mach-use-reliable-get-clock",\

View File

@ -1,8 +1,19 @@
#ifndef FW_CFG_H
#define FW_CFG_H
#include "qemu/typedefs.h"
#include "exec/hwaddr.h"
#include "hw/nvram/fw_cfg_keys.h"
#include "hw/sysbus.h"
#include "sysemu/dma.h"
#define TYPE_FW_CFG "fw_cfg"
#define TYPE_FW_CFG_IO "fw_cfg_io"
#define TYPE_FW_CFG_MEM "fw_cfg_mem"
#define FW_CFG(obj) OBJECT_CHECK(FWCfgState, (obj), TYPE_FW_CFG)
#define FW_CFG_IO(obj) OBJECT_CHECK(FWCfgIoState, (obj), TYPE_FW_CFG_IO)
#define FW_CFG_MEM(obj) OBJECT_CHECK(FWCfgMemState, (obj), TYPE_FW_CFG_MEM)
typedef struct FWCfgFile {
uint32_t size; /* file size */
@ -35,6 +46,45 @@ typedef struct FWCfgDmaAccess {
typedef void (*FWCfgReadCallback)(void *opaque);
struct FWCfgState {
/*< private >*/
SysBusDevice parent_obj;
/*< public >*/
uint16_t file_slots;
FWCfgEntry *entries[2];
int *entry_order;
FWCfgFiles *files;
uint16_t cur_entry;
uint32_t cur_offset;
Notifier machine_ready;
int fw_cfg_order_override;
bool dma_enabled;
dma_addr_t dma_addr;
AddressSpace *dma_as;
MemoryRegion dma_iomem;
};
struct FWCfgIoState {
/*< private >*/
FWCfgState parent_obj;
/*< public >*/
MemoryRegion comb_iomem;
};
struct FWCfgMemState {
/*< private >*/
FWCfgState parent_obj;
/*< public >*/
MemoryRegion ctl_iomem, data_iomem;
uint32_t data_width;
MemoryRegionOps wide_data_ops;
};
/**
* fw_cfg_add_bytes:
* @s: fw_cfg device being modified

View File

@ -30,6 +30,7 @@ typedef struct DisplaySurface DisplaySurface;
typedef struct DriveInfo DriveInfo;
typedef struct Error Error;
typedef struct EventNotifier EventNotifier;
typedef struct FWCfgEntry FWCfgEntry;
typedef struct FWCfgIoState FWCfgIoState;
typedef struct FWCfgMemState FWCfgMemState;
typedef struct FWCfgState FWCfgState;

View File

@ -3051,10 +3051,15 @@
#
# @name: the type name found in the search
#
# @abstract: the type is abstract and can't be directly instantiated.
# Omitted if false. (since 2.10)
#
# @parent: Name of parent type, if any (since 2.10)
#
# Since: 1.1
##
{ 'struct': 'ObjectTypeInfo',
'data': { 'name': 'str' } }
'data': { 'name': 'str', '*abstract': 'bool', '*parent': 'str' } }
##
# @qom-list-types:

6
qmp.c
View File

@ -430,9 +430,15 @@ static void qom_list_types_tramp(ObjectClass *klass, void *data)
{
ObjectTypeInfoList *e, **pret = data;
ObjectTypeInfo *info;
ObjectClass *parent = object_class_get_parent(klass);
info = g_malloc0(sizeof(*info));
info->name = g_strdup(object_class_get_name(klass));
info->has_abstract = info->abstract = object_class_is_abstract(klass);
if (parent) {
info->has_parent = true;
info->parent = g_strdup(object_class_get_name(parent));
}
e = g_malloc0(sizeof(*e));
e->value = info;

View File

@ -1712,15 +1712,13 @@ static Object *object_resolve_partial_path(Object *parent,
typename, ambiguous);
if (found) {
if (obj) {
if (ambiguous) {
*ambiguous = true;
}
*ambiguous = true;
return NULL;
}
obj = found;
}
if (ambiguous && *ambiguous) {
if (*ambiguous) {
return NULL;
}
}
@ -1729,7 +1727,7 @@ static Object *object_resolve_partial_path(Object *parent,
}
Object *object_resolve_path_type(const char *path, const char *typename,
bool *ambiguous)
bool *ambiguousp)
{
Object *obj;
gchar **parts;
@ -1738,11 +1736,12 @@ Object *object_resolve_path_type(const char *path, const char *typename,
assert(parts);
if (parts[0] == NULL || strcmp(parts[0], "") != 0) {
if (ambiguous) {
*ambiguous = false;
}
bool ambiguous = false;
obj = object_resolve_partial_path(object_get_root(), parts,
typename, ambiguous);
typename, &ambiguous);
if (ambiguousp) {
*ambiguousp = ambiguous;
}
} else {
obj = object_resolve_abs_path(object_get_root(), parts, typename, 1);
}

View File

@ -219,7 +219,7 @@ ERROR_WHITELIST = [
{'exitcode':-6, 'log':r"Object .* is not an instance of type spapr-machine", 'loglevel':logging.ERROR},
{'exitcode':-6, 'log':r"Object .* is not an instance of type generic-pc-machine", 'loglevel':logging.ERROR},
{'exitcode':-6, 'log':r"Object .* is not an instance of type e500-ccsr", 'loglevel':logging.ERROR},
{'exitcode':-6, 'log':r"vmstate_register_with_alias_id: Assertion `!se->compat || se->instance_id == 0' failed", 'loglevel':logging.ERROR},
{'exitcode':-6, 'log':r"vmstate_register_with_alias_id: Assertion `!se->compat \|\| se->instance_id == 0' failed", 'loglevel':logging.ERROR},
{'exitcode':-11, 'device':'stm32f205-soc', 'loglevel':logging.ERROR, 'expected':True},
{'exitcode':-11, 'device':'xlnx,zynqmp', 'loglevel':logging.ERROR, 'expected':True},
{'exitcode':-11, 'device':'mips-cps', 'loglevel':logging.ERROR, 'expected':True},

View File

@ -1331,7 +1331,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_MPX,
/* Missing: XSAVES (not supported by some Linux versions,
* including v4.1 to v4.6).
* including v4.1 to v4.12).
* KVM doesn't yet expose any XSAVES state save component,
* and the only one defined in Skylake (processor tracing)
* probably will block migration anyway.
@ -1344,6 +1344,54 @@ static X86CPUDefinition builtin_x86_defs[] = {
.xlevel = 0x80000008,
.model_id = "Intel Core Processor (Skylake)",
},
{
.name = "Skylake-Server",
.level = 0xd,
.vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 85,
.stepping = 4,
.features[FEAT_1_EDX] =
CPUID_VME | CPUID_SSE2 | CPUID_SSE | CPUID_FXSR | CPUID_MMX |
CPUID_CLFLUSH | CPUID_PSE36 | CPUID_PAT | CPUID_CMOV | CPUID_MCA |
CPUID_PGE | CPUID_MTRR | CPUID_SEP | CPUID_APIC | CPUID_CX8 |
CPUID_MCE | CPUID_PAE | CPUID_MSR | CPUID_TSC | CPUID_PSE |
CPUID_DE | CPUID_FP87,
.features[FEAT_1_ECX] =
CPUID_EXT_AVX | CPUID_EXT_XSAVE | CPUID_EXT_AES |
CPUID_EXT_POPCNT | CPUID_EXT_X2APIC | CPUID_EXT_SSE42 |
CPUID_EXT_SSE41 | CPUID_EXT_CX16 | CPUID_EXT_SSSE3 |
CPUID_EXT_PCLMULQDQ | CPUID_EXT_SSE3 |
CPUID_EXT_TSC_DEADLINE_TIMER | CPUID_EXT_FMA | CPUID_EXT_MOVBE |
CPUID_EXT_PCID | CPUID_EXT_F16C | CPUID_EXT_RDRAND,
.features[FEAT_8000_0001_EDX] =
CPUID_EXT2_LM | CPUID_EXT2_PDPE1GB | CPUID_EXT2_RDTSCP |
CPUID_EXT2_NX | CPUID_EXT2_SYSCALL,
.features[FEAT_8000_0001_ECX] =
CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH,
.features[FEAT_7_0_EBX] =
CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
CPUID_7_0_EBX_HLE | CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ERMS | CPUID_7_0_EBX_INVPCID |
CPUID_7_0_EBX_RTM | CPUID_7_0_EBX_RDSEED | CPUID_7_0_EBX_ADX |
CPUID_7_0_EBX_SMAP | CPUID_7_0_EBX_MPX | CPUID_7_0_EBX_CLWB |
CPUID_7_0_EBX_AVX512F | CPUID_7_0_EBX_AVX512DQ |
CPUID_7_0_EBX_AVX512BW | CPUID_7_0_EBX_AVX512CD |
CPUID_7_0_EBX_AVX512VL,
/* Missing: XSAVES (not supported by some Linux versions,
* including v4.1 to v4.12).
* KVM doesn't yet expose any XSAVES state save component,
* and the only one defined in Skylake (processor tracing)
* probably will block migration anyway.
*/
.features[FEAT_XSAVE] =
CPUID_XSAVE_XSAVEOPT | CPUID_XSAVE_XSAVEC |
CPUID_XSAVE_XGETBV1,
.features[FEAT_6_EAX] =
CPUID_6_EAX_ARAT,
.xlevel = 0x80000008,
.model_id = "Intel Xeon Processor (Skylake)",
},
{
.name = "Opteron_G1",
.level = 5,
@ -2632,12 +2680,15 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
CPUState *cs = CPU(cpu);
uint32_t pkg_offset;
uint32_t limit;
uint32_t signature[3];
/* Calculate & apply limits for different index ranges */
if (index >= 0xC0000000) {
limit = env->cpuid_xlevel2;
} else if (index >= 0x80000000) {
limit = env->cpuid_xlevel;
} else if (index >= 0x40000000) {
limit = 0x40000001;
} else {
limit = env->cpuid_level;
}
@ -2872,6 +2923,30 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
}
break;
}
case 0x40000000:
/*
* CPUID code in kvm_arch_init_vcpu() ignores stuff
* set here, but we restrict to TCG none the less.
*/
if (tcg_enabled() && cpu->expose_tcg) {
memcpy(signature, "TCGTCGTCGTCG", 12);
*eax = 0x40000001;
*ebx = signature[0];
*ecx = signature[1];
*edx = signature[2];
} else {
*eax = 0;
*ebx = 0;
*ecx = 0;
*edx = 0;
}
break;
case 0x40000001:
*eax = 0;
*ebx = 0;
*ecx = 0;
*edx = 0;
break;
case 0x80000000:
*eax = env->cpuid_xlevel;
*ebx = env->cpuid_vendor1;
@ -4018,6 +4093,7 @@ static Property x86_cpu_properties[] = {
DEFINE_PROP_BOOL("kvm-no-smi-migration", X86CPU, kvm_no_smi_migration,
false),
DEFINE_PROP_BOOL("vmware-cpuid-freq", X86CPU, vmware_cpuid_freq, true),
DEFINE_PROP_BOOL("tcg-cpuid", X86CPU, expose_tcg, true),
DEFINE_PROP_END_OF_LIST()
};

View File

@ -1218,6 +1218,7 @@ struct X86CPU {
bool check_cpuid;
bool enforce_cpuid;
bool expose_kvm;
bool expose_tcg;
bool migratable;
bool max_features; /* Enable all supported features automatically */
uint32_t apic_id;

View File

@ -568,6 +568,47 @@ static void test_dummy_delchild(void)
object_unparent(OBJECT(dev));
}
static void test_qom_partial_path(void)
{
Object *root = object_get_objects_root();
Object *cont1 = container_get(root, "/cont1");
Object *obj1 = object_new(TYPE_DUMMY);
Object *obj2a = object_new(TYPE_DUMMY);
Object *obj2b = object_new(TYPE_DUMMY);
bool ambiguous;
/* Objects created:
* /cont1
* /cont1/obj1
* /cont1/obj2 (obj2a)
* /obj2 (obj2b)
*/
object_property_add_child(cont1, "obj1", obj1, &error_abort);
object_unref(obj1);
object_property_add_child(cont1, "obj2", obj2a, &error_abort);
object_unref(obj2a);
object_property_add_child(root, "obj2", obj2b, &error_abort);
object_unref(obj2b);
ambiguous = false;
g_assert(!object_resolve_path_type("", TYPE_DUMMY, &ambiguous));
g_assert(ambiguous);
g_assert(!object_resolve_path_type("", TYPE_DUMMY, NULL));
ambiguous = false;
g_assert(!object_resolve_path("obj2", &ambiguous));
g_assert(ambiguous);
g_assert(!object_resolve_path("obj2", NULL));
ambiguous = false;
g_assert(object_resolve_path("obj1", &ambiguous) == obj1);
g_assert(!ambiguous);
g_assert(object_resolve_path("obj1", NULL) == obj1);
object_unparent(obj2b);
object_unparent(cont1);
}
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
@ -585,6 +626,7 @@ int main(int argc, char **argv)
g_test_add_func("/qom/proplist/getenum", test_dummy_getenum);
g_test_add_func("/qom/proplist/iterator", test_dummy_iterator);
g_test_add_func("/qom/proplist/delchild", test_dummy_delchild);
g_test_add_func("/qom/resolve/partial", test_qom_partial_path);
return g_test_run();
}

View File

@ -45,6 +45,56 @@ static QList *qom_list_types(const char *implements, bool abstract)
return ret;
}
/* Build a name -> ObjectTypeInfo index from a ObjectTypeInfo list */
static QDict *qom_type_index(QList *types)
{
QDict *index = qdict_new();
QListEntry *e;
QLIST_FOREACH_ENTRY(types, e) {
QDict *d = qobject_to_qdict(qlist_entry_obj(e));
const char *name = qdict_get_str(d, "name");
QINCREF(d);
qdict_put(index, name, d);
}
return index;
}
/* Check if @parent is present in the parent chain of @type */
static bool qom_has_parent(QDict *index, const char *type, const char *parent)
{
while (type) {
QDict *d = qdict_get_qdict(index, type);
const char *p = d && qdict_haskey(d, "parent") ?
qdict_get_str(d, "parent") :
NULL;
if (!strcmp(type, parent)) {
return true;
}
type = p;
}
return false;
}
/* Find an entry on a list returned by qom-list-types */
static QDict *type_list_find(QList *types, const char *name)
{
QListEntry *e;
QLIST_FOREACH_ENTRY(types, e) {
QDict *d = qobject_to_qdict(qlist_entry_obj(e));
const char *ename = qdict_get_str(d, "name");
if (!strcmp(ename, name)) {
return d;
}
}
return NULL;
}
static QList *device_type_list(bool abstract)
{
return qom_list_types("device", abstract);
@ -87,6 +137,61 @@ static void test_device_intro_list(void)
qtest_end();
}
/*
* Ensure all entries returned by qom-list-types implements=<parent>
* have <parent> as a parent.
*/
static void test_qom_list_parents(const char *parent)
{
QList *types;
QListEntry *e;
QDict *index;
types = qom_list_types(parent, true);
index = qom_type_index(types);
QLIST_FOREACH_ENTRY(types, e) {
QDict *d = qobject_to_qdict(qlist_entry_obj(e));
const char *name = qdict_get_str(d, "name");
g_assert(qom_has_parent(index, name, parent));
}
QDECREF(types);
QDECREF(index);
}
static void test_qom_list_fields(void)
{
QList *all_types;
QList *non_abstract;
QListEntry *e;
qtest_start(common_args);
all_types = qom_list_types(NULL, true);
non_abstract = qom_list_types(NULL, false);
QLIST_FOREACH_ENTRY(all_types, e) {
QDict *d = qobject_to_qdict(qlist_entry_obj(e));
const char *name = qdict_get_str(d, "name");
bool abstract = qdict_haskey(d, "abstract") ?
qdict_get_bool(d, "abstract") :
false;
bool expected_abstract = !type_list_find(non_abstract, name);
g_assert(abstract == expected_abstract);
}
test_qom_list_parents("object");
test_qom_list_parents("device");
test_qom_list_parents("sys-bus-device");
QDECREF(all_types);
QDECREF(non_abstract);
qtest_end();
}
static void test_device_intro_none(void)
{
qtest_start(common_args);
@ -124,42 +229,34 @@ static void test_device_intro_concrete(void)
static void test_abstract_interfaces(void)
{
QList *all_types;
QList *obj_types;
QListEntry *ae;
QListEntry *e;
QDict *index;
qtest_start(common_args);
/* qom-list-types implements=interface would return any type
* that implements _any_ interface (not just interface types),
* so use a trick to find the interface type names:
* - list all object types
* - list all types, and look for items that are not
* on the first list
*/
all_types = qom_list_types(NULL, false);
obj_types = qom_list_types("object", false);
QLIST_FOREACH_ENTRY(all_types, ae) {
QDict *at = qobject_to_qdict(qlist_entry_obj(ae));
const char *aname = qdict_get_str(at, "name");
QListEntry *oe;
const char *found = NULL;
all_types = qom_list_types("interface", true);
index = qom_type_index(all_types);
QLIST_FOREACH_ENTRY(obj_types, oe) {
QDict *ot = qobject_to_qdict(qlist_entry_obj(oe));
const char *oname = qdict_get_str(ot, "name");
if (!strcmp(aname, oname)) {
found = oname;
break;
}
QLIST_FOREACH_ENTRY(all_types, e) {
QDict *d = qobject_to_qdict(qlist_entry_obj(e));
const char *name = qdict_get_str(d, "name");
/*
* qom-list-types implements=interface returns all types
* that implement _any_ interface (not just interface
* types), so skip the ones that don't have "interface"
* on the parent type chain.
*/
if (!qom_has_parent(index, name, "interface")) {
/* Not an interface type */
continue;
}
/* Using g_assert_cmpstr() will give more useful failure
* messages than g_assert(found) */
g_assert_cmpstr(aname, ==, found);
g_assert(qdict_haskey(d, "abstract") && qdict_get_bool(d, "abstract"));
}
QDECREF(all_types);
QDECREF(obj_types);
QDECREF(index);
qtest_end();
}
@ -168,6 +265,7 @@ int main(int argc, char **argv)
g_test_init(&argc, &argv, NULL);
qtest_add_func("device/introspect/list", test_device_intro_list);
qtest_add_func("device/introspect/list-fields", test_qom_list_fields);
qtest_add_func("device/introspect/none", test_device_intro_none);
qtest_add_func("device/introspect/abstract", test_device_intro_abstract);
qtest_add_func("device/introspect/concrete", test_device_intro_concrete);

View File

@ -33,6 +33,8 @@
#define STATIC_TYPE(obj) \
OBJECT_CHECK(MyType, (obj), TYPE_STATIC_PROPS)
#define TYPE_SUBCLASS "static_prop_subtype"
#define PROP_DEFAULT 100
typedef struct MyType {
@ -63,6 +65,11 @@ static const TypeInfo static_prop_type = {
.class_init = static_prop_class_init,
};
static const TypeInfo subclass_type = {
.name = TYPE_SUBCLASS,
.parent = TYPE_STATIC_PROPS,
};
/* Test simple static property setting to default value */
static void test_static_prop_subprocess(void)
{
@ -279,12 +286,35 @@ static void test_dynamic_globalprop_nouser(void)
g_test_trap_assert_stdout("");
}
/* Test if global props affecting subclasses are applied in the right order */
static void test_subclass_global_props(void)
{
MyType *mt;
/* Global properties must be applied in the order they were registered */
static GlobalProperty props[] = {
{ TYPE_STATIC_PROPS, "prop1", "101" },
{ TYPE_SUBCLASS, "prop1", "102" },
{ TYPE_SUBCLASS, "prop2", "103" },
{ TYPE_STATIC_PROPS, "prop2", "104" },
{}
};
qdev_prop_register_global_list(props);
mt = STATIC_TYPE(object_new(TYPE_SUBCLASS));
qdev_init_nofail(DEVICE(mt));
g_assert_cmpuint(mt->prop1, ==, 102);
g_assert_cmpuint(mt->prop2, ==, 104);
}
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
module_call_init(MODULE_INIT_QOM);
type_register_static(&static_prop_type);
type_register_static(&subclass_type);
type_register_static(&dynamic_prop_type);
type_register_static(&hotplug_type);
type_register_static(&nohotplug_type);
@ -310,6 +340,9 @@ int main(int argc, char **argv)
g_test_add_func("/qdev/properties/dynamic/global/nouser",
test_dynamic_globalprop_nouser);
g_test_add_func("/qdev/properties/global/subclass",
test_subclass_global_props);
g_test_run();
return 0;