mirror of
https://github.com/xemu-project/xemu.git
synced 2024-11-24 03:59:52 +00:00
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>
This commit is contained in:
parent
990368650f
commit
ab443475c9
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user