Merge remote-tracking branch 'afaerber/qom-cpu' into staging

* afaerber/qom-cpu: (37 commits)
  kvm: Pass CPUState to kvm_on_sigbus_vcpu()
  cpu: Unconditionalize CPUState fields
  target-m68k: Use type_register() instead of type_register_static()
  target-unicore32: Use type_register() instead of type_register_static()
  target-openrisc: Use type_register() instead of type_register_static()
  target-unicore32: Catch attempt to instantiate abstract type in cpu_init()
  target-openrisc: Catch attempt to instantiate abstract type in cpu_init()
  target-m68k: Catch attempt to instantiate abstract type in cpu_init()
  target-arm: Catch attempt to instantiate abstract type in cpu_init()
  target-alpha: Catch attempt to instantiate abstract type in cpu_init()
  qom: Introduce object_class_is_abstract()
  target-unicore32: Detect attempt to instantiate non-CPU type in cpu_init()
  target-openrisc: Detect attempt to instantiate non-CPU type in cpu_init()
  target-m68k: Detect attempt to instantiate non-CPU type in cpu_init()
  target-alpha: Detect attempt to instantiate non-CPU type in cpu_init()
  target-arm: Detect attempt to instantiate non-CPU type in cpu_init()
  cpu: Add model resolution support to CPUClass
  target-i386: Remove setting tsc-frequency from x86_def_t
  target-i386: Set custom features/properties without intermediate x86_def_t
  target-i386: Remove vendor_override field from CPUX86State
  ...

Conflicts:
	tests/Makefile

Resolved simple conflict caused by lack of context in Makefile

Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
Anthony Liguori 2013-01-28 14:48:03 -06:00
commit ec9466ff2e
40 changed files with 710 additions and 293 deletions

8
cpus.c
View file

@ -517,7 +517,7 @@ static void qemu_init_sigbus(void)
prctl(PR_MCE_KILL, PR_MCE_KILL_SET, PR_MCE_KILL_EARLY, 0, 0);
}
static void qemu_kvm_eat_signals(CPUArchState *env)
static void qemu_kvm_eat_signals(CPUState *cpu)
{
struct timespec ts = { 0, 0 };
siginfo_t siginfo;
@ -538,7 +538,7 @@ static void qemu_kvm_eat_signals(CPUArchState *env)
switch (r) {
case SIGBUS:
if (kvm_on_sigbus_vcpu(env, siginfo.si_code, siginfo.si_addr)) {
if (kvm_on_sigbus_vcpu(cpu, siginfo.si_code, siginfo.si_addr)) {
sigbus_reraise();
}
break;
@ -560,7 +560,7 @@ static void qemu_init_sigbus(void)
{
}
static void qemu_kvm_eat_signals(CPUArchState *env)
static void qemu_kvm_eat_signals(CPUState *cpu)
{
}
#endif /* !CONFIG_LINUX */
@ -727,7 +727,7 @@ static void qemu_kvm_wait_io_event(CPUArchState *env)
qemu_cond_wait(cpu->halt_cond, &qemu_global_mutex);
}
qemu_kvm_eat_signals(env);
qemu_kvm_eat_signals(cpu);
qemu_wait_io_event_common(cpu);
}

View file

@ -504,7 +504,6 @@ FWCfgState *fw_cfg_init(uint32_t ctl_port, uint32_t data_port,
fw_cfg_add_bytes(s, FW_CFG_UUID, qemu_uuid, 16);
fw_cfg_add_i16(s, FW_CFG_NOGRAPHIC, (uint16_t)(display_type == DT_NOGRAPHIC));
fw_cfg_add_i16(s, FW_CFG_NB_CPUS, (uint16_t)smp_cpus);
fw_cfg_add_i16(s, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
fw_cfg_add_i16(s, FW_CFG_BOOT_MENU, (uint16_t)boot_menu);
fw_cfg_bootsplash(s);
fw_cfg_reboot(s);

40
hw/pc.c
View file

@ -551,6 +551,18 @@ int e820_add_entry(uint64_t address, uint64_t length, uint32_t type)
return index;
}
/* Calculates the limit to CPU APIC ID values
*
* This function returns the limit for the APIC ID value, so that all
* CPU APIC IDs are < pc_apic_id_limit().
*
* This is used for FW_CFG_MAX_CPUS. See comments on bochs_bios_init().
*/
static unsigned int pc_apic_id_limit(unsigned int max_cpus)
{
return x86_cpu_apic_id_from_index(max_cpus - 1) + 1;
}
static void *bochs_bios_init(void)
{
void *fw_cfg;
@ -558,9 +570,24 @@ static void *bochs_bios_init(void)
size_t smbios_len;
uint64_t *numa_fw_cfg;
int i, j;
unsigned int apic_id_limit = pc_apic_id_limit(max_cpus);
fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
/* FW_CFG_MAX_CPUS is a bit confusing/problematic on x86:
*
* SeaBIOS needs FW_CFG_MAX_CPUS for CPU hotplug, but the CPU hotplug
* QEMU<->SeaBIOS interface is not based on the "CPU index", but on the APIC
* ID of hotplugged CPUs[1]. This means that FW_CFG_MAX_CPUS is not the
* "maximum number of CPUs", but the "limit to the APIC ID values SeaBIOS
* may see".
*
* So, this means we must not use max_cpus, here, but the maximum possible
* APIC ID value, plus one.
*
* [1] The only kind of "CPU identifier" used between SeaBIOS and QEMU is
* the APIC ID, not the "CPU index"
*/
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)apic_id_limit);
fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
fw_cfg_add_bytes(fw_cfg, FW_CFG_ACPI_TABLES,
@ -579,21 +606,24 @@ static void *bochs_bios_init(void)
* of nodes, one word for each VCPU->node and one word for each node to
* hold the amount of memory.
*/
numa_fw_cfg = g_new0(uint64_t, 1 + max_cpus + nb_numa_nodes);
numa_fw_cfg = g_new0(uint64_t, 1 + apic_id_limit + nb_numa_nodes);
numa_fw_cfg[0] = cpu_to_le64(nb_numa_nodes);
for (i = 0; i < max_cpus; i++) {
unsigned int apic_id = x86_cpu_apic_id_from_index(i);
assert(apic_id < apic_id_limit);
for (j = 0; j < nb_numa_nodes; j++) {
if (test_bit(i, node_cpumask[j])) {
numa_fw_cfg[i + 1] = cpu_to_le64(j);
numa_fw_cfg[apic_id + 1] = cpu_to_le64(j);
break;
}
}
}
for (i = 0; i < nb_numa_nodes; i++) {
numa_fw_cfg[max_cpus + 1 + i] = cpu_to_le64(node_mem[i]);
numa_fw_cfg[apic_id_limit + 1 + i] = cpu_to_le64(node_mem[i]);
}
fw_cfg_add_bytes(fw_cfg, FW_CFG_NUMA, numa_fw_cfg,
(1 + max_cpus + nb_numa_nodes) * sizeof(*numa_fw_cfg));
(1 + apic_id_limit + nb_numa_nodes) *
sizeof(*numa_fw_cfg));
return fw_cfg;
}

View file

@ -235,10 +235,18 @@ static void pc_init_pci(QEMUMachineInitArgs *args)
static void pc_init_pci_1_3(QEMUMachineInitArgs *args)
{
enable_kvm_pv_eoi();
enable_compat_apic_id_mode();
pc_init_pci(args);
}
/* PC machine init function for pc-0.14 to pc-1.2 */
static void pc_init_pci_1_2(QEMUMachineInitArgs *args)
{
disable_kvm_pv_eoi();
pc_init_pci_1_3(args);
}
/* PC init function for pc-0.10 to pc-0.13, and reused by xenfv */
static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args)
{
ram_addr_t ram_size = args->ram_size;
@ -247,6 +255,8 @@ static void pc_init_pci_no_kvmclock(QEMUMachineInitArgs *args)
const char *kernel_cmdline = args->kernel_cmdline;
const char *initrd_filename = args->initrd_filename;
const char *boot_device = args->boot_device;
disable_kvm_pv_eoi();
enable_compat_apic_id_mode();
pc_init1(get_system_memory(),
get_system_io(),
ram_size, boot_device,
@ -264,6 +274,8 @@ static void pc_init_isa(QEMUMachineInitArgs *args)
const char *boot_device = args->boot_device;
if (cpu_model == NULL)
cpu_model = "486";
disable_kvm_pv_eoi();
enable_compat_apic_id_mode();
pc_init1(get_system_memory(),
get_system_io(),
ram_size, boot_device,
@ -286,7 +298,7 @@ static QEMUMachine pc_i440fx_machine_v1_4 = {
.name = "pc-i440fx-1.4",
.alias = "pc",
.desc = "Standard PC (i440FX + PIIX, 1996)",
.init = pc_init_pci_1_3,
.init = pc_init_pci,
.max_cpus = 255,
.is_default = 1,
DEFAULT_MACHINE_OPTIONS,
@ -342,7 +354,7 @@ static QEMUMachine pc_machine_v1_3 = {
static QEMUMachine pc_machine_v1_2 = {
.name = "pc-1.2",
.desc = "Standard PC",
.init = pc_init_pci,
.init = pc_init_pci_1_2,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {
PC_COMPAT_1_2,
@ -386,7 +398,7 @@ static QEMUMachine pc_machine_v1_2 = {
static QEMUMachine pc_machine_v1_1 = {
.name = "pc-1.1",
.desc = "Standard PC",
.init = pc_init_pci,
.init = pc_init_pci_1_2,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {
PC_COMPAT_1_1,
@ -422,7 +434,7 @@ static QEMUMachine pc_machine_v1_1 = {
static QEMUMachine pc_machine_v1_0 = {
.name = "pc-1.0",
.desc = "Standard PC",
.init = pc_init_pci,
.init = pc_init_pci_1_2,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {
PC_COMPAT_1_0,
@ -438,7 +450,7 @@ static QEMUMachine pc_machine_v1_0 = {
static QEMUMachine pc_machine_v0_15 = {
.name = "pc-0.15",
.desc = "Standard PC",
.init = pc_init_pci,
.init = pc_init_pci_1_2,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {
PC_COMPAT_0_15,
@ -471,7 +483,7 @@ static QEMUMachine pc_machine_v0_15 = {
static QEMUMachine pc_machine_v0_14 = {
.name = "pc-0.14",
.desc = "Standard PC",
.init = pc_init_pci,
.init = pc_init_pci_1_2,
.max_cpus = 255,
.compat_props = (GlobalProperty[]) {
PC_COMPAT_0_14,

View file

@ -413,6 +413,7 @@ static void ppc_core99_init(QEMUMachineInitArgs *args)
/* No PCI init: the BIOS will do it */
fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, machine_arch);

View file

@ -299,6 +299,7 @@ static void ppc_heathrow_init(QEMUMachineInitArgs *args)
/* No PCI init: the BIOS will do it */
fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, ARCH_HEATHROW);

View file

@ -1021,6 +1021,7 @@ static void sun4m_hw_init(const struct sun4m_hwdef *hwdef, ram_addr_t RAM_size,
hwdef->ecc_version);
fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id);
@ -1665,6 +1666,7 @@ static void sun4d_hw_init(const struct sun4d_hwdef *hwdef, ram_addr_t RAM_size,
"Sun4d");
fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id);
@ -1865,6 +1867,7 @@ static void sun4c_hw_init(const struct sun4c_hwdef *hwdef, ram_addr_t RAM_size,
"Sun4c");
fw_cfg = fw_cfg_init(0, 0, CFG_ADDR, CFG_ADDR + 2);
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id);

View file

@ -878,6 +878,7 @@ static void sun4uv_init(MemoryRegion *address_space_mem,
(uint8_t *)&nd_table[0].macaddr);
fw_cfg = fw_cfg_init(BIOS_CFG_IOPORT, BIOS_CFG_IOPORT + 1, 0, 0);
fw_cfg_add_i16(fw_cfg, FW_CFG_MAX_CPUS, (uint16_t)max_cpus);
fw_cfg_add_i32(fw_cfg, FW_CFG_ID, 1);
fw_cfg_add_i64(fw_cfg, FW_CFG_RAM_SIZE, (uint64_t)ram_size);
fw_cfg_add_i16(fw_cfg, FW_CFG_MACHINE_ID, hwdef->machine_id);

View file

@ -40,6 +40,8 @@ typedef struct CPUState CPUState;
/**
* CPUClass:
* @class_by_name: Callback to map -cpu command line model name to an
* instantiatable CPU type.
* @reset: Callback to reset the #CPUState to its initial state.
*
* Represents a CPU family or model.
@ -49,6 +51,8 @@ typedef struct CPUClass {
DeviceClass parent_class;
/*< public >*/
ObjectClass *(*class_by_name)(const char *cpu_model);
void (*reset)(CPUState *cpu);
} CPUClass;
@ -89,10 +93,8 @@ struct CPUState {
bool stop;
bool stopped;
#if !defined(CONFIG_USER_ONLY)
int kvm_fd;
bool kvm_vcpu_dirty;
#endif
struct KVMState *kvm_state;
struct kvm_run *kvm_run;
@ -107,6 +109,17 @@ struct CPUState {
*/
void cpu_reset(CPUState *cpu);
/**
* cpu_class_by_name:
* @typename: The CPU base type.
* @cpu_model: The model string without any parameters.
*
* Looks up a CPU #ObjectClass matching name @cpu_model.
*
* Returns: A #CPUClass or %NULL if not matching class is found.
*/
ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model);
/**
* qemu_cpu_has_work:
* @cpu: The vCPU to check.

View file

@ -690,6 +690,14 @@ ObjectClass *object_class_get_parent(ObjectClass *klass);
*/
const char *object_class_get_name(ObjectClass *klass);
/**
* object_class_is_abstract:
* @klass: The class to obtain the abstractness for.
*
* Returns: %true if @klass is abstract, %false otherwise.
*/
bool object_class_is_abstract(ObjectClass *klass);
/**
* object_class_by_name:
* @typename: The QOM typename to obtain the class for.

View file

@ -13,9 +13,16 @@ void cpu_synchronize_all_post_init(void);
void qtest_clock_warp(int64_t dest);
#ifndef CONFIG_USER_ONLY
/* vl.c */
extern int smp_cores;
extern int smp_threads;
#else
/* *-user doesn't have configurable SMP topology */
#define smp_cores 1
#define smp_threads 1
#endif
void set_numa_modes(void);
void set_cpu_log(const char *optarg);
void set_cpu_log_filename(const char *optarg);

View file

@ -36,6 +36,7 @@
#define KVM_FEATURE_ASYNC_PF 0
#define KVM_FEATURE_STEAL_TIME 0
#define KVM_FEATURE_PV_EOI 0
#define KVM_FEATURE_CLOCKSOURCE_STABLE_BIT 0
#endif
extern int kvm_allowed;
@ -158,7 +159,7 @@ int kvm_update_guest_debug(CPUArchState *env, unsigned long reinject_trap);
int kvm_set_signal_mask(CPUArchState *env, const sigset_t *sigset);
#endif
int kvm_on_sigbus_vcpu(CPUArchState *env, int code, void *addr);
int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr);
int kvm_on_sigbus(int code, void *addr);
/* internal API */
@ -195,6 +196,9 @@ int kvm_arch_init(KVMState *s);
int kvm_arch_init_vcpu(CPUState *cpu);
/* Returns VCPU ID to be used on KVM_CREATE_VCPU ioctl() */
unsigned long kvm_arch_vcpu_id(CPUState *cpu);
void kvm_arch_reset_vcpu(CPUState *cpu);
int kvm_arch_on_sigbus_vcpu(CPUState *cpu, int code, void *addr);

View file

@ -222,7 +222,7 @@ int kvm_init_vcpu(CPUState *cpu)
DPRINTF("kvm_init_vcpu\n");
ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, cpu->cpu_index);
ret = kvm_vm_ioctl(s, KVM_CREATE_VCPU, (void *)kvm_arch_vcpu_id(cpu));
if (ret < 0) {
DPRINTF("kvm_create_vcpu failed\n");
goto err;
@ -2026,9 +2026,8 @@ int kvm_set_ioeventfd_pio_word(int fd, uint16_t addr, uint16_t val, bool assign)
return 0;
}
int kvm_on_sigbus_vcpu(CPUArchState *env, int code, void *addr)
int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr)
{
CPUState *cpu = ENV_GET_CPU(env);
return kvm_arch_on_sigbus_vcpu(cpu, code, addr);
}

View file

@ -112,7 +112,7 @@ int kvm_set_ioeventfd_mmio(int fd, uint32_t adr, uint32_t val, bool assign, uint
return -ENOSYS;
}
int kvm_on_sigbus_vcpu(CPUArchState *env, int code, void *addr)
int kvm_on_sigbus_vcpu(CPUState *cpu, int code, void *addr)
{
return 1;
}

View file

@ -34,11 +34,24 @@ static void cpu_common_reset(CPUState *cpu)
{
}
ObjectClass *cpu_class_by_name(const char *typename, const char *cpu_model)
{
CPUClass *cc = CPU_CLASS(object_class_by_name(typename));
return cc->class_by_name(cpu_model);
}
static ObjectClass *cpu_common_class_by_name(const char *cpu_model)
{
return NULL;
}
static void cpu_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
CPUClass *k = CPU_CLASS(klass);
k->class_by_name = cpu_common_class_by_name;
k->reset = cpu_common_reset;
dc->no_user = 1;
}

View file

@ -501,6 +501,11 @@ ObjectClass *object_get_class(Object *obj)
return obj->class;
}
bool object_class_is_abstract(ObjectClass *klass)
{
return klass->type->abstract;
}
const char *object_class_get_name(ObjectClass *klass)
{
return klass->type->name;

View file

@ -96,14 +96,15 @@ static ObjectClass *alpha_cpu_class_by_name(const char *cpu_model)
}
oc = object_class_by_name(cpu_model);
if (oc != NULL) {
if (oc != NULL && object_class_dynamic_cast(oc, TYPE_ALPHA_CPU) != NULL &&
!object_class_is_abstract(oc)) {
return oc;
}
for (i = 0; i < ARRAY_SIZE(alpha_cpu_aliases); i++) {
if (strcmp(cpu_model, alpha_cpu_aliases[i].alias) == 0) {
oc = object_class_by_name(alpha_cpu_aliases[i].typename);
assert(oc != NULL);
assert(oc != NULL && !object_class_is_abstract(oc));
return oc;
}
}
@ -111,6 +112,9 @@ static ObjectClass *alpha_cpu_class_by_name(const char *cpu_model)
typename = g_strdup_printf("%s-" TYPE_ALPHA_CPU, cpu_model);
oc = object_class_by_name(typename);
g_free(typename);
if (oc != NULL && object_class_is_abstract(oc)) {
oc = NULL;
}
return oc;
}
@ -244,6 +248,13 @@ static void alpha_cpu_initfn(Object *obj)
env->fen = 1;
}
static void alpha_cpu_class_init(ObjectClass *oc, void *data)
{
CPUClass *cc = CPU_CLASS(oc);
cc->class_by_name = alpha_cpu_class_by_name;
}
static const TypeInfo alpha_cpu_type_info = {
.name = TYPE_ALPHA_CPU,
.parent = TYPE_CPU,
@ -251,6 +262,7 @@ static const TypeInfo alpha_cpu_type_info = {
.instance_init = alpha_cpu_initfn,
.abstract = true,
.class_size = sizeof(AlphaCPUClass),
.class_init = alpha_cpu_class_init,
};
static void alpha_cpu_register_types(void)

View file

@ -201,6 +201,22 @@ void arm_cpu_realize(ARMCPU *cpu)
/* CPU models */
static ObjectClass *arm_cpu_class_by_name(const char *cpu_model)
{
ObjectClass *oc;
if (!cpu_model) {
return NULL;
}
oc = object_class_by_name(cpu_model);
if (!oc || !object_class_dynamic_cast(oc, TYPE_ARM_CPU) ||
object_class_is_abstract(oc)) {
return NULL;
}
return oc;
}
static void arm926_initfn(Object *obj)
{
ARMCPU *cpu = ARM_CPU(obj);
@ -766,6 +782,8 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
acc->parent_reset = cc->reset;
cc->reset = arm_cpu_reset;
cc->class_by_name = arm_cpu_class_by_name;
}
static void cpu_register(const ARMCPUInfo *info)

View file

@ -1262,12 +1262,14 @@ ARMCPU *cpu_arm_init(const char *cpu_model)
{
ARMCPU *cpu;
CPUARMState *env;
ObjectClass *oc;
static int inited = 0;
if (!object_class_by_name(cpu_model)) {
oc = cpu_class_by_name(TYPE_ARM_CPU, cpu_model);
if (!oc) {
return NULL;
}
cpu = ARM_CPU(object_new(cpu_model));
cpu = ARM_CPU(object_new(object_class_get_name(oc)));
env = &cpu->env;
env->cpu_model_str = cpu_model;
arm_cpu_realize(cpu);

View file

@ -23,6 +23,8 @@
#include "cpu.h"
#include "sysemu/kvm.h"
#include "sysemu/cpus.h"
#include "topology.h"
#include "qemu/option.h"
#include "qemu/config-file.h"
@ -45,6 +47,18 @@
#include "hw/apic_internal.h"
#endif
static void x86_cpu_vendor_words2str(char *dst, uint32_t vendor1,
uint32_t vendor2, uint32_t vendor3)
{
int i;
for (i = 0; i < 4; i++) {
dst[i] = vendor1 >> (8 * i);
dst[i + 4] = vendor2 >> (8 * i);
dst[i + 8] = vendor3 >> (8 * i);
}
dst[CPUID_VENDOR_SZ] = '\0';
}
/* feature flags taken from "Intel Processor Identification and the CPUID
* Instruction" and AMD's "CPUID Specification". In cases of disagreement
* between feature naming conventions, aliases may be added.
@ -206,22 +220,17 @@ typedef struct model_features_t {
int check_cpuid = 0;
int enforce_cpuid = 0;
#if defined(CONFIG_KVM)
static uint32_t kvm_default_features = (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);
static const uint32_t kvm_pv_eoi_features = (0x1 << KVM_FEATURE_PV_EOI);
#else
static uint32_t kvm_default_features = 0;
static const uint32_t kvm_pv_eoi_features = 0;
#endif
void enable_kvm_pv_eoi(void)
void disable_kvm_pv_eoi(void)
{
kvm_default_features |= kvm_pv_eoi_features;
kvm_default_features &= ~(1UL << KVM_FEATURE_PV_EOI);
}
void host_cpuid(uint32_t function, uint32_t count,
@ -338,19 +347,17 @@ static void add_flagname_to_bitmaps(const char *flagname,
}
typedef struct x86_def_t {
struct x86_def_t *next;
const char *name;
uint32_t level;
uint32_t vendor1, vendor2, vendor3;
/* vendor is zero-terminated, 12 character ASCII string */
char vendor[CPUID_VENDOR_SZ + 1];
int family;
int model;
int stepping;
int tsc_khz;
uint32_t features, ext_features, ext2_features, ext3_features;
uint32_t kvm_features, svm_features;
uint32_t xlevel;
char model_id[48];
int vendor_override;
/* Store the results of Centaur's CPUID instructions */
uint32_t ext4_features;
uint32_t xlevel2;
@ -396,19 +403,13 @@ typedef struct x86_def_t {
#define TCG_SVM_FEATURES 0
#define TCG_7_0_EBX_FEATURES (CPUID_7_0_EBX_SMEP | CPUID_7_0_EBX_SMAP)
/* maintains list of cpu model definitions
*/
static x86_def_t *x86_defs = {NULL};
/* built-in cpu model definitions (deprecated)
/* built-in CPU model definitions
*/
static x86_def_t builtin_x86_defs[] = {
{
.name = "qemu64",
.level = 4,
.vendor1 = CPUID_VENDOR_AMD_1,
.vendor2 = CPUID_VENDOR_AMD_2,
.vendor3 = CPUID_VENDOR_AMD_3,
.vendor = CPUID_VENDOR_AMD,
.family = 6,
.model = 2,
.stepping = 3,
@ -425,9 +426,7 @@ static x86_def_t builtin_x86_defs[] = {
{
.name = "phenom",
.level = 5,
.vendor1 = CPUID_VENDOR_AMD_1,
.vendor2 = CPUID_VENDOR_AMD_2,
.vendor3 = CPUID_VENDOR_AMD_3,
.vendor = CPUID_VENDOR_AMD,
.family = 16,
.model = 2,
.stepping = 3,
@ -453,9 +452,7 @@ static x86_def_t builtin_x86_defs[] = {
{
.name = "core2duo",
.level = 10,
.vendor1 = CPUID_VENDOR_INTEL_1,
.vendor2 = CPUID_VENDOR_INTEL_2,
.vendor3 = CPUID_VENDOR_INTEL_3,
.vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 15,
.stepping = 11,
@ -474,9 +471,7 @@ static x86_def_t builtin_x86_defs[] = {
{
.name = "kvm64",
.level = 5,
.vendor1 = CPUID_VENDOR_INTEL_1,
.vendor2 = CPUID_VENDOR_INTEL_2,
.vendor3 = CPUID_VENDOR_INTEL_3,
.vendor = CPUID_VENDOR_INTEL,
.family = 15,
.model = 6,
.stepping = 1,
@ -500,9 +495,7 @@ static x86_def_t builtin_x86_defs[] = {
{
.name = "qemu32",
.level = 4,
.vendor1 = CPUID_VENDOR_INTEL_1,
.vendor2 = CPUID_VENDOR_INTEL_2,
.vendor3 = CPUID_VENDOR_INTEL_3,
.vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 3,
.stepping = 3,
@ -513,9 +506,7 @@ static x86_def_t builtin_x86_defs[] = {
{
.name = "kvm32",
.level = 5,
.vendor1 = CPUID_VENDOR_INTEL_1,
.vendor2 = CPUID_VENDOR_INTEL_2,
.vendor3 = CPUID_VENDOR_INTEL_3,
.vendor = CPUID_VENDOR_INTEL,
.family = 15,
.model = 6,
.stepping = 1,
@ -530,9 +521,7 @@ static x86_def_t builtin_x86_defs[] = {
{
.name = "coreduo",
.level = 10,
.vendor1 = CPUID_VENDOR_INTEL_1,
.vendor2 = CPUID_VENDOR_INTEL_2,
.vendor3 = CPUID_VENDOR_INTEL_3,
.vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 14,
.stepping = 8,
@ -548,9 +537,7 @@ static x86_def_t builtin_x86_defs[] = {
{
.name = "486",
.level = 1,
.vendor1 = CPUID_VENDOR_INTEL_1,
.vendor2 = CPUID_VENDOR_INTEL_2,
.vendor3 = CPUID_VENDOR_INTEL_3,
.vendor = CPUID_VENDOR_INTEL,
.family = 4,
.model = 0,
.stepping = 0,
@ -560,9 +547,7 @@ static x86_def_t builtin_x86_defs[] = {
{
.name = "pentium",
.level = 1,
.vendor1 = CPUID_VENDOR_INTEL_1,
.vendor2 = CPUID_VENDOR_INTEL_2,
.vendor3 = CPUID_VENDOR_INTEL_3,
.vendor = CPUID_VENDOR_INTEL,
.family = 5,
.model = 4,
.stepping = 3,
@ -572,9 +557,7 @@ static x86_def_t builtin_x86_defs[] = {
{
.name = "pentium2",
.level = 2,
.vendor1 = CPUID_VENDOR_INTEL_1,
.vendor2 = CPUID_VENDOR_INTEL_2,
.vendor3 = CPUID_VENDOR_INTEL_3,
.vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 5,
.stepping = 2,
@ -584,9 +567,7 @@ static x86_def_t builtin_x86_defs[] = {
{
.name = "pentium3",
.level = 2,
.vendor1 = CPUID_VENDOR_INTEL_1,
.vendor2 = CPUID_VENDOR_INTEL_2,
.vendor3 = CPUID_VENDOR_INTEL_3,
.vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 7,
.stepping = 3,
@ -596,9 +577,7 @@ static x86_def_t builtin_x86_defs[] = {
{
.name = "athlon",
.level = 2,
.vendor1 = CPUID_VENDOR_AMD_1,
.vendor2 = CPUID_VENDOR_AMD_2,
.vendor3 = CPUID_VENDOR_AMD_3,
.vendor = CPUID_VENDOR_AMD,
.family = 6,
.model = 2,
.stepping = 3,
@ -612,9 +591,7 @@ static x86_def_t builtin_x86_defs[] = {
.name = "n270",
/* original is on level 10 */
.level = 5,
.vendor1 = CPUID_VENDOR_INTEL_1,
.vendor2 = CPUID_VENDOR_INTEL_2,
.vendor3 = CPUID_VENDOR_INTEL_3,
.vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 28,
.stepping = 2,
@ -633,9 +610,7 @@ static x86_def_t builtin_x86_defs[] = {
{
.name = "Conroe",
.level = 2,
.vendor1 = CPUID_VENDOR_INTEL_1,
.vendor2 = CPUID_VENDOR_INTEL_2,
.vendor3 = CPUID_VENDOR_INTEL_3,
.vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 2,
.stepping = 3,
@ -653,9 +628,7 @@ static x86_def_t builtin_x86_defs[] = {
{
.name = "Penryn",
.level = 2,
.vendor1 = CPUID_VENDOR_INTEL_1,
.vendor2 = CPUID_VENDOR_INTEL_2,
.vendor3 = CPUID_VENDOR_INTEL_3,
.vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 2,
.stepping = 3,
@ -674,9 +647,7 @@ static x86_def_t builtin_x86_defs[] = {
{
.name = "Nehalem",
.level = 2,
.vendor1 = CPUID_VENDOR_INTEL_1,
.vendor2 = CPUID_VENDOR_INTEL_2,
.vendor3 = CPUID_VENDOR_INTEL_3,
.vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 2,
.stepping = 3,
@ -695,9 +666,7 @@ static x86_def_t builtin_x86_defs[] = {
{
.name = "Westmere",
.level = 11,
.vendor1 = CPUID_VENDOR_INTEL_1,
.vendor2 = CPUID_VENDOR_INTEL_2,
.vendor3 = CPUID_VENDOR_INTEL_3,
.vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 44,
.stepping = 1,
@ -717,9 +686,7 @@ static x86_def_t builtin_x86_defs[] = {
{
.name = "SandyBridge",
.level = 0xd,
.vendor1 = CPUID_VENDOR_INTEL_1,
.vendor2 = CPUID_VENDOR_INTEL_2,
.vendor3 = CPUID_VENDOR_INTEL_3,
.vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 42,
.stepping = 1,
@ -742,9 +709,7 @@ static x86_def_t builtin_x86_defs[] = {
{
.name = "Haswell",
.level = 0xd,
.vendor1 = CPUID_VENDOR_INTEL_1,
.vendor2 = CPUID_VENDOR_INTEL_2,
.vendor3 = CPUID_VENDOR_INTEL_3,
.vendor = CPUID_VENDOR_INTEL,
.family = 6,
.model = 60,
.stepping = 1,
@ -772,9 +737,7 @@ static x86_def_t builtin_x86_defs[] = {
{
.name = "Opteron_G1",
.level = 5,
.vendor1 = CPUID_VENDOR_AMD_1,
.vendor2 = CPUID_VENDOR_AMD_2,
.vendor3 = CPUID_VENDOR_AMD_3,
.vendor = CPUID_VENDOR_AMD,
.family = 15,
.model = 6,
.stepping = 1,
@ -796,9 +759,7 @@ static x86_def_t builtin_x86_defs[] = {
{
.name = "Opteron_G2",
.level = 5,
.vendor1 = CPUID_VENDOR_AMD_1,
.vendor2 = CPUID_VENDOR_AMD_2,
.vendor3 = CPUID_VENDOR_AMD_3,
.vendor = CPUID_VENDOR_AMD,
.family = 15,
.model = 6,
.stepping = 1,
@ -822,9 +783,7 @@ static x86_def_t builtin_x86_defs[] = {
{
.name = "Opteron_G3",
.level = 5,
.vendor1 = CPUID_VENDOR_AMD_1,
.vendor2 = CPUID_VENDOR_AMD_2,
.vendor3 = CPUID_VENDOR_AMD_3,
.vendor = CPUID_VENDOR_AMD,
.family = 15,
.model = 6,
.stepping = 1,
@ -850,9 +809,7 @@ static x86_def_t builtin_x86_defs[] = {
{
.name = "Opteron_G4",
.level = 0xd,
.vendor1 = CPUID_VENDOR_AMD_1,
.vendor2 = CPUID_VENDOR_AMD_2,
.vendor3 = CPUID_VENDOR_AMD_3,
.vendor = CPUID_VENDOR_AMD,
.family = 21,
.model = 1,
.stepping = 2,
@ -882,9 +839,7 @@ static x86_def_t builtin_x86_defs[] = {
{
.name = "Opteron_G5",
.level = 0xd,
.vendor1 = CPUID_VENDOR_AMD_1,
.vendor2 = CPUID_VENDOR_AMD_2,
.vendor3 = CPUID_VENDOR_AMD_3,
.vendor = CPUID_VENDOR_AMD,
.family = 21,
.model = 2,
.stepping = 0,
@ -945,9 +900,7 @@ static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def)
x86_cpu_def->name = "host";
host_cpuid(0x0, 0, &eax, &ebx, &ecx, &edx);
x86_cpu_def->vendor1 = ebx;
x86_cpu_def->vendor2 = edx;
x86_cpu_def->vendor3 = ecx;
x86_cpu_vendor_words2str(x86_cpu_def->vendor, ebx, edx, ecx);
host_cpuid(0x1, 0, &eax, &ebx, &ecx, &edx);
x86_cpu_def->family = ((eax >> 8) & 0x0F) + ((eax >> 20) & 0xFF);
@ -972,12 +925,9 @@ static void kvm_cpu_fill_host(x86_def_t *x86_cpu_def)
kvm_arch_get_supported_cpuid(s, 0x80000001, 0, R_ECX);
cpu_x86_fill_model_id(x86_cpu_def->model_id);
x86_cpu_def->vendor_override = 0;
/* Call Centaur's CPUID instruction. */
if (x86_cpu_def->vendor1 == CPUID_VENDOR_VIA_1 &&
x86_cpu_def->vendor2 == CPUID_VENDOR_VIA_2 &&
x86_cpu_def->vendor3 == CPUID_VENDOR_VIA_3) {
if (!strcmp(x86_cpu_def->vendor, CPUID_VENDOR_VIA)) {
host_cpuid(0xC0000000, 0, &eax, &ebx, &ecx, &edx);
eax = kvm_arch_get_supported_cpuid(s, 0xC0000000, 0, R_EAX);
if (eax >= 0xC0000001) {
@ -1213,15 +1163,10 @@ static char *x86_cpuid_get_vendor(Object *obj, Error **errp)
X86CPU *cpu = X86_CPU(obj);
CPUX86State *env = &cpu->env;
char *value;
int i;
value = (char *)g_malloc(CPUID_VENDOR_SZ + 1);
for (i = 0; i < 4; i++) {
value[i ] = env->cpuid_vendor1 >> (8 * i);
value[i + 4] = env->cpuid_vendor2 >> (8 * i);
value[i + 8] = env->cpuid_vendor3 >> (8 * i);
}
value[CPUID_VENDOR_SZ] = '\0';
x86_cpu_vendor_words2str(value, env->cpuid_vendor1, env->cpuid_vendor2,
env->cpuid_vendor3);
return value;
}
@ -1246,7 +1191,6 @@ static void x86_cpuid_set_vendor(Object *obj, const char *value,
env->cpuid_vendor2 |= ((uint8_t)value[i + 4]) << (8 * i);
env->cpuid_vendor3 |= ((uint8_t)value[i + 8]) << (8 * i);
}
env->cpuid_vendor_override = 1;
}
static char *x86_cpuid_get_model_id(Object *obj, Error **errp)
@ -1320,34 +1264,50 @@ static void x86_cpuid_set_tsc_freq(Object *obj, Visitor *v, void *opaque,
static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *name)
{
x86_def_t *def;
int i;
for (def = x86_defs; def; def = def->next) {
if (name && !strcmp(name, def->name)) {
break;
if (name == NULL) {
return -1;
}
if (kvm_enabled() && strcmp(name, "host") == 0) {
kvm_cpu_fill_host(x86_cpu_def);
return 0;
}
for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
def = &builtin_x86_defs[i];
if (strcmp(name, def->name) == 0) {
memcpy(x86_cpu_def, def, sizeof(*def));
/* sysenter isn't supported in compatibility mode on AMD,
* syscall isn't supported in compatibility mode on Intel.
* Normally we advertise the actual CPU vendor, but you can
* override this using the 'vendor' property if you want to use
* KVM's sysenter/syscall emulation in compatibility mode and
* when doing cross vendor migration
*/
if (kvm_enabled()) {
uint32_t ebx = 0, ecx = 0, edx = 0;
host_cpuid(0, 0, NULL, &ebx, &ecx, &edx);
x86_cpu_vendor_words2str(x86_cpu_def->vendor, ebx, edx, ecx);
}
return 0;
}
}
if (kvm_enabled() && name && strcmp(name, "host") == 0) {
kvm_cpu_fill_host(x86_cpu_def);
} else if (!def) {
return -1;
} else {
memcpy(x86_cpu_def, def, sizeof(*def));
}
return 0;
return -1;
}
/* Parse "+feature,-feature,feature=foo" CPU feature string
*/
static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features)
static void cpu_x86_parse_featurestr(X86CPU *cpu, char *features, Error **errp)
{
unsigned int i;
char *featurestr; /* Single 'key=value" string being parsed */
/* Features to be added */
FeatureWordArray plus_features = { 0 };
/* Features to be removed */
FeatureWordArray minus_features = { 0 };
uint32_t numvalue;
CPUX86State *env = &cpu->env;
featurestr = features ? strtok(features, ",") : NULL;
@ -1360,87 +1320,57 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features)
} else if ((val = strchr(featurestr, '='))) {
*val = 0; val++;
if (!strcmp(featurestr, "family")) {
char *err;
numvalue = strtoul(val, &err, 0);
if (!*val || *err || numvalue > 0xff + 0xf) {
fprintf(stderr, "bad numerical value %s\n", val);
goto error;
}
x86_cpu_def->family = numvalue;
object_property_parse(OBJECT(cpu), val, featurestr, errp);
} else if (!strcmp(featurestr, "model")) {
char *err;
numvalue = strtoul(val, &err, 0);
if (!*val || *err || numvalue > 0xff) {
fprintf(stderr, "bad numerical value %s\n", val);
goto error;
}
x86_cpu_def->model = numvalue;
object_property_parse(OBJECT(cpu), val, featurestr, errp);
} else if (!strcmp(featurestr, "stepping")) {
char *err;
numvalue = strtoul(val, &err, 0);
if (!*val || *err || numvalue > 0xf) {
fprintf(stderr, "bad numerical value %s\n", val);
goto error;
}
x86_cpu_def->stepping = numvalue ;
object_property_parse(OBJECT(cpu), val, featurestr, errp);
} else if (!strcmp(featurestr, "level")) {
char *err;
numvalue = strtoul(val, &err, 0);
if (!*val || *err) {
fprintf(stderr, "bad numerical value %s\n", val);
goto error;
}
x86_cpu_def->level = numvalue;
object_property_parse(OBJECT(cpu), val, featurestr, errp);
} else if (!strcmp(featurestr, "xlevel")) {
char *err;
char num[32];
numvalue = strtoul(val, &err, 0);
if (!*val || *err) {
fprintf(stderr, "bad numerical value %s\n", val);
goto error;
error_setg(errp, "bad numerical value %s\n", val);
goto out;
}
if (numvalue < 0x80000000) {
fprintf(stderr, "xlevel value shall always be >= 0x80000000"
", fixup will be removed in future versions\n");
numvalue += 0x80000000;
}
x86_cpu_def->xlevel = numvalue;
snprintf(num, sizeof(num), "%" PRIu32, numvalue);
object_property_parse(OBJECT(cpu), num, featurestr, errp);
} else if (!strcmp(featurestr, "vendor")) {
if (strlen(val) != 12) {
fprintf(stderr, "vendor string must be 12 chars long\n");
goto error;
}
x86_cpu_def->vendor1 = 0;
x86_cpu_def->vendor2 = 0;
x86_cpu_def->vendor3 = 0;
for(i = 0; i < 4; i++) {
x86_cpu_def->vendor1 |= ((uint8_t)val[i ]) << (8 * i);
x86_cpu_def->vendor2 |= ((uint8_t)val[i + 4]) << (8 * i);
x86_cpu_def->vendor3 |= ((uint8_t)val[i + 8]) << (8 * i);
}
x86_cpu_def->vendor_override = 1;
object_property_parse(OBJECT(cpu), val, featurestr, errp);
} else if (!strcmp(featurestr, "model_id")) {
pstrcpy(x86_cpu_def->model_id, sizeof(x86_cpu_def->model_id),
val);
object_property_parse(OBJECT(cpu), val, "model-id", errp);
} else if (!strcmp(featurestr, "tsc_freq")) {
int64_t tsc_freq;
char *err;
char num[32];
tsc_freq = strtosz_suffix_unit(val, &err,
STRTOSZ_DEFSUFFIX_B, 1000);
if (tsc_freq < 0 || *err) {
fprintf(stderr, "bad numerical value %s\n", val);
goto error;
error_setg(errp, "bad numerical value %s\n", val);
goto out;
}
x86_cpu_def->tsc_khz = tsc_freq / 1000;
snprintf(num, sizeof(num), "%" PRId64, tsc_freq);
object_property_parse(OBJECT(cpu), num, "tsc-frequency", errp);
} else if (!strcmp(featurestr, "hv_spinlocks")) {
char *err;
numvalue = strtoul(val, &err, 0);
if (!*val || *err) {
fprintf(stderr, "bad numerical value %s\n", val);
goto error;
error_setg(errp, "bad numerical value %s\n", val);
goto out;
}
hyperv_set_spinlock_retries(numvalue);
} else {
fprintf(stderr, "unrecognized feature %s\n", featurestr);
goto error;
error_setg(errp, "unrecognized feature %s\n", featurestr);
goto out;
}
} else if (!strcmp(featurestr, "check")) {
check_cpuid = 1;
@ -1451,31 +1381,34 @@ static int cpu_x86_parse_featurestr(x86_def_t *x86_cpu_def, char *features)
} else if (!strcmp(featurestr, "hv_vapic")) {
hyperv_enable_vapic_recommended(true);
} else {
fprintf(stderr, "feature string `%s' not in format (+feature|-feature|feature=xyz)\n", featurestr);
goto error;
error_setg(errp, "feature string `%s' not in format (+feature|"
"-feature|feature=xyz)\n", featurestr);
goto out;
}
if (error_is_set(errp)) {
goto out;
}
featurestr = strtok(NULL, ",");
}
x86_cpu_def->features |= plus_features[FEAT_1_EDX];
x86_cpu_def->ext_features |= plus_features[FEAT_1_ECX];
x86_cpu_def->ext2_features |= plus_features[FEAT_8000_0001_EDX];
x86_cpu_def->ext3_features |= plus_features[FEAT_8000_0001_ECX];
x86_cpu_def->ext4_features |= plus_features[FEAT_C000_0001_EDX];
x86_cpu_def->kvm_features |= plus_features[FEAT_KVM];
x86_cpu_def->svm_features |= plus_features[FEAT_SVM];
x86_cpu_def->cpuid_7_0_ebx_features |= plus_features[FEAT_7_0_EBX];
x86_cpu_def->features &= ~minus_features[FEAT_1_EDX];
x86_cpu_def->ext_features &= ~minus_features[FEAT_1_ECX];
x86_cpu_def->ext2_features &= ~minus_features[FEAT_8000_0001_EDX];
x86_cpu_def->ext3_features &= ~minus_features[FEAT_8000_0001_ECX];
x86_cpu_def->ext4_features &= ~minus_features[FEAT_C000_0001_EDX];
x86_cpu_def->kvm_features &= ~minus_features[FEAT_KVM];
x86_cpu_def->svm_features &= ~minus_features[FEAT_SVM];
x86_cpu_def->cpuid_7_0_ebx_features &= ~minus_features[FEAT_7_0_EBX];
return 0;
env->cpuid_features |= plus_features[FEAT_1_EDX];
env->cpuid_ext_features |= plus_features[FEAT_1_ECX];
env->cpuid_ext2_features |= plus_features[FEAT_8000_0001_EDX];
env->cpuid_ext3_features |= plus_features[FEAT_8000_0001_ECX];
env->cpuid_ext4_features |= plus_features[FEAT_C000_0001_EDX];
env->cpuid_kvm_features |= plus_features[FEAT_KVM];
env->cpuid_svm_features |= plus_features[FEAT_SVM];
env->cpuid_7_0_ebx_features |= plus_features[FEAT_7_0_EBX];
env->cpuid_features &= ~minus_features[FEAT_1_EDX];
env->cpuid_ext_features &= ~minus_features[FEAT_1_ECX];
env->cpuid_ext2_features &= ~minus_features[FEAT_8000_0001_EDX];
env->cpuid_ext3_features &= ~minus_features[FEAT_8000_0001_ECX];
env->cpuid_ext4_features &= ~minus_features[FEAT_C000_0001_EDX];
env->cpuid_kvm_features &= ~minus_features[FEAT_KVM];
env->cpuid_svm_features &= ~minus_features[FEAT_SVM];
env->cpuid_7_0_ebx_features &= ~minus_features[FEAT_7_0_EBX];
error:
return -1;
out:
return;
}
/* generate a composite string into buf of all cpuid names in featureset
@ -1513,8 +1446,10 @@ void x86_cpu_list(FILE *f, fprintf_function cpu_fprintf)
{
x86_def_t *def;
char buf[256];
int i;
for (def = x86_defs; def; def = def->next) {
for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
def = &builtin_x86_defs[i];
snprintf(buf, sizeof(buf), "%s", def->name);
(*cpu_fprintf)(f, "x86 %16s %-48s\n", buf, def->model_id);
}
@ -1536,11 +1471,13 @@ CpuDefinitionInfoList *arch_query_cpu_definitions(Error **errp)
{
CpuDefinitionInfoList *cpu_list = NULL;
x86_def_t *def;
int i;
for (def = x86_defs; def; def = def->next) {
for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); i++) {
CpuDefinitionInfoList *entry;
CpuDefinitionInfo *info;
def = &builtin_x86_defs[i];
info = g_malloc0(sizeof(*info));
info->name = g_strdup(def->name);
@ -1602,18 +1539,12 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model)
goto out;
}
def->kvm_features |= kvm_default_features;
if (kvm_enabled()) {
def->kvm_features |= kvm_default_features;
}
def->ext_features |= CPUID_EXT_HYPERVISOR;
if (cpu_x86_parse_featurestr(def, features) < 0) {
error_setg(&error, "Invalid cpu_model string format: %s", cpu_model);
goto out;
}
assert(def->vendor1);
env->cpuid_vendor1 = def->vendor1;
env->cpuid_vendor2 = def->vendor2;
env->cpuid_vendor3 = def->vendor3;
env->cpuid_vendor_override = def->vendor_override;
object_property_set_str(OBJECT(cpu), def->vendor, "vendor", &error);
object_property_set_int(OBJECT(cpu), def->level, "level", &error);
object_property_set_int(OBJECT(cpu), def->family, "family", &error);
object_property_set_int(OBJECT(cpu), def->model, "model", &error);
@ -1628,11 +1559,13 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model)
env->cpuid_ext4_features = def->ext4_features;
env->cpuid_7_0_ebx_features = def->cpuid_7_0_ebx_features;
env->cpuid_xlevel2 = def->xlevel2;
object_property_set_int(OBJECT(cpu), (int64_t)def->tsc_khz * 1000,
"tsc-frequency", &error);
object_property_set_str(OBJECT(cpu), def->model_id, "model-id", &error);
if (error) {
goto out;
}
cpu_x86_parse_featurestr(cpu, features, &error);
out:
g_strfreev(model_pieces);
if (error) {
@ -1661,7 +1594,6 @@ void x86_cpudef_setup(void)
for (i = 0; i < ARRAY_SIZE(builtin_x86_defs); ++i) {
x86_def_t *def = &builtin_x86_defs[i];
def->next = x86_defs;
/* Look for specific "cpudef" models that */
/* have the QEMU version in .model_id */
@ -1674,8 +1606,6 @@ void x86_cpudef_setup(void)
break;
}
}
x86_defs = def;
}
}
@ -1685,16 +1615,6 @@ static void get_cpuid_vendor(CPUX86State *env, uint32_t *ebx,
*ebx = env->cpuid_vendor1;
*edx = env->cpuid_vendor2;
*ecx = env->cpuid_vendor3;
/* sysenter isn't supported on compatibility mode on AMD, syscall
* isn't supported in compatibility mode on Intel.
* Normally we advertise the actual cpu vendor, but you can override
* this if you want to use KVM's sysenter/syscall emulation
* in compatibility mode and when doing cross vendor migration
*/
if (kvm_enabled() && ! env->cpuid_vendor_override) {
host_cpuid(0, 0, NULL, ebx, ecx, edx);
}
}
void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
@ -2197,6 +2117,39 @@ void x86_cpu_realize(Object *obj, Error **errp)
cpu_reset(CPU(cpu));
}
/* Enables contiguous-apic-ID mode, for compatibility */
static bool compat_apic_id_mode;
void enable_compat_apic_id_mode(void)
{
compat_apic_id_mode = true;
}
/* Calculates initial APIC ID for a specific CPU index
*
* Currently we need to be able to calculate the APIC ID from the CPU index
* alone (without requiring a CPU object), as the QEMU<->Seabios interfaces have
* no concept of "CPU index", and the NUMA tables on fw_cfg need the APIC ID of
* all CPUs up to max_cpus.
*/
uint32_t x86_cpu_apic_id_from_index(unsigned int cpu_index)
{
uint32_t correct_id;
static bool warned;
correct_id = x86_apicid_from_cpu_idx(smp_cores, smp_threads, cpu_index);
if (compat_apic_id_mode) {
if (cpu_index != correct_id && !warned) {
error_report("APIC IDs set in compatibility mode, "
"CPU topology won't match the configuration");
warned = true;
}
return cpu_index;
} else {
return correct_id;
}
}
static void x86_cpu_initfn(Object *obj)
{
CPUState *cs = CPU(obj);
@ -2231,7 +2184,7 @@ static void x86_cpu_initfn(Object *obj)
x86_cpuid_get_tsc_freq,
x86_cpuid_set_tsc_freq, NULL, NULL, NULL);
env->cpuid_apic_id = cs->cpu_index;
env->cpuid_apic_id = x86_cpu_apic_id_from_index(cs->cpu_index);
/* init various static tables used in TCG mode */
if (tcg_enabled() && !inited) {

View file

@ -537,14 +537,14 @@ typedef uint32_t FeatureWordArray[FEATURE_WORDS];
#define CPUID_VENDOR_INTEL_1 0x756e6547 /* "Genu" */
#define CPUID_VENDOR_INTEL_2 0x49656e69 /* "ineI" */
#define CPUID_VENDOR_INTEL_3 0x6c65746e /* "ntel" */
#define CPUID_VENDOR_INTEL "GenuineIntel"
#define CPUID_VENDOR_AMD_1 0x68747541 /* "Auth" */
#define CPUID_VENDOR_AMD_2 0x69746e65 /* "enti" */
#define CPUID_VENDOR_AMD_3 0x444d4163 /* "cAMD" */
#define CPUID_VENDOR_AMD "AuthenticAMD"
#define CPUID_VENDOR_VIA_1 0x746e6543 /* "Cent" */
#define CPUID_VENDOR_VIA_2 0x48727561 /* "aurH" */
#define CPUID_VENDOR_VIA_3 0x736c7561 /* "auls" */
#define CPUID_VENDOR_VIA "CentaurHauls"
#define CPUID_MWAIT_IBE (1 << 1) /* Interrupts can exit capability */
#define CPUID_MWAIT_EMX (1 << 0) /* enumeration supported */
@ -835,7 +835,6 @@ typedef struct CPUX86State {
uint32_t cpuid_ext2_features;
uint32_t cpuid_ext3_features;
uint32_t cpuid_apic_id;
int cpuid_vendor_override;
/* Store the results of Centaur's CPUID instructions */
uint32_t cpuid_xlevel2;
uint32_t cpuid_ext4_features;
@ -1250,9 +1249,12 @@ void do_smm_enter(CPUX86State *env1);
void cpu_report_tpr_access(CPUX86State *env, TPRAccess access);
void enable_kvm_pv_eoi(void);
void disable_kvm_pv_eoi(void);
/* Return name of 32-bit register, from a R_* constant */
const char *get_register_name_32(unsigned int reg);
uint32_t x86_cpu_apic_id_from_index(unsigned int cpu_index);
void enable_compat_apic_id_mode(void);
#endif /* CPU_I386_H */

View file

@ -411,6 +411,12 @@ static void cpu_update_state(void *opaque, int running, RunState state)
}
}
unsigned long kvm_arch_vcpu_id(CPUState *cs)
{
X86CPU *cpu = X86_CPU(cs);
return cpu->env.cpuid_apic_id;
}
int kvm_arch_init_vcpu(CPUState *cs)
{
struct {

136
target-i386/topology.h Normal file
View file

@ -0,0 +1,136 @@
/*
* x86 CPU topology data structures and functions
*
* Copyright (c) 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef TARGET_I386_TOPOLOGY_H
#define TARGET_I386_TOPOLOGY_H
/* This file implements the APIC-ID-based CPU topology enumeration logic,
* documented at the following document:
* Intel® 64 Architecture Processor Topology Enumeration
* http://software.intel.com/en-us/articles/intel-64-architecture-processor-topology-enumeration/
*
* This code should be compatible with AMD's "Extended Method" described at:
* AMD CPUID Specification (Publication #25481)
* Section 3: Multiple Core Calcuation
* as long as:
* nr_threads is set to 1;
* OFFSET_IDX is assumed to be 0;
* CPUID Fn8000_0008_ECX[ApicIdCoreIdSize[3:0]] is set to apicid_core_width().
*/
#include <stdint.h>
#include <string.h>
#include "qemu/bitops.h"
/* APIC IDs can be 32-bit, but beware: APIC IDs > 255 require x2APIC support
*/
typedef uint32_t apic_id_t;
/* Return the bit width needed for 'count' IDs
*/
static unsigned apicid_bitwidth_for_count(unsigned count)
{
g_assert(count >= 1);
if (count == 1) {
return 0;
}
return bitops_flsl(count - 1) + 1;
}
/* Bit width of the SMT_ID (thread ID) field on the APIC ID
*/
static inline unsigned apicid_smt_width(unsigned nr_cores, unsigned nr_threads)
{
return apicid_bitwidth_for_count(nr_threads);
}
/* Bit width of the Core_ID field
*/
static inline unsigned apicid_core_width(unsigned nr_cores, unsigned nr_threads)
{
return apicid_bitwidth_for_count(nr_cores);
}
/* Bit offset of the Core_ID field
*/
static inline unsigned apicid_core_offset(unsigned nr_cores,
unsigned nr_threads)
{
return apicid_smt_width(nr_cores, nr_threads);
}
/* Bit offset of the Pkg_ID (socket ID) field
*/
static inline unsigned apicid_pkg_offset(unsigned nr_cores, unsigned nr_threads)
{
return apicid_core_offset(nr_cores, nr_threads) +
apicid_core_width(nr_cores, nr_threads);
}
/* Make APIC ID for the CPU based on Pkg_ID, Core_ID, SMT_ID
*
* The caller must make sure core_id < nr_cores and smt_id < 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)
{
return (pkg_id << apicid_pkg_offset(nr_cores, nr_threads)) |
(core_id << apicid_core_offset(nr_cores, nr_threads)) |
smt_id;
}
/* Calculate thread/core/package IDs for a specific topology,
* based on (contiguous) CPU index
*/
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)
{
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;
}
/* Make APIC ID for the CPU 'cpu_index'
*
* 'cpu_index' is a sequential, contiguous ID for the CPU.
*/
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);
}
#endif /* TARGET_I386_TOPOLOGY_H */

View file

@ -55,6 +55,22 @@ static void m68k_cpu_reset(CPUState *s)
/* CPU models */
static ObjectClass *m68k_cpu_class_by_name(const char *cpu_model)
{
ObjectClass *oc;
if (cpu_model == NULL) {
return NULL;
}
oc = object_class_by_name(cpu_model);
if (oc != NULL && (object_class_dynamic_cast(oc, TYPE_M68K_CPU) == NULL ||
object_class_is_abstract(oc))) {
return NULL;
}
return oc;
}
static void m5206_cpu_initfn(Object *obj)
{
M68kCPU *cpu = M68K_CPU(obj);
@ -134,6 +150,8 @@ static void m68k_cpu_class_init(ObjectClass *c, void *data)
mcc->parent_reset = cc->reset;
cc->reset = m68k_cpu_reset;
cc->class_by_name = m68k_cpu_class_by_name;
}
static void register_cpu_type(const M68kCPUInfo *info)
@ -144,7 +162,7 @@ static void register_cpu_type(const M68kCPUInfo *info)
.instance_init = info->instance_init,
};
type_register_static(&type_info);
type_register(&type_info);
}
static const TypeInfo m68k_cpu_type_info = {

View file

@ -97,12 +97,14 @@ CPUM68KState *cpu_m68k_init(const char *cpu_model)
{
M68kCPU *cpu;
CPUM68KState *env;
ObjectClass *oc;
static int inited;
if (object_class_by_name(cpu_model) == NULL) {
oc = cpu_class_by_name(TYPE_M68K_CPU, cpu_model);
if (oc == NULL) {
return NULL;
}
cpu = M68K_CPU(object_new(cpu_model));
cpu = M68K_CPU(object_new(object_class_get_name(oc)));
env = &cpu->env;
if (!inited) {

View file

@ -88,6 +88,23 @@ static void openrisc_cpu_initfn(Object *obj)
}
/* CPU models */
static ObjectClass *openrisc_cpu_class_by_name(const char *cpu_model)
{
ObjectClass *oc;
if (cpu_model == NULL) {
return NULL;
}
oc = object_class_by_name(cpu_model);
if (oc != NULL && (!object_class_dynamic_cast(oc, TYPE_OPENRISC_CPU) ||
object_class_is_abstract(oc))) {
return NULL;
}
return oc;
}
static void or1200_initfn(Object *obj)
{
OpenRISCCPU *cpu = OPENRISC_CPU(obj);
@ -120,6 +137,8 @@ static void openrisc_cpu_class_init(ObjectClass *oc, void *data)
occ->parent_reset = cc->reset;
cc->reset = openrisc_cpu_reset;
cc->class_by_name = openrisc_cpu_class_by_name;
}
static void cpu_register(const OpenRISCCPUInfo *info)
@ -132,7 +151,7 @@ static void cpu_register(const OpenRISCCPUInfo *info)
.class_size = sizeof(OpenRISCCPUClass),
};
type_register_static(&type_info);
type_register(&type_info);
}
static const TypeInfo openrisc_cpu_type_info = {
@ -158,11 +177,13 @@ static void openrisc_cpu_register_types(void)
OpenRISCCPU *cpu_openrisc_init(const char *cpu_model)
{
OpenRISCCPU *cpu;
ObjectClass *oc;
if (!object_class_by_name(cpu_model)) {
oc = openrisc_cpu_class_by_name(cpu_model);
if (oc == NULL) {
return NULL;
}
cpu = OPENRISC_CPU(object_new(cpu_model));
cpu = OPENRISC_CPU(object_new(object_class_get_name(oc)));
cpu->env.cpu_model_str = cpu_model;
openrisc_cpu_realize(OBJECT(cpu), NULL);
@ -170,11 +191,6 @@ OpenRISCCPU *cpu_openrisc_init(const char *cpu_model)
return cpu;
}
typedef struct OpenRISCCPUList {
fprintf_function cpu_fprintf;
FILE *file;
} OpenRISCCPUList;
/* Sort alphabetically by type name, except for "any". */
static gint openrisc_cpu_list_compare(gconstpointer a, gconstpointer b)
{
@ -196,7 +212,7 @@ static gint openrisc_cpu_list_compare(gconstpointer a, gconstpointer b)
static void openrisc_cpu_list_entry(gpointer data, gpointer user_data)
{
ObjectClass *oc = data;
OpenRISCCPUList *s = user_data;
CPUListState *s = user_data;
(*s->cpu_fprintf)(s->file, " %s\n",
object_class_get_name(oc));
@ -204,7 +220,7 @@ static void openrisc_cpu_list_entry(gpointer data, gpointer user_data)
void cpu_openrisc_list(FILE *f, fprintf_function cpu_fprintf)
{
OpenRISCCPUList s = {
CPUListState s = {
.file = f,
.cpu_fprintf = cpu_fprintf,
};

View file

@ -23,7 +23,7 @@
void HELPER(exception)(CPUOpenRISCState *env, uint32_t excp)
{
OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
raise_exception(cpu, excp);
}

View file

@ -68,7 +68,7 @@ static inline void update_fpcsr(OpenRISCCPU *cpu)
uint64_t HELPER(itofd)(CPUOpenRISCState *env, uint64_t val)
{
uint64_t itofd;
OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
set_float_exception_flags(0, &cpu->env.fp_status);
itofd = int32_to_float64(val, &cpu->env.fp_status);
@ -80,7 +80,7 @@ uint64_t HELPER(itofd)(CPUOpenRISCState *env, uint64_t val)
uint32_t HELPER(itofs)(CPUOpenRISCState *env, uint32_t val)
{
uint32_t itofs;
OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
set_float_exception_flags(0, &cpu->env.fp_status);
itofs = int32_to_float32(val, &cpu->env.fp_status);
@ -92,7 +92,7 @@ uint32_t HELPER(itofs)(CPUOpenRISCState *env, uint32_t val)
uint64_t HELPER(ftoid)(CPUOpenRISCState *env, uint64_t val)
{
uint64_t ftoid;
OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
set_float_exception_flags(0, &cpu->env.fp_status);
ftoid = float32_to_int64(val, &cpu->env.fp_status);
@ -104,7 +104,7 @@ uint64_t HELPER(ftoid)(CPUOpenRISCState *env, uint64_t val)
uint32_t HELPER(ftois)(CPUOpenRISCState *env, uint32_t val)
{
uint32_t ftois;
OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
set_float_exception_flags(0, &cpu->env.fp_status);
ftois = float32_to_int32(val, &cpu->env.fp_status);
@ -120,7 +120,7 @@ uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \
uint64_t fdt0, uint64_t fdt1) \
{ \
uint64_t result; \
OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \
OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \
set_float_exception_flags(0, &cpu->env.fp_status); \
result = float64_ ## name(fdt0, fdt1, &cpu->env.fp_status); \
update_fpcsr(cpu); \
@ -131,7 +131,7 @@ uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \
uint32_t fdt0, uint32_t fdt1) \
{ \
uint32_t result; \
OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \
OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \
set_float_exception_flags(0, &cpu->env.fp_status); \
result = float32_ ## name(fdt0, fdt1, &cpu->env.fp_status); \
update_fpcsr(cpu); \
@ -152,7 +152,7 @@ uint64_t helper_float_ ## name1 ## name2 ## _d(CPUOpenRISCState *env, \
{ \
uint64_t result, temp, hi, lo; \
uint32_t val1, val2; \
OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \
OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \
hi = env->fpmaddhi; \
lo = env->fpmaddlo; \
set_float_exception_flags(0, &cpu->env.fp_status); \
@ -174,7 +174,7 @@ uint32_t helper_float_ ## name1 ## name2 ## _s(CPUOpenRISCState *env, \
{ \
uint64_t result, temp, hi, lo; \
uint32_t val1, val2; \
OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \
OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \
hi = cpu->env.fpmaddhi; \
lo = cpu->env.fpmaddlo; \
set_float_exception_flags(0, &cpu->env.fp_status); \
@ -198,7 +198,7 @@ uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \
uint64_t fdt0, uint64_t fdt1) \
{ \
int res; \
OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \
OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \
set_float_exception_flags(0, &cpu->env.fp_status); \
res = float64_ ## name(fdt0, fdt1, &cpu->env.fp_status); \
update_fpcsr(cpu); \
@ -209,7 +209,7 @@ uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \
uint32_t fdt0, uint32_t fdt1)\
{ \
int res; \
OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \
OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \
set_float_exception_flags(0, &cpu->env.fp_status); \
res = float32_ ## name(fdt0, fdt1, &cpu->env.fp_status); \
update_fpcsr(cpu); \
@ -227,7 +227,7 @@ uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \
uint64_t fdt0, uint64_t fdt1) \
{ \
int res; \
OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \
OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \
set_float_exception_flags(0, &cpu->env.fp_status); \
res = !float64_eq_quiet(fdt0, fdt1, &cpu->env.fp_status); \
update_fpcsr(cpu); \
@ -238,7 +238,7 @@ uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \
uint32_t fdt0, uint32_t fdt1) \
{ \
int res; \
OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \
OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \
set_float_exception_flags(0, &cpu->env.fp_status); \
res = !float32_eq_quiet(fdt0, fdt1, &cpu->env.fp_status); \
update_fpcsr(cpu); \
@ -253,7 +253,7 @@ uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \
uint64_t fdt0, uint64_t fdt1) \
{ \
int res; \
OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \
OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \
set_float_exception_flags(0, &cpu->env.fp_status); \
res = !float64_le(fdt0, fdt1, &cpu->env.fp_status); \
update_fpcsr(cpu); \
@ -264,7 +264,7 @@ uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \
uint32_t fdt0, uint32_t fdt1) \
{ \
int res; \
OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \
OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \
set_float_exception_flags(0, &cpu->env.fp_status); \
res = !float32_le(fdt0, fdt1, &cpu->env.fp_status); \
update_fpcsr(cpu); \
@ -278,7 +278,7 @@ uint64_t helper_float_ ## name ## _d(CPUOpenRISCState *env, \
uint64_t fdt0, uint64_t fdt1) \
{ \
int res; \
OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \
OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \
set_float_exception_flags(0, &cpu->env.fp_status); \
res = !float64_lt(fdt0, fdt1, &cpu->env.fp_status); \
update_fpcsr(cpu); \
@ -289,7 +289,7 @@ uint32_t helper_float_ ## name ## _s(CPUOpenRISCState *env, \
uint32_t fdt0, uint32_t fdt1) \
{ \
int res; \
OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env)); \
OpenRISCCPU *cpu = openrisc_env_get_cpu(env); \
set_float_exception_flags(0, &cpu->env.fp_status); \
res = !float32_lt(fdt0, fdt1, &cpu->env.fp_status); \
update_fpcsr(cpu); \

View file

@ -48,7 +48,7 @@ uint32_t HELPER(mul32)(CPUOpenRISCState *env,
uint64_t result;
uint32_t high, cy;
OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
result = (uint64_t)ra * rb;
/* regisiers in or32 is 32bit, so 32 is NOT a magic number.

View file

@ -23,7 +23,7 @@
void HELPER(rfe)(CPUOpenRISCState *env)
{
OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
#ifndef CONFIG_USER_ONLY
int need_flush_tlb = (cpu->env.sr & (SR_SM | SR_IME | SR_DME)) ^
(cpu->env.esr & (SR_SM | SR_IME | SR_DME));

View file

@ -187,7 +187,7 @@ int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env,
int ret = 0;
hwaddr physical = 0;
int prot = 0;
OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
ret = cpu_openrisc_get_phys_addr(cpu, &physical, &prot,
address, rw);
@ -209,7 +209,7 @@ int cpu_openrisc_handle_mmu_fault(CPUOpenRISCState *env,
target_ulong address, int rw, int mmu_idx)
{
int ret = 0;
OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
cpu_openrisc_raise_mmu_exception(cpu, address, rw, ret);
ret = 1;
@ -224,7 +224,7 @@ hwaddr cpu_get_phys_page_debug(CPUOpenRISCState *env,
{
hwaddr phys_addr;
int prot;
OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
if (cpu_openrisc_get_phys_addr(cpu, &phys_addr, &prot, addr, 0)) {
return -1;

View file

@ -30,7 +30,7 @@ void HELPER(mtspr)(CPUOpenRISCState *env,
int spr = (ra | offset);
int idx;
OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
switch (spr) {
case TO_SPR(0, 0): /* VR */
@ -177,7 +177,7 @@ target_ulong HELPER(mfspr)(CPUOpenRISCState *env,
int spr = (ra | offset);
int idx;
OpenRISCCPU *cpu = OPENRISC_CPU(ENV_GET_CPU(env));
OpenRISCCPU *cpu = openrisc_env_get_cpu(env);
switch (spr) {
case TO_SPR(0, 0): /* VR */

View file

@ -384,6 +384,11 @@ static inline void kvm_fixup_page_sizes(PowerPCCPU *cpu)
#endif /* !defined (TARGET_PPC64) */
unsigned long kvm_arch_vcpu_id(CPUState *cpu)
{
return cpu->cpu_index;
}
int kvm_arch_init_vcpu(CPUState *cs)
{
PowerPCCPU *cpu = POWERPC_CPU(cs);

View file

@ -10578,6 +10578,8 @@ static void ppc_cpu_class_init(ObjectClass *oc, void *data)
pcc->parent_reset = cc->reset;
cc->reset = ppc_cpu_reset;
cc->class_by_name = ppc_cpu_class_by_name;
}
static const TypeInfo ppc_cpu_type_info = {

View file

@ -76,6 +76,11 @@ int kvm_arch_init(KVMState *s)
return 0;
}
unsigned long kvm_arch_vcpu_id(CPUState *cpu)
{
return cpu->cpu_index;
}
int kvm_arch_init_vcpu(CPUState *cpu)
{
int ret = 0;

View file

@ -22,6 +22,22 @@ static inline void set_feature(CPUUniCore32State *env, int feature)
/* CPU models */
static ObjectClass *uc32_cpu_class_by_name(const char *cpu_model)
{
ObjectClass *oc;
if (cpu_model == NULL) {
return NULL;
}
oc = object_class_by_name(cpu_model);
if (oc != NULL && (!object_class_dynamic_cast(oc, TYPE_UNICORE32_CPU) ||
object_class_is_abstract(oc))) {
oc = NULL;
}
return oc;
}
typedef struct UniCore32CPUInfo {
const char *name;
void (*instance_init)(Object *obj);
@ -80,6 +96,13 @@ static void uc32_cpu_initfn(Object *obj)
tlb_flush(env, 1);
}
static void uc32_cpu_class_init(ObjectClass *oc, void *data)
{
CPUClass *cc = CPU_CLASS(oc);
cc->class_by_name = uc32_cpu_class_by_name;
}
static void uc32_register_cpu_type(const UniCore32CPUInfo *info)
{
TypeInfo type_info = {
@ -88,7 +111,7 @@ static void uc32_register_cpu_type(const UniCore32CPUInfo *info)
.instance_init = info->instance_init,
};
type_register_static(&type_info);
type_register(&type_info);
}
static const TypeInfo uc32_cpu_type_info = {
@ -98,6 +121,7 @@ static const TypeInfo uc32_cpu_type_info = {
.instance_init = uc32_cpu_initfn,
.abstract = true,
.class_size = sizeof(UniCore32CPUClass),
.class_init = uc32_cpu_class_init,
};
static void uc32_cpu_register_types(void)

View file

@ -29,12 +29,14 @@ CPUUniCore32State *uc32_cpu_init(const char *cpu_model)
{
UniCore32CPU *cpu;
CPUUniCore32State *env;
ObjectClass *oc;
static int inited = 1;
if (object_class_by_name(cpu_model) == NULL) {
oc = cpu_class_by_name(TYPE_UNICORE32_CPU, cpu_model);
if (oc == NULL) {
return NULL;
}
cpu = UNICORE32_CPU(object_new(cpu_model));
cpu = UNICORE32_CPU(object_new(object_class_get_name(oc)));
env = &cpu->env;
if (inited) {

1
tests/.gitignore vendored
View file

@ -10,4 +10,5 @@ test-qmp-commands.h
test-qmp-commands
test-qmp-input-strict
test-qmp-marshal.c
test-x86-cpuid
*-test

View file

@ -47,6 +47,9 @@ check-unit-y += tests/test-thread-pool$(EXESUF)
gcov-files-test-thread-pool-y = thread-pool.c
gcov-files-test-hbitmap-y = util/hbitmap.c
check-unit-y += tests/test-hbitmap$(EXESUF)
check-unit-y += tests/test-x86-cpuid$(EXESUF)
# all code tested by test-x86-cpuid is inside topology.h
gcov-files-test-x86-cpuid-y =
check-block-$(CONFIG_POSIX) += tests/qemu-iotests-quick.sh
@ -74,12 +77,15 @@ test-obj-y = tests/check-qint.o tests/check-qstring.o tests/check-qdict.o \
tests/test-coroutine.o tests/test-string-output-visitor.o \
tests/test-string-input-visitor.o tests/test-qmp-output-visitor.o \
tests/test-qmp-input-visitor.o tests/test-qmp-input-strict.o \
tests/test-qmp-commands.o tests/test-visitor-serialization.o
tests/test-qmp-commands.o tests/test-visitor-serialization.o \
tests/test-x86-cpuid.o
test-qapi-obj-y = tests/test-qapi-visit.o tests/test-qapi-types.o
$(test-obj-y): QEMU_INCLUDES += -Itests
tests/test-x86-cpuid.o: QEMU_INCLUDES += -I$(SRC_PATH)/target-i386
tests/check-qint$(EXESUF): tests/check-qint.o libqemuutil.a
tests/check-qstring$(EXESUF): tests/check-qstring.o libqemuutil.a
tests/check-qdict$(EXESUF): tests/check-qdict.o libqemuutil.a
@ -91,6 +97,7 @@ tests/test-aio$(EXESUF): tests/test-aio.o $(block-obj-y) libqemuutil.a libqemust
tests/test-thread-pool$(EXESUF): tests/test-thread-pool.o $(block-obj-y) libqemuutil.a libqemustub.a
tests/test-iov$(EXESUF): tests/test-iov.o libqemuutil.a
tests/test-hbitmap$(EXESUF): tests/test-hbitmap.o libqemuutil.a libqemustub.a
tests/test-x86-cpuid$(EXESUF): tests/test-x86-cpuid.o
tests/test-qapi-types.c tests/test-qapi-types.h :\
$(SRC_PATH)/qapi-schema-test.json $(SRC_PATH)/scripts/qapi-types.py

110
tests/test-x86-cpuid.c Normal file
View file

@ -0,0 +1,110 @@
/*
* Test code for x86 CPUID and Topology functions
*
* Copyright (c) 2012 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <glib.h>
#include "topology.h"
static void test_topo_bits(void)
{
/* simple tests for 1 thread per core, 1 core per socket */
g_assert_cmpuint(apicid_smt_width(1, 1), ==, 0);
g_assert_cmpuint(apicid_core_width(1, 1), ==, 0);
g_assert_cmpuint(x86_apicid_from_cpu_idx(1, 1, 0), ==, 0);
g_assert_cmpuint(x86_apicid_from_cpu_idx(1, 1, 1), ==, 1);
g_assert_cmpuint(x86_apicid_from_cpu_idx(1, 1, 2), ==, 2);
g_assert_cmpuint(x86_apicid_from_cpu_idx(1, 1, 3), ==, 3);
/* Test field width calculation for multiple values
*/
g_assert_cmpuint(apicid_smt_width(1, 2), ==, 1);
g_assert_cmpuint(apicid_smt_width(1, 3), ==, 2);
g_assert_cmpuint(apicid_smt_width(1, 4), ==, 2);
g_assert_cmpuint(apicid_smt_width(1, 14), ==, 4);
g_assert_cmpuint(apicid_smt_width(1, 15), ==, 4);
g_assert_cmpuint(apicid_smt_width(1, 16), ==, 4);
g_assert_cmpuint(apicid_smt_width(1, 17), ==, 5);
g_assert_cmpuint(apicid_core_width(30, 2), ==, 5);
g_assert_cmpuint(apicid_core_width(31, 2), ==, 5);
g_assert_cmpuint(apicid_core_width(32, 2), ==, 5);
g_assert_cmpuint(apicid_core_width(33, 2), ==, 6);
/* build a weird topology and see if IDs are calculated correctly
*/
/* This will use 2 bits for thread ID and 3 bits for core ID
*/
g_assert_cmpuint(apicid_smt_width(6, 3), ==, 2);
g_assert_cmpuint(apicid_core_width(6, 3), ==, 3);
g_assert_cmpuint(apicid_pkg_offset(6, 3), ==, 5);
g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 0), ==, 0);
g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 1), ==, 1);
g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 2), ==, 2);
g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 1 * 3 + 0), ==,
(1 << 2) | 0);
g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 1 * 3 + 1), ==,
(1 << 2) | 1);
g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 1 * 3 + 2), ==,
(1 << 2) | 2);
g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 2 * 3 + 0), ==,
(2 << 2) | 0);
g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 2 * 3 + 1), ==,
(2 << 2) | 1);
g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 2 * 3 + 2), ==,
(2 << 2) | 2);
g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 5 * 3 + 0), ==,
(5 << 2) | 0);
g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 5 * 3 + 1), ==,
(5 << 2) | 1);
g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 5 * 3 + 2), ==,
(5 << 2) | 2);
g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 1 * 6 * 3 + 0 * 3 + 0), ==,
(1 << 5));
g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 1 * 6 * 3 + 1 * 3 + 1), ==,
(1 << 5) | (1 << 2) | 1);
g_assert_cmpuint(x86_apicid_from_cpu_idx(6, 3, 3 * 6 * 3 + 5 * 3 + 2), ==,
(3 << 5) | (5 << 2) | 2);
}
int main(int argc, char **argv)
{
g_test_init(&argc, &argv, NULL);
g_test_add_func("/cpuid/topology/basic", test_topo_bits);
g_test_run();
return 0;
}