diff --git a/cpu-all.h b/cpu-all.h index 30ae17d41d..4ce4e83032 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -964,6 +964,7 @@ int cpu_memory_rw_debug(CPUState *env, target_ulong addr, uint8_t *buf, int len, int is_write); void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, - uint64_t mcg_status, uint64_t addr, uint64_t misc); + uint64_t mcg_status, uint64_t addr, uint64_t misc, + int broadcast); #endif /* CPU_ALL_H */ diff --git a/hmp-commands.hx b/hmp-commands.hx index 1cea572b15..d65a41f523 100644 --- a/hmp-commands.hx +++ b/hmp-commands.hx @@ -1116,9 +1116,9 @@ ETEXI { .name = "mce", - .args_type = "cpu_index:i,bank:i,status:l,mcg_status:l,addr:l,misc:l", - .params = "cpu bank status mcgstatus addr misc", - .help = "inject a MCE on the given CPU", + .args_type = "broadcast:-b,cpu_index:i,bank:i,status:l,mcg_status:l,addr:l,misc:l", + .params = "[-b] cpu bank status mcgstatus addr misc", + .help = "inject a MCE on the given CPU [and broadcast to other CPUs with -b option]", .mhandler.cmd = do_inject_mce, }, diff --git a/monitor.c b/monitor.c index d291158c2f..396d5cdda3 100644 --- a/monitor.c +++ b/monitor.c @@ -2671,12 +2671,15 @@ static void do_inject_mce(Monitor *mon, const QDict *qdict) uint64_t mcg_status = qdict_get_int(qdict, "mcg_status"); uint64_t addr = qdict_get_int(qdict, "addr"); uint64_t misc = qdict_get_int(qdict, "misc"); + int broadcast = qdict_get_try_bool(qdict, "broadcast", 0); - for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) + for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) { if (cenv->cpu_index == cpu_index && cenv->mcg_cap) { - cpu_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc); + cpu_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc, + broadcast); break; } + } } #endif diff --git a/target-i386/helper.c b/target-i386/helper.c index 2c94130a15..2cfb4a42a7 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1069,18 +1069,34 @@ static void qemu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, } void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, - uint64_t mcg_status, uint64_t addr, uint64_t misc) + uint64_t mcg_status, uint64_t addr, uint64_t misc, + int broadcast) { unsigned bank_num = cenv->mcg_cap & 0xff; + CPUState *env; + int flag = 0; if (bank >= bank_num || !(status & MCI_STATUS_VAL)) { return; } if (kvm_enabled()) { - kvm_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc, 0); + if (broadcast) { + flag |= MCE_BROADCAST; + } + + kvm_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc, flag); } else { qemu_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc); + if (broadcast) { + for (env = first_cpu; env != NULL; env = env->next_cpu) { + if (cenv == env) { + continue; + } + + qemu_inject_x86_mce(env, 1, 0xa000000000000000, 0, 0, 0); + } + } } } #endif /* !CONFIG_USER_ONLY */ diff --git a/target-i386/kvm.c b/target-i386/kvm.c index 4004de76dd..8b868ad40a 100644 --- a/target-i386/kvm.c +++ b/target-i386/kvm.c @@ -264,11 +264,13 @@ static void kvm_do_inject_x86_mce(void *_data) } } } + +static void kvm_mce_broadcast_rest(CPUState *env); #endif void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, uint64_t mcg_status, uint64_t addr, uint64_t misc, - int abort_on_error) + int flag) { #ifdef KVM_CAP_MCE struct kvm_x86_mce mce = { @@ -288,10 +290,15 @@ void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, return; } + if (flag & MCE_BROADCAST) { + kvm_mce_broadcast_rest(cenv); + } + run_on_cpu(cenv, kvm_do_inject_x86_mce, &data); #else - if (abort_on_error) + if (flag & ABORT_ON_ERROR) { abort(); + } #endif } @@ -1716,7 +1723,8 @@ static void kvm_mce_broadcast_rest(CPUState *env) continue; } kvm_inject_x86_mce(cenv, 1, MCI_STATUS_VAL | MCI_STATUS_UC, - MCG_STATUS_MCIP | MCG_STATUS_RIPV, 0, 0, 1); + MCG_STATUS_MCIP | MCG_STATUS_RIPV, 0, 0, + ABORT_ON_ERROR); } } } @@ -1816,7 +1824,7 @@ int kvm_on_sigbus(int code, void *addr) | 0xc0; kvm_inject_x86_mce(first_cpu, 9, status, MCG_STATUS_MCIP | MCG_STATUS_RIPV, paddr, - (MCM_ADDR_PHYS << 6) | 0xc, 1); + (MCM_ADDR_PHYS << 6) | 0xc, ABORT_ON_ERROR); kvm_mce_broadcast_rest(first_cpu); } else #endif diff --git a/target-i386/kvm_x86.h b/target-i386/kvm_x86.h index 04932cf4c8..9d7b584267 100644 --- a/target-i386/kvm_x86.h +++ b/target-i386/kvm_x86.h @@ -15,8 +15,11 @@ #ifndef __KVM_X86_H__ #define __KVM_X86_H__ +#define ABORT_ON_ERROR 0x01 +#define MCE_BROADCAST 0x02 + void kvm_inject_x86_mce(CPUState *cenv, int bank, uint64_t status, uint64_t mcg_status, uint64_t addr, uint64_t misc, - int abort_on_error); + int flag); #endif