x86: Optionally avoid injecting AO MCEs while others are pending

Allow to tell cpu_x86_inject_mce that it should ignore Action Optional
MCE events when the target VCPU is still processing another one. This
will be used by KVM soon.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
CC: Huang Ying <ying.huang@intel.com>
CC: Hidetoshi Seto <seto.hidetoshi@jp.fujitsu.com>
CC: Jin Dongming <jin.dongming@np.css.fujitsu.com>
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
This commit is contained in:
Jan Kiszka 2011-03-02 08:56:10 +01:00 committed by Marcelo Tosatti
parent 316378e4d0
commit 747461c76b
3 changed files with 28 additions and 10 deletions

View File

@ -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 mcg_status = qdict_get_int(qdict, "mcg_status");
uint64_t addr = qdict_get_int(qdict, "addr"); uint64_t addr = qdict_get_int(qdict, "addr");
uint64_t misc = qdict_get_int(qdict, "misc"); 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) { for (cenv = first_cpu; cenv != NULL; cenv = cenv->next_cpu) {
if (cenv->cpu_index == cpu_index) { if (cenv->cpu_index == cpu_index) {
cpu_x86_inject_mce(mon, cenv, bank, status, mcg_status, addr, misc, cpu_x86_inject_mce(mon, cenv, bank, status, mcg_status, addr, misc,
broadcast); flags);
break; break;
} }
} }

View File

@ -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_init(CPUState *env);
void do_cpu_sipi(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, void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank,
uint64_t status, uint64_t mcg_status, uint64_t addr, uint64_t status, uint64_t mcg_status, uint64_t addr,
uint64_t misc, int broadcast); uint64_t misc, int flags);
#endif /* CPU_I386_H */ #endif /* CPU_I386_H */

View File

@ -1069,11 +1069,20 @@ static void breakpoint_handler(CPUState *env)
static void static void
qemu_inject_x86_mce(Monitor *mon, CPUState *cenv, int bank, uint64_t status, 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 mcg_cap = cenv->mcg_cap;
uint64_t *banks = cenv->mce_banks + 4 * bank; 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 (status & MCI_STATUS_UC) {
/* /*
* if MSR_MCG_CTL is not all 1s, the uncorrected error * 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, void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank,
uint64_t status, uint64_t mcg_status, uint64_t addr, 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; unsigned bank_num = cenv->mcg_cap & 0xff;
CPUState *env; 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"); monitor_printf(mon, "Invalid MCE status code\n");
return; 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"); monitor_printf(mon, "Guest CPU does not support MCA broadcast\n");
return; return;
} }
if (kvm_enabled()) { if (kvm_enabled()) {
if (broadcast) { if (flags & MCE_INJECT_BROADCAST) {
flag |= MCE_BROADCAST; flag |= MCE_BROADCAST;
} }
kvm_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc, flag); kvm_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc, flag);
} else { } else {
qemu_inject_x86_mce(mon, cenv, bank, status, mcg_status, addr, misc); qemu_inject_x86_mce(mon, cenv, bank, status, mcg_status, addr, misc,
if (broadcast) { flags);
if (flags & MCE_INJECT_BROADCAST) {
for (env = first_cpu; env != NULL; env = env->next_cpu) { for (env = first_cpu; env != NULL; env = env->next_cpu) {
if (cenv == env) { if (cenv == env) {
continue; continue;
} }
qemu_inject_x86_mce(mon, env, 1, qemu_inject_x86_mce(mon, env, 1,
MCI_STATUS_VAL | MCI_STATUS_UC, MCI_STATUS_VAL | MCI_STATUS_UC,
MCG_STATUS_MCIP | MCG_STATUS_RIPV, 0, 0); MCG_STATUS_MCIP | MCG_STATUS_RIPV, 0, 0,
flags);
} }
} }
} }