diff options
author | Jan Kiszka <jan.kiszka@siemens.com> | 2011-03-02 08:56:14 +0100 |
---|---|---|
committer | Marcelo Tosatti <mtosatti@redhat.com> | 2011-03-15 01:19:05 -0300 |
commit | ab443475c9235822e329e1bfde89be6c71e2c21e (patch) | |
tree | 773ee3ac440c93a30a76e7a9886af6cf31a8e035 | |
parent | 990368650f77d6f2b428b034209331ada7cb463f (diff) |
kvm: x86: Inject pending MCE events on state writeback
The current way of injecting MCE events without updating of and
synchronizing with the CPUState is broken and causes spurious
corruptions of the MCE-related parts of the CPUState.
As a first step towards a fix, enhance the state writeback code with
support for injecting events that are pending in the CPUState. A pending
exception will then be signaled via cpu_interrupt(CPU_INTERRUPT_MCE).
And, just like for TCG, we need to leave the halt state when
CPU_INTERRUPT_MCE is pending (left broken for the to-be-removed old KVM
code).
This will also allow to unify TCG and KVM injection code.
Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
CC: Huang Ying <ying.huang@intel.com>
CC: Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
CC: Jin Dongming <jin.dongming@np.css.fujitsu.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
-rw-r--r-- | target-i386/kvm.c | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 0aef810418..d9a6fc501b 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -467,6 +467,38 @@ void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, #endif /* !KVM_CAP_MCE*/ } +static int kvm_inject_mce_oldstyle(CPUState *env) +{ +#ifdef KVM_CAP_MCE + if (!kvm_has_vcpu_events() && env->exception_injected == EXCP12_MCHK) { + unsigned int bank, bank_num = env->mcg_cap & 0xff; + struct kvm_x86_mce mce; + + env->exception_injected = -1; + + /* + * There must be at least one bank in use if an MCE is pending. + * Find it and use its values for the event injection. + */ + for (bank = 0; bank < bank_num; bank++) { + if (env->mce_banks[bank * 4 + 1] & MCI_STATUS_VAL) { + break; + } + } + assert(bank < bank_num); + + mce.bank = bank; + mce.status = env->mce_banks[bank * 4 + 1]; + mce.mcg_status = env->mcg_status; + mce.addr = env->mce_banks[bank * 4 + 2]; + mce.misc = env->mce_banks[bank * 4 + 3]; + + return kvm_vcpu_ioctl(env, KVM_X86_SET_MCE, &mce); + } +#endif /* KVM_CAP_MCE */ + return 0; +} + static void cpu_update_state(void *opaque, int running, int reason) { CPUState *env = opaque; @@ -1539,6 +1571,11 @@ int kvm_arch_put_registers(CPUState *env, int level) if (ret < 0) { return ret; } + /* must be before kvm_put_msrs */ + ret = kvm_inject_mce_oldstyle(env); + if (ret < 0) { + return ret; + } ret = kvm_put_msrs(env, level); if (ret < 0) { return ret; @@ -1677,6 +1714,29 @@ void kvm_arch_post_run(CPUState *env, struct kvm_run *run) int kvm_arch_process_async_events(CPUState *env) { + if (env->interrupt_request & CPU_INTERRUPT_MCE) { + /* We must not raise CPU_INTERRUPT_MCE if it's not supported. */ + assert(env->mcg_cap); + + env->interrupt_request &= ~CPU_INTERRUPT_MCE; + + kvm_cpu_synchronize_state(env); + + if (env->exception_injected == EXCP08_DBLE) { + /* this means triple fault */ + qemu_system_reset_request(); + env->exit_request = 1; + return 0; + } + env->exception_injected = EXCP12_MCHK; + env->has_error_code = 0; + + env->halted = 0; + if (kvm_irqchip_in_kernel() && env->mp_state == KVM_MP_STATE_HALTED) { + env->mp_state = KVM_MP_STATE_RUNNABLE; + } + } + if (kvm_irqchip_in_kernel()) { return 0; } |