From patchwork Wed Mar 2 07:56:12 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 602221 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 p227vnIh008596 for ; Wed, 2 Mar 2011 07:57:49 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755685Ab1CBH5f (ORCPT ); Wed, 2 Mar 2011 02:57:35 -0500 Received: from david.siemens.de ([192.35.17.14]:22842 "EHLO david.siemens.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755695Ab1CBH4v (ORCPT ); Wed, 2 Mar 2011 02:56:51 -0500 Received: from mail1.siemens.de (localhost [127.0.0.1]) by david.siemens.de (8.13.6/8.13.6) with ESMTP id p227uUu3011245; Wed, 2 Mar 2011 08:56:30 +0100 Received: from mchn199C.mchp.siemens.de ([146.254.217.97]) by mail1.siemens.de (8.13.6/8.13.6) with ESMTP id p227uKnN031204; Wed, 2 Mar 2011 08:56:29 +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 v3 09/17] kvm: x86: Move MCE functions together Date: Wed, 2 Mar 2011 08:56:12 +0100 Message-Id: <74043a39fbf8212cc6e56a3d2308b3a48007d955.1299052578.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]); Wed, 02 Mar 2011 07:57:49 +0000 (UTC) diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 0aa0a41..f909661 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -172,7 +172,7 @@ static int get_para_features(CPUState *env) #endif return features; } -#endif +#endif /* CONFIG_KVM_PARA */ #ifdef KVM_CAP_MCE static int kvm_get_mce_cap_supported(KVMState *s, uint64_t *mce_cap, @@ -273,8 +273,174 @@ static void kvm_inject_x86_mce_on(CPUState *env, struct kvm_x86_mce *mce, run_on_cpu(env, kvm_do_inject_x86_mce, &data); } -static void kvm_mce_broadcast_rest(CPUState *env); -#endif +static void kvm_mce_broadcast_rest(CPUState *env) +{ + struct kvm_x86_mce mce = { + .bank = 1, + .status = MCI_STATUS_VAL | MCI_STATUS_UC, + .mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV, + .addr = 0, + .misc = 0, + }; + CPUState *cenv; + + /* Broadcast MCA signal for processor version 06H_EH and above */ + if (cpu_x86_support_mca_broadcast(env)) { + for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) { + if (cenv == env) { + continue; + } + kvm_inject_x86_mce_on(cenv, &mce, ABORT_ON_ERROR); + } + } +} + +static void kvm_mce_inj_srar_dataload(CPUState *env, target_phys_addr_t paddr) +{ + struct kvm_x86_mce mce = { + .bank = 9, + .status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN + | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S + | MCI_STATUS_AR | 0x134, + .mcg_status = MCG_STATUS_MCIP | MCG_STATUS_EIPV, + .addr = paddr, + .misc = (MCM_ADDR_PHYS << 6) | 0xc, + }; + int r; + + r = kvm_set_mce(env, &mce); + if (r < 0) { + fprintf(stderr, "kvm_set_mce: %s\n", strerror(errno)); + abort(); + } + kvm_mce_broadcast_rest(env); +} + +static void kvm_mce_inj_srao_memscrub(CPUState *env, target_phys_addr_t paddr) +{ + struct kvm_x86_mce mce = { + .bank = 9, + .status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN + | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S + | 0xc0, + .mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV, + .addr = paddr, + .misc = (MCM_ADDR_PHYS << 6) | 0xc, + }; + int r; + + r = kvm_set_mce(env, &mce); + if (r < 0) { + fprintf(stderr, "kvm_set_mce: %s\n", strerror(errno)); + abort(); + } + kvm_mce_broadcast_rest(env); +} + +static void kvm_mce_inj_srao_memscrub2(CPUState *env, target_phys_addr_t paddr) +{ + struct kvm_x86_mce mce = { + .bank = 9, + .status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN + | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S + | 0xc0, + .mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV, + .addr = paddr, + .misc = (MCM_ADDR_PHYS << 6) | 0xc, + }; + + kvm_inject_x86_mce_on(env, &mce, ABORT_ON_ERROR); + kvm_mce_broadcast_rest(env); +} +#endif /* KVM_CAP_MCE */ + +static void hardware_memory_error(void) +{ + fprintf(stderr, "Hardware memory error!\n"); + exit(1); +} + +int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr) +{ +#ifdef KVM_CAP_MCE + void *vaddr; + ram_addr_t ram_addr; + target_phys_addr_t paddr; + + if ((env->mcg_cap & MCG_SER_P) && addr + && (code == BUS_MCEERR_AR + || code == BUS_MCEERR_AO)) { + vaddr = (void *)addr; + if (qemu_ram_addr_from_host(vaddr, &ram_addr) || + !kvm_physical_memory_addr_from_ram(env->kvm_state, ram_addr, &paddr)) { + fprintf(stderr, "Hardware memory error for memory used by " + "QEMU itself instead of guest system!\n"); + /* Hope we are lucky for AO MCE */ + if (code == BUS_MCEERR_AO) { + return 0; + } else { + hardware_memory_error(); + } + } + + if (code == BUS_MCEERR_AR) { + /* Fake an Intel architectural Data Load SRAR UCR */ + kvm_mce_inj_srar_dataload(env, paddr); + } else { + /* + * If there is an MCE excpetion being processed, ignore + * this SRAO MCE + */ + if (!kvm_mce_in_progress(env)) { + /* Fake an Intel architectural Memory scrubbing UCR */ + kvm_mce_inj_srao_memscrub(env, paddr); + } + } + } else +#endif /* KVM_CAP_MCE */ + { + if (code == BUS_MCEERR_AO) { + return 0; + } else if (code == BUS_MCEERR_AR) { + hardware_memory_error(); + } else { + return 1; + } + } + return 0; +} + +int kvm_arch_on_sigbus(int code, void *addr) +{ +#ifdef KVM_CAP_MCE + if ((first_cpu->mcg_cap & MCG_SER_P) && addr && code == BUS_MCEERR_AO) { + void *vaddr; + ram_addr_t ram_addr; + target_phys_addr_t paddr; + + /* Hope we are lucky for AO MCE */ + vaddr = addr; + if (qemu_ram_addr_from_host(vaddr, &ram_addr) || + !kvm_physical_memory_addr_from_ram(first_cpu->kvm_state, ram_addr, + &paddr)) { + fprintf(stderr, "Hardware memory error for memory used by " + "QEMU itself instead of guest system!: %p\n", addr); + return 0; + } + kvm_mce_inj_srao_memscrub2(first_cpu, paddr); + } else +#endif /* KVM_CAP_MCE */ + { + if (code == BUS_MCEERR_AO) { + return 0; + } else if (code == BUS_MCEERR_AR) { + hardware_memory_error(); + } else { + return 1; + } + } + return 0; +} void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, uint64_t mcg_status, uint64_t addr, uint64_t misc, @@ -294,11 +460,11 @@ void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, } kvm_inject_x86_mce_on(cenv, &mce, flag); -#else +#else /* !KVM_CAP_MCE*/ if (flag & ABORT_ON_ERROR) { abort(); } -#endif +#endif /* !KVM_CAP_MCE*/ } static void cpu_update_state(void *opaque, int running, int reason) @@ -1783,173 +1949,3 @@ bool kvm_arch_stop_on_emulation_error(CPUState *env) return !(env->cr[0] & CR0_PE_MASK) || ((env->segs[R_CS].selector & 3) != 3); } - -static void hardware_memory_error(void) -{ - fprintf(stderr, "Hardware memory error!\n"); - exit(1); -} - -#ifdef KVM_CAP_MCE -static void kvm_mce_broadcast_rest(CPUState *env) -{ - struct kvm_x86_mce mce = { - .bank = 1, - .status = MCI_STATUS_VAL | MCI_STATUS_UC, - .mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV, - .addr = 0, - .misc = 0, - }; - CPUState *cenv; - - /* Broadcast MCA signal for processor version 06H_EH and above */ - if (cpu_x86_support_mca_broadcast(env)) { - for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) { - if (cenv == env) { - continue; - } - kvm_inject_x86_mce_on(cenv, &mce, ABORT_ON_ERROR); - } - } -} - -static void kvm_mce_inj_srar_dataload(CPUState *env, target_phys_addr_t paddr) -{ - struct kvm_x86_mce mce = { - .bank = 9, - .status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN - | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S - | MCI_STATUS_AR | 0x134, - .mcg_status = MCG_STATUS_MCIP | MCG_STATUS_EIPV, - .addr = paddr, - .misc = (MCM_ADDR_PHYS << 6) | 0xc, - }; - int r; - - r = kvm_set_mce(env, &mce); - if (r < 0) { - fprintf(stderr, "kvm_set_mce: %s\n", strerror(errno)); - abort(); - } - kvm_mce_broadcast_rest(env); -} - -static void kvm_mce_inj_srao_memscrub(CPUState *env, target_phys_addr_t paddr) -{ - struct kvm_x86_mce mce = { - .bank = 9, - .status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN - | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S - | 0xc0, - .mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV, - .addr = paddr, - .misc = (MCM_ADDR_PHYS << 6) | 0xc, - }; - int r; - - r = kvm_set_mce(env, &mce); - if (r < 0) { - fprintf(stderr, "kvm_set_mce: %s\n", strerror(errno)); - abort(); - } - kvm_mce_broadcast_rest(env); -} - -static void kvm_mce_inj_srao_memscrub2(CPUState *env, target_phys_addr_t paddr) -{ - struct kvm_x86_mce mce = { - .bank = 9, - .status = MCI_STATUS_VAL | MCI_STATUS_UC | MCI_STATUS_EN - | MCI_STATUS_MISCV | MCI_STATUS_ADDRV | MCI_STATUS_S - | 0xc0, - .mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV, - .addr = paddr, - .misc = (MCM_ADDR_PHYS << 6) | 0xc, - }; - - kvm_inject_x86_mce_on(env, &mce, ABORT_ON_ERROR); - kvm_mce_broadcast_rest(env); -} - -#endif - -int kvm_arch_on_sigbus_vcpu(CPUState *env, int code, void *addr) -{ -#if defined(KVM_CAP_MCE) - void *vaddr; - ram_addr_t ram_addr; - target_phys_addr_t paddr; - - if ((env->mcg_cap & MCG_SER_P) && addr - && (code == BUS_MCEERR_AR - || code == BUS_MCEERR_AO)) { - vaddr = (void *)addr; - if (qemu_ram_addr_from_host(vaddr, &ram_addr) || - !kvm_physical_memory_addr_from_ram(env->kvm_state, ram_addr, &paddr)) { - fprintf(stderr, "Hardware memory error for memory used by " - "QEMU itself instead of guest system!\n"); - /* Hope we are lucky for AO MCE */ - if (code == BUS_MCEERR_AO) { - return 0; - } else { - hardware_memory_error(); - } - } - - if (code == BUS_MCEERR_AR) { - /* Fake an Intel architectural Data Load SRAR UCR */ - kvm_mce_inj_srar_dataload(env, paddr); - } else { - /* - * If there is an MCE excpetion being processed, ignore - * this SRAO MCE - */ - if (!kvm_mce_in_progress(env)) { - /* Fake an Intel architectural Memory scrubbing UCR */ - kvm_mce_inj_srao_memscrub(env, paddr); - } - } - } else -#endif - { - if (code == BUS_MCEERR_AO) { - return 0; - } else if (code == BUS_MCEERR_AR) { - hardware_memory_error(); - } else { - return 1; - } - } - return 0; -} - -int kvm_arch_on_sigbus(int code, void *addr) -{ -#if defined(KVM_CAP_MCE) - if ((first_cpu->mcg_cap & MCG_SER_P) && addr && code == BUS_MCEERR_AO) { - void *vaddr; - ram_addr_t ram_addr; - target_phys_addr_t paddr; - - /* Hope we are lucky for AO MCE */ - vaddr = addr; - if (qemu_ram_addr_from_host(vaddr, &ram_addr) || - !kvm_physical_memory_addr_from_ram(first_cpu->kvm_state, ram_addr, &paddr)) { - fprintf(stderr, "Hardware memory error for memory used by " - "QEMU itself instead of guest system!: %p\n", addr); - return 0; - } - kvm_mce_inj_srao_memscrub2(first_cpu, paddr); - } else -#endif - { - if (code == BUS_MCEERR_AO) { - return 0; - } else if (code == BUS_MCEERR_AR) { - hardware_memory_error(); - } else { - return 1; - } - } - return 0; -}