#include <stdio.h>
#include <string.h>
#include <inttypes.h>
-#include <signal.h>
#include "cpu.h"
-#include "exec-all.h"
#include "qemu-common.h"
#include "kvm.h"
-#include "kvm_x86.h"
+#ifndef CONFIG_USER_ONLY
+#include "sysemu.h"
+#include "monitor.h"
+#endif
//#define DEBUG_MMU
env->mxcsr = 0x1f80;
+ env->pat = 0x0007040600070406ULL;
+
memset(env->dr, 0, sizeof(env->dr));
env->dr[6] = DR6_FIXED_1;
env->dr[7] = DR7_FIXED_1;
cpu_breakpoint_remove_all(env, BP_CPU);
cpu_watchpoint_remove_all(env, BP_CPU);
-
- env->mcg_status = 0;
}
void cpu_x86_close(CPUX86State *env)
qemu_free(env);
}
+static void cpu_x86_version(CPUState *env, int *family, int *model)
+{
+ int cpuver = env->cpuid_version;
+
+ if (family == NULL || model == NULL) {
+ return;
+ }
+
+ *family = (cpuver >> 8) & 0x0f;
+ *model = ((cpuver >> 12) & 0xf0) + ((cpuver >> 4) & 0x0f);
+}
+
+/* Broadcast MCA signal for processor version 06H_EH and above */
+int cpu_x86_support_mca_broadcast(CPUState *env)
+{
+ int family = 0;
+ int model = 0;
+
+ cpu_x86_version(env, &family, &model);
+ if ((family == 6 && model >= 14) || family > 6) {
+ return 1;
+ }
+
+ return 0;
+}
+
/***********************************************************/
/* x86 debug */
cpu_fprintf(f, "\n");
}
+#define DUMP_CODE_BYTES_TOTAL 50
+#define DUMP_CODE_BYTES_BACKWARD 20
+
void cpu_dump_state(CPUState *env, FILE *f, fprintf_function cpu_fprintf,
int flags)
{
fptag,
env->mxcsr);
for(i=0;i<8;i++) {
-#if defined(USE_X86LDOUBLE)
- union {
- long double d;
- struct {
- uint64_t lower;
- uint16_t upper;
- } l;
- } tmp;
- tmp.d = env->fpregs[i].d;
+ CPU_LDoubleU u;
+ u.d = env->fpregs[i].d;
cpu_fprintf(f, "FPR%d=%016" PRIx64 " %04x",
- i, tmp.l.lower, tmp.l.upper);
-#else
- cpu_fprintf(f, "FPR%d=%016" PRIx64,
- i, env->fpregs[i].mmx.q);
-#endif
+ i, u.l.lower, u.l.upper);
if ((i & 1) == 1)
cpu_fprintf(f, "\n");
else
cpu_fprintf(f, " ");
}
}
+ if (flags & CPU_DUMP_CODE) {
+ target_ulong base = env->segs[R_CS].base + env->eip;
+ target_ulong offs = MIN(env->eip, DUMP_CODE_BYTES_BACKWARD);
+ uint8_t code;
+ char codestr[3];
+
+ cpu_fprintf(f, "Code=");
+ for (i = 0; i < DUMP_CODE_BYTES_TOTAL; i++) {
+ if (cpu_memory_rw_debug(env, base - offs + i, &code, 1, 0) == 0) {
+ snprintf(codestr, sizeof(codestr), "%02x", code);
+ } else {
+ snprintf(codestr, sizeof(codestr), "??");
+ }
+ cpu_fprintf(f, "%s%s%s%s", i > 0 ? " " : "",
+ i == offs ? "<" : "", codestr, i == offs ? ">" : "");
+ }
+ cpu_fprintf(f, "\n");
+ }
}
/***********************************************************/
prev_debug_excp_handler(env);
}
-/* This should come from sysemu.h - if we could include it here... */
-void qemu_system_reset_request(void);
-
-void cpu_inject_x86_mce(CPUState *cenv, int bank, uint64_t status,
- uint64_t mcg_status, uint64_t addr, uint64_t misc)
+typedef struct MCEInjectionParams {
+ Monitor *mon;
+ CPUState *env;
+ int bank;
+ uint64_t status;
+ uint64_t mcg_status;
+ uint64_t addr;
+ uint64_t misc;
+ int flags;
+} MCEInjectionParams;
+
+static void do_inject_x86_mce(void *data)
{
- uint64_t mcg_cap = cenv->mcg_cap;
- unsigned bank_num = mcg_cap & 0xff;
- uint64_t *banks = cenv->mce_banks;
-
- if (bank >= bank_num || !(status & MCI_STATUS_VAL))
- return;
+ MCEInjectionParams *params = data;
+ CPUState *cenv = params->env;
+ uint64_t *banks = cenv->mce_banks + 4 * params->bank;
- if (kvm_enabled()) {
- kvm_inject_x86_mce(cenv, bank, status, mcg_status, addr, misc, 0);
- return;
- }
+ cpu_synchronize_state(cenv);
/*
- * if MSR_MCG_CTL is not all 1s, the uncorrected error
- * reporting is disabled
+ * If there is an MCE exception being processed, ignore this SRAO MCE
+ * unless unconditional injection was requested.
*/
- if ((status & MCI_STATUS_UC) && (mcg_cap & MCG_CTL_P) &&
- cenv->mcg_ctl != ~(uint64_t)0)
+ if (!(params->flags & MCE_INJECT_UNCOND_AO)
+ && !(params->status & MCI_STATUS_AR)
+ && (cenv->mcg_status & MCG_STATUS_MCIP)) {
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 (params->status & MCI_STATUS_UC) {
+ /*
+ * if MSR_MCG_CTL is not all 1s, the uncorrected error
+ * reporting is disabled
+ */
+ if ((cenv->mcg_cap & MCG_CTL_P) && cenv->mcg_ctl != ~(uint64_t)0) {
+ monitor_printf(params->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(params->mon,
+ "CPU %d: Uncorrected error reporting disabled for"
+ " bank %d\n",
+ cenv->cpu_index, params->bank);
+ return;
+ }
+
if ((cenv->mcg_status & MCG_STATUS_MCIP) ||
!(cenv->cr[4] & CR4_MCE_MASK)) {
- fprintf(stderr, "injects mce exception while previous "
- "one is in progress!\n");
+ monitor_printf(params->mon,
+ "CPU %d: Previous MCE still in progress, raising"
+ " triple fault\n",
+ cenv->cpu_index);
qemu_log_mask(CPU_LOG_RESET, "Triple fault\n");
qemu_system_reset_request();
return;
}
- if (banks[1] & MCI_STATUS_VAL)
- status |= MCI_STATUS_OVER;
- banks[2] = addr;
- banks[3] = misc;
- cenv->mcg_status = mcg_status;
- banks[1] = status;
+ if (banks[1] & MCI_STATUS_VAL) {
+ params->status |= MCI_STATUS_OVER;
+ }
+ banks[2] = params->addr;
+ banks[3] = params->misc;
+ cenv->mcg_status = params->mcg_status;
+ banks[1] = params->status;
cpu_interrupt(cenv, CPU_INTERRUPT_MCE);
} else if (!(banks[1] & MCI_STATUS_VAL)
|| !(banks[1] & MCI_STATUS_UC)) {
- if (banks[1] & MCI_STATUS_VAL)
- status |= MCI_STATUS_OVER;
- banks[2] = addr;
- banks[3] = misc;
- banks[1] = status;
- } else
+ if (banks[1] & MCI_STATUS_VAL) {
+ params->status |= MCI_STATUS_OVER;
+ }
+ banks[2] = params->addr;
+ banks[3] = params->misc;
+ banks[1] = params->status;
+ } else {
banks[1] |= MCI_STATUS_OVER;
+ }
+}
+
+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 flags)
+{
+ MCEInjectionParams params = {
+ .mon = mon,
+ .env = cenv,
+ .bank = bank,
+ .status = status,
+ .mcg_status = mcg_status,
+ .addr = addr,
+ .misc = misc,
+ .flags = flags,
+ };
+ unsigned bank_num = cenv->mcg_cap & 0xff;
+ CPUState *env;
+
+ if (!cenv->mcg_cap) {
+ monitor_printf(mon, "MCE injection not supported\n");
+ return;
+ }
+ if (bank >= bank_num) {
+ monitor_printf(mon, "Invalid MCE bank number\n");
+ return;
+ }
+ if (!(status & MCI_STATUS_VAL)) {
+ monitor_printf(mon, "Invalid MCE status code\n");
+ return;
+ }
+ if ((flags & MCE_INJECT_BROADCAST)
+ && !cpu_x86_support_mca_broadcast(cenv)) {
+ monitor_printf(mon, "Guest CPU does not support MCA broadcast\n");
+ return;
+ }
+
+ run_on_cpu(cenv, do_inject_x86_mce, ¶ms);
+ if (flags & MCE_INJECT_BROADCAST) {
+ params.bank = 1;
+ params.status = MCI_STATUS_VAL | MCI_STATUS_UC;
+ params.mcg_status = MCG_STATUS_MCIP | MCG_STATUS_RIPV;
+ params.addr = 0;
+ params.misc = 0;
+ for (env = first_cpu; env != NULL; env = env->next_cpu) {
+ if (cenv == env) {
+ continue;
+ }
+ params.env = env;
+ run_on_cpu(cenv, do_inject_x86_mce, ¶ms);
+ }
+ }
}
#endif /* !CONFIG_USER_ONLY */
static void mce_init(CPUX86State *cenv)
{
- unsigned int bank, bank_num;
+ unsigned int bank;
- if (((cenv->cpuid_version >> 8)&0xf) >= 6
- && (cenv->cpuid_features&(CPUID_MCE|CPUID_MCA)) == (CPUID_MCE|CPUID_MCA)) {
+ if (((cenv->cpuid_version >> 8) & 0xf) >= 6
+ && (cenv->cpuid_features & (CPUID_MCE | CPUID_MCA)) ==
+ (CPUID_MCE | CPUID_MCA)) {
cenv->mcg_cap = MCE_CAP_DEF | MCE_BANKS_DEF;
cenv->mcg_ctl = ~(uint64_t)0;
- bank_num = MCE_BANKS_DEF;
- for (bank = 0; bank < bank_num; bank++)
- cenv->mce_banks[bank*4] = ~(uint64_t)0;
+ for (bank = 0; bank < MCE_BANKS_DEF; bank++) {
+ cenv->mce_banks[bank * 4] = ~(uint64_t)0;
+ }
}
}
void do_cpu_init(CPUState *env)
{
int sipi = env->interrupt_request & CPU_INTERRUPT_SIPI;
+ uint64_t pat = env->pat;
+
cpu_reset(env);
env->interrupt_request = sipi;
+ env->pat = pat;
apic_init_reset(env->apic_state);
env->halted = !cpu_is_bsp(env);
}