提交 e8ddc2ea 编写于 作者: P Peter Maydell

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

x86 queue, 2016-10-17

# gpg: Signature made Mon 17 Oct 2016 18:51:07 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-pull-request: (21 commits)
  target-i386: Don't use cpu->migratable when filtering features
  target-i386: Return runnability information on query-cpu-definitions
  target-i386: x86_cpu_load_features() function
  target-i386: Unset cannot_destroy_with_object_finalize_yet
  target-i386/kvm: cache the return value of kvm_enable_x2apic()
  intel_iommu: reject broken EIM
  intel_iommu: add OnOffAuto intr_eim as "eim" property
  intel_iommu: redo configuraton check in realize
  intel_iommu: pass whole remapped addresses to apic
  apic: add send_msi() to APICCommonClass
  apic: add global apic_get_class()
  target-i386: Move warning code outside x86_cpu_filter_features()
  qmp: Add runnability information to query-cpu-definitions
  target-i386: xsave: Add FP and SSE bits to x86_ext_save_areas
  target-i386: Register properties for feature aliases manually
  target-i386: Remove underscores from feat_names arrays
  target-i386: Make plus_features/minus_features QOM-based
  target-i386: Register aliases for feature names with underscores
  target-i386: Disable VME by default with TCG
  target-i386: List CPU models using subclass list
  ...
Signed-off-by: NPeter Maydell <peter.maydell@linaro.org>
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#include "qapi/error.h"
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "exec/address-spaces.h" #include "exec/address-spaces.h"
#include "intel_iommu_internal.h" #include "intel_iommu_internal.h"
...@@ -32,6 +33,8 @@ ...@@ -32,6 +33,8 @@
#include "hw/i386/x86-iommu.h" #include "hw/i386/x86-iommu.h"
#include "hw/pci-host/q35.h" #include "hw/pci-host/q35.h"
#include "sysemu/kvm.h" #include "sysemu/kvm.h"
#include "hw/i386/apic_internal.h"
#include "kvm_i386.h"
/*#define DEBUG_INTEL_IOMMU*/ /*#define DEBUG_INTEL_IOMMU*/
#ifdef DEBUG_INTEL_IOMMU #ifdef DEBUG_INTEL_IOMMU
...@@ -280,18 +283,17 @@ static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id, ...@@ -280,18 +283,17 @@ static void vtd_update_iotlb(IntelIOMMUState *s, uint16_t source_id,
static void vtd_generate_interrupt(IntelIOMMUState *s, hwaddr mesg_addr_reg, static void vtd_generate_interrupt(IntelIOMMUState *s, hwaddr mesg_addr_reg,
hwaddr mesg_data_reg) hwaddr mesg_data_reg)
{ {
hwaddr addr; MSIMessage msi;
uint32_t data;
assert(mesg_data_reg < DMAR_REG_SIZE); assert(mesg_data_reg < DMAR_REG_SIZE);
assert(mesg_addr_reg < DMAR_REG_SIZE); assert(mesg_addr_reg < DMAR_REG_SIZE);
addr = vtd_get_long_raw(s, mesg_addr_reg); msi.address = vtd_get_long_raw(s, mesg_addr_reg);
data = vtd_get_long_raw(s, mesg_data_reg); msi.data = vtd_get_long_raw(s, mesg_data_reg);
VTD_DPRINTF(FLOG, "msi: addr 0x%"PRIx64 " data 0x%"PRIx32, addr, data); VTD_DPRINTF(FLOG, "msi: addr 0x%"PRIx64 " data 0x%"PRIx32,
address_space_stl_le(&address_space_memory, addr, data, msi.address, msi.data);
MEMTXATTRS_UNSPECIFIED, NULL); apic_get_class()->send_msi(&msi);
} }
/* Generate a fault event to software via MSI if conditions are met. /* Generate a fault event to software via MSI if conditions are met.
...@@ -2012,6 +2014,9 @@ static const MemoryRegionOps vtd_mem_ops = { ...@@ -2012,6 +2014,9 @@ static const MemoryRegionOps vtd_mem_ops = {
static Property vtd_properties[] = { static Property vtd_properties[] = {
DEFINE_PROP_UINT32("version", IntelIOMMUState, version, 0), DEFINE_PROP_UINT32("version", IntelIOMMUState, version, 0),
DEFINE_PROP_ON_OFF_AUTO("eim", IntelIOMMUState, intr_eim,
ON_OFF_AUTO_AUTO),
DEFINE_PROP_BOOL("x-buggy-eim", IntelIOMMUState, buggy_eim, false),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
...@@ -2134,6 +2139,7 @@ static void vtd_generate_msi_message(VTDIrq *irq, MSIMessage *msg_out) ...@@ -2134,6 +2139,7 @@ static void vtd_generate_msi_message(VTDIrq *irq, MSIMessage *msg_out)
msg.dest_mode = irq->dest_mode; msg.dest_mode = irq->dest_mode;
msg.redir_hint = irq->redir_hint; msg.redir_hint = irq->redir_hint;
msg.dest = irq->dest; msg.dest = irq->dest;
msg.__addr_hi = irq->dest & 0xffffff00;
msg.__addr_head = cpu_to_le32(0xfee); msg.__addr_head = cpu_to_le32(0xfee);
/* Keep this from original MSI address bits */ /* Keep this from original MSI address bits */
msg.__not_used = irq->msi_addr_last_bits; msg.__not_used = irq->msi_addr_last_bits;
...@@ -2293,11 +2299,7 @@ static MemTxResult vtd_mem_ir_write(void *opaque, hwaddr addr, ...@@ -2293,11 +2299,7 @@ static MemTxResult vtd_mem_ir_write(void *opaque, hwaddr addr,
" for device sid 0x%04x", " for device sid 0x%04x",
to.address, to.data, sid); to.address, to.data, sid);
if (dma_memory_write(&address_space_memory, to.address, apic_get_class()->send_msi(&to);
&to.data, size)) {
VTD_DPRINTF(GENERAL, "error: fail to write 0x%"PRIx64
" value 0x%"PRIx32, to.address, to.data);
}
return MEMTX_OK; return MEMTX_OK;
} }
...@@ -2382,7 +2384,11 @@ static void vtd_init(IntelIOMMUState *s) ...@@ -2382,7 +2384,11 @@ static void vtd_init(IntelIOMMUState *s)
s->ecap = VTD_ECAP_QI | VTD_ECAP_IRO; s->ecap = VTD_ECAP_QI | VTD_ECAP_IRO;
if (x86_iommu->intr_supported) { if (x86_iommu->intr_supported) {
s->ecap |= VTD_ECAP_IR | VTD_ECAP_EIM | VTD_ECAP_MHMV; s->ecap |= VTD_ECAP_IR | VTD_ECAP_MHMV;
if (s->intr_eim == ON_OFF_AUTO_ON) {
s->ecap |= VTD_ECAP_EIM;
}
assert(s->intr_eim != ON_OFF_AUTO_AUTO);
} }
vtd_reset_context_cache(s); vtd_reset_context_cache(s);
...@@ -2463,6 +2469,42 @@ static AddressSpace *vtd_host_dma_iommu(PCIBus *bus, void *opaque, int devfn) ...@@ -2463,6 +2469,42 @@ static AddressSpace *vtd_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
return &vtd_as->as; return &vtd_as->as;
} }
static bool vtd_decide_config(IntelIOMMUState *s, Error **errp)
{
X86IOMMUState *x86_iommu = X86_IOMMU_DEVICE(s);
/* Currently Intel IOMMU IR only support "kernel-irqchip={off|split}" */
if (x86_iommu->intr_supported && kvm_irqchip_in_kernel() &&
!kvm_irqchip_is_split()) {
error_setg(errp, "Intel Interrupt Remapping cannot work with "
"kernel-irqchip=on, please use 'split|off'.");
return false;
}
if (s->intr_eim == ON_OFF_AUTO_ON && !x86_iommu->intr_supported) {
error_setg(errp, "eim=on cannot be selected without intremap=on");
return false;
}
if (s->intr_eim == ON_OFF_AUTO_AUTO) {
s->intr_eim = (kvm_irqchip_in_kernel() || s->buggy_eim)
&& x86_iommu->intr_supported ?
ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
}
if (s->intr_eim == ON_OFF_AUTO_ON && !s->buggy_eim) {
if (!kvm_irqchip_in_kernel()) {
error_setg(errp, "eim=on requires accel=kvm,kernel-irqchip=split");
return false;
}
if (!kvm_enable_x2apic()) {
error_setg(errp, "eim=on requires support on the KVM side"
"(X2APIC_API, first shipped in v4.7)");
return false;
}
}
return true;
}
static void vtd_realize(DeviceState *dev, Error **errp) static void vtd_realize(DeviceState *dev, Error **errp)
{ {
PCMachineState *pcms = PC_MACHINE(qdev_get_machine()); PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
...@@ -2472,6 +2514,11 @@ static void vtd_realize(DeviceState *dev, Error **errp) ...@@ -2472,6 +2514,11 @@ static void vtd_realize(DeviceState *dev, Error **errp)
VTD_DPRINTF(GENERAL, ""); VTD_DPRINTF(GENERAL, "");
x86_iommu->type = TYPE_INTEL; x86_iommu->type = TYPE_INTEL;
if (!vtd_decide_config(s, errp)) {
return;
}
memset(s->vtd_as_by_bus_num, 0, sizeof(s->vtd_as_by_bus_num)); memset(s->vtd_as_by_bus_num, 0, sizeof(s->vtd_as_by_bus_num));
memory_region_init_io(&s->csrmem, OBJECT(s), &vtd_mem_ops, s, memory_region_init_io(&s->csrmem, OBJECT(s), &vtd_mem_ops, s,
"intel_iommu", DMAR_REG_SIZE); "intel_iommu", DMAR_REG_SIZE);
...@@ -2486,14 +2533,6 @@ static void vtd_realize(DeviceState *dev, Error **errp) ...@@ -2486,14 +2533,6 @@ static void vtd_realize(DeviceState *dev, Error **errp)
pci_setup_iommu(bus, vtd_host_dma_iommu, dev); pci_setup_iommu(bus, vtd_host_dma_iommu, dev);
/* Pseudo address space under root PCI bus. */ /* Pseudo address space under root PCI bus. */
pcms->ioapic_as = vtd_host_dma_iommu(bus, s, Q35_PSEUDO_DEVFN_IOAPIC); pcms->ioapic_as = vtd_host_dma_iommu(bus, s, Q35_PSEUDO_DEVFN_IOAPIC);
/* Currently Intel IOMMU IR only support "kernel-irqchip={off|split}" */
if (x86_iommu->intr_supported && kvm_irqchip_in_kernel() &&
!kvm_irqchip_is_split()) {
error_report("Intel Interrupt Remapping cannot work with "
"kernel-irqchip=on, please use 'split|off'.");
exit(1);
}
} }
static void vtd_class_init(ObjectClass *klass, void *data) static void vtd_class_init(ObjectClass *klass, void *data)
......
...@@ -169,6 +169,17 @@ static void kvm_apic_external_nmi(APICCommonState *s) ...@@ -169,6 +169,17 @@ static void kvm_apic_external_nmi(APICCommonState *s)
run_on_cpu(CPU(s->cpu), do_inject_external_nmi, s); run_on_cpu(CPU(s->cpu), do_inject_external_nmi, s);
} }
static void kvm_send_msi(MSIMessage *msg)
{
int ret;
ret = kvm_irqchip_send_msi(kvm_state, *msg);
if (ret < 0) {
fprintf(stderr, "KVM: injection failed, MSI lost (%s)\n",
strerror(-ret));
}
}
static uint64_t kvm_apic_mem_read(void *opaque, hwaddr addr, static uint64_t kvm_apic_mem_read(void *opaque, hwaddr addr,
unsigned size) unsigned size)
{ {
...@@ -179,13 +190,8 @@ static void kvm_apic_mem_write(void *opaque, hwaddr addr, ...@@ -179,13 +190,8 @@ static void kvm_apic_mem_write(void *opaque, hwaddr addr,
uint64_t data, unsigned size) uint64_t data, unsigned size)
{ {
MSIMessage msg = { .address = addr, .data = data }; MSIMessage msg = { .address = addr, .data = data };
int ret;
ret = kvm_irqchip_send_msi(kvm_state, msg); kvm_send_msi(&msg);
if (ret < 0) {
fprintf(stderr, "KVM: injection failed, MSI lost (%s)\n",
strerror(-ret));
}
} }
static const MemoryRegionOps kvm_apic_io_ops = { static const MemoryRegionOps kvm_apic_io_ops = {
...@@ -232,6 +238,7 @@ static void kvm_apic_class_init(ObjectClass *klass, void *data) ...@@ -232,6 +238,7 @@ static void kvm_apic_class_init(ObjectClass *klass, void *data)
k->enable_tpr_reporting = kvm_apic_enable_tpr_reporting; k->enable_tpr_reporting = kvm_apic_enable_tpr_reporting;
k->vapic_base_update = kvm_apic_vapic_base_update; k->vapic_base_update = kvm_apic_vapic_base_update;
k->external_nmi = kvm_apic_external_nmi; k->external_nmi = kvm_apic_external_nmi;
k->send_msi = kvm_send_msi;
} }
static const TypeInfo kvm_apic_info = { static const TypeInfo kvm_apic_info = {
......
...@@ -68,6 +68,11 @@ static void xen_apic_external_nmi(APICCommonState *s) ...@@ -68,6 +68,11 @@ static void xen_apic_external_nmi(APICCommonState *s)
{ {
} }
static void xen_send_msi(MSIMessage *msi)
{
xen_hvm_inject_msi(msi->address, msi->data);
}
static void xen_apic_class_init(ObjectClass *klass, void *data) static void xen_apic_class_init(ObjectClass *klass, void *data)
{ {
APICCommonClass *k = APIC_COMMON_CLASS(klass); APICCommonClass *k = APIC_COMMON_CLASS(klass);
...@@ -78,6 +83,7 @@ static void xen_apic_class_init(ObjectClass *klass, void *data) ...@@ -78,6 +83,7 @@ static void xen_apic_class_init(ObjectClass *klass, void *data)
k->get_tpr = xen_apic_get_tpr; k->get_tpr = xen_apic_get_tpr;
k->vapic_base_update = xen_apic_vapic_base_update; k->vapic_base_update = xen_apic_vapic_base_update;
k->external_nmi = xen_apic_external_nmi; k->external_nmi = xen_apic_external_nmi;
k->send_msi = xen_send_msi;
} }
static const TypeInfo xen_apic_info = { static const TypeInfo xen_apic_info = {
......
...@@ -740,8 +740,10 @@ static uint32_t apic_mem_readl(void *opaque, hwaddr addr) ...@@ -740,8 +740,10 @@ static uint32_t apic_mem_readl(void *opaque, hwaddr addr)
return val; return val;
} }
static void apic_send_msi(hwaddr addr, uint32_t data) static void apic_send_msi(MSIMessage *msi)
{ {
uint64_t addr = msi->address;
uint32_t data = msi->data;
uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT; uint8_t dest = (addr & MSI_ADDR_DEST_ID_MASK) >> MSI_ADDR_DEST_ID_SHIFT;
uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT; uint8_t vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1; uint8_t dest_mode = (addr >> MSI_ADDR_DEST_MODE_SHIFT) & 0x1;
...@@ -762,7 +764,8 @@ static void apic_mem_writel(void *opaque, hwaddr addr, uint32_t val) ...@@ -762,7 +764,8 @@ static void apic_mem_writel(void *opaque, hwaddr addr, uint32_t val)
* APIC is connected directly to the CPU. * APIC is connected directly to the CPU.
* Mapping them on the global bus happens to work because * Mapping them on the global bus happens to work because
* MSI registers are reserved in APIC MMIO and vice versa. */ * MSI registers are reserved in APIC MMIO and vice versa. */
apic_send_msi(addr, val); MSIMessage msi = { .address = addr, .data = val };
apic_send_msi(&msi);
return; return;
} }
...@@ -913,6 +916,7 @@ static void apic_class_init(ObjectClass *klass, void *data) ...@@ -913,6 +916,7 @@ static void apic_class_init(ObjectClass *klass, void *data)
k->external_nmi = apic_external_nmi; k->external_nmi = apic_external_nmi;
k->pre_save = apic_pre_save; k->pre_save = apic_pre_save;
k->post_load = apic_post_load; k->post_load = apic_post_load;
k->send_msi = apic_send_msi;
} }
static const TypeInfo apic_info = { static const TypeInfo apic_info = {
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
* License along with this library; if not, see <http://www.gnu.org/licenses/> * License along with this library; if not, see <http://www.gnu.org/licenses/>
*/ */
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu-common.h" #include "qemu-common.h"
#include "cpu.h" #include "cpu.h"
......
...@@ -14,6 +14,10 @@ ...@@ -14,6 +14,10 @@
.driver = "ioapic",\ .driver = "ioapic",\
.property = "version",\ .property = "version",\
.value = "0x11",\ .value = "0x11",\
},{\
.driver = "intel-iommu",\
.property = "x-buggy-eim",\
.value = "true",\
}, },
#define HW_COMPAT_2_6 \ #define HW_COMPAT_2_6 \
......
...@@ -146,6 +146,10 @@ typedef struct APICCommonClass ...@@ -146,6 +146,10 @@ typedef struct APICCommonClass
void (*pre_save)(APICCommonState *s); void (*pre_save)(APICCommonState *s);
void (*post_load)(APICCommonState *s); void (*post_load)(APICCommonState *s);
void (*reset)(APICCommonState *s); void (*reset)(APICCommonState *s);
/* send_msi emulates an APIC bus and its proper place would be in a new
* device, but it's convenient to have it here for now.
*/
void (*send_msi)(MSIMessage *msi);
} APICCommonClass; } APICCommonClass;
struct APICCommonState { struct APICCommonState {
...@@ -222,4 +226,6 @@ static inline int apic_get_bit(uint32_t *tab, int index) ...@@ -222,4 +226,6 @@ static inline int apic_get_bit(uint32_t *tab, int index)
return !!(tab[i] & mask); return !!(tab[i] & mask);
} }
APICCommonClass *apic_get_class(void);
#endif /* QEMU_APIC_INTERNAL_H */ #endif /* QEMU_APIC_INTERNAL_H */
...@@ -289,6 +289,8 @@ struct IntelIOMMUState { ...@@ -289,6 +289,8 @@ struct IntelIOMMUState {
dma_addr_t intr_root; /* Interrupt remapping table pointer */ dma_addr_t intr_root; /* Interrupt remapping table pointer */
uint32_t intr_size; /* Number of IR table entries */ uint32_t intr_size; /* Number of IR table entries */
bool intr_eime; /* Extended interrupt mode enabled */ bool intr_eime; /* Extended interrupt mode enabled */
OnOffAuto intr_eim; /* Toggle for EIM cabability */
bool buggy_eim; /* Force buggy EIM unless eim=off */
}; };
/* Find the VTD Address space associated with the given bus pointer, /* Find the VTD Address space associated with the given bus pointer,
......
...@@ -3101,10 +3101,31 @@ ...@@ -3101,10 +3101,31 @@
# QEMU version, machine type, machine options and accelerator options. # QEMU version, machine type, machine options and accelerator options.
# A static model is always migration-safe. (since 2.8) # A static model is always migration-safe. (since 2.8)
# #
# @unavailable-features: #optional List of properties that prevent
# the CPU model from running in the current
# host. (since 2.8)
#
# @unavailable-features is a list of QOM property names that
# represent CPU model attributes that prevent the CPU from running.
# If the QOM property is read-only, that means there's no known
# way to make the CPU model run in the current host. Implementations
# that choose not to provide specific information return the
# property name "type".
# If the property is read-write, it means that it MAY be possible
# to run the CPU model in the current host if that property is
# changed. Management software can use it as hints to suggest or
# choose an alternative for the user, or just to generate meaningful
# error messages explaining why the CPU model can't be used.
# If @unavailable-features is an empty list, the CPU model is
# runnable using the current host and machine-type.
# If @unavailable-features is not present, runnability
# information for the CPU is not available.
#
# Since: 1.2.0 # Since: 1.2.0
## ##
{ 'struct': 'CpuDefinitionInfo', { 'struct': 'CpuDefinitionInfo',
'data': { 'name': 'str', '*migration-safe': 'bool', 'static': 'bool' } } 'data': { 'name': 'str', '*migration-safe': 'bool', 'static': 'bool',
'*unavailable-features': [ 'str' ] } }
## ##
# @query-cpu-definitions: # @query-cpu-definitions:
......
...@@ -63,6 +63,10 @@ typedef struct X86CPUClass { ...@@ -63,6 +63,10 @@ typedef struct X86CPUClass {
bool kvm_required; bool kvm_required;
/* Optional description of CPU model.
* If unavailable, cpu_def->model_id is used */
const char *model_description;
DeviceRealize parent_realize; DeviceRealize parent_realize;
void (*parent_reset)(CPUState *cpu); void (*parent_reset)(CPUState *cpu);
} X86CPUClass; } X86CPUClass;
......
此差异已折叠。
...@@ -25,6 +25,11 @@ bool kvm_has_smm(void) ...@@ -25,6 +25,11 @@ bool kvm_has_smm(void)
return 1; return 1;
} }
bool kvm_enable_x2apic(void)
{
return false;
}
/* This function is only called inside conditionals which we /* This function is only called inside conditionals which we
* rely on the compiler to optimize out when CONFIG_KVM is not * rely on the compiler to optimize out when CONFIG_KVM is not
* defined. * defined.
......
...@@ -122,6 +122,32 @@ bool kvm_allows_irq0_override(void) ...@@ -122,6 +122,32 @@ bool kvm_allows_irq0_override(void)
return !kvm_irqchip_in_kernel() || kvm_has_gsi_routing(); return !kvm_irqchip_in_kernel() || kvm_has_gsi_routing();
} }
static bool kvm_x2apic_api_set_flags(uint64_t flags)
{
KVMState *s = KVM_STATE(current_machine->accelerator);
return !kvm_vm_enable_cap(s, KVM_CAP_X2APIC_API, 0, flags);
}
#define MEMORIZE(fn) \
({ \
static typeof(fn) _result; \
static bool _memorized; \
\
if (_memorized) { \
return _result; \
} \
_memorized = true; \
_result = fn; \
})
bool kvm_enable_x2apic(void)
{
return MEMORIZE(
kvm_x2apic_api_set_flags(KVM_X2APIC_API_USE_32BIT_IDS |
KVM_X2APIC_API_DISABLE_BROADCAST_QUIRK));
}
static int kvm_get_tsc(CPUState *cs) static int kvm_get_tsc(CPUState *cs)
{ {
X86CPU *cpu = X86_CPU(cs); X86CPU *cpu = X86_CPU(cs);
......
...@@ -43,4 +43,5 @@ int kvm_device_msix_deassign(KVMState *s, uint32_t dev_id); ...@@ -43,4 +43,5 @@ int kvm_device_msix_deassign(KVMState *s, uint32_t dev_id);
void kvm_put_apicbase(X86CPU *cpu, uint64_t value); void kvm_put_apicbase(X86CPU *cpu, uint64_t value);
bool kvm_enable_x2apic(void);
#endif #endif
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "qapi/qmp/qlist.h" #include "qapi/qmp/qlist.h"
#include "qapi/qmp/qdict.h" #include "qapi/qmp/qdict.h"
#include "qapi/qmp/qint.h" #include "qapi/qmp/qint.h"
#include "qapi/qmp/qbool.h"
#include "libqtest.h" #include "libqtest.h"
static char *get_cpu0_qom_path(void) static char *get_cpu0_qom_path(void)
...@@ -34,6 +35,15 @@ static QObject *qom_get(const char *path, const char *prop) ...@@ -34,6 +35,15 @@ static QObject *qom_get(const char *path, const char *prop)
return ret; return ret;
} }
static bool qom_get_bool(const char *path, const char *prop)
{
QBool *value = qobject_to_qbool(qom_get(path, prop));
bool b = qbool_get_bool(value);
QDECREF(value);
return b;
}
typedef struct CpuidTestArgs { typedef struct CpuidTestArgs {
const char *cmdline; const char *cmdline;
const char *property; const char *property;
...@@ -66,10 +76,44 @@ static void add_cpuid_test(const char *name, const char *cmdline, ...@@ -66,10 +76,44 @@ static void add_cpuid_test(const char *name, const char *cmdline,
qtest_add_data_func(name, args, test_cpuid_prop); qtest_add_data_func(name, args, test_cpuid_prop);
} }
static void test_plus_minus(void)
{
char *path;
/* Rules:
* 1)"-foo" overrides "+foo"
* 2) "[+-]foo" overrides "foo=..."
* 3) Old feature names with underscores (e.g. "sse4_2")
* should keep working
*
* Note: rules 1 and 2 are planned to be removed soon, but we
* need to keep compatibility for a while until we start
* warning users about it.
*/
qtest_start("-cpu pentium,-fpu,+fpu,-mce,mce=on,+cx8,cx8=off,+sse4_1,sse4_2=on");
path = get_cpu0_qom_path();
g_assert_false(qom_get_bool(path, "fpu"));
g_assert_false(qom_get_bool(path, "mce"));
g_assert_true(qom_get_bool(path, "cx8"));
/* Test both the original and the alias feature names: */
g_assert_true(qom_get_bool(path, "sse4-1"));
g_assert_true(qom_get_bool(path, "sse4.1"));
g_assert_true(qom_get_bool(path, "sse4-2"));
g_assert_true(qom_get_bool(path, "sse4.2"));
qtest_end();
g_free(path);
}
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
g_test_init(&argc, &argv, NULL); g_test_init(&argc, &argv, NULL);
qtest_add_func("x86/cpuid/parsing-plus-minus", test_plus_minus);
/* Original level values for CPU models: */ /* Original level values for CPU models: */
add_cpuid_test("x86/cpuid/phenom/level", add_cpuid_test("x86/cpuid/phenom/level",
"-cpu phenom", "level", 5); "-cpu phenom", "level", 5);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册