diff options
author | Peter Maydell <peter.maydell@linaro.org> | 2017-07-18 15:24:11 +0100 |
---|---|---|
committer | Peter Maydell <peter.maydell@linaro.org> | 2017-07-18 15:24:11 +0100 |
commit | 368e708b4c95501574ab11632c7a0b8bb3ddc7e8 (patch) | |
tree | 3f0a487b338ca6d6ddb1abf17f193c38255666cc | |
parent | e9277a19a1a50ab5662c16795531bac332f142f9 (diff) | |
parent | f86285c571c49e781d3fa46f3bef3835b8e6f393 (diff) |
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>
-rw-r--r-- | hw/core/machine.c | 26 | ||||
-rw-r--r-- | hw/core/qdev-properties.c | 15 | ||||
-rw-r--r-- | hw/nvram/fw_cfg.c | 79 | ||||
-rw-r--r-- | include/hw/i386/pc.h | 5 | ||||
-rw-r--r-- | include/hw/nvram/fw_cfg.h | 50 | ||||
-rw-r--r-- | include/qemu/typedefs.h | 1 | ||||
-rw-r--r-- | qapi-schema.json | 7 | ||||
-rw-r--r-- | qmp.c | 6 | ||||
-rw-r--r-- | qom/object.c | 17 | ||||
-rwxr-xr-x | scripts/device-crash-test | 2 | ||||
-rw-r--r-- | target/i386/cpu.c | 78 | ||||
-rw-r--r-- | target/i386/cpu.h | 1 | ||||
-rw-r--r-- | tests/check-qom-proplist.c | 42 | ||||
-rw-r--r-- | tests/device-introspect-test.c | 156 | ||||
-rw-r--r-- | tests/test-qdev-global-props.c | 33 |
15 files changed, 381 insertions, 137 deletions
diff --git a/hw/core/machine.c b/hw/core/machine.c index dc431fabf5..41b53a17ad 100644 --- a/hw/core/machine.c +++ b/hw/core/machine.c @@ -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); } } diff --git a/hw/core/qdev-properties.c b/hw/core/qdev-properties.c index dcecdf03e5..58a8f92d92 100644 --- a/hw/core/qdev-properties.c +++ b/hw/core/qdev-properties.c @@ -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, diff --git a/hw/nvram/fw_cfg.c b/hw/nvram/fw_cfg.c index e881e3b812..5bd904487f 100644 --- a/hw/nvram/fw_cfg.c +++ b/hw/nvram/fw_cfg.c @@ -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) diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h index f48d167207..d80859bfad 100644 --- a/include/hw/i386/pc.h +++ b/include/hw/i386/pc.h @@ -380,6 +380,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",\ .value = "off",\ diff --git a/include/hw/nvram/fw_cfg.h b/include/hw/nvram/fw_cfg.h index b980cbaebf..b77ea48abb 100644 --- a/include/hw/nvram/fw_cfg.h +++ b/include/hw/nvram/fw_cfg.h @@ -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 diff --git a/include/qemu/typedefs.h b/include/qemu/typedefs.h index b19159104c..7b0d4e7e05 100644 --- a/include/qemu/typedefs.h +++ b/include/qemu/typedefs.h @@ -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; diff --git a/qapi-schema.json b/qapi-schema.json index ab438ead70..8b015bee2e 100644 --- a/qapi-schema.json +++ b/qapi-schema.json @@ -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: @@ -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; diff --git a/qom/object.c b/qom/object.c index dfdbd50f04..fe6e744b4d 100644 --- a/qom/object.c +++ b/qom/object.c @@ -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); } diff --git a/scripts/device-crash-test b/scripts/device-crash-test index 5f90e9bb54..e77b693eb2 100755 --- a/scripts/device-crash-test +++ b/scripts/device-crash-test @@ -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}, diff --git a/target/i386/cpu.c b/target/i386/cpu.c index 4de91d5801..0bbda76323 100644 --- a/target/i386/cpu.c +++ b/target/i386/cpu.c @@ -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. @@ -1345,6 +1345,54 @@ static X86CPUDefinition builtin_x86_defs[] = { .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, .vendor = CPUID_VENDOR_AMD, @@ -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() }; diff --git a/target/i386/cpu.h b/target/i386/cpu.h index 7a228afd04..051867399b 100644 --- a/target/i386/cpu.h +++ b/target/i386/cpu.h @@ -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; diff --git a/tests/check-qom-proplist.c b/tests/check-qom-proplist.c index 8e432e9ab6..432b66585f 100644 --- a/tests/check-qom-proplist.c +++ b/tests/check-qom-proplist.c @@ -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(); } diff --git a/tests/device-introspect-test.c b/tests/device-introspect-test.c index b1abb2ad89..f7162c023f 100644 --- a/tests/device-introspect-test.c +++ b/tests/device-introspect-test.c @@ -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; - - 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; - } + + all_types = qom_list_types("interface", true); + index = qom_type_index(all_types); + + 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); diff --git a/tests/test-qdev-global-props.c b/tests/test-qdev-global-props.c index b25fe892ed..d81b0862d5 100644 --- a/tests/test-qdev-global-props.c +++ b/tests/test-qdev-global-props.c @@ -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; |