aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--monitor.c7
-rw-r--r--target-i386/cpu.h5
-rw-r--r--target-i386/helper.c26
3 files changed, 28 insertions, 10 deletions
diff --git a/monitor.c b/monitor.c
index 662df7ceb4..ae20927c5a 100644
--- a/monitor.c
+++ b/monitor.c
@@ -2709,12 +2709,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);
+ int flags = MCE_INJECT_UNCOND_AO;
+ if (qdict_get_try_bool(qdict, "broadcast", 0)) {
+ flags |= MCE_INJECT_BROADCAST;
+ }
for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
if (cenv->cpu_index == cpu_index) {
cpu_x86_inject_mce(mon, cenv, bank, status, mcg_status, addr, misc,
- broadcast);
+ flags);
break;
}
}
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 486af1d6e7..d0eae754cc 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -987,8 +987,11 @@ static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
void do_cpu_init(CPUState *env);
void do_cpu_sipi(CPUState *env);
+#define MCE_INJECT_BROADCAST 1
+#define MCE_INJECT_UNCOND_AO 2
+
void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank,
uint64_t status, uint64_t mcg_status, uint64_t addr,
- uint64_t misc, int broadcast);
+ uint64_t misc, int flags);
#endif /* CPU_I386_H */
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 462d3329db..e3ef40cbca 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -1069,11 +1069,20 @@ static void breakpoint_handler(CPUState *env)
static void
qemu_inject_x86_mce(Monitor *mon, 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 flags)
{
uint64_t mcg_cap = cenv->mcg_cap;
uint64_t *banks = cenv->mce_banks + 4 * bank;
+ /*
+ * If there is an MCE exception being processed, ignore this SRAO MCE
+ * unless unconditional injection was requested.
+ */
+ if (!(flags & MCE_INJECT_UNCOND_AO) && !(status & MCI_STATUS_AR)
+ && (cenv->mcg_status & MCG_STATUS_MCIP)) {
+ return;
+ }
if (status & MCI_STATUS_UC) {
/*
* if MSR_MCG_CTL is not all 1s, the uncorrected error
@@ -1127,7 +1136,7 @@ qemu_inject_x86_mce(Monitor *mon, CPUState *cenv, int bank, uint64_t status,
void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank,
uint64_t status, uint64_t mcg_status, uint64_t addr,
- uint64_t misc, int broadcast)
+ uint64_t misc, int flags)
{
unsigned bank_num = cenv->mcg_cap & 0xff;
CPUState *env;
@@ -1145,27 +1154,30 @@ void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank,
monitor_printf(mon, "Invalid MCE status code\n");
return;
}
- if (broadcast && !cpu_x86_support_mca_broadcast(cenv)) {
+ if ((flags & MCE_INJECT_BROADCAST)
+ && !cpu_x86_support_mca_broadcast(cenv)) {
monitor_printf(mon, "Guest CPU does not support MCA broadcast\n");
return;
}
if (kvm_enabled()) {
- if (broadcast) {
+ if (flags & MCE_INJECT_BROADCAST) {
flag |= MCE_BROADCAST;
}
kvm_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc, flag);
} else {
- qemu_inject_x86_mce(mon, cenv, bank, status, mcg_status, addr, misc);
- if (broadcast) {
+ qemu_inject_x86_mce(mon, cenv, bank, status, mcg_status, addr, misc,
+ flags);
+ if (flags & MCE_INJECT_BROADCAST) {
for (env = first_cpu; env != NULL; env = env->next_cpu) {
if (cenv == env) {
continue;
}
qemu_inject_x86_mce(mon, env, 1,
MCI_STATUS_VAL | MCI_STATUS_UC,
- MCG_STATUS_MCIP | MCG_STATUS_RIPV, 0, 0);
+ MCG_STATUS_MCIP | MCG_STATUS_RIPV, 0, 0,
+ flags);
}
}
}