aboutsummaryrefslogtreecommitdiff
path: root/target-i386
diff options
context:
space:
mode:
authorAnthony Liguori <aliguori@us.ibm.com>2012-11-01 11:12:32 -0500
committerAnthony Liguori <aliguori@us.ibm.com>2012-11-01 11:12:32 -0500
commit98c8a73b2e82eecac359b0b55a2d9d69f0a916ff (patch)
tree83411ea890eb54266773ad4337fc91c49dd36999 /target-i386
parentfc53b7d4b7fe409acae7d8d55a868eb5c696d71c (diff)
parent839b5630cd4f49ce10618a7bf0b705b76f3a01ca (diff)
Merge remote-tracking branch 'afaerber/qom-cpu' into staging
* afaerber/qom-cpu: (35 commits) target-i386: Pass X86CPU to kvm_handle_halt() target-i386: Pass X86CPU to kvm_get_mp_state() cpu: Move thread_id to CPUState cpus: Pass CPUState to run_on_cpu() target-i386: Pass X86CPU to cpu_x86_inject_mce() target-i386: Pass X86CPU to kvm_mce_inject() cpus: Pass CPUState to [qemu_]cpu_has_work() spapr: Pass PowerPCCPU to hypercalls spapr: Pass PowerPCCPU to spapr_hypercall() target-ppc: Pass PowerPCCPU to cpu_ppc_hypercall target-ppc: Pass PowerPCCPU to powerpc_excp() xtensa_pic: Pass XtensaCPU to xtensa_ccompare_cb() cpus: Pass CPUState to qemu_wait_io_event_common() cpus: Pass CPUState to flush_queued_work() cpu: Move queued_work_{first,last} to CPUState cpus: Pass CPUState to qemu_cpu_kick() target-ppc: Rename kvm_kick_{env => cpu} and pass PowerPCCPU ppc: Pass PowerPCCPU to {ppc6xx,ppc970,power7,ppc40x,ppce500}_set_irq() cpus: Pass CPUState to qemu_tcg_init_vcpu() cpus: Pass CPUState to qemu_tcg_cpu_thread_fn ... Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Diffstat (limited to 'target-i386')
-rw-r--r--target-i386/cpu.c63
-rw-r--r--target-i386/cpu.h10
-rw-r--r--target-i386/helper.c16
-rw-r--r--target-i386/kvm.c28
4 files changed, 98 insertions, 19 deletions
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index d4f2e65cd9..156e9199ed 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -37,6 +37,13 @@
#include <linux/kvm_para.h>
#endif
+#include "sysemu.h"
+#ifndef CONFIG_USER_ONLY
+#include "hw/xen.h"
+#include "hw/sysbus.h"
+#include "hw/apic_internal.h"
+#endif
+
/* 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.
@@ -1427,7 +1434,8 @@ int cpu_x86_register(X86CPU *cpu, const char *cpu_model)
env->cpuid_svm_features &= TCG_SVM_FEATURES;
}
object_property_set_str(OBJECT(cpu), def->model_id, "model-id", &error);
- if (error_is_set(&error)) {
+ if (error) {
+ fprintf(stderr, "%s\n", error_get_pretty(error));
error_free(error);
return -1;
}
@@ -1878,12 +1886,65 @@ static void mce_init(X86CPU *cpu)
}
}
+#define MSI_ADDR_BASE 0xfee00000
+
+#ifndef CONFIG_USER_ONLY
+static void x86_cpu_apic_init(X86CPU *cpu, Error **errp)
+{
+ static int apic_mapped;
+ CPUX86State *env = &cpu->env;
+ APICCommonState *apic;
+ const char *apic_type = "apic";
+
+ if (kvm_irqchip_in_kernel()) {
+ apic_type = "kvm-apic";
+ } else if (xen_enabled()) {
+ apic_type = "xen-apic";
+ }
+
+ env->apic_state = qdev_try_create(NULL, apic_type);
+ if (env->apic_state == NULL) {
+ error_setg(errp, "APIC device '%s' could not be created", apic_type);
+ return;
+ }
+
+ object_property_add_child(OBJECT(cpu), "apic",
+ OBJECT(env->apic_state), NULL);
+ qdev_prop_set_uint8(env->apic_state, "id", env->cpuid_apic_id);
+ /* TODO: convert to link<> */
+ apic = APIC_COMMON(env->apic_state);
+ apic->cpu = cpu;
+
+ if (qdev_init(env->apic_state)) {
+ error_setg(errp, "APIC device '%s' could not be initialized",
+ object_get_typename(OBJECT(env->apic_state)));
+ return;
+ }
+
+ /* XXX: mapping more APICs at the same memory location */
+ if (apic_mapped == 0) {
+ /* NOTE: the APIC is directly connected to the CPU - it is not
+ on the global memory bus. */
+ /* XXX: what if the base changes? */
+ sysbus_mmio_map(sysbus_from_qdev(env->apic_state), 0, MSI_ADDR_BASE);
+ apic_mapped = 1;
+ }
+}
+#endif
+
void x86_cpu_realize(Object *obj, Error **errp)
{
X86CPU *cpu = X86_CPU(obj);
#ifndef CONFIG_USER_ONLY
qemu_register_reset(x86_cpu_machine_reset_cb, cpu);
+
+ if (cpu->env.cpuid_features & CPUID_APIC || smp_cpus > 1) {
+ x86_cpu_apic_init(cpu, errp);
+ if (error_is_set(errp)) {
+ return;
+ }
+ }
#endif
mce_init(cpu);
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index de33303dea..cdc59dc0ca 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -907,9 +907,11 @@ static inline void cpu_x86_load_seg_cache(CPUX86State *env,
}
}
-static inline void cpu_x86_load_seg_cache_sipi(CPUX86State *env,
+static inline void cpu_x86_load_seg_cache_sipi(X86CPU *cpu,
int sipi_vector)
{
+ CPUX86State *env = &cpu->env;
+
env->eip = 0;
cpu_x86_load_seg_cache(env, R_CS, sipi_vector << 8,
sipi_vector << 12,
@@ -1098,8 +1100,10 @@ static inline void cpu_clone_regs(CPUX86State *env, target_ulong newsp)
#include "hw/apic.h"
#endif
-static inline bool cpu_has_work(CPUX86State *env)
+static inline bool cpu_has_work(CPUState *cpu)
{
+ CPUX86State *env = &X86_CPU(cpu)->env;
+
return ((env->interrupt_request & (CPU_INTERRUPT_HARD |
CPU_INTERRUPT_POLL)) &&
(env->eflags & IF_MASK)) ||
@@ -1131,7 +1135,7 @@ void do_cpu_sipi(X86CPU *cpu);
#define MCE_INJECT_BROADCAST 1
#define MCE_INJECT_UNCOND_AO 2
-void cpu_x86_inject_mce(Monitor *mon, CPUX86State *cenv, int bank,
+void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank,
uint64_t status, uint64_t mcg_status, uint64_t addr,
uint64_t misc, int flags);
diff --git a/target-i386/helper.c b/target-i386/helper.c
index c5d42c5916..bf206cfa97 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -1141,10 +1141,11 @@ static void do_inject_x86_mce(void *data)
}
}
-void cpu_x86_inject_mce(Monitor *mon, CPUX86State *cenv, int bank,
+void cpu_x86_inject_mce(Monitor *mon, X86CPU *cpu, int bank,
uint64_t status, uint64_t mcg_status, uint64_t addr,
uint64_t misc, int flags)
{
+ CPUX86State *cenv = &cpu->env;
MCEInjectionParams params = {
.mon = mon,
.env = cenv,
@@ -1176,7 +1177,7 @@ void cpu_x86_inject_mce(Monitor *mon, CPUX86State *cenv, int bank,
return;
}
- run_on_cpu(cenv, do_inject_x86_mce, &params);
+ run_on_cpu(CPU(cpu), do_inject_x86_mce, &params);
if (flags & MCE_INJECT_BROADCAST) {
params.bank = 1;
params.status = MCI_STATUS_VAL | MCI_STATUS_UC;
@@ -1188,7 +1189,7 @@ void cpu_x86_inject_mce(Monitor *mon, CPUX86State *cenv, int bank,
continue;
}
params.env = env;
- run_on_cpu(cenv, do_inject_x86_mce, &params);
+ run_on_cpu(CPU(cpu), do_inject_x86_mce, &params);
}
}
}
@@ -1243,6 +1244,7 @@ X86CPU *cpu_x86_init(const char *cpu_model)
{
X86CPU *cpu;
CPUX86State *env;
+ Error *error = NULL;
cpu = X86_CPU(object_new(TYPE_X86_CPU));
env = &cpu->env;
@@ -1253,8 +1255,12 @@ X86CPU *cpu_x86_init(const char *cpu_model)
return NULL;
}
- x86_cpu_realize(OBJECT(cpu), NULL);
-
+ x86_cpu_realize(OBJECT(cpu), &error);
+ if (error) {
+ error_free(error);
+ object_delete(OBJECT(cpu));
+ return NULL;
+ }
return cpu;
}
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 3aa62b20ff..9ccbcb5be5 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -229,8 +229,9 @@ static int kvm_get_mce_cap_supported(KVMState *s, uint64_t *mce_cap,
return -ENOSYS;
}
-static void kvm_mce_inject(CPUX86State *env, hwaddr paddr, int code)
+static void kvm_mce_inject(X86CPU *cpu, hwaddr paddr, int code)
{
+ CPUX86State *env = &cpu->env;
uint64_t status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN |
MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S;
uint64_t mcg_status = MCG_STATUS_MCIP;
@@ -242,7 +243,7 @@ static void kvm_mce_inject(CPUX86State *env, hwaddr paddr, int code)
status |= 0xc0;
mcg_status |= MCG_STATUS_RIPV;
}
- cpu_x86_inject_mce(NULL, env, 9, status, mcg_status, paddr,
+ cpu_x86_inject_mce(NULL, cpu, 9, status, mcg_status, paddr,
(MCM_ADDR_PHYS << 6) | 0xc,
cpu_x86_support_mca_broadcast(env) ?
MCE_INJECT_BROADCAST : 0);
@@ -256,6 +257,7 @@ static void hardware_memory_error(void)
int kvm_arch_on_sigbus_vcpu(CPUX86State *env, int code, void *addr)
{
+ X86CPU *cpu = x86_env_get_cpu(env);
ram_addr_t ram_addr;
hwaddr paddr;
@@ -273,7 +275,7 @@ int kvm_arch_on_sigbus_vcpu(CPUX86State *env, int code, void *addr)
}
}
kvm_hwpoison_page_add(ram_addr);
- kvm_mce_inject(env, paddr, code);
+ kvm_mce_inject(cpu, paddr, code);
} else {
if (code == BUS_MCEERR_AO) {
return 0;
@@ -301,7 +303,7 @@ int kvm_arch_on_sigbus(int code, void *addr)
return 0;
}
kvm_hwpoison_page_add(ram_addr);
- kvm_mce_inject(first_cpu, paddr, code);
+ kvm_mce_inject(x86_env_get_cpu(first_cpu), paddr, code);
} else {
if (code == BUS_MCEERR_AO) {
return 0;
@@ -1365,8 +1367,9 @@ static int kvm_put_mp_state(CPUX86State *env)
return kvm_vcpu_ioctl(env, KVM_SET_MP_STATE, &mp_state);
}
-static int kvm_get_mp_state(CPUX86State *env)
+static int kvm_get_mp_state(X86CPU *cpu)
{
+ CPUX86State *env = &cpu->env;
struct kvm_mp_state mp_state;
int ret;
@@ -1552,9 +1555,10 @@ static int kvm_get_debugregs(CPUX86State *env)
int kvm_arch_put_registers(CPUX86State *env, int level)
{
+ CPUState *cpu = ENV_GET_CPU(env);
int ret;
- assert(cpu_is_stopped(env) || qemu_cpu_is_self(env));
+ assert(cpu_is_stopped(cpu) || qemu_cpu_is_self(cpu));
ret = kvm_getput_regs(env, 1);
if (ret < 0) {
@@ -1609,9 +1613,10 @@ int kvm_arch_put_registers(CPUX86State *env, int level)
int kvm_arch_get_registers(CPUX86State *env)
{
+ X86CPU *cpu = x86_env_get_cpu(env);
int ret;
- assert(cpu_is_stopped(env) || qemu_cpu_is_self(env));
+ assert(cpu_is_stopped(CPU(cpu)) || qemu_cpu_is_self(CPU(cpu)));
ret = kvm_getput_regs(env, 0);
if (ret < 0) {
@@ -1633,7 +1638,7 @@ int kvm_arch_get_registers(CPUX86State *env)
if (ret < 0) {
return ret;
}
- ret = kvm_get_mp_state(env);
+ ret = kvm_get_mp_state(cpu);
if (ret < 0) {
return ret;
}
@@ -1781,8 +1786,10 @@ int kvm_arch_process_async_events(CPUX86State *env)
return env->halted;
}
-static int kvm_handle_halt(CPUX86State *env)
+static int kvm_handle_halt(X86CPU *cpu)
{
+ CPUX86State *env = &cpu->env;
+
if (!((env->interrupt_request & CPU_INTERRUPT_HARD) &&
(env->eflags & IF_MASK)) &&
!(env->interrupt_request & CPU_INTERRUPT_NMI)) {
@@ -1996,13 +2003,14 @@ static bool host_supports_vmx(void)
int kvm_arch_handle_exit(CPUX86State *env, struct kvm_run *run)
{
+ X86CPU *cpu = x86_env_get_cpu(env);
uint64_t code;
int ret;
switch (run->exit_reason) {
case KVM_EXIT_HLT:
DPRINTF("handle_hlt\n");
- ret = kvm_handle_halt(env);
+ ret = kvm_handle_halt(cpu);
break;
case KVM_EXIT_SET_TPR:
ret = 0;