aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2015-10-06 13:42:33 +0100
committerPeter Maydell <peter.maydell@linaro.org>2015-10-06 13:42:33 +0100
commit5fdb4671b08e0d1631447e81348b2b50a6b85bf7 (patch)
tree74f90ebc7549b56e3727fe697eae1f30e8a603b6
parent006d5c741bbfcdbedeb59e14527fe58d45c9c76b (diff)
parentdfeb8679db358e1f8e0ee4dd84f903d71f000378 (diff)
Merge remote-tracking branch 'remotes/ehabkost/tags/x86-pull-request' into staging
X86 queue, 2015-10-05 # gpg: Signature made Mon 05 Oct 2015 17:04:38 BST using RSA key ID 984DC5A6 # gpg: Good signature from "Eduardo Habkost <ehabkost@redhat.com>" * remotes/ehabkost/tags/x86-pull-request: icc_bus: drop the unused files cpu/apic: drop icc bus/bridge x86: use new method to correct reset sequence apic: move APIC's MMIO region mapping into APIC Correctly re-init EFER state during INIT IPI target-i386: add ABM to Haswell* and Broadwell* CPU models target-i386: get/put MSR_TSC_AUX across reset and migration target-i386: Make check_hw_breakpoints static target-i386: Move breakpoint related functions to new file target-i386: Convert kvm_default_*features to property/value pairs vl: Add another sanity check to smp_parse() function cpu: Introduce X86CPUTopoInfo structure for argument simplification Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
-rw-r--r--default-configs/i386-softmmu.mak1
-rw-r--r--default-configs/x86_64-softmmu.mak1
-rw-r--r--hw/cpu/Makefile.objs1
-rw-r--r--hw/cpu/icc_bus.c118
-rw-r--r--hw/i386/pc.c52
-rw-r--r--hw/i386/pc_piix.c17
-rw-r--r--hw/i386/pc_q35.c13
-rw-r--r--hw/intc/apic_common.c11
-rw-r--r--include/hw/cpu/icc_bus.h82
-rw-r--r--include/hw/i386/apic_internal.h7
-rw-r--r--include/hw/i386/pc.h24
-rw-r--r--include/hw/i386/topology.h33
-rw-r--r--target-i386/Makefile.objs2
-rw-r--r--target-i386/bpt_helper.c182
-rw-r--r--target-i386/cpu.c119
-rw-r--r--target-i386/cpu.h14
-rw-r--r--target-i386/helper.c128
-rw-r--r--target-i386/kvm.c14
-rw-r--r--target-i386/misc_helper.c34
-rw-r--r--vl.c8
20 files changed, 364 insertions, 497 deletions
diff --git a/default-configs/i386-softmmu.mak b/default-configs/i386-softmmu.mak
index 9393cf0ac9..43c96d1c91 100644
--- a/default-configs/i386-softmmu.mak
+++ b/default-configs/i386-softmmu.mak
@@ -44,7 +44,6 @@ CONFIG_LPC_ICH9=y
CONFIG_PCI_Q35=y
CONFIG_APIC=y
CONFIG_IOAPIC=y
-CONFIG_ICC_BUS=y
CONFIG_PVPANIC=y
CONFIG_MEM_HOTPLUG=y
CONFIG_XIO3130=y
diff --git a/default-configs/x86_64-softmmu.mak b/default-configs/x86_64-softmmu.mak
index 28e2099187..dfb80954d4 100644
--- a/default-configs/x86_64-softmmu.mak
+++ b/default-configs/x86_64-softmmu.mak
@@ -44,7 +44,6 @@ CONFIG_LPC_ICH9=y
CONFIG_PCI_Q35=y
CONFIG_APIC=y
CONFIG_IOAPIC=y
-CONFIG_ICC_BUS=y
CONFIG_PVPANIC=y
CONFIG_MEM_HOTPLUG=y
CONFIG_XIO3130=y
diff --git a/hw/cpu/Makefile.objs b/hw/cpu/Makefile.objs
index 6381238cc5..0954a1872f 100644
--- a/hw/cpu/Makefile.objs
+++ b/hw/cpu/Makefile.objs
@@ -2,5 +2,4 @@ obj-$(CONFIG_ARM11MPCORE) += arm11mpcore.o
obj-$(CONFIG_REALVIEW) += realview_mpcore.o
obj-$(CONFIG_A9MPCORE) += a9mpcore.o
obj-$(CONFIG_A15MPCORE) += a15mpcore.o
-obj-$(CONFIG_ICC_BUS) += icc_bus.o
diff --git a/hw/cpu/icc_bus.c b/hw/cpu/icc_bus.c
deleted file mode 100644
index 6646ea2b34..0000000000
--- a/hw/cpu/icc_bus.c
+++ /dev/null
@@ -1,118 +0,0 @@
-/* icc_bus.c
- * emulate x86 ICC (Interrupt Controller Communications) bus
- *
- * Copyright (c) 2013 Red Hat, Inc
- *
- * Authors:
- * Igor Mammedov <imammedo@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>
- */
-#include "hw/cpu/icc_bus.h"
-#include "hw/sysbus.h"
-
-/* icc-bridge implementation */
-
-static const TypeInfo icc_bus_info = {
- .name = TYPE_ICC_BUS,
- .parent = TYPE_BUS,
- .instance_size = sizeof(ICCBus),
-};
-
-
-/* icc-device implementation */
-
-static void icc_device_realize(DeviceState *dev, Error **errp)
-{
- ICCDeviceClass *idc = ICC_DEVICE_GET_CLASS(dev);
-
- /* convert to QOM */
- if (idc->realize) {
- idc->realize(dev, errp);
- }
-
-}
-
-static void icc_device_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- dc->realize = icc_device_realize;
- dc->bus_type = TYPE_ICC_BUS;
-}
-
-static const TypeInfo icc_device_info = {
- .name = TYPE_ICC_DEVICE,
- .parent = TYPE_DEVICE,
- .abstract = true,
- .instance_size = sizeof(ICCDevice),
- .class_size = sizeof(ICCDeviceClass),
- .class_init = icc_device_class_init,
-};
-
-
-/* icc-bridge implementation */
-
-typedef struct ICCBridgeState {
- /*< private >*/
- SysBusDevice parent_obj;
- /*< public >*/
-
- ICCBus icc_bus;
- MemoryRegion apic_container;
-} ICCBridgeState;
-
-#define ICC_BRIDGE(obj) OBJECT_CHECK(ICCBridgeState, (obj), TYPE_ICC_BRIDGE)
-
-static void icc_bridge_init(Object *obj)
-{
- ICCBridgeState *s = ICC_BRIDGE(obj);
- SysBusDevice *sb = SYS_BUS_DEVICE(obj);
-
- qbus_create_inplace(&s->icc_bus, sizeof(s->icc_bus), TYPE_ICC_BUS,
- DEVICE(s), "icc");
-
- /* Do not change order of registering regions,
- * APIC must be first registered region, board maps it by 0 index
- */
- memory_region_init(&s->apic_container, obj, "icc-apic-container",
- APIC_SPACE_SIZE);
- sysbus_init_mmio(sb, &s->apic_container);
- s->icc_bus.apic_address_space = &s->apic_container;
-}
-
-static void icc_bridge_class_init(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
-
- set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
-}
-
-static const TypeInfo icc_bridge_info = {
- .name = TYPE_ICC_BRIDGE,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_init = icc_bridge_init,
- .instance_size = sizeof(ICCBridgeState),
- .class_init = icc_bridge_class_init,
-};
-
-
-static void icc_bus_register_types(void)
-{
- type_register_static(&icc_bus_info);
- type_register_static(&icc_device_info);
- type_register_static(&icc_bridge_info);
-}
-
-type_init(icc_bus_register_types)
diff --git a/hw/i386/pc.c b/hw/i386/pc.c
index efbd41a1f1..9275297adc 100644
--- a/hw/i386/pc.c
+++ b/hw/i386/pc.c
@@ -59,7 +59,6 @@
#include "qemu/error-report.h"
#include "hw/acpi/acpi.h"
#include "hw/acpi/cpu_hotplug.h"
-#include "hw/cpu/icc_bus.h"
#include "hw/boards.h"
#include "hw/pci/pci_host.h"
#include "acpi-build.h"
@@ -1052,23 +1051,16 @@ void pc_acpi_smi_interrupt(void *opaque, int irq, int level)
}
static X86CPU *pc_new_cpu(const char *cpu_model, int64_t apic_id,
- DeviceState *icc_bridge, Error **errp)
+ Error **errp)
{
X86CPU *cpu = NULL;
Error *local_err = NULL;
- if (icc_bridge == NULL) {
- error_setg(&local_err, "Invalid icc-bridge value");
- goto out;
- }
-
cpu = cpu_x86_create(cpu_model, &local_err);
if (local_err != NULL) {
goto out;
}
- qdev_set_parent_bus(DEVICE(cpu), qdev_get_child_bus(icc_bridge, "icc"));
-
object_property_set_int(OBJECT(cpu), apic_id, "apic-id", &local_err);
object_property_set_bool(OBJECT(cpu), true, "realized", &local_err);
@@ -1085,7 +1077,6 @@ static const char *current_cpu_model;
void pc_hot_add_cpu(const int64_t id, Error **errp)
{
- DeviceState *icc_bridge;
X86CPU *cpu;
int64_t apic_id = x86_cpu_apic_id_from_index(id);
Error *local_err = NULL;
@@ -1114,9 +1105,7 @@ void pc_hot_add_cpu(const int64_t id, Error **errp)
return;
}
- icc_bridge = DEVICE(object_resolve_path_type("icc-bridge",
- TYPE_ICC_BRIDGE, NULL));
- cpu = pc_new_cpu(current_cpu_model, apic_id, icc_bridge, &local_err);
+ cpu = pc_new_cpu(current_cpu_model, apic_id, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return;
@@ -1124,7 +1113,7 @@ void pc_hot_add_cpu(const int64_t id, Error **errp)
object_unref(OBJECT(cpu));
}
-void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge)
+void pc_cpus_init(const char *cpu_model)
{
int i;
X86CPU *cpu = NULL;
@@ -1150,7 +1139,7 @@ void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge)
for (i = 0; i < smp_cpus; i++) {
cpu = pc_new_cpu(cpu_model, x86_cpu_apic_id_from_index(i),
- icc_bridge, &error);
+ &error);
if (error) {
error_report_err(error);
exit(1);
@@ -1158,13 +1147,6 @@ void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge)
object_unref(OBJECT(cpu));
}
- /* map APIC MMIO area if CPU has APIC */
- if (cpu && cpu->apic_state) {
- /* XXX: what if the base changes? */
- sysbus_mmio_map_overlap(SYS_BUS_DEVICE(icc_bridge), 0,
- APIC_DEFAULT_ADDRESS, 0x1000);
- }
-
/* tell smbios about cpuid version and features */
smbios_set_cpuid(cpu->env.cpuid_version, cpu->env.features[FEAT_1_EDX]);
}
@@ -1933,12 +1915,31 @@ static void pc_machine_initfn(Object *obj)
NULL, &error_abort);
}
+static void pc_machine_reset(void)
+{
+ CPUState *cs;
+ X86CPU *cpu;
+
+ qemu_devices_reset();
+
+ /* Reset APIC after devices have been reset to cancel
+ * any changes that qemu_devices_reset() might have done.
+ */
+ CPU_FOREACH(cs) {
+ cpu = X86_CPU(cs);
+
+ if (cpu->apic_state) {
+ device_reset(cpu->apic_state);
+ }
+ }
+}
+
static unsigned pc_cpu_index_to_socket_id(unsigned cpu_index)
{
- unsigned pkg_id, core_id, smt_id;
+ X86CPUTopoInfo topo;
x86_topo_ids_from_idx(smp_cores, smp_threads, cpu_index,
- &pkg_id, &core_id, &smt_id);
- return pkg_id;
+ &topo);
+ return topo.pkg_id;
}
static void pc_machine_class_init(ObjectClass *oc, void *data)
@@ -1954,6 +1955,7 @@ static void pc_machine_class_init(ObjectClass *oc, void *data)
mc->default_boot_order = "cad";
mc->hot_add_cpu = pc_hot_add_cpu;
mc->max_cpus = 255;
+ mc->reset = pc_machine_reset;
hc->plug = pc_machine_device_plug_cb;
hc->unplug_request = pc_machine_device_unplug_request_cb;
hc->unplug = pc_machine_device_unplug_cb;
diff --git a/hw/i386/pc_piix.c b/hw/i386/pc_piix.c
index 4514cd1462..ae7bbebd0f 100644
--- a/hw/i386/pc_piix.c
+++ b/hw/i386/pc_piix.c
@@ -39,7 +39,6 @@
#include "hw/kvm/clock.h"
#include "sysemu/sysemu.h"
#include "hw/sysbus.h"
-#include "hw/cpu/icc_bus.h"
#include "sysemu/arch_init.h"
#include "sysemu/block-backend.h"
#include "hw/i2c/smbus.h"
@@ -98,7 +97,6 @@ static void pc_init1(MachineState *machine,
MemoryRegion *ram_memory;
MemoryRegion *pci_memory;
MemoryRegion *rom_memory;
- DeviceState *icc_bridge;
PcGuestInfo *guest_info;
ram_addr_t lowmem;
@@ -141,11 +139,7 @@ static void pc_init1(MachineState *machine,
exit(1);
}
- icc_bridge = qdev_create(NULL, TYPE_ICC_BRIDGE);
- object_property_add_child(qdev_get_machine(), "icc-bridge",
- OBJECT(icc_bridge), NULL);
-
- pc_cpus_init(machine->cpu_model, icc_bridge);
+ pc_cpus_init(machine->cpu_model);
if (kvm_enabled() && kvmclock_enabled) {
kvmclock_create();
@@ -226,7 +220,6 @@ static void pc_init1(MachineState *machine,
if (pci_enabled) {
ioapic_init_gsi(gsi_state, "i440fx");
}
- qdev_init_nofail(icc_bridge);
pc_register_ferr_irq(gsi[13]);
@@ -332,7 +325,7 @@ static void pc_compat_2_1(MachineState *machine)
pc_compat_2_2(machine);
smbios_uuid_encoded = false;
- x86_cpu_compat_kvm_no_autodisable(FEAT_8000_0001_ECX, CPUID_EXT3_SVM);
+ x86_cpu_change_kvm_default("svm", NULL);
pcms->enforce_aligned_dimm = false;
}
@@ -368,7 +361,7 @@ static void pc_compat_1_7(MachineState *machine)
gigabyte_align = false;
option_rom_has_mr = true;
legacy_acpi_table_size = 6414;
- x86_cpu_compat_kvm_no_autoenable(FEAT_1_ECX, CPUID_EXT_X2APIC);
+ x86_cpu_change_kvm_default("x2apic", NULL);
}
static void pc_compat_1_6(MachineState *machine)
@@ -398,7 +391,7 @@ static void pc_compat_1_3(MachineState *machine)
static void pc_compat_1_2(MachineState *machine)
{
pc_compat_1_3(machine);
- x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, 1 << KVM_FEATURE_PV_EOI);
+ x86_cpu_change_kvm_default("kvm-pv-eoi", NULL);
}
/* PC compat function for pc-0.10 to pc-0.13 */
@@ -421,7 +414,7 @@ static void pc_init_isa(MachineState *machine)
if (!machine->cpu_model) {
machine->cpu_model = "486";
}
- x86_cpu_compat_kvm_no_autoenable(FEAT_KVM, 1 << KVM_FEATURE_PV_EOI);
+ x86_cpu_change_kvm_default("kvm-pv-eoi", NULL);
enable_compat_apic_id_mode();
pc_init1(machine, TYPE_I440FX_PCI_HOST_BRIDGE, TYPE_I440FX_PCI_DEVICE);
}
diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c
index 1f100b1a69..19e66702e0 100644
--- a/hw/i386/pc_q35.c
+++ b/hw/i386/pc_q35.c
@@ -43,7 +43,6 @@
#include "hw/ide/pci.h"
#include "hw/ide/ahci.h"
#include "hw/usb.h"
-#include "hw/cpu/icc_bus.h"
#include "qemu/error-report.h"
#include "migration/migration.h"
@@ -83,7 +82,6 @@ static void pc_q35_init(MachineState *machine)
int i;
ICH9LPCState *ich9_lpc;
PCIDevice *ahci;
- DeviceState *icc_bridge;
PcGuestInfo *guest_info;
ram_addr_t lowmem;
DriveInfo *hd[MAX_SATA_PORTS];
@@ -130,11 +128,7 @@ static void pc_q35_init(MachineState *machine)
exit(1);
}
- icc_bridge = qdev_create(NULL, TYPE_ICC_BRIDGE);
- object_property_add_child(qdev_get_machine(), "icc-bridge",
- OBJECT(icc_bridge), NULL);
-
- pc_cpus_init(machine->cpu_model, icc_bridge);
+ pc_cpus_init(machine->cpu_model);
pc_acpi_init("q35-acpi-dsdt.aml");
kvmclock_create();
@@ -236,7 +230,6 @@ static void pc_q35_init(MachineState *machine)
if (pci_enabled) {
ioapic_init_gsi(gsi_state, "q35");
}
- qdev_init_nofail(icc_bridge);
pc_register_ferr_irq(gsi[13]);
@@ -316,7 +309,7 @@ static void pc_compat_2_1(MachineState *machine)
pc_compat_2_2(machine);
pcms->enforce_aligned_dimm = false;
smbios_uuid_encoded = false;
- x86_cpu_compat_kvm_no_autodisable(FEAT_8000_0001_ECX, CPUID_EXT3_SVM);
+ x86_cpu_change_kvm_default("svm", NULL);
}
static void pc_compat_2_0(MachineState *machine)
@@ -333,7 +326,7 @@ static void pc_compat_1_7(MachineState *machine)
smbios_defaults = false;
gigabyte_align = false;
option_rom_has_mr = true;
- x86_cpu_compat_kvm_no_autoenable(FEAT_1_ECX, CPUID_EXT_X2APIC);
+ x86_cpu_change_kvm_default("x2apic", NULL);
}
static void pc_compat_1_6(MachineState *machine)
diff --git a/hw/intc/apic_common.c b/hw/intc/apic_common.c
index 0032b97c5f..ad959c4e77 100644
--- a/hw/intc/apic_common.c
+++ b/hw/intc/apic_common.c
@@ -296,7 +296,6 @@ static void apic_common_realize(DeviceState *dev, Error **errp)
APICCommonClass *info;
static DeviceState *vapic;
static int apic_no;
- static bool mmio_registered;
if (apic_no >= MAX_APICS) {
error_setg(errp, "%s initialization failed.",
@@ -307,11 +306,6 @@ static void apic_common_realize(DeviceState *dev, Error **errp)
info = APIC_COMMON_GET_CLASS(s);
info->realize(dev, errp);
- if (!mmio_registered) {
- ICCBus *b = ICC_BUS(qdev_get_parent_bus(dev));
- memory_region_add_subregion(b->apic_address_space, 0, &s->io_memory);
- mmio_registered = true;
- }
/* Note: We need at least 1M to map the VAPIC option ROM */
if (!vapic && s->vapic_control & VAPIC_ENABLE_MASK &&
@@ -425,13 +419,12 @@ static Property apic_properties_common[] = {
static void apic_common_class_init(ObjectClass *klass, void *data)
{
- ICCDeviceClass *idc = ICC_DEVICE_CLASS(klass);
DeviceClass *dc = DEVICE_CLASS(klass);
dc->vmsd = &vmstate_apic_common;
dc->reset = apic_reset_common;
dc->props = apic_properties_common;
- idc->realize = apic_common_realize;
+ dc->realize = apic_common_realize;
/*
* Reason: APIC and CPU need to be wired up by
* x86_cpu_apic_create()
@@ -441,7 +434,7 @@ static void apic_common_class_init(ObjectClass *klass, void *data)
static const TypeInfo apic_common_type = {
.name = TYPE_APIC_COMMON,
- .parent = TYPE_ICC_DEVICE,
+ .parent = TYPE_DEVICE,
.instance_size = sizeof(APICCommonState),
.class_size = sizeof(APICCommonClass),
.class_init = apic_common_class_init,
diff --git a/include/hw/cpu/icc_bus.h b/include/hw/cpu/icc_bus.h
deleted file mode 100644
index 98a979fa1c..0000000000
--- a/include/hw/cpu/icc_bus.h
+++ /dev/null
@@ -1,82 +0,0 @@
-/* icc_bus.h
- * emulate x86 ICC (Interrupt Controller Communications) bus
- *
- * Copyright (c) 2013 Red Hat, Inc
- *
- * Authors:
- * Igor Mammedov <imammedo@redhat.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, see <http://www.gnu.org/licenses/>
- */
-#ifndef ICC_BUS_H
-#define ICC_BUS_H
-
-#include "exec/memory.h"
-#include "hw/qdev-core.h"
-
-#define TYPE_ICC_BUS "icc-bus"
-
-#ifndef CONFIG_USER_ONLY
-
-/**
- * ICCBus:
- *
- * ICC bus
- */
-typedef struct ICCBus {
- /*< private >*/
- BusState parent_obj;
- /*< public >*/
-
- MemoryRegion *apic_address_space;
-} ICCBus;
-
-#define ICC_BUS(obj) OBJECT_CHECK(ICCBus, (obj), TYPE_ICC_BUS)
-
-/**
- * ICCDevice:
- *
- * ICC device
- */
-typedef struct ICCDevice {
- /*< private >*/
- DeviceState qdev;
- /*< public >*/
-} ICCDevice;
-
-/**
- * ICCDeviceClass:
- * @init: Initialization callback for derived classes.
- *
- * ICC device class
- */
-typedef struct ICCDeviceClass {
- /*< private >*/
- DeviceClass parent_class;
- /*< public >*/
-
- DeviceRealize realize;
-} ICCDeviceClass;
-
-#define TYPE_ICC_DEVICE "icc-device"
-#define ICC_DEVICE(obj) OBJECT_CHECK(ICCDevice, (obj), TYPE_ICC_DEVICE)
-#define ICC_DEVICE_CLASS(klass) \
- OBJECT_CLASS_CHECK(ICCDeviceClass, (klass), TYPE_ICC_DEVICE)
-#define ICC_DEVICE_GET_CLASS(obj) \
- OBJECT_GET_CLASS(ICCDeviceClass, (obj), TYPE_ICC_DEVICE)
-
-#define TYPE_ICC_BRIDGE "icc-bridge"
-
-#endif /* CONFIG_USER_ONLY */
-#endif
diff --git a/include/hw/i386/apic_internal.h b/include/hw/i386/apic_internal.h
index 7813396e49..74fe935e8e 100644
--- a/include/hw/i386/apic_internal.h
+++ b/include/hw/i386/apic_internal.h
@@ -22,7 +22,6 @@
#include "cpu.h"
#include "exec/memory.h"
-#include "hw/cpu/icc_bus.h"
#include "qemu/timer.h"
/* APIC Local Vector Table */
@@ -135,7 +134,7 @@ typedef struct APICCommonState APICCommonState;
typedef struct APICCommonClass
{
- ICCDeviceClass parent_class;
+ DeviceClass parent_class;
DeviceRealize realize;
void (*set_base)(APICCommonState *s, uint64_t val);
@@ -150,7 +149,9 @@ typedef struct APICCommonClass
} APICCommonClass;
struct APICCommonState {
- ICCDevice busdev;
+ /*< private >*/
+ DeviceState parent_obj;
+ /*< public >*/
MemoryRegion io_memory;
X86CPU *cpu;
diff --git a/include/hw/i386/pc.h b/include/hw/i386/pc.h
index c13e91ddde..0503485cd0 100644
--- a/include/hw/i386/pc.h
+++ b/include/hw/i386/pc.h
@@ -168,7 +168,7 @@ bool pc_machine_is_smm_enabled(PCMachineState *pcms);
void pc_register_ferr_irq(qemu_irq irq);
void pc_acpi_smi_interrupt(void *opaque, int irq, int level);
-void pc_cpus_init(const char *cpu_model, DeviceState *icc_bridge);
+void pc_cpus_init(const char *cpu_model);
void pc_hot_add_cpu(const int64_t id, Error **errp);
void pc_acpi_init(const char *default_dsdt);
@@ -298,7 +298,27 @@ int e820_get_num_entries(void);
bool e820_get_entry(int, uint32_t, uint64_t *, uint64_t *);
#define PC_COMPAT_2_4 \
- HW_COMPAT_2_4
+ HW_COMPAT_2_4 \
+ {\
+ .driver = "Haswell-" TYPE_X86_CPU,\
+ .property = "abm",\
+ .value = "off",\
+ },\
+ {\
+ .driver = "Haswell-noTSX-" TYPE_X86_CPU,\
+ .property = "abm",\
+ .value = "off",\
+ },\
+ {\
+ .driver = "Broadwell-" TYPE_X86_CPU,\
+ .property = "abm",\
+ .value = "off",\
+ },\
+ {\
+ .driver = "Broadwell-noTSX-" TYPE_X86_CPU,\
+ .property = "abm",\
+ .value = "off",\
+ },
#define PC_COMPAT_2_3 \
PC_COMPAT_2_4 \
diff --git a/include/hw/i386/topology.h b/include/hw/i386/topology.h
index 9c6f3a937a..148cc1bbc8 100644
--- a/include/hw/i386/topology.h
+++ b/include/hw/i386/topology.h
@@ -47,6 +47,12 @@
*/
typedef uint32_t apic_id_t;
+typedef struct X86CPUTopoInfo {
+ unsigned pkg_id;
+ unsigned core_id;
+ unsigned smt_id;
+} X86CPUTopoInfo;
+
/* Return the bit width needed for 'count' IDs
*/
static unsigned apicid_bitwidth_for_count(unsigned count)
@@ -92,13 +98,11 @@ static inline unsigned apicid_pkg_offset(unsigned nr_cores, unsigned nr_threads)
*/
static inline apic_id_t apicid_from_topo_ids(unsigned nr_cores,
unsigned nr_threads,
- unsigned pkg_id,
- unsigned core_id,
- unsigned smt_id)
+ const X86CPUTopoInfo *topo)
{
- return (pkg_id << apicid_pkg_offset(nr_cores, nr_threads)) |
- (core_id << apicid_core_offset(nr_cores, nr_threads)) |
- smt_id;
+ return (topo->pkg_id << apicid_pkg_offset(nr_cores, nr_threads)) |
+ (topo->core_id << apicid_core_offset(nr_cores, nr_threads)) |
+ topo->smt_id;
}
/* Calculate thread/core/package IDs for a specific topology,
@@ -107,14 +111,12 @@ static inline apic_id_t apicid_from_topo_ids(unsigned nr_cores,
static inline void x86_topo_ids_from_idx(unsigned nr_cores,
unsigned nr_threads,
unsigned cpu_index,
- unsigned *pkg_id,
- unsigned *core_id,
- unsigned *smt_id)
+ X86CPUTopoInfo *topo)
{
unsigned core_index = cpu_index / nr_threads;
- *smt_id = cpu_index % nr_threads;
- *core_id = core_index % nr_cores;
- *pkg_id = core_index / nr_cores;
+ topo->smt_id = cpu_index % nr_threads;
+ topo->core_id = core_index % nr_cores;
+ topo->pkg_id = core_index / nr_cores;
}
/* Make APIC ID for the CPU 'cpu_index'
@@ -125,10 +127,9 @@ static inline apic_id_t x86_apicid_from_cpu_idx(unsigned nr_cores,
unsigned nr_threads,
unsigned cpu_index)
{
- unsigned pkg_id, core_id, smt_id;
- x86_topo_ids_from_idx(nr_cores, nr_threads, cpu_index,
- &pkg_id, &core_id, &smt_id);
- return apicid_from_topo_ids(nr_cores, nr_threads, pkg_id, core_id, smt_id);
+ X86CPUTopoInfo topo;
+ x86_topo_ids_from_idx(nr_cores, nr_threads, cpu_index, &topo);
+ return apicid_from_topo_ids(nr_cores, nr_threads, &topo);
}
#endif /* HW_I386_TOPOLOGY_H */
diff --git a/target-i386/Makefile.objs b/target-i386/Makefile.objs
index 3da413e8bd..437d9975b9 100644
--- a/target-i386/Makefile.objs
+++ b/target-i386/Makefile.objs
@@ -1,4 +1,4 @@
-obj-y += translate.o helper.o cpu.o
+obj-y += translate.o helper.o cpu.o bpt_helper.o
obj-y += excp_helper.o fpu_helper.o cc_helper.o int_helper.o svm_helper.o
obj-y += smm_helper.o misc_helper.o mem_helper.o seg_helper.o
obj-y += gdbstub.o
diff --git a/target-i386/bpt_helper.c b/target-i386/bpt_helper.c
new file mode 100644
index 0000000000..c071c24782
--- /dev/null
+++ b/target-i386/bpt_helper.c
@@ -0,0 +1,182 @@
+/*
+ * i386 breakpoint helpers
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "cpu.h"
+#include "exec/helper-proto.h"
+
+
+void hw_breakpoint_insert(CPUX86State *env, int index)
+{
+ CPUState *cs = CPU(x86_env_get_cpu(env));
+ int type = 0, err = 0;
+
+ switch (hw_breakpoint_type(env->dr[7], index)) {
+ case DR7_TYPE_BP_INST:
+ if (hw_breakpoint_enabled(env->dr[7], index)) {
+ err = cpu_breakpoint_insert(cs, env->dr[index], BP_CPU,
+ &env->cpu_breakpoint[index]);
+ }
+ break;
+ case DR7_TYPE_DATA_WR:
+ type = BP_CPU | BP_MEM_WRITE;
+ break;
+ case DR7_TYPE_IO_RW:
+ /* No support for I/O watchpoints yet */
+ break;
+ case DR7_TYPE_DATA_RW:
+ type = BP_CPU | BP_MEM_ACCESS;
+ break;
+ }
+
+ if (type != 0) {
+ err = cpu_watchpoint_insert(cs, env->dr[index],
+ hw_breakpoint_len(env->dr[7], index),
+ type, &env->cpu_watchpoint[index]);
+ }
+
+ if (err) {
+ env->cpu_breakpoint[index] = NULL;
+ }
+}
+
+void hw_breakpoint_remove(CPUX86State *env, int index)
+{
+ CPUState *cs;
+
+ if (!env->cpu_breakpoint[index]) {
+ return;
+ }
+ cs = CPU(x86_env_get_cpu(env));
+ switch (hw_breakpoint_type(env->dr[7], index)) {
+ case DR7_TYPE_BP_INST:
+ if (hw_breakpoint_enabled(env->dr[7], index)) {
+ cpu_breakpoint_remove_by_ref(cs, env->cpu_breakpoint[index]);
+ }
+ break;
+ case DR7_TYPE_DATA_WR:
+ case DR7_TYPE_DATA_RW:
+ cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[index]);
+ break;
+ case DR7_TYPE_IO_RW:
+ /* No support for I/O watchpoints yet */
+ break;
+ }
+}
+
+static bool check_hw_breakpoints(CPUX86State *env, bool force_dr6_update)
+{
+ target_ulong dr6;
+ int reg;
+ bool hit_enabled = false;
+
+ dr6 = env->dr[6] & ~0xf;
+ for (reg = 0; reg < DR7_MAX_BP; reg++) {
+ bool bp_match = false;
+ bool wp_match = false;
+
+ switch (hw_breakpoint_type(env->dr[7], reg)) {
+ case DR7_TYPE_BP_INST:
+ if (env->dr[reg] == env->eip) {
+ bp_match = true;
+ }
+ break;
+ case DR7_TYPE_DATA_WR:
+ case DR7_TYPE_DATA_RW:
+ if (env->cpu_watchpoint[reg] &&
+ env->cpu_watchpoint[reg]->flags & BP_WATCHPOINT_HIT) {
+ wp_match = true;
+ }
+ break;
+ case DR7_TYPE_IO_RW:
+ break;
+ }
+ if (bp_match || wp_match) {
+ dr6 |= 1 << reg;
+ if (hw_breakpoint_enabled(env->dr[7], reg)) {
+ hit_enabled = true;
+ }
+ }
+ }
+
+ if (hit_enabled || force_dr6_update) {
+ env->dr[6] = dr6;
+ }
+
+ return hit_enabled;
+}
+
+void breakpoint_handler(CPUState *cs)
+{
+ X86CPU *cpu = X86_CPU(cs);
+ CPUX86State *env = &cpu->env;
+ CPUBreakpoint *bp;
+
+ if (cs->watchpoint_hit) {
+ if (cs->watchpoint_hit->flags & BP_CPU) {
+ cs->watchpoint_hit = NULL;
+ if (check_hw_breakpoints(env, false)) {
+ raise_exception(env, EXCP01_DB);
+ } else {
+ cpu_resume_from_signal(cs, NULL);
+ }
+ }
+ } else {
+ QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
+ if (bp->pc == env->eip) {
+ if (bp->flags & BP_CPU) {
+ check_hw_breakpoints(env, true);
+ raise_exception(env, EXCP01_DB);
+ }
+ break;
+ }
+ }
+ }
+}
+
+void helper_single_step(CPUX86State *env)
+{
+#ifndef CONFIG_USER_ONLY
+ check_hw_breakpoints(env, true);
+ env->dr[6] |= DR6_BS;
+#endif
+ raise_exception(env, EXCP01_DB);
+}
+
+void helper_movl_drN_T0(CPUX86State *env, int reg, target_ulong t0)
+{
+#ifndef CONFIG_USER_ONLY
+ int i;
+
+ if (reg < 4) {
+ hw_breakpoint_remove(env, reg);
+ env->dr[reg] = t0;
+ hw_breakpoint_insert(env, reg);
+ } else if (reg == 7) {
+ for (i = 0; i < DR7_MAX_BP; i++) {
+ hw_breakpoint_remove(env, i);
+ }
+ env->dr[7] = t0;
+ for (i = 0; i < DR7_MAX_BP; i++) {
+ hw_breakpoint_insert(env, i);
+ }
+ } else {
+ env->dr[reg] = t0;
+ }
+#endif
+}
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index bd411b9d8d..c793812cc2 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -43,7 +43,6 @@
#include "sysemu/sysemu.h"
#include "hw/qdev-properties.h"
-#include "hw/cpu/icc_bus.h"
#ifndef CONFIG_USER_ONLY
#include "exec/address-spaces.h"
#include "hw/xen/xen.h"
@@ -478,38 +477,6 @@ const char *get_register_name_32(unsigned int reg)
return x86_reg_info_32[reg].name;
}
-/* KVM-specific features that are automatically added to all CPU models
- * when KVM is enabled.
- */
-static uint32_t kvm_default_features[FEATURE_WORDS] = {
- [FEAT_KVM] = (1 << KVM_FEATURE_CLOCKSOURCE) |
- (1 << KVM_FEATURE_NOP_IO_DELAY) |
- (1 << KVM_FEATURE_CLOCKSOURCE2) |
- (1 << KVM_FEATURE_ASYNC_PF) |
- (1 << KVM_FEATURE_STEAL_TIME) |
- (1 << KVM_FEATURE_PV_EOI) |
- (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT),
- [FEAT_1_ECX] = CPUID_EXT_X2APIC,
-};
-
-/* Features that are not added by default to any CPU model when KVM is enabled.
- */
-static uint32_t kvm_default_unset_features[FEATURE_WORDS] = {
- [FEAT_1_EDX] = CPUID_ACPI,
- [FEAT_1_ECX] = CPUID_EXT_MONITOR,
- [FEAT_8000_0001_ECX] = CPUID_EXT3_SVM,
-};
-
-void x86_cpu_compat_kvm_no_autoenable(FeatureWord w, uint32_t features)
-{
- kvm_default_features[w] &= ~features;
-}
-
-void x86_cpu_compat_kvm_no_autodisable(FeatureWord w, uint32_t features)
-{
- kvm_default_unset_features[w] &= ~features;
-}
-
/*
* Returns the set of feature flags that are supported and migratable by
* QEMU, for a given FeatureWord.
@@ -1113,7 +1080,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
CPUID_EXT2_SYSCALL,
.features[FEAT_8000_0001_ECX] =
- CPUID_EXT3_LAHF_LM,
+ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM,
.features[FEAT_7_0_EBX] =
CPUID_7_0_EBX_FSGSBASE | CPUID_7_0_EBX_BMI1 |
CPUID_7_0_EBX_AVX2 | CPUID_7_0_EBX_SMEP |
@@ -1148,7 +1115,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
CPUID_EXT2_SYSCALL,
.features[FEAT_8000_0001_ECX] =
- CPUID_EXT3_LAHF_LM,
+ CPUID_EXT3_ABM | CPUID_EXT3_LAHF_LM,
.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 |
@@ -1185,7 +1152,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
CPUID_EXT2_SYSCALL,
.features[FEAT_8000_0001_ECX] =
- CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH,
+ 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_AVX2 | CPUID_7_0_EBX_SMEP |
@@ -1223,7 +1190,7 @@ static X86CPUDefinition builtin_x86_defs[] = {
CPUID_EXT2_LM | CPUID_EXT2_RDTSCP | CPUID_EXT2_NX |
CPUID_EXT2_SYSCALL,
.features[FEAT_8000_0001_ECX] =
- CPUID_EXT3_LAHF_LM | CPUID_EXT3_3DNOWPREFETCH,
+ 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 |
@@ -1392,6 +1359,43 @@ static X86CPUDefinition builtin_x86_defs[] = {
},
};
+typedef struct PropValue {
+ const char *prop, *value;
+} PropValue;
+
+/* KVM-specific features that are automatically added/removed
+ * from all CPU models when KVM is enabled.
+ */
+static PropValue kvm_default_props[] = {
+ { "kvmclock", "on" },
+ { "kvm-nopiodelay", "on" },
+ { "kvm-asyncpf", "on" },
+ { "kvm-steal-time", "on" },
+ { "kvm-pv-eoi", "on" },
+ { "kvmclock-stable-bit", "on" },
+ { "x2apic", "on" },
+ { "acpi", "off" },
+ { "monitor", "off" },
+ { "svm", "off" },
+ { NULL, NULL },
+};
+
+void x86_cpu_change_kvm_default(const char *prop, const char *value)
+{
+ PropValue *pv;
+ for (pv = kvm_default_props; pv->prop; pv++) {
+ if (!strcmp(pv->prop, prop)) {
+ pv->value = value;
+ break;
+ }
+ }
+
+ /* It is valid to call this function only for properties that
+ * are already present in the kvm_default_props table.
+ */
+ assert(pv->prop);
+}
+
static uint32_t x86_cpu_get_supported_feature_word(FeatureWord w,
bool migratable_only);
@@ -2061,6 +2065,18 @@ static int x86_cpu_filter_features(X86CPU *cpu)
return rv;
}
+static void x86_cpu_apply_props(X86CPU *cpu, PropValue *props)
+{
+ PropValue *pv;
+ for (pv = props; pv->prop; pv++) {
+ if (!pv->value) {
+ continue;
+ }
+ object_property_parse(OBJECT(cpu), pv->value, pv->prop,
+ &error_abort);
+ }
+}
+
/* Load data from X86CPUDefinition
*/
static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error **errp)
@@ -2084,11 +2100,7 @@ static void x86_cpu_load_def(X86CPU *cpu, X86CPUDefinition *def, Error **errp)
/* Special cases not set in the X86CPUDefinition structs: */
if (kvm_enabled()) {
- FeatureWord w;
- for (w = 0; w < FEATURE_WORDS; w++) {
- env->features[w] |= kvm_default_features[w];
- env->features[w] &= ~kvm_default_unset_features[w];
- }
+ x86_cpu_apply_props(cpu, kvm_default_props);
}
env->features[FEAT_1_ECX] |= CPUID_EXT_HYPERVISOR;
@@ -2723,7 +2735,6 @@ static void mce_init(X86CPU *cpu)
#ifndef CONFIG_USER_ONLY
static void x86_cpu_apic_create(X86CPU *cpu, Error **errp)
{
- DeviceState *dev = DEVICE(cpu);
APICCommonState *apic;
const char *apic_type = "apic";
@@ -2733,11 +2744,7 @@ static void x86_cpu_apic_create(X86CPU *cpu, Error **errp)
apic_type = "xen-apic";
}
- cpu->apic_state = qdev_try_create(qdev_get_parent_bus(dev), apic_type);
- if (cpu->apic_state == NULL) {
- error_setg(errp, "APIC device '%s' could not be created", apic_type);
- return;
- }
+ cpu->apic_state = DEVICE(object_new(apic_type));
object_property_add_child(OBJECT(cpu), "apic",
OBJECT(cpu->apic_state), NULL);
@@ -2745,15 +2752,30 @@ static void x86_cpu_apic_create(X86CPU *cpu, Error **errp)
/* TODO: convert to link<> */
apic = APIC_COMMON(cpu->apic_state);
apic->cpu = cpu;
+ apic->apicbase = APIC_DEFAULT_ADDRESS | MSR_IA32_APICBASE_ENABLE;
}
static void x86_cpu_apic_realize(X86CPU *cpu, Error **errp)
{
+ APICCommonState *apic;
+ static bool apic_mmio_map_once;
+
if (cpu->apic_state == NULL) {
return;
}
object_property_set_bool(OBJECT(cpu->apic_state), true, "realized",
errp);
+
+ /* Map APIC MMIO area */
+ apic = APIC_COMMON(cpu->apic_state);
+ if (!apic_mmio_map_once) {
+ memory_region_add_subregion_overlap(get_system_memory(),
+ apic->apicbase &
+ MSR_IA32_APICBASE_BASE,
+ &apic->io_memory,
+ 0x1000);
+ apic_mmio_map_once = true;
+ }
}
static void x86_cpu_machine_done(Notifier *n, void *unused)
@@ -3133,7 +3155,6 @@ static void x86_cpu_common_class_init(ObjectClass *oc, void *data)
xcc->parent_realize = dc->realize;
dc->realize = x86_cpu_realizefn;
- dc->bus_type = TYPE_ICC_BUS;
dc->props = x86_cpu_properties;
xcc->parent_reset = cc->reset;
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 034fab6f39..8926780e85 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -833,6 +833,7 @@ typedef struct CPUX86State {
BNDReg bnd_regs[4];
BNDCSReg bndcs_regs;
uint64_t msr_bndcfgs;
+ uint64_t efer;
/* Beginning of state preserved by INIT (dummy marker). */
struct {} start_init_save;
@@ -865,7 +866,6 @@ typedef struct CPUX86State {
uint32_t sysenter_cs;
target_ulong sysenter_esp;
target_ulong sysenter_eip;
- uint64_t efer;
uint64_t star;
uint64_t vm_hsave;
@@ -1154,7 +1154,6 @@ static inline int hw_breakpoint_len(unsigned long dr7, int index)
void hw_breakpoint_insert(CPUX86State *env, int index);
void hw_breakpoint_remove(CPUX86State *env, int index);
-bool check_hw_breakpoints(CPUX86State *env, bool force_dr6_update);
void breakpoint_handler(CPUState *cs);
/* will be suppressed */
@@ -1341,8 +1340,15 @@ void cpu_smm_update(X86CPU *cpu);
void cpu_report_tpr_access(CPUX86State *env, TPRAccess access);
-void x86_cpu_compat_kvm_no_autoenable(FeatureWord w, uint32_t features);
-void x86_cpu_compat_kvm_no_autodisable(FeatureWord w, uint32_t features);
+/* Change the value of a KVM-specific default
+ *
+ * If value is NULL, no default will be set and the original
+ * value from the CPU model table will be kept.
+ *
+ * It is valid to call this funciton only for properties that
+ * are already present in the kvm_default_props table.
+ */
+void x86_cpu_change_kvm_default(const char *prop, const char *value);
/* Return name of 32-bit register, from a R_* constant */
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 9364d96f96..d18be95c3f 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -1096,134 +1096,6 @@ out:
return pte | page_offset;
}
-void hw_breakpoint_insert(CPUX86State *env, int index)
-{
- CPUState *cs = CPU(x86_env_get_cpu(env));
- int type = 0, err = 0;
-
- switch (hw_breakpoint_type(env->dr[7], index)) {
- case DR7_TYPE_BP_INST:
- if (hw_breakpoint_enabled(env->dr[7], index)) {
- err = cpu_breakpoint_insert(cs, env->dr[index], BP_CPU,
- &env->cpu_breakpoint[index]);
- }
- break;
- case DR7_TYPE_DATA_WR:
- type = BP_CPU | BP_MEM_WRITE;
- break;
- case DR7_TYPE_IO_RW:
- /* No support for I/O watchpoints yet */
- break;
- case DR7_TYPE_DATA_RW:
- type = BP_CPU | BP_MEM_ACCESS;
- break;
- }
-
- if (type != 0) {
- err = cpu_watchpoint_insert(cs, env->dr[index],
- hw_breakpoint_len(env->dr[7], index),
- type, &env->cpu_watchpoint[index]);
- }
-
- if (err) {
- env->cpu_breakpoint[index] = NULL;
- }
-}
-
-void hw_breakpoint_remove(CPUX86State *env, int index)
-{
- CPUState *cs;
-
- if (!env->cpu_breakpoint[index]) {
- return;
- }
- cs = CPU(x86_env_get_cpu(env));
- switch (hw_breakpoint_type(env->dr[7], index)) {
- case DR7_TYPE_BP_INST:
- if (hw_breakpoint_enabled(env->dr[7], index)) {
- cpu_breakpoint_remove_by_ref(cs, env->cpu_breakpoint[index]);
- }
- break;
- case DR7_TYPE_DATA_WR:
- case DR7_TYPE_DATA_RW:
- cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[index]);
- break;
- case DR7_TYPE_IO_RW:
- /* No support for I/O watchpoints yet */
- break;
- }
-}
-
-bool check_hw_breakpoints(CPUX86State *env, bool force_dr6_update)
-{
- target_ulong dr6;
- int reg;
- bool hit_enabled = false;
-
- dr6 = env->dr[6] & ~0xf;
- for (reg = 0; reg < DR7_MAX_BP; reg++) {
- bool bp_match = false;
- bool wp_match = false;
-
- switch (hw_breakpoint_type(env->dr[7], reg)) {
- case DR7_TYPE_BP_INST:
- if (env->dr[reg] == env->eip) {
- bp_match = true;
- }
- break;
- case DR7_TYPE_DATA_WR:
- case DR7_TYPE_DATA_RW:
- if (env->cpu_watchpoint[reg] &&
- env->cpu_watchpoint[reg]->flags & BP_WATCHPOINT_HIT) {
- wp_match = true;
- }
- break;
- case DR7_TYPE_IO_RW:
- break;
- }
- if (bp_match || wp_match) {
- dr6 |= 1 << reg;
- if (hw_breakpoint_enabled(env->dr[7], reg)) {
- hit_enabled = true;
- }
- }
- }
-
- if (hit_enabled || force_dr6_update) {
- env->dr[6] = dr6;
- }
-
- return hit_enabled;
-}
-
-void breakpoint_handler(CPUState *cs)
-{
- X86CPU *cpu = X86_CPU(cs);
- CPUX86State *env = &cpu->env;
- CPUBreakpoint *bp;
-
- if (cs->watchpoint_hit) {
- if (cs->watchpoint_hit->flags & BP_CPU) {
- cs->watchpoint_hit = NULL;
- if (check_hw_breakpoints(env, false)) {
- raise_exception(env, EXCP01_DB);
- } else {
- cpu_resume_from_signal(cs, NULL);
- }
- }
- } else {
- QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
- if (bp->pc == env->eip) {
- if (bp->flags & BP_CPU) {
- check_hw_breakpoints(env, true);
- raise_exception(env, EXCP01_DB);
- }
- break;
- }
- }
- }
-}
-
typedef struct MCEInjectionParams {
Monitor *mon;
X86CPU *cpu;
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 7b0ba179cc..80d1a7e01e 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -67,6 +67,7 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
static bool has_msr_star;
static bool has_msr_hsave_pa;
+static bool has_msr_tsc_aux;
static bool has_msr_tsc_adjust;
static bool has_msr_tsc_deadline;
static bool has_msr_feature_control;
@@ -825,6 +826,10 @@ static int kvm_get_supported_msrs(KVMState *s)
has_msr_hsave_pa = true;
continue;
}
+ if (kvm_msr_list->indices[i] == MSR_TSC_AUX) {
+ has_msr_tsc_aux = true;
+ continue;
+ }
if (kvm_msr_list->indices[i] == MSR_TSC_ADJUST) {
has_msr_tsc_adjust = true;
continue;
@@ -1299,6 +1304,9 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
if (has_msr_hsave_pa) {
kvm_msr_entry_set(&msrs[n++], MSR_VM_HSAVE_PA, env->vm_hsave);
}
+ if (has_msr_tsc_aux) {
+ kvm_msr_entry_set(&msrs[n++], MSR_TSC_AUX, env->tsc_aux);
+ }
if (has_msr_tsc_adjust) {
kvm_msr_entry_set(&msrs[n++], MSR_TSC_ADJUST, env->tsc_adjust);
}
@@ -1671,6 +1679,9 @@ static int kvm_get_msrs(X86CPU *cpu)
if (has_msr_hsave_pa) {
msrs[n++].index = MSR_VM_HSAVE_PA;
}
+ if (has_msr_tsc_aux) {
+ msrs[n++].index = MSR_TSC_AUX;
+ }
if (has_msr_tsc_adjust) {
msrs[n++].index = MSR_TSC_ADJUST;
}
@@ -1820,6 +1831,9 @@ static int kvm_get_msrs(X86CPU *cpu)
case MSR_IA32_TSC:
env->tsc = msrs[i].data;
break;
+ case MSR_TSC_AUX:
+ env->tsc_aux = msrs[i].data;
+ break;
case MSR_TSC_ADJUST:
env->tsc_adjust = msrs[i].data;
break;
diff --git a/target-i386/misc_helper.c b/target-i386/misc_helper.c
index 6bfc7dd24e..13bd4f5eec 100644
--- a/target-i386/misc_helper.c
+++ b/target-i386/misc_helper.c
@@ -95,15 +95,6 @@ void helper_into(CPUX86State *env, int next_eip_addend)
}
}
-void helper_single_step(CPUX86State *env)
-{
-#ifndef CONFIG_USER_ONLY
- check_hw_breakpoints(env, true);
- env->dr[6] |= DR6_BS;
-#endif
- raise_exception(env, EXCP01_DB);
-}
-
void helper_cpuid(CPUX86State *env)
{
uint32_t eax, ebx, ecx, edx;
@@ -127,10 +118,6 @@ target_ulong helper_read_crN(CPUX86State *env, int reg)
void helper_write_crN(CPUX86State *env, int reg, target_ulong t0)
{
}
-
-void helper_movl_drN_T0(CPUX86State *env, int reg, target_ulong t0)
-{
-}
#else
target_ulong helper_read_crN(CPUX86State *env, int reg)
{
@@ -176,27 +163,6 @@ void helper_write_crN(CPUX86State *env, int reg, target_ulong t0)
break;
}
}
-
-void helper_movl_drN_T0(CPUX86State *env, int reg, target_ulong t0)
-{
- int i;
-
- if (reg < 4) {
- hw_breakpoint_remove(env, reg);
- env->dr[reg] = t0;
- hw_breakpoint_insert(env, reg);
- } else if (reg == 7) {
- for (i = 0; i < DR7_MAX_BP; i++) {
- hw_breakpoint_remove(env, i);
- }
- env->dr[7] = t0;
- for (i = 0; i < DR7_MAX_BP; i++) {
- hw_breakpoint_insert(env, i);
- }
- } else {
- env->dr[reg] = t0;
- }
-}
#endif
void helper_lmsw(CPUX86State *env, target_ulong t0)
diff --git a/vl.c b/vl.c
index 8d1846c06c..f2bd8d20fb 100644
--- a/vl.c
+++ b/vl.c
@@ -1223,7 +1223,13 @@ static void smp_parse(QemuOpts *opts)
exit(1);
}
- max_cpus = qemu_opt_get_number(opts, "maxcpus", 0);
+ max_cpus = qemu_opt_get_number(opts, "maxcpus", cpus);
+ if (sockets * cores * threads > max_cpus) {
+ fprintf(stderr, "cpu topology: error: "
+ "sockets (%u) * cores (%u) * threads (%u) > maxcpus (%u)\n",
+ sockets, cores, threads, max_cpus);
+ exit(1);
+ }
smp_cpus = cpus;
smp_cores = cores > 0 ? cores : 1;