mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-23 11:39:53 +00:00
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:
commit
368e708b4c
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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",\
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
6
qmp.c
@ -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;
|
||||
|
17
qom/object.c
17
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);
|
||||
}
|
||||
|
@ -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},
|
||||
|
@ -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()
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user