diff options
40 files changed, 709 insertions, 292 deletions
@@ -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); } diff --git a/hw/fw_cfg.c b/hw/fw_cfg.c index bdcd836986..02618f2480 100644 --- a/hw/fw_cfg.c +++ b/hw/fw_cfg.c @@ -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); @@ -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; } diff --git a/hw/pc_piix.c b/hw/pc_piix.c index 0a6923dcef..b9a9b2efe1 100644 --- a/hw/pc_piix.c +++ b/hw/pc_piix.c @@ -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, diff --git a/hw/ppc/mac_newworld.c b/hw/ppc/mac_newworld.c index 6de810bde1..065ea871b3 100644 --- a/hw/ppc/mac_newworld.c +++ b/hw/ppc/mac_newworld.c @@ -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); diff --git a/hw/ppc/mac_oldworld.c b/hw/ppc/mac_oldworld.c index 9ed303a5e5..2778e45879 100644 --- a/hw/ppc/mac_oldworld.c +++ b/hw/ppc/mac_oldworld.c @@ -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); diff --git a/hw/sun4m.c b/hw/sun4m.c index 035a011768..9903f443cb 100644 --- a/hw/sun4m.c +++ b/hw/sun4m.c @@ -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); diff --git a/hw/sun4u.c b/hw/sun4u.c index b891b84c9c..9fbda29ac4 100644 --- a/hw/sun4u.c +++ b/hw/sun4u.c @@ -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); diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 773caf9fa1..46f2247274 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -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; @@ -108,6 +110,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. * diff --git a/include/qom/object.h b/include/qom/object.h index 8e16ea8a44..48e80ba229 100644 --- a/include/qom/object.h +++ b/include/qom/object.h @@ -691,6 +691,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. * diff --git a/include/sysemu/cpus.h b/include/sysemu/cpus.h index 81bd81773f..f7f6854259 100644 --- a/include/sysemu/cpus.h +++ b/include/sysemu/cpus.h @@ -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); diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index 6bdd51373e..6e6dfb374a 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -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); @@ -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); } diff --git a/kvm-stub.c b/kvm-stub.c index 47f8dca7d5..760aadc874 100644 --- a/kvm-stub.c +++ b/kvm-stub.c @@ -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; } @@ -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; } diff --git a/qom/object.c b/qom/object.c index 03e6f24d28..e200282172 100644 --- a/qom/object.c +++ b/qom/object.c @@ -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; diff --git a/target-alpha/cpu.c b/target-alpha/cpu.c index 40e980933f..0ad69f0859 100644 --- a/target-alpha/cpu.c +++ b/target-alpha/cpu.c @@ -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) diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 07588a13b2..d1a4c82680 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -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) diff --git a/target-arm/helper.c b/target-arm/helper.c index 37c34a11c4..7a10fddf25 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -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); diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 376d4c8737..5c108e17ab 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -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() && name && strcmp(name, "host") == 0) { + if (kvm_enabled() && 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 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; + } + } + + 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) { diff --git a/target-i386/cpu.h b/target-i386/cpu.h index 4e091cdec3..62508dc688 100644 --- a/target-i386/cpu.h +++ b/target-i386/cpu.h @@ -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 */ diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 3acff40c47..c440809cb2 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -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 { diff --git a/target-i386/topology.h b/target-i386/topology.h new file mode 100644 index 0000000000..24ed525453 --- /dev/null +++ b/target-i386/topology.h @@ -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 */ diff --git a/target-m68k/cpu.c b/target-m68k/cpu.c index ce89674a08..5c7803181d 100644 --- a/target-m68k/cpu.c +++ b/target-m68k/cpu.c @@ -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 = { diff --git a/target-m68k/helper.c b/target-m68k/helper.c index 097fc789d4..f66e12b6ba 100644 --- a/target-m68k/helper.c +++ b/target-m68k/helper.c @@ -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) { diff --git a/target-openrisc/cpu.c b/target-openrisc/cpu.c index 56544d8ab5..54876d904b 100644 --- a/target-openrisc/cpu.c +++ b/target-openrisc/cpu.c @@ -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, }; diff --git a/target-openrisc/exception_helper.c b/target-openrisc/exception_helper.c index dab4148151..0c53b7755b 100644 --- a/target-openrisc/exception_helper.c +++ b/target-openrisc/exception_helper.c @@ -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); } diff --git a/target-openrisc/fpu_helper.c b/target-openrisc/fpu_helper.c index b184d5ef73..4615a366d1 100644 --- a/target-openrisc/fpu_helper.c +++ b/target-openrisc/fpu_helper.c @@ -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); \ diff --git a/target-openrisc/int_helper.c b/target-openrisc/int_helper.c index 20f9837e6a..16cb5abfcd 100644 --- a/target-openrisc/int_helper.c +++ b/target-openrisc/int_helper.c @@ -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. diff --git a/target-openrisc/interrupt_helper.c b/target-openrisc/interrupt_helper.c index 79f5afed44..a176441b01 100644 --- a/target-openrisc/interrupt_helper.c +++ b/target-openrisc/interrupt_helper.c @@ -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)); diff --git a/target-openrisc/mmu.c b/target-openrisc/mmu.c index 836465259a..d354e1f8b2 100644 --- a/target-openrisc/mmu.c +++ b/target-openrisc/mmu.c @@ -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; diff --git a/target-openrisc/sys_helper.c b/target-openrisc/sys_helper.c index f160dc397c..3c5f45ab75 100644 --- a/target-openrisc/sys_helper.c +++ b/target-openrisc/sys_helper.c @@ -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 */ diff --git a/target-ppc/kvm.c b/target-ppc/kvm.c index 2f4f06818a..2c64c634f1 100644 --- a/target-ppc/kvm.c +++ b/target-ppc/kvm.c @@ -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); diff --git a/target-ppc/translate_init.c b/target-ppc/translate_init.c index 4f767c9751..e143af532a 100644 --- a/target-ppc/translate_init.c +++ b/target-ppc/translate_init.c @@ -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 = { diff --git a/target-s390x/kvm.c b/target-s390x/kvm.c index add6a58f9c..99deddf96d 100644 --- a/target-s390x/kvm.c +++ b/target-s390x/kvm.c @@ -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; diff --git a/target-unicore32/cpu.c b/target-unicore32/cpu.c index 884c101010..c120440653 100644 --- a/target-unicore32/cpu.c +++ b/target-unicore32/cpu.c @@ -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) diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c index 5359538ea5..183b5b3577 100644 --- a/target-unicore32/helper.c +++ b/target-unicore32/helper.c @@ -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) { diff --git a/tests/.gitignore b/tests/.gitignore index f9041f3d32..38c94ef1da 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -10,4 +10,5 @@ test-qmp-commands.h test-qmp-commands test-qmp-input-strict test-qmp-marshal.c +test-x86-cpuid *-test diff --git a/tests/Makefile b/tests/Makefile index a77f26a256..c681cebd18 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -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 diff --git a/tests/test-x86-cpuid.c b/tests/test-x86-cpuid.c new file mode 100644 index 0000000000..8d9f96a113 --- /dev/null +++ b/tests/test-x86-cpuid.c @@ -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; +} |