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:
commit
ec9466ff2e
8
cpus.c
8
cpus.c
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
40
hw/pc.c
@ -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;
|
||||
}
|
||||
|
26
hw/pc_piix.c
26
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,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
13
qom/cpu.c
13
qom/cpu.c
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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 */
|
||||
|
@ -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
136
target-i386/topology.h
Normal 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 */
|
@ -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 = {
|
||||
|
@ -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) {
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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); \
|
||||
|
@ -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.
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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 = {
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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
1
tests/.gitignore
vendored
@ -10,4 +10,5 @@ test-qmp-commands.h
|
||||
test-qmp-commands
|
||||
test-qmp-input-strict
|
||||
test-qmp-marshal.c
|
||||
test-x86-cpuid
|
||||
*-test
|
||||
|
@ -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
110
tests/test-x86-cpuid.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user