mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
+60
-21
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "intel_iommu_internal.h"
|
||||
@@ -32,6 +33,8 @@
|
||||
#include "hw/i386/x86-iommu.h"
|
||||
#include "hw/pci-host/q35.h"
|
||||
#include "sysemu/kvm.h"
|
||||
#include "hw/i386/apic_internal.h"
|
||||
#include "kvm_i386.h"
|
||||
|
||||
/*#define DEBUG_INTEL_IOMMU*/
|
||||
#ifdef DEBUG_INTEL_IOMMU
|
||||
@@ -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,
|
||||
hwaddr mesg_data_reg)
|
||||
{
|
||||
hwaddr addr;
|
||||
uint32_t data;
|
||||
MSIMessage msi;
|
||||
|
||||
assert(mesg_data_reg < DMAR_REG_SIZE);
|
||||
assert(mesg_addr_reg < DMAR_REG_SIZE);
|
||||
|
||||
addr = vtd_get_long_raw(s, mesg_addr_reg);
|
||||
data = vtd_get_long_raw(s, mesg_data_reg);
|
||||
msi.address = vtd_get_long_raw(s, mesg_addr_reg);
|
||||
msi.data = vtd_get_long_raw(s, mesg_data_reg);
|
||||
|
||||
VTD_DPRINTF(FLOG, "msi: addr 0x%"PRIx64 " data 0x%"PRIx32, addr, data);
|
||||
address_space_stl_le(&address_space_memory, addr, data,
|
||||
MEMTXATTRS_UNSPECIFIED, NULL);
|
||||
VTD_DPRINTF(FLOG, "msi: addr 0x%"PRIx64 " data 0x%"PRIx32,
|
||||
msi.address, msi.data);
|
||||
apic_get_class()->send_msi(&msi);
|
||||
}
|
||||
|
||||
/* Generate a fault event to software via MSI if conditions are met.
|
||||
@@ -2012,6 +2014,9 @@ static const MemoryRegionOps vtd_mem_ops = {
|
||||
|
||||
static Property vtd_properties[] = {
|
||||
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(),
|
||||
};
|
||||
|
||||
@@ -2134,6 +2139,7 @@ static void vtd_generate_msi_message(VTDIrq *irq, MSIMessage *msg_out)
|
||||
msg.dest_mode = irq->dest_mode;
|
||||
msg.redir_hint = irq->redir_hint;
|
||||
msg.dest = irq->dest;
|
||||
msg.__addr_hi = irq->dest & 0xffffff00;
|
||||
msg.__addr_head = cpu_to_le32(0xfee);
|
||||
/* Keep this from original MSI address bits */
|
||||
msg.__not_used = irq->msi_addr_last_bits;
|
||||
@@ -2293,11 +2299,7 @@ static MemTxResult vtd_mem_ir_write(void *opaque, hwaddr addr,
|
||||
" for device sid 0x%04x",
|
||||
to.address, to.data, sid);
|
||||
|
||||
if (dma_memory_write(&address_space_memory, to.address,
|
||||
&to.data, size)) {
|
||||
VTD_DPRINTF(GENERAL, "error: fail to write 0x%"PRIx64
|
||||
" value 0x%"PRIx32, to.address, to.data);
|
||||
}
|
||||
apic_get_class()->send_msi(&to);
|
||||
|
||||
return MEMTX_OK;
|
||||
}
|
||||
@@ -2382,7 +2384,11 @@ static void vtd_init(IntelIOMMUState *s)
|
||||
s->ecap = VTD_ECAP_QI | VTD_ECAP_IRO;
|
||||
|
||||
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);
|
||||
@@ -2463,6 +2469,42 @@ static AddressSpace *vtd_host_dma_iommu(PCIBus *bus, void *opaque, int devfn)
|
||||
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)
|
||||
{
|
||||
PCMachineState *pcms = PC_MACHINE(qdev_get_machine());
|
||||
@@ -2472,6 +2514,11 @@ static void vtd_realize(DeviceState *dev, Error **errp)
|
||||
|
||||
VTD_DPRINTF(GENERAL, "");
|
||||
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));
|
||||
memory_region_init_io(&s->csrmem, OBJECT(s), &vtd_mem_ops, s,
|
||||
"intel_iommu", DMAR_REG_SIZE);
|
||||
@@ -2486,14 +2533,6 @@ static void vtd_realize(DeviceState *dev, Error **errp)
|
||||
pci_setup_iommu(bus, vtd_host_dma_iommu, dev);
|
||||
/* Pseudo address space under root PCI bus. */
|
||||
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)
|
||||
|
||||
+13
-6
@@ -169,6 +169,17 @@ static void kvm_apic_external_nmi(APICCommonState *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,
|
||||
unsigned size)
|
||||
{
|
||||
@@ -179,13 +190,8 @@ static void kvm_apic_mem_write(void *opaque, hwaddr addr,
|
||||
uint64_t data, unsigned size)
|
||||
{
|
||||
MSIMessage msg = { .address = addr, .data = data };
|
||||
int ret;
|
||||
|
||||
ret = kvm_irqchip_send_msi(kvm_state, msg);
|
||||
if (ret < 0) {
|
||||
fprintf(stderr, "KVM: injection failed, MSI lost (%s)\n",
|
||||
strerror(-ret));
|
||||
}
|
||||
kvm_send_msi(&msg);
|
||||
}
|
||||
|
||||
static const MemoryRegionOps kvm_apic_io_ops = {
|
||||
@@ -232,6 +238,7 @@ static void kvm_apic_class_init(ObjectClass *klass, void *data)
|
||||
k->enable_tpr_reporting = kvm_apic_enable_tpr_reporting;
|
||||
k->vapic_base_update = kvm_apic_vapic_base_update;
|
||||
k->external_nmi = kvm_apic_external_nmi;
|
||||
k->send_msi = kvm_send_msi;
|
||||
}
|
||||
|
||||
static const TypeInfo kvm_apic_info = {
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
APICCommonClass *k = APIC_COMMON_CLASS(klass);
|
||||
@@ -78,6 +83,7 @@ static void xen_apic_class_init(ObjectClass *klass, void *data)
|
||||
k->get_tpr = xen_apic_get_tpr;
|
||||
k->vapic_base_update = xen_apic_vapic_base_update;
|
||||
k->external_nmi = xen_apic_external_nmi;
|
||||
k->send_msi = xen_send_msi;
|
||||
}
|
||||
|
||||
static const TypeInfo xen_apic_info = {
|
||||
|
||||
+6
-2
@@ -740,8 +740,10 @@ static uint32_t apic_mem_readl(void *opaque, hwaddr addr)
|
||||
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 vector = (data & MSI_DATA_VECTOR_MASK) >> MSI_DATA_VECTOR_SHIFT;
|
||||
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)
|
||||
* APIC is connected directly to the CPU.
|
||||
* Mapping them on the global bus happens to work because
|
||||
* 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;
|
||||
}
|
||||
|
||||
@@ -913,6 +916,7 @@ static void apic_class_init(ObjectClass *klass, void *data)
|
||||
k->external_nmi = apic_external_nmi;
|
||||
k->pre_save = apic_pre_save;
|
||||
k->post_load = apic_post_load;
|
||||
k->send_msi = apic_send_msi;
|
||||
}
|
||||
|
||||
static const TypeInfo apic_info = {
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
#include "qemu/osdep.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu-common.h"
|
||||
#include "cpu.h"
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
.driver = "ioapic",\
|
||||
.property = "version",\
|
||||
.value = "0x11",\
|
||||
},{\
|
||||
.driver = "intel-iommu",\
|
||||
.property = "x-buggy-eim",\
|
||||
.value = "true",\
|
||||
},
|
||||
|
||||
#define HW_COMPAT_2_6 \
|
||||
|
||||
@@ -146,6 +146,10 @@ typedef struct APICCommonClass
|
||||
void (*pre_save)(APICCommonState *s);
|
||||
void (*post_load)(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;
|
||||
|
||||
struct APICCommonState {
|
||||
@@ -222,4 +226,6 @@ static inline int apic_get_bit(uint32_t *tab, int index)
|
||||
return !!(tab[i] & mask);
|
||||
}
|
||||
|
||||
APICCommonClass *apic_get_class(void);
|
||||
|
||||
#endif /* QEMU_APIC_INTERNAL_H */
|
||||
|
||||
@@ -289,6 +289,8 @@ struct IntelIOMMUState {
|
||||
dma_addr_t intr_root; /* Interrupt remapping table pointer */
|
||||
uint32_t intr_size; /* Number of IR table entries */
|
||||
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,
|
||||
|
||||
+22
-1
@@ -3101,10 +3101,31 @@
|
||||
# QEMU version, machine type, machine options and accelerator options.
|
||||
# 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
|
||||
##
|
||||
{ 'struct': 'CpuDefinitionInfo',
|
||||
'data': { 'name': 'str', '*migration-safe': 'bool', 'static': 'bool' } }
|
||||
'data': { 'name': 'str', '*migration-safe': 'bool', 'static': 'bool',
|
||||
'*unavailable-features': [ 'str' ] } }
|
||||
|
||||
##
|
||||
# @query-cpu-definitions:
|
||||
|
||||
@@ -63,6 +63,10 @@ typedef struct X86CPUClass {
|
||||
|
||||
bool kvm_required;
|
||||
|
||||
/* Optional description of CPU model.
|
||||
* If unavailable, cpu_def->model_id is used */
|
||||
const char *model_description;
|
||||
|
||||
DeviceRealize parent_realize;
|
||||
void (*parent_reset)(CPUState *cpu);
|
||||
} X86CPUClass;
|
||||
|
||||
+327
-194
File diff suppressed because it is too large
Load Diff
@@ -25,6 +25,11 @@ bool kvm_has_smm(void)
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool kvm_enable_x2apic(void)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* This function is only called inside conditionals which we
|
||||
* rely on the compiler to optimize out when CONFIG_KVM is not
|
||||
* defined.
|
||||
|
||||
@@ -122,6 +122,32 @@ bool kvm_allows_irq0_override(void)
|
||||
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)
|
||||
{
|
||||
X86CPU *cpu = X86_CPU(cs);
|
||||
|
||||
@@ -43,4 +43,5 @@ int kvm_device_msix_deassign(KVMState *s, uint32_t dev_id);
|
||||
|
||||
void kvm_put_apicbase(X86CPU *cpu, uint64_t value);
|
||||
|
||||
bool kvm_enable_x2apic(void);
|
||||
#endif
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "qapi/qmp/qlist.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi/qmp/qint.h"
|
||||
#include "qapi/qmp/qbool.h"
|
||||
#include "libqtest.h"
|
||||
|
||||
static char *get_cpu0_qom_path(void)
|
||||
@@ -34,6 +35,15 @@ static QObject *qom_get(const char *path, const char *prop)
|
||||
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 {
|
||||
const char *cmdline;
|
||||
const char *property;
|
||||
@@ -66,10 +76,44 @@ static void add_cpuid_test(const char *name, const char *cmdline,
|
||||
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)
|
||||
{
|
||||
g_test_init(&argc, &argv, NULL);
|
||||
|
||||
qtest_add_func("x86/cpuid/parsing-plus-minus", test_plus_minus);
|
||||
|
||||
/* Original level values for CPU models: */
|
||||
add_cpuid_test("x86/cpuid/phenom/level",
|
||||
"-cpu phenom", "level", 5);
|
||||
|
||||
Reference in New Issue
Block a user