From patchwork Tue Feb 15 08:23:32 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 558121 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p1F8OJ5n015630 for ; Tue, 15 Feb 2011 08:24:38 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754428Ab1BOIYM (ORCPT ); Tue, 15 Feb 2011 03:24:12 -0500 Received: from goliath.siemens.de ([192.35.17.28]:22323 "EHLO goliath.siemens.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754263Ab1BOIX6 (ORCPT ); Tue, 15 Feb 2011 03:23:58 -0500 Received: from mail1.siemens.de (localhost [127.0.0.1]) by goliath.siemens.de (8.13.6/8.13.6) with ESMTP id p1F8Nd5O011887; Tue, 15 Feb 2011 09:23:39 +0100 Received: from mchn199C.mchp.siemens.de ([139.25.246.60]) by mail1.siemens.de (8.13.6/8.13.6) with ESMTP id p1F8Nb0s027686; Tue, 15 Feb 2011 09:23:38 +0100 From: Jan Kiszka To: Avi Kivity , Marcelo Tosatti Cc: kvm@vger.kernel.org, qemu-devel@nongnu.org, Huang Ying , Hidetoshi Seto , Jin Dongming Subject: [PATCH 08/13] kvm: x86: Inject pending MCE events on state writeback Date: Tue, 15 Feb 2011 09:23:32 +0100 Message-Id: <56bf7460c65f7fc5c89fa9673b880a556b99e0fc.1297758211.git.jan.kiszka@siemens.com> X-Mailer: git-send-email 1.7.1 In-Reply-To: References: In-Reply-To: References: Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Tue, 15 Feb 2011 08:24:38 +0000 (UTC) diff --git a/target-i386/kvm.c b/target-i386/kvm.c index f909661..46f45db 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -467,6 +467,44 @@ 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()) { + return 0; + } + if (env->interrupt_request & CPU_INTERRUPT_MCE) { + unsigned int bank, bank_num = env->mcg_cap & 0xff; + struct kvm_x86_mce mce; + + /* We must not raise CPU_INTERRUPT_MCE if it's not supported. */ + assert(env->mcg_cap); + + env->interrupt_request &= ~CPU_INTERRUPT_MCE; + + /* + * There must be at least one bank in use if CPU_INTERRUPT_MCE was set. + * 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; @@ -1375,10 +1413,25 @@ static int kvm_put_vcpu_events(CPUState *env, int level) return 0; } - events.exception.injected = (env->exception_injected >= 0); - events.exception.nr = env->exception_injected; - events.exception.has_error_code = env->has_error_code; - events.exception.error_code = env->error_code; + 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; + if (env->exception_injected == EXCP08_DBLE) { + /* this means triple fault */ + qemu_system_reset_request(); + env->exit_request = 1; + } + events.exception.injected = 1; + events.exception.nr = EXCP12_MCHK; + events.exception.has_error_code = 0; + } else { + events.exception.injected = (env->exception_injected >= 0); + events.exception.nr = env->exception_injected; + events.exception.has_error_code = env->has_error_code; + events.exception.error_code = env->error_code; + } events.interrupt.injected = (env->interrupt_injected >= 0); events.interrupt.nr = env->interrupt_injected; @@ -1539,6 +1592,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; @@ -1678,10 +1736,17 @@ void kvm_arch_post_run(CPUState *env, struct kvm_run *run) int kvm_arch_process_irqchip_events(CPUState *env) { if (kvm_irqchip_in_kernel()) { + if (env->interrupt_request & CPU_INTERRUPT_MCE) { + kvm_cpu_synchronize_state(env); + if (env->mp_state == KVM_MP_STATE_HALTED) { + env->mp_state = KVM_MP_STATE_RUNNABLE; + } + } return 0; } - if (env->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI)) { + if (env->interrupt_request & + (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI | CPU_INTERRUPT_MCE)) { env->halted = 0; } if (env->interrupt_request & CPU_INTERRUPT_INIT) {