x86: Refine error reporting of MCE injection services

As this service is used by the human monitor, make sure that errors get
reported to the right channel, and also raise the verbosity.

This requires to move Monitor typedef in qemu-common.h to resolve the
include dependency.

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:09 +01:00 committed by Marcelo Tosatti
parent 2fa11da0c3
commit 316378e4d0
4 changed files with 53 additions and 40 deletions

View File

@ -2712,8 +2712,8 @@ static void do_inject_mce(Monitor *mon, const QDict *qdict)
int broadcast = qdict_get_try_bool(qdict, "broadcast", 0); 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) { if (cenv->cpu_index == cpu_index) {
cpu_x86_inject_mce(cenv, bank, status, mcg_status, addr, misc, cpu_x86_inject_mce(mon, cenv, bank, status, mcg_status, addr, misc,
broadcast); broadcast);
break; break;
} }

View File

@ -18,6 +18,9 @@ typedef struct QEMUFile QEMUFile;
typedef struct QEMUBH QEMUBH; typedef struct QEMUBH QEMUBH;
typedef struct DeviceState DeviceState; typedef struct DeviceState DeviceState;
struct Monitor;
typedef struct Monitor Monitor;
/* we put basic includes here to avoid repeating them in device drivers */ /* we put basic includes here to avoid repeating them in device drivers */
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
@ -327,9 +330,6 @@ void qemu_iovec_memset(QEMUIOVector *qiov, int c, size_t count);
void qemu_iovec_memset_skip(QEMUIOVector *qiov, int c, size_t count, void qemu_iovec_memset_skip(QEMUIOVector *qiov, int c, size_t count,
size_t skip); size_t skip);
struct Monitor;
typedef struct Monitor Monitor;
/* Convert a byte between binary and BCD. */ /* Convert a byte between binary and BCD. */
static inline uint8_t to_bcd(uint8_t val) static inline uint8_t to_bcd(uint8_t val)
{ {

View File

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

View File

@ -30,6 +30,7 @@
#include "kvm_x86.h" #include "kvm_x86.h"
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
#include "sysemu.h" #include "sysemu.h"
#include "monitor.h"
#endif #endif
//#define DEBUG_MMU //#define DEBUG_MMU
@ -1067,33 +1068,38 @@ static void breakpoint_handler(CPUState *env)
} }
static void static void
qemu_inject_x86_mce(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)
{ {
uint64_t mcg_cap = cenv->mcg_cap; uint64_t mcg_cap = cenv->mcg_cap;
uint64_t *banks = cenv->mce_banks; uint64_t *banks = cenv->mce_banks + 4 * bank;
/*
* if MSR_MCG_CTL is not all 1s, the uncorrected error
* reporting is disabled
*/
if ((status & MCI_STATUS_UC) && (mcg_cap & MCG_CTL_P) &&
cenv->mcg_ctl != ~(uint64_t)0) {
return;
}
banks += 4 * bank;
/*
* if MSR_MCi_CTL is not all 1s, the uncorrected error
* reporting is disabled for the bank
*/
if ((status & MCI_STATUS_UC) && banks[0] != ~(uint64_t)0) {
return;
}
if (status & MCI_STATUS_UC) { if (status & MCI_STATUS_UC) {
/*
* if MSR_MCG_CTL is not all 1s, the uncorrected error
* reporting is disabled
*/
if ((mcg_cap & MCG_CTL_P) && cenv->mcg_ctl != ~(uint64_t)0) {
monitor_printf(mon,
"CPU %d: Uncorrected error reporting disabled\n",
cenv->cpu_index);
return;
}
/*
* if MSR_MCi_CTL is not all 1s, the uncorrected error
* reporting is disabled for the bank
*/
if (banks[0] != ~(uint64_t)0) {
monitor_printf(mon, "CPU %d: Uncorrected error reporting disabled "
"for bank %d\n", cenv->cpu_index, bank);
return;
}
if ((cenv->mcg_status & MCG_STATUS_MCIP) || if ((cenv->mcg_status & MCG_STATUS_MCIP) ||
!(cenv->cr[4] & CR4_MCE_MASK)) { !(cenv->cr[4] & CR4_MCE_MASK)) {
fprintf(stderr, "injects mce exception while previous " monitor_printf(mon, "CPU %d: Previous MCE still in progress, "
"one is in progress!\n"); "raising triple fault\n", cenv->cpu_index);
qemu_log_mask(CPU_LOG_RESET, "Triple fault\n"); qemu_log_mask(CPU_LOG_RESET, "Triple fault\n");
qemu_system_reset_request(); qemu_system_reset_request();
return; return;
@ -1119,23 +1125,29 @@ qemu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
} }
} }
void cpu_x86_inject_mce(CPUState *cenv, int bank, uint64_t status, void cpu_x86_inject_mce(Monitor *mon, CPUState *cenv, int bank,
uint64_t mcg_status, uint64_t addr, uint64_t misc, uint64_t status, uint64_t mcg_status, uint64_t addr,
int broadcast) uint64_t misc, int broadcast)
{ {
unsigned bank_num = cenv->mcg_cap & 0xff; unsigned bank_num = cenv->mcg_cap & 0xff;
CPUState *env; CPUState *env;
int flag = 0; int flag = 0;
if (bank >= bank_num || !(status & MCI_STATUS_VAL)) { if (!cenv->mcg_cap) {
monitor_printf(mon, "MCE injection not supported\n");
return; return;
} }
if (bank >= bank_num) {
if (broadcast) { monitor_printf(mon, "Invalid MCE bank number\n");
if (!cpu_x86_support_mca_broadcast(cenv)) { return;
fprintf(stderr, "Current CPU does not support broadcast\n"); }
return; if (!(status & MCI_STATUS_VAL)) {
} monitor_printf(mon, "Invalid MCE status code\n");
return;
}
if (broadcast && !cpu_x86_support_mca_broadcast(cenv)) {
monitor_printf(mon, "Guest CPU does not support MCA broadcast\n");
return;
} }
if (kvm_enabled()) { if (kvm_enabled()) {
@ -1145,13 +1157,14 @@ void cpu_x86_inject_mce(CPUState *cenv, int bank, uint64_t status,
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(cenv, bank, status, mcg_status, addr, misc); qemu_inject_x86_mce(mon, cenv, bank, status, mcg_status, addr, misc);
if (broadcast) { if (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(env, 1, MCI_STATUS_VAL | MCI_STATUS_UC, 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);
} }
} }