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 */
{
.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,
},
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
}
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 */
}
}
}
+
+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 = {
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
}
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);
}
}
}
| 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
#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