# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1276066450 -3600
# Node ID 9a3f422cf9809462b323243a674549673180e339
# Parent 05bfc5a472b6c607c7a28ca963541751f0dd3618
x86 mce: Make indentation consistent (soft tabs) in a couple of files.
Signed-off-by: Keir Fraser <keir.fraser@xxxxxxxxxx>
---
xen/arch/x86/cpu/mcheck/mce.c | 2206 ++++++++++++++++++------------------
xen/arch/x86/cpu/mcheck/mce_intel.c | 8
2 files changed, 1107 insertions(+), 1107 deletions(-)
diff -r 05bfc5a472b6 -r 9a3f422cf980 xen/arch/x86/cpu/mcheck/mce.c
--- a/xen/arch/x86/cpu/mcheck/mce.c Wed Jun 09 07:51:31 2010 +0100
+++ b/xen/arch/x86/cpu/mcheck/mce.c Wed Jun 09 07:54:10 2010 +0100
@@ -35,8 +35,8 @@ static void mcinfo_clear(struct mc_info
static void mcinfo_clear(struct mc_info *);
struct mca_banks *mca_allbanks;
-#define SEG_PL(segsel) ((segsel) & 0x3)
-#define _MC_MSRINJ_F_REQ_HWCR_WREN (1 << 16)
+#define SEG_PL(segsel) ((segsel) & 0x3)
+#define _MC_MSRINJ_F_REQ_HWCR_WREN (1 << 16)
#if 0
static int x86_mcerr(const char *msg, int err)
@@ -56,15 +56,15 @@ static void __init mce_set_verbosity(cha
mce_verbosity = MCE_VERBOSE;
else
printk(KERN_DEBUG "Machine Check verbosity level %s not recognised"
- "use mce_verbosity=verbose", str);
+ "use mce_verbosity=verbose", str);
}
custom_param("mce_verbosity", mce_set_verbosity);
/* Handle unconfigured int18 (should never happen) */
static void unexpected_machine_check(struct cpu_user_regs *regs, long
error_code)
{
- printk(XENLOG_ERR "CPU#%d: Unexpected int18 (Machine Check).\n",
- smp_processor_id());
+ printk(XENLOG_ERR "CPU#%d: Unexpected int18 (Machine Check).\n",
+ smp_processor_id());
}
@@ -72,15 +72,15 @@ static x86_mce_vector_t _machine_check_v
void x86_mce_vector_register(x86_mce_vector_t hdlr)
{
- _machine_check_vector = hdlr;
- wmb();
+ _machine_check_vector = hdlr;
+ wmb();
}
/* Call the installed machine check handler for this CPU setup. */
void machine_check_vector(struct cpu_user_regs *regs, long error_code)
{
- _machine_check_vector(regs, error_code);
+ _machine_check_vector(regs, error_code);
}
/* Init machine check callback handler
@@ -92,7 +92,7 @@ static x86_mce_callback_t mc_callback_ba
void x86_mce_callback_register(x86_mce_callback_t cbfunc)
{
- mc_callback_bank_extended = cbfunc;
+ mc_callback_bank_extended = cbfunc;
}
/* Machine check recoverable judgement callback handler
@@ -114,7 +114,7 @@ struct mca_banks *mcabanks_alloc(void)
return NULL;
mb->bank_map = xmalloc_array(unsigned long,
- BITS_TO_LONGS(nr_mce_banks));
+ BITS_TO_LONGS(nr_mce_banks));
if (!mb->bank_map)
{
xfree(mb);
@@ -150,83 +150,83 @@ static struct mcinfo_bank *mca_init_bank
static struct mcinfo_bank *mca_init_bank(enum mca_source who,
struct mc_info *mi, int bank)
{
- struct mcinfo_bank *mib;
- uint64_t addr=0, misc = 0;
-
- if (!mi)
- return NULL;
-
- mib = x86_mcinfo_reserve(mi, sizeof(struct mcinfo_bank));
- if (!mib)
- {
- mi->flags |= MCINFO_FLAGS_UNCOMPLETE;
- return NULL;
- }
-
- memset(mib, 0, sizeof (struct mcinfo_bank));
- mca_rdmsrl(MSR_IA32_MC0_STATUS + bank * 4, mib->mc_status);
-
- mib->common.type = MC_TYPE_BANK;
- mib->common.size = sizeof (struct mcinfo_bank);
- mib->mc_bank = bank;
-
- addr = misc = 0;
- if (mib->mc_status & MCi_STATUS_MISCV)
- mca_rdmsrl(MSR_IA32_MC0_MISC + 4 * bank, mib->mc_misc);
-
- if (mib->mc_status & MCi_STATUS_ADDRV)
- {
- mca_rdmsrl(MSR_IA32_MC0_ADDR + 4 * bank, mib->mc_addr);
-
- if (mfn_valid(paddr_to_pfn(mib->mc_addr))) {
- struct domain *d;
-
- d = maddr_get_owner(mib->mc_addr);
- if (d != NULL && (who == MCA_POLLER ||
- who == MCA_CMCI_HANDLER))
- mib->mc_domid = d->domain_id;
- }
- }
-
- if (who == MCA_CMCI_HANDLER) {
- mca_rdmsrl(MSR_IA32_MC0_CTL2 + bank, mib->mc_ctrl2);
- rdtscll(mib->mc_tsc);
- }
-
- return mib;
+ struct mcinfo_bank *mib;
+ uint64_t addr=0, misc = 0;
+
+ if (!mi)
+ return NULL;
+
+ mib = x86_mcinfo_reserve(mi, sizeof(struct mcinfo_bank));
+ if (!mib)
+ {
+ mi->flags |= MCINFO_FLAGS_UNCOMPLETE;
+ return NULL;
+ }
+
+ memset(mib, 0, sizeof (struct mcinfo_bank));
+ mca_rdmsrl(MSR_IA32_MC0_STATUS + bank * 4, mib->mc_status);
+
+ mib->common.type = MC_TYPE_BANK;
+ mib->common.size = sizeof (struct mcinfo_bank);
+ mib->mc_bank = bank;
+
+ addr = misc = 0;
+ if (mib->mc_status & MCi_STATUS_MISCV)
+ mca_rdmsrl(MSR_IA32_MC0_MISC + 4 * bank, mib->mc_misc);
+
+ if (mib->mc_status & MCi_STATUS_ADDRV)
+ {
+ mca_rdmsrl(MSR_IA32_MC0_ADDR + 4 * bank, mib->mc_addr);
+
+ if (mfn_valid(paddr_to_pfn(mib->mc_addr))) {
+ struct domain *d;
+
+ d = maddr_get_owner(mib->mc_addr);
+ if (d != NULL && (who == MCA_POLLER ||
+ who == MCA_CMCI_HANDLER))
+ mib->mc_domid = d->domain_id;
+ }
+ }
+
+ if (who == MCA_CMCI_HANDLER) {
+ mca_rdmsrl(MSR_IA32_MC0_CTL2 + bank, mib->mc_ctrl2);
+ rdtscll(mib->mc_tsc);
+ }
+
+ return mib;
}
static int mca_init_global(uint32_t flags, struct mcinfo_global *mig)
{
- uint64_t status;
- int cpu_nr;
- struct vcpu *v = current;
- struct domain *d;
-
- /* Set global information */
- memset(mig, 0, sizeof (struct mcinfo_global));
- mig->common.type = MC_TYPE_GLOBAL;
- mig->common.size = sizeof (struct mcinfo_global);
- mca_rdmsrl(MSR_IA32_MCG_STATUS, status);
- mig->mc_gstatus = status;
- mig->mc_domid = mig->mc_vcpuid = -1;
- mig->mc_flags = flags;
- cpu_nr = smp_processor_id();
- /* Retrieve detector information */
- x86_mc_get_cpu_info(cpu_nr, &mig->mc_socketid,
- &mig->mc_coreid, &mig->mc_core_threadid,
- &mig->mc_apicid, NULL, NULL, NULL);
-
- /* This is really meaningless */
- if (v != NULL && ((d = v->domain) != NULL)) {
- mig->mc_domid = d->domain_id;
- mig->mc_vcpuid = v->vcpu_id;
- } else {
- mig->mc_domid = -1;
- mig->mc_vcpuid = -1;
- }
-
- return 0;
+ uint64_t status;
+ int cpu_nr;
+ struct vcpu *v = current;
+ struct domain *d;
+
+ /* Set global information */
+ memset(mig, 0, sizeof (struct mcinfo_global));
+ mig->common.type = MC_TYPE_GLOBAL;
+ mig->common.size = sizeof (struct mcinfo_global);
+ mca_rdmsrl(MSR_IA32_MCG_STATUS, status);
+ mig->mc_gstatus = status;
+ mig->mc_domid = mig->mc_vcpuid = -1;
+ mig->mc_flags = flags;
+ cpu_nr = smp_processor_id();
+ /* Retrieve detector information */
+ x86_mc_get_cpu_info(cpu_nr, &mig->mc_socketid,
+ &mig->mc_coreid, &mig->mc_core_threadid,
+ &mig->mc_apicid, NULL, NULL, NULL);
+
+ /* This is really meaningless */
+ if (v != NULL && ((d = v->domain) != NULL)) {
+ mig->mc_domid = d->domain_id;
+ mig->mc_vcpuid = v->vcpu_id;
+ } else {
+ mig->mc_domid = -1;
+ mig->mc_vcpuid = -1;
+ }
+
+ return 0;
}
/* Utility function to perform MCA bank telemetry readout and to push that
@@ -241,405 +241,405 @@ static int mca_init_global(uint32_t flag
* be judged by the callback function defined above.
*/
mctelem_cookie_t mcheck_mca_logout(enum mca_source who, struct mca_banks
*bankmask,
- struct mca_summary *sp, struct mca_banks* clear_bank)
-{
- uint64_t gstatus, status;
- struct mcinfo_global *mig = NULL; /* on stack */
- mctelem_cookie_t mctc = NULL;
- uint32_t uc = 0, pcc = 0, recover, need_clear = 1, mc_flags = 0;
- struct mc_info *mci = NULL;
- mctelem_class_t which = MC_URGENT; /* XXXgcc */
- int errcnt = 0;
- int i;
-
- mca_rdmsrl(MSR_IA32_MCG_STATUS, gstatus);
- switch (who) {
- case MCA_MCE_HANDLER:
- case MCA_MCE_SCAN:
- mc_flags = MC_FLAG_MCE;
- which = MC_URGENT;
- break;
-
- case MCA_POLLER:
- case MCA_RESET:
- mc_flags = MC_FLAG_POLLED;
- which = MC_NONURGENT;
- break;
-
- case MCA_CMCI_HANDLER:
- mc_flags = MC_FLAG_CMCI;
- which = MC_NONURGENT;
- break;
-
- default:
- BUG();
- }
-
- /* If no mc_recovery_scan callback handler registered,
- * this error is not recoverable
- */
- recover = (mc_recoverable_scan)? 1: 0;
-
- for (i = 0; i < 32 && i < nr_mce_banks; i++) {
- struct mcinfo_bank *mib; /* on stack */
-
- /* Skip bank if corresponding bit in bankmask is clear */
- if (!mcabanks_test(i, bankmask))
- continue;
-
- mca_rdmsrl(MSR_IA32_MC0_STATUS + i * 4, status);
- if (!(status & MCi_STATUS_VAL))
- continue; /* this bank has no valid telemetry */
-
- /* For Intel Latest CPU CMCI/MCE Handler caller, we need to
- * decide whether to clear bank by MCi_STATUS bit value such as
- * OVER/UC/EN/PCC/S/AR
- */
- if ( mc_need_clearbank_scan )
- need_clear = mc_need_clearbank_scan(who, status);
-
- /* If this is the first bank with valid MCA DATA, then
- * try to reserve an entry from the urgent/nonurgent queue
- * depending on whethere we are called from an exception or
- * a poller; this can fail (for example dom0 may not
- * yet have consumed past telemetry). */
- if (errcnt++ == 0) {
- if ( (mctc = mctelem_reserve(which)) != NULL ) {
- mci = mctelem_dataptr(mctc);
- mcinfo_clear(mci);
- mig = (struct mcinfo_global*)x86_mcinfo_reserve
- (mci, sizeof(struct mcinfo_global));
- /* mc_info should at least hold up the global
information */
- ASSERT(mig);
- mca_init_global(mc_flags, mig);
- /* A hook here to get global extended msrs */
- {
- struct mcinfo_extended
*intel_get_extended_msrs(
- struct mcinfo_global *mig, struct
mc_info *mi);
-
- if (boot_cpu_data.x86_vendor ==
- X86_VENDOR_INTEL)
- intel_get_extended_msrs(mig,
mci);
- }
- }
- }
-
- /* form a mask of which banks have logged uncorrected errors */
- if ((status & MCi_STATUS_UC) != 0)
- uc |= (1 << i);
-
- /* likewise for those with processor context corrupt */
- if ((status & MCi_STATUS_PCC) != 0)
- pcc |= (1 << i);
-
- if (recover && uc)
- /* uc = 1, recover = 1, we need not panic.
- */
- recover = mc_recoverable_scan(status);
-
- mib = mca_init_bank(who, mci, i);
-
- if (mc_callback_bank_extended)
- mc_callback_bank_extended(mci, i, status);
-
- /* By default, need_clear = 1 */
- if (who != MCA_MCE_SCAN && need_clear)
- /* Clear status */
- mca_wrmsrl(MSR_IA32_MC0_STATUS + 4 * i, 0x0ULL);
- else if ( who == MCA_MCE_SCAN && need_clear)
- mcabanks_set(i, clear_bank);
-
- wmb();
- }
-
- if (mig && errcnt > 0) {
- if (pcc)
- mig->mc_flags |= MC_FLAG_UNCORRECTABLE;
- else if (uc)
- mig->mc_flags |= MC_FLAG_RECOVERABLE;
- else
- mig->mc_flags |= MC_FLAG_CORRECTABLE;
- }
-
-
- if (sp) {
- sp->errcnt = errcnt;
- sp->ripv = (gstatus & MCG_STATUS_RIPV) != 0;
- sp->eipv = (gstatus & MCG_STATUS_EIPV) != 0;
- sp->uc = uc;
- sp->pcc = pcc;
- sp->recoverable = recover;
- }
-
- return mci != NULL ? mctc : NULL; /* may be NULL */
-}
-
-#define DOM_NORMAL 0
-#define DOM0_TRAP 1
-#define DOMU_TRAP 2
-#define DOMU_KILLED 4
+ struct mca_summary *sp, struct mca_banks*
clear_bank)
+{
+ uint64_t gstatus, status;
+ struct mcinfo_global *mig = NULL; /* on stack */
+ mctelem_cookie_t mctc = NULL;
+ uint32_t uc = 0, pcc = 0, recover, need_clear = 1, mc_flags = 0;
+ struct mc_info *mci = NULL;
+ mctelem_class_t which = MC_URGENT; /* XXXgcc */
+ int errcnt = 0;
+ int i;
+
+ mca_rdmsrl(MSR_IA32_MCG_STATUS, gstatus);
+ switch (who) {
+ case MCA_MCE_HANDLER:
+ case MCA_MCE_SCAN:
+ mc_flags = MC_FLAG_MCE;
+ which = MC_URGENT;
+ break;
+
+ case MCA_POLLER:
+ case MCA_RESET:
+ mc_flags = MC_FLAG_POLLED;
+ which = MC_NONURGENT;
+ break;
+
+ case MCA_CMCI_HANDLER:
+ mc_flags = MC_FLAG_CMCI;
+ which = MC_NONURGENT;
+ break;
+
+ default:
+ BUG();
+ }
+
+ /* If no mc_recovery_scan callback handler registered,
+ * this error is not recoverable
+ */
+ recover = (mc_recoverable_scan)? 1: 0;
+
+ for (i = 0; i < 32 && i < nr_mce_banks; i++) {
+ struct mcinfo_bank *mib; /* on stack */
+
+ /* Skip bank if corresponding bit in bankmask is clear */
+ if (!mcabanks_test(i, bankmask))
+ continue;
+
+ mca_rdmsrl(MSR_IA32_MC0_STATUS + i * 4, status);
+ if (!(status & MCi_STATUS_VAL))
+ continue; /* this bank has no valid telemetry */
+
+ /* For Intel Latest CPU CMCI/MCE Handler caller, we need to
+ * decide whether to clear bank by MCi_STATUS bit value such as
+ * OVER/UC/EN/PCC/S/AR
+ */
+ if ( mc_need_clearbank_scan )
+ need_clear = mc_need_clearbank_scan(who, status);
+
+ /* If this is the first bank with valid MCA DATA, then
+ * try to reserve an entry from the urgent/nonurgent queue
+ * depending on whethere we are called from an exception or
+ * a poller; this can fail (for example dom0 may not
+ * yet have consumed past telemetry). */
+ if (errcnt++ == 0) {
+ if ( (mctc = mctelem_reserve(which)) != NULL ) {
+ mci = mctelem_dataptr(mctc);
+ mcinfo_clear(mci);
+ mig = (struct mcinfo_global*)x86_mcinfo_reserve
+ (mci, sizeof(struct mcinfo_global));
+ /* mc_info should at least hold up the global information */
+ ASSERT(mig);
+ mca_init_global(mc_flags, mig);
+ /* A hook here to get global extended msrs */
+ {
+ struct mcinfo_extended *intel_get_extended_msrs(
+ struct mcinfo_global *mig, struct mc_info *mi);
+
+ if (boot_cpu_data.x86_vendor ==
+ X86_VENDOR_INTEL)
+ intel_get_extended_msrs(mig, mci);
+ }
+ }
+ }
+
+ /* form a mask of which banks have logged uncorrected errors */
+ if ((status & MCi_STATUS_UC) != 0)
+ uc |= (1 << i);
+
+ /* likewise for those with processor context corrupt */
+ if ((status & MCi_STATUS_PCC) != 0)
+ pcc |= (1 << i);
+
+ if (recover && uc)
+ /* uc = 1, recover = 1, we need not panic.
+ */
+ recover = mc_recoverable_scan(status);
+
+ mib = mca_init_bank(who, mci, i);
+
+ if (mc_callback_bank_extended)
+ mc_callback_bank_extended(mci, i, status);
+
+ /* By default, need_clear = 1 */
+ if (who != MCA_MCE_SCAN && need_clear)
+ /* Clear status */
+ mca_wrmsrl(MSR_IA32_MC0_STATUS + 4 * i, 0x0ULL);
+ else if ( who == MCA_MCE_SCAN && need_clear)
+ mcabanks_set(i, clear_bank);
+
+ wmb();
+ }
+
+ if (mig && errcnt > 0) {
+ if (pcc)
+ mig->mc_flags |= MC_FLAG_UNCORRECTABLE;
+ else if (uc)
+ mig->mc_flags |= MC_FLAG_RECOVERABLE;
+ else
+ mig->mc_flags |= MC_FLAG_CORRECTABLE;
+ }
+
+
+ if (sp) {
+ sp->errcnt = errcnt;
+ sp->ripv = (gstatus & MCG_STATUS_RIPV) != 0;
+ sp->eipv = (gstatus & MCG_STATUS_EIPV) != 0;
+ sp->uc = uc;
+ sp->pcc = pcc;
+ sp->recoverable = recover;
+ }
+
+ return mci != NULL ? mctc : NULL; /* may be NULL */
+}
+
+#define DOM_NORMAL 0
+#define DOM0_TRAP 1
+#define DOMU_TRAP 2
+#define DOMU_KILLED 4
/* Shared #MC handler. */
void mcheck_cmn_handler(struct cpu_user_regs *regs, long error_code,
- struct mca_banks *bankmask)
-{
- int xen_state_lost, dom0_state_lost, domU_state_lost;
- struct vcpu *v = current;
- struct domain *curdom = v->domain;
- domid_t domid = curdom->domain_id;
- int ctx_xen, ctx_dom0, ctx_domU;
- uint32_t dom_state = DOM_NORMAL;
- mctelem_cookie_t mctc = NULL;
- struct mca_summary bs;
- struct mc_info *mci = NULL;
- int irqlocked = 0;
- uint64_t gstatus;
- int ripv;
-
- /* This handler runs as interrupt gate. So IPIs from the
- * polling service routine are defered until we're finished.
- */
-
- /* Disable interrupts for the _vcpu_. It may not re-scheduled to
- * another physical CPU. */
- vcpu_schedule_lock_irq(v);
- irqlocked = 1;
-
- /* Read global status; if it does not indicate machine check
- * in progress then bail as long as we have a valid ip to return to. */
- mca_rdmsrl(MSR_IA32_MCG_STATUS, gstatus);
- ripv = ((gstatus & MCG_STATUS_RIPV) != 0);
- if (!(gstatus & MCG_STATUS_MCIP) && ripv) {
- add_taint(TAINT_MACHINE_CHECK); /* questionable */
- vcpu_schedule_unlock_irq(v);
- irqlocked = 0;
- goto cmn_handler_done;
- }
-
- /* Go and grab error telemetry. We must choose whether to commit
- * for logging or dismiss the cookie that is returned, and must not
- * reference the cookie after that action.
- */
- mctc = mcheck_mca_logout(MCA_MCE_HANDLER, bankmask, &bs, NULL);
- if (mctc != NULL)
- mci = (struct mc_info *)mctelem_dataptr(mctc);
-
- /* Clear MCIP or another #MC will enter shutdown state */
- gstatus &= ~MCG_STATUS_MCIP;
- mca_wrmsrl(MSR_IA32_MCG_STATUS, gstatus);
- wmb();
-
- /* If no valid errors and our stack is intact, we're done */
- if (ripv && bs.errcnt == 0) {
- vcpu_schedule_unlock_irq(v);
- irqlocked = 0;
- goto cmn_handler_done;
- }
-
- if (bs.uc || bs.pcc)
- add_taint(TAINT_MACHINE_CHECK);
-
- /* Machine check exceptions will usually be for UC and/or PCC errors,
- * but it is possible to configure machine check for some classes
- * of corrected error.
- *
- * UC errors could compromise any domain or the hypervisor
- * itself - for example a cache writeback of modified data that
- * turned out to be bad could be for data belonging to anyone, not
- * just the current domain. In the absence of known data poisoning
- * to prevent consumption of such bad data in the system we regard
- * all UC errors as terminal. It may be possible to attempt some
- * heuristics based on the address affected, which guests have
- * mappings to that mfn etc.
- *
- * PCC errors apply to the current context.
- *
- * If MCG_STATUS indicates !RIPV then even a #MC that is not UC
- * and not PCC is terminal - the return instruction pointer
- * pushed onto the stack is bogus. If the interrupt context is
- * the hypervisor or dom0 the game is over, otherwise we can
- * limit the impact to a single domU but only if we trampoline
- * somewhere safely - we can't return and unwind the stack.
- * Since there is no trampoline in place we will treat !RIPV
- * as terminal for any context.
- */
- ctx_xen = SEG_PL(regs->cs) == 0;
- ctx_dom0 = !ctx_xen && (domid == 0);
- ctx_domU = !ctx_xen && !ctx_dom0;
-
- xen_state_lost = bs.uc != 0 || (ctx_xen && (bs.pcc || !ripv)) ||
- !ripv;
- dom0_state_lost = bs.uc != 0 || (ctx_dom0 && (bs.pcc || !ripv));
- domU_state_lost = bs.uc != 0 || (ctx_domU && (bs.pcc || !ripv));
-
- if (xen_state_lost) {
- /* Now we are going to panic anyway. Allow interrupts, so that
- * printk on serial console can work. */
- vcpu_schedule_unlock_irq(v);
- irqlocked = 0;
-
- printk("Terminal machine check exception occurred in "
- "hypervisor context.\n");
-
- /* If MCG_STATUS_EIPV indicates, the IP on the stack is related
- * to the error then it makes sense to print a stack trace.
- * That can be useful for more detailed error analysis and/or
- * error case studies to figure out, if we can clear
- * xen_impacted and kill a DomU instead
- * (i.e. if a guest only control structure is affected, but then
- * we must ensure the bad pages are not re-used again).
- */
- if (bs.eipv & MCG_STATUS_EIPV) {
- printk("MCE: Instruction Pointer is related to the "
- "error, therefore print the execution state.\n");
- show_execution_state(regs);
- }
-
- /* Commit the telemetry so that panic flow can find it. */
- if (mctc != NULL) {
- x86_mcinfo_dump(mci);
- mctelem_commit(mctc);
- }
- mc_panic("Hypervisor state lost due to machine check "
- "exception.\n");
- /*NOTREACHED*/
- }
-
- /*
- * Xen hypervisor state is intact. If dom0 state is lost then
- * give it a chance to decide what to do if it has registered
- * a handler for this event, otherwise panic.
- *
- * XXFM Could add some Solaris dom0 contract kill here?
- */
- if (dom0_state_lost) {
- if (dom0 && dom0->max_vcpus && dom0->vcpu[0] &&
- guest_has_trap_callback(dom0, 0, TRAP_machine_check)) {
- dom_state = DOM0_TRAP;
- send_guest_trap(dom0, 0, TRAP_machine_check);
- /* XXFM case of return with !ripv ??? */
- } else {
- /* Commit telemetry for panic flow. */
- if (mctc != NULL) {
- x86_mcinfo_dump(mci);
- mctelem_commit(mctc);
- }
- mc_panic("Dom0 state lost due to machine check "
- "exception\n");
- /*NOTREACHED*/
- }
- }
-
- /*
- * If a domU has lost state then send it a trap if it has registered
- * a handler, otherwise crash the domain.
- * XXFM Revisit this functionality.
- */
- if (domU_state_lost) {
- if (guest_has_trap_callback(v->domain, v->vcpu_id,
- TRAP_machine_check)) {
- dom_state = DOMU_TRAP;
- send_guest_trap(curdom, v->vcpu_id,
- TRAP_machine_check);
- } else {
- dom_state = DOMU_KILLED;
- /* Enable interrupts. This basically results in
- * calling sti on the *physical* cpu. But after
- * domain_crash() the vcpu pointer is invalid.
- * Therefore, we must unlock the irqs before killing
- * it. */
- vcpu_schedule_unlock_irq(v);
- irqlocked = 0;
-
- /* DomU is impacted. Kill it and continue. */
- domain_crash(curdom);
- }
- }
-
- switch (dom_state) {
- case DOM0_TRAP:
- case DOMU_TRAP:
- /* Enable interrupts. */
- vcpu_schedule_unlock_irq(v);
- irqlocked = 0;
-
- /* guest softirqs and event callbacks are scheduled
- * immediately after this handler exits. */
- break;
- case DOMU_KILLED:
- /* Nothing to do here. */
- break;
-
- case DOM_NORMAL:
- vcpu_schedule_unlock_irq(v);
- irqlocked = 0;
- break;
- }
-
-cmn_handler_done:
- BUG_ON(irqlocked);
- BUG_ON(!ripv);
-
- if (bs.errcnt) {
- /* Not panicing, so forward telemetry to dom0 now if it
- * is interested. */
- if (dom0_vmce_enabled()) {
- if (mctc != NULL)
- mctelem_commit(mctc);
- send_guest_global_virq(dom0, VIRQ_MCA);
- } else {
- x86_mcinfo_dump(mci);
- if (mctc != NULL)
- mctelem_dismiss(mctc);
- }
- } else if (mctc != NULL) {
- mctelem_dismiss(mctc);
- }
+ struct mca_banks *bankmask)
+{
+ int xen_state_lost, dom0_state_lost, domU_state_lost;
+ struct vcpu *v = current;
+ struct domain *curdom = v->domain;
+ domid_t domid = curdom->domain_id;
+ int ctx_xen, ctx_dom0, ctx_domU;
+ uint32_t dom_state = DOM_NORMAL;
+ mctelem_cookie_t mctc = NULL;
+ struct mca_summary bs;
+ struct mc_info *mci = NULL;
+ int irqlocked = 0;
+ uint64_t gstatus;
+ int ripv;
+
+ /* This handler runs as interrupt gate. So IPIs from the
+ * polling service routine are defered until we're finished.
+ */
+
+ /* Disable interrupts for the _vcpu_. It may not re-scheduled to
+ * another physical CPU. */
+ vcpu_schedule_lock_irq(v);
+ irqlocked = 1;
+
+ /* Read global status; if it does not indicate machine check
+ * in progress then bail as long as we have a valid ip to return to. */
+ mca_rdmsrl(MSR_IA32_MCG_STATUS, gstatus);
+ ripv = ((gstatus & MCG_STATUS_RIPV) != 0);
+ if (!(gstatus & MCG_STATUS_MCIP) && ripv) {
+ add_taint(TAINT_MACHINE_CHECK); /* questionable */
+ vcpu_schedule_unlock_irq(v);
+ irqlocked = 0;
+ goto cmn_handler_done;
+ }
+
+ /* Go and grab error telemetry. We must choose whether to commit
+ * for logging or dismiss the cookie that is returned, and must not
+ * reference the cookie after that action.
+ */
+ mctc = mcheck_mca_logout(MCA_MCE_HANDLER, bankmask, &bs, NULL);
+ if (mctc != NULL)
+ mci = (struct mc_info *)mctelem_dataptr(mctc);
+
+ /* Clear MCIP or another #MC will enter shutdown state */
+ gstatus &= ~MCG_STATUS_MCIP;
+ mca_wrmsrl(MSR_IA32_MCG_STATUS, gstatus);
+ wmb();
+
+ /* If no valid errors and our stack is intact, we're done */
+ if (ripv && bs.errcnt == 0) {
+ vcpu_schedule_unlock_irq(v);
+ irqlocked = 0;
+ goto cmn_handler_done;
+ }
+
+ if (bs.uc || bs.pcc)
+ add_taint(TAINT_MACHINE_CHECK);
+
+ /* Machine check exceptions will usually be for UC and/or PCC errors,
+ * but it is possible to configure machine check for some classes
+ * of corrected error.
+ *
+ * UC errors could compromise any domain or the hypervisor
+ * itself - for example a cache writeback of modified data that
+ * turned out to be bad could be for data belonging to anyone, not
+ * just the current domain. In the absence of known data poisoning
+ * to prevent consumption of such bad data in the system we regard
+ * all UC errors as terminal. It may be possible to attempt some
+ * heuristics based on the address affected, which guests have
+ * mappings to that mfn etc.
+ *
+ * PCC errors apply to the current context.
+ *
+ * If MCG_STATUS indicates !RIPV then even a #MC that is not UC
+ * and not PCC is terminal - the return instruction pointer
+ * pushed onto the stack is bogus. If the interrupt context is
+ * the hypervisor or dom0 the game is over, otherwise we can
+ * limit the impact to a single domU but only if we trampoline
+ * somewhere safely - we can't return and unwind the stack.
+ * Since there is no trampoline in place we will treat !RIPV
+ * as terminal for any context.
+ */
+ ctx_xen = SEG_PL(regs->cs) == 0;
+ ctx_dom0 = !ctx_xen && (domid == 0);
+ ctx_domU = !ctx_xen && !ctx_dom0;
+
+ xen_state_lost = bs.uc != 0 || (ctx_xen && (bs.pcc || !ripv)) ||
+ !ripv;
+ dom0_state_lost = bs.uc != 0 || (ctx_dom0 && (bs.pcc || !ripv));
+ domU_state_lost = bs.uc != 0 || (ctx_domU && (bs.pcc || !ripv));
+
+ if (xen_state_lost) {
+ /* Now we are going to panic anyway. Allow interrupts, so that
+ * printk on serial console can work. */
+ vcpu_schedule_unlock_irq(v);
+ irqlocked = 0;
+
+ printk("Terminal machine check exception occurred in "
+ "hypervisor context.\n");
+
+ /* If MCG_STATUS_EIPV indicates, the IP on the stack is related
+ * to the error then it makes sense to print a stack trace.
+ * That can be useful for more detailed error analysis and/or
+ * error case studies to figure out, if we can clear
+ * xen_impacted and kill a DomU instead
+ * (i.e. if a guest only control structure is affected, but then
+ * we must ensure the bad pages are not re-used again).
+ */
+ if (bs.eipv & MCG_STATUS_EIPV) {
+ printk("MCE: Instruction Pointer is related to the "
+ "error, therefore print the execution state.\n");
+ show_execution_state(regs);
+ }
+
+ /* Commit the telemetry so that panic flow can find it. */
+ if (mctc != NULL) {
+ x86_mcinfo_dump(mci);
+ mctelem_commit(mctc);
+ }
+ mc_panic("Hypervisor state lost due to machine check "
+ "exception.\n");
+ /*NOTREACHED*/
+ }
+
+ /*
+ * Xen hypervisor state is intact. If dom0 state is lost then
+ * give it a chance to decide what to do if it has registered
+ * a handler for this event, otherwise panic.
+ *
+ * XXFM Could add some Solaris dom0 contract kill here?
+ */
+ if (dom0_state_lost) {
+ if (dom0 && dom0->max_vcpus && dom0->vcpu[0] &&
+ guest_has_trap_callback(dom0, 0, TRAP_machine_check)) {
+ dom_state = DOM0_TRAP;
+ send_guest_trap(dom0, 0, TRAP_machine_check);
+ /* XXFM case of return with !ripv ??? */
+ } else {
+ /* Commit telemetry for panic flow. */
+ if (mctc != NULL) {
+ x86_mcinfo_dump(mci);
+ mctelem_commit(mctc);
+ }
+ mc_panic("Dom0 state lost due to machine check "
+ "exception\n");
+ /*NOTREACHED*/
+ }
+ }
+
+ /*
+ * If a domU has lost state then send it a trap if it has registered
+ * a handler, otherwise crash the domain.
+ * XXFM Revisit this functionality.
+ */
+ if (domU_state_lost) {
+ if (guest_has_trap_callback(v->domain, v->vcpu_id,
+ TRAP_machine_check)) {
+ dom_state = DOMU_TRAP;
+ send_guest_trap(curdom, v->vcpu_id,
+ TRAP_machine_check);
+ } else {
+ dom_state = DOMU_KILLED;
+ /* Enable interrupts. This basically results in
+ * calling sti on the *physical* cpu. But after
+ * domain_crash() the vcpu pointer is invalid.
+ * Therefore, we must unlock the irqs before killing
+ * it. */
+ vcpu_schedule_unlock_irq(v);
+ irqlocked = 0;
+
+ /* DomU is impacted. Kill it and continue. */
+ domain_crash(curdom);
+ }
+ }
+
+ switch (dom_state) {
+ case DOM0_TRAP:
+ case DOMU_TRAP:
+ /* Enable interrupts. */
+ vcpu_schedule_unlock_irq(v);
+ irqlocked = 0;
+
+ /* guest softirqs and event callbacks are scheduled
+ * immediately after this handler exits. */
+ break;
+ case DOMU_KILLED:
+ /* Nothing to do here. */
+ break;
+
+ case DOM_NORMAL:
+ vcpu_schedule_unlock_irq(v);
+ irqlocked = 0;
+ break;
+ }
+
+ cmn_handler_done:
+ BUG_ON(irqlocked);
+ BUG_ON(!ripv);
+
+ if (bs.errcnt) {
+ /* Not panicing, so forward telemetry to dom0 now if it
+ * is interested. */
+ if (dom0_vmce_enabled()) {
+ if (mctc != NULL)
+ mctelem_commit(mctc);
+ send_guest_global_virq(dom0, VIRQ_MCA);
+ } else {
+ x86_mcinfo_dump(mci);
+ if (mctc != NULL)
+ mctelem_dismiss(mctc);
+ }
+ } else if (mctc != NULL) {
+ mctelem_dismiss(mctc);
+ }
}
void mcheck_mca_clearbanks(struct mca_banks *bankmask)
{
- int i;
- uint64_t status;
-
- for (i = 0; i < 32 && i < nr_mce_banks; i++) {
- if (!mcabanks_test(i, bankmask))
- continue;
- mca_rdmsrl(MSR_IA32_MC0_STATUS + i * 4, status);
- if (!(status & MCi_STATUS_VAL))
- continue;
- mca_wrmsrl(MSR_IA32_MC0_STATUS + 4 * i, 0x0ULL);
- }
+ int i;
+ uint64_t status;
+
+ for (i = 0; i < 32 && i < nr_mce_banks; i++) {
+ if (!mcabanks_test(i, bankmask))
+ continue;
+ mca_rdmsrl(MSR_IA32_MC0_STATUS + i * 4, status);
+ if (!(status & MCi_STATUS_VAL))
+ continue;
+ mca_wrmsrl(MSR_IA32_MC0_STATUS + 4 * i, 0x0ULL);
+ }
}
static enum mcheck_type amd_mcheck_init(struct cpuinfo_x86 *ci)
{
- enum mcheck_type rc = mcheck_none;
-
- switch (ci->x86) {
- case 6:
- rc = amd_k7_mcheck_init(ci);
- break;
-
- default:
- /* Assume that machine check support is available.
- * The minimum provided support is at least the K8. */
- case 0xf:
- rc = amd_k8_mcheck_init(ci);
- break;
-
- case 0x10 ... 0x17:
- rc = amd_f10_mcheck_init(ci);
- break;
- }
-
- return rc;
+ enum mcheck_type rc = mcheck_none;
+
+ switch (ci->x86) {
+ case 6:
+ rc = amd_k7_mcheck_init(ci);
+ break;
+
+ default:
+ /* Assume that machine check support is available.
+ * The minimum provided support is at least the K8. */
+ case 0xf:
+ rc = amd_k8_mcheck_init(ci);
+ break;
+
+ case 0x10 ... 0x17:
+ rc = amd_f10_mcheck_init(ci);
+ break;
+ }
+
+ return rc;
}
/*check the existence of Machine Check*/
int mce_available(struct cpuinfo_x86 *c)
{
- return cpu_has(c, X86_FEATURE_MCE) && cpu_has(c, X86_FEATURE_MCA);
+ return cpu_has(c, X86_FEATURE_MCE) && cpu_has(c, X86_FEATURE_MCA);
}
/*
@@ -648,50 +648,50 @@ int mce_available(struct cpuinfo_x86 *c)
*/
int mce_firstbank(struct cpuinfo_x86 *c)
{
- if (c->x86 == 6) {
- if (c->x86_vendor == X86_VENDOR_AMD)
- return 1;
-
- if (c->x86_vendor == X86_VENDOR_INTEL && c->x86_model < 0x1a)
- return 1;
- }
-
- return 0;
+ if (c->x86 == 6) {
+ if (c->x86_vendor == X86_VENDOR_AMD)
+ return 1;
+
+ if (c->x86_vendor == X86_VENDOR_INTEL && c->x86_model < 0x1a)
+ return 1;
+ }
+
+ return 0;
}
int show_mca_info(int inited, struct cpuinfo_x86 *c)
{
- static enum mcheck_type g_type = mcheck_unset;
-
- if (inited != g_type) {
- char prefix[20];
- static const char *const type_str[] = {
- [mcheck_amd_famXX] = "AMD",
- [mcheck_amd_k7] = "AMD K7",
- [mcheck_amd_k8] = "AMD K8",
- [mcheck_intel] = "Intel"
- };
-
- snprintf(prefix, ARRAY_SIZE(prefix),
- g_type != mcheck_unset ? XENLOG_WARNING "CPU%i: "
- : XENLOG_INFO,
- smp_processor_id());
- BUG_ON(inited >= ARRAY_SIZE(type_str));
- switch (inited) {
- default:
- printk("%s%s machine check reporting enabled\n",
- prefix, type_str[inited]);
- break;
- case mcheck_amd_famXX:
- printk("%s%s Fam%xh machine check reporting enabled\n",
- prefix, type_str[inited], c->x86);
- break;
- case mcheck_none:
- printk("%sNo machine check initialization\n", prefix);
- break;
- }
+ static enum mcheck_type g_type = mcheck_unset;
+
+ if (inited != g_type) {
+ char prefix[20];
+ static const char *const type_str[] = {
+ [mcheck_amd_famXX] = "AMD",
+ [mcheck_amd_k7] = "AMD K7",
+ [mcheck_amd_k8] = "AMD K8",
+ [mcheck_intel] = "Intel"
+ };
+
+ snprintf(prefix, ARRAY_SIZE(prefix),
+ g_type != mcheck_unset ? XENLOG_WARNING "CPU%i: "
+ : XENLOG_INFO,
+ smp_processor_id());
+ BUG_ON(inited >= ARRAY_SIZE(type_str));
+ switch (inited) {
+ default:
+ printk("%s%s machine check reporting enabled\n",
+ prefix, type_str[inited]);
+ break;
+ case mcheck_amd_famXX:
+ printk("%s%s Fam%xh machine check reporting enabled\n",
+ prefix, type_str[inited], c->x86);
+ break;
+ case mcheck_none:
+ printk("%sNo machine check initialization\n", prefix);
+ break;
+ }
g_type = inited;
- }
+ }
return 0;
}
@@ -708,7 +708,7 @@ int set_poll_bankmask(struct cpuinfo_x86
if (cmci_support && !mce_disabled) {
mb->num = per_cpu(no_cmci_banks, cpu)->num;
bitmap_copy(mb->bank_map, per_cpu(no_cmci_banks, cpu)->bank_map,
- nr_mce_banks);
+ nr_mce_banks);
}
else {
bitmap_copy(mb->bank_map, mca_allbanks->bank_map, nr_mce_banks);
@@ -756,116 +756,116 @@ int mca_cap_init(void)
/* This has to be run for each processor */
void mcheck_init(struct cpuinfo_x86 *c)
{
- enum mcheck_type inited = mcheck_none;
-
- if (mce_disabled == 1) {
- dprintk(XENLOG_INFO, "MCE support disabled by bootparam\n");
- return;
- }
-
- if (!mce_available(c))
- {
- printk(XENLOG_INFO "CPU%i: No machine check support
available\n",
- smp_processor_id());
- return;
- }
-
- /*Hardware Enable */
- if (mca_cap_init())
- return;
-
- switch (c->x86_vendor) {
- case X86_VENDOR_AMD:
- inited = amd_mcheck_init(c);
- break;
-
- case X86_VENDOR_INTEL:
- switch (c->x86) {
- case 6:
- case 15:
- inited = intel_mcheck_init(c);
- break;
- }
- break;
-
- default:
- break;
- }
-
- show_mca_info(inited, c);
- if (inited == mcheck_none || inited == mcheck_unset)
- goto out;
-
- intpose_init();
-
- mctelem_init(sizeof(struct mc_info));
-
- vmce_init(c);
+ enum mcheck_type inited = mcheck_none;
+
+ if (mce_disabled == 1) {
+ dprintk(XENLOG_INFO, "MCE support disabled by bootparam\n");
+ return;
+ }
+
+ if (!mce_available(c))
+ {
+ printk(XENLOG_INFO "CPU%i: No machine check support available\n",
+ smp_processor_id());
+ return;
+ }
+
+ /*Hardware Enable */
+ if (mca_cap_init())
+ return;
+
+ switch (c->x86_vendor) {
+ case X86_VENDOR_AMD:
+ inited = amd_mcheck_init(c);
+ break;
+
+ case X86_VENDOR_INTEL:
+ switch (c->x86) {
+ case 6:
+ case 15:
+ inited = intel_mcheck_init(c);
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ show_mca_info(inited, c);
+ if (inited == mcheck_none || inited == mcheck_unset)
+ goto out;
+
+ intpose_init();
+
+ mctelem_init(sizeof(struct mc_info));
+
+ vmce_init(c);
/* Turn on MCE now */
- set_in_cr4(X86_CR4_MCE);
-
- set_poll_bankmask(c);
-
- return;
-out:
- if (smp_processor_id() == 0)
- {
- mcabanks_free(mca_allbanks);
- mca_allbanks = NULL;
- }
+ set_in_cr4(X86_CR4_MCE);
+
+ set_poll_bankmask(c);
+
+ return;
+ out:
+ if (smp_processor_id() == 0)
+ {
+ mcabanks_free(mca_allbanks);
+ mca_allbanks = NULL;
+ }
}
static void mcinfo_clear(struct mc_info *mi)
{
- memset(mi, 0, sizeof(struct mc_info));
- x86_mcinfo_nentries(mi) = 0;
+ memset(mi, 0, sizeof(struct mc_info));
+ x86_mcinfo_nentries(mi) = 0;
}
void *x86_mcinfo_reserve(struct mc_info *mi, int size)
{
- int i;
- unsigned long end1, end2;
- struct mcinfo_common *mic_base, *mic_index;
-
- mic_index = mic_base = x86_mcinfo_first(mi);
-
- /* go to first free entry */
- for (i = 0; i < x86_mcinfo_nentries(mi); i++) {
- mic_index = x86_mcinfo_next(mic_index);
- }
-
- /* check if there is enough size */
- end1 = (unsigned long)((uint8_t *)mic_base + sizeof(struct mc_info));
- end2 = (unsigned long)((uint8_t *)mic_index + size);
-
- if (end1 < end2)
- {
- mce_printk(MCE_CRITICAL,
- "mcinfo_add: No space left in mc_info\n");
- return NULL;
- }
-
- /* there's enough space. add entry. */
- x86_mcinfo_nentries(mi)++;
+ int i;
+ unsigned long end1, end2;
+ struct mcinfo_common *mic_base, *mic_index;
+
+ mic_index = mic_base = x86_mcinfo_first(mi);
+
+ /* go to first free entry */
+ for (i = 0; i < x86_mcinfo_nentries(mi); i++) {
+ mic_index = x86_mcinfo_next(mic_index);
+ }
+
+ /* check if there is enough size */
+ end1 = (unsigned long)((uint8_t *)mic_base + sizeof(struct mc_info));
+ end2 = (unsigned long)((uint8_t *)mic_index + size);
+
+ if (end1 < end2)
+ {
+ mce_printk(MCE_CRITICAL,
+ "mcinfo_add: No space left in mc_info\n");
+ return NULL;
+ }
+
+ /* there's enough space. add entry. */
+ x86_mcinfo_nentries(mi)++;
return mic_index;
}
void *x86_mcinfo_add(struct mc_info *mi, void *mcinfo)
{
- struct mcinfo_common *mic, *buf;
-
- mic = (struct mcinfo_common *)mcinfo;
- buf = x86_mcinfo_reserve(mi, mic->size);
-
- if ( !buf )
- mce_printk(MCE_CRITICAL,
- "mcinfo_add: No space left in mc_info\n");
- else
- memcpy(buf, mic, mic->size);
-
- return buf;
+ struct mcinfo_common *mic, *buf;
+
+ mic = (struct mcinfo_common *)mcinfo;
+ buf = x86_mcinfo_reserve(mi, mic->size);
+
+ if ( !buf )
+ mce_printk(MCE_CRITICAL,
+ "mcinfo_add: No space left in mc_info\n");
+ else
+ memcpy(buf, mic, mic->size);
+
+ return buf;
}
/* Dump machine check information in a format,
@@ -873,354 +873,354 @@ void *x86_mcinfo_add(struct mc_info *mi,
* Dom0 does not take the notification. */
void x86_mcinfo_dump(struct mc_info *mi)
{
- struct mcinfo_common *mic = NULL;
- struct mcinfo_global *mc_global;
- struct mcinfo_bank *mc_bank;
-
- /* first print the global info */
- x86_mcinfo_lookup(mic, mi, MC_TYPE_GLOBAL);
- if (mic == NULL)
- return;
- mc_global = (struct mcinfo_global *)mic;
- if (mc_global->mc_flags & MC_FLAG_MCE) {
- printk(XENLOG_WARNING
- "CPU%d: Machine Check Exception: %16"PRIx64"\n",
- mc_global->mc_coreid, mc_global->mc_gstatus);
- } else {
- printk(XENLOG_WARNING "MCE: The hardware reports a non "
- "fatal, correctable incident occurred on "
- "CPU %d.\n",
- mc_global->mc_coreid);
- }
-
- /* then the bank information */
- x86_mcinfo_lookup(mic, mi, MC_TYPE_BANK); /* finds the first entry */
- do {
- if (mic == NULL)
- return;
- if (mic->type != MC_TYPE_BANK)
- goto next;
-
- mc_bank = (struct mcinfo_bank *)mic;
-
- printk(XENLOG_WARNING "Bank %d: %16"PRIx64,
- mc_bank->mc_bank,
- mc_bank->mc_status);
- if (mc_bank->mc_status & MCi_STATUS_MISCV)
- printk("[%16"PRIx64"]", mc_bank->mc_misc);
- if (mc_bank->mc_status & MCi_STATUS_ADDRV)
- printk(" at %16"PRIx64, mc_bank->mc_addr);
-
- printk("\n");
-next:
- mic = x86_mcinfo_next(mic); /* next entry */
- if ((mic == NULL) || (mic->size == 0))
- break;
- } while (1);
+ struct mcinfo_common *mic = NULL;
+ struct mcinfo_global *mc_global;
+ struct mcinfo_bank *mc_bank;
+
+ /* first print the global info */
+ x86_mcinfo_lookup(mic, mi, MC_TYPE_GLOBAL);
+ if (mic == NULL)
+ return;
+ mc_global = (struct mcinfo_global *)mic;
+ if (mc_global->mc_flags & MC_FLAG_MCE) {
+ printk(XENLOG_WARNING
+ "CPU%d: Machine Check Exception: %16"PRIx64"\n",
+ mc_global->mc_coreid, mc_global->mc_gstatus);
+ } else {
+ printk(XENLOG_WARNING "MCE: The hardware reports a non "
+ "fatal, correctable incident occurred on "
+ "CPU %d.\n",
+ mc_global->mc_coreid);
+ }
+
+ /* then the bank information */
+ x86_mcinfo_lookup(mic, mi, MC_TYPE_BANK); /* finds the first entry */
+ do {
+ if (mic == NULL)
+ return;
+ if (mic->type != MC_TYPE_BANK)
+ goto next;
+
+ mc_bank = (struct mcinfo_bank *)mic;
+
+ printk(XENLOG_WARNING "Bank %d: %16"PRIx64,
+ mc_bank->mc_bank,
+ mc_bank->mc_status);
+ if (mc_bank->mc_status & MCi_STATUS_MISCV)
+ printk("[%16"PRIx64"]", mc_bank->mc_misc);
+ if (mc_bank->mc_status & MCi_STATUS_ADDRV)
+ printk(" at %16"PRIx64, mc_bank->mc_addr);
+
+ printk("\n");
+ next:
+ mic = x86_mcinfo_next(mic); /* next entry */
+ if ((mic == NULL) || (mic->size == 0))
+ break;
+ } while (1);
}
static void do_mc_get_cpu_info(void *v)
{
- int cpu = smp_processor_id();
- int cindex, cpn;
- struct cpuinfo_x86 *c;
- xen_mc_logical_cpu_t *log_cpus, *xcp;
- uint32_t junk, ebx;
-
- log_cpus = v;
- c = &cpu_data[cpu];
- cindex = 0;
- cpn = cpu - 1;
-
- /*
- * Deal with sparse masks, condensed into a contig array.
- */
- while (cpn >= 0) {
- if (cpu_isset(cpn, cpu_online_map))
- cindex++;
- cpn--;
- }
-
- xcp = &log_cpus[cindex];
- c = &cpu_data[cpu];
- xcp->mc_cpunr = cpu;
- x86_mc_get_cpu_info(cpu, &xcp->mc_chipid,
- &xcp->mc_coreid, &xcp->mc_threadid,
- &xcp->mc_apicid, &xcp->mc_ncores,
- &xcp->mc_ncores_active, &xcp->mc_nthreads);
- xcp->mc_cpuid_level = c->cpuid_level;
- xcp->mc_family = c->x86;
- xcp->mc_vendor = c->x86_vendor;
- xcp->mc_model = c->x86_model;
- xcp->mc_step = c->x86_mask;
- xcp->mc_cache_size = c->x86_cache_size;
- xcp->mc_cache_alignment = c->x86_cache_alignment;
- memcpy(xcp->mc_vendorid, c->x86_vendor_id, sizeof xcp->mc_vendorid);
- memcpy(xcp->mc_brandid, c->x86_model_id, sizeof xcp->mc_brandid);
- memcpy(xcp->mc_cpu_caps, c->x86_capability, sizeof xcp->mc_cpu_caps);
-
- /*
- * This part needs to run on the CPU itself.
- */
- xcp->mc_nmsrvals = __MC_NMSRS;
- xcp->mc_msrvalues[0].reg = MSR_IA32_MCG_CAP;
- rdmsrl(MSR_IA32_MCG_CAP, xcp->mc_msrvalues[0].value);
-
- if (c->cpuid_level >= 1) {
- cpuid(1, &junk, &ebx, &junk, &junk);
- xcp->mc_clusterid = (ebx >> 24) & 0xff;
- } else
- xcp->mc_clusterid = hard_smp_processor_id();
+ int cpu = smp_processor_id();
+ int cindex, cpn;
+ struct cpuinfo_x86 *c;
+ xen_mc_logical_cpu_t *log_cpus, *xcp;
+ uint32_t junk, ebx;
+
+ log_cpus = v;
+ c = &cpu_data[cpu];
+ cindex = 0;
+ cpn = cpu - 1;
+
+ /*
+ * Deal with sparse masks, condensed into a contig array.
+ */
+ while (cpn >= 0) {
+ if (cpu_isset(cpn, cpu_online_map))
+ cindex++;
+ cpn--;
+ }
+
+ xcp = &log_cpus[cindex];
+ c = &cpu_data[cpu];
+ xcp->mc_cpunr = cpu;
+ x86_mc_get_cpu_info(cpu, &xcp->mc_chipid,
+ &xcp->mc_coreid, &xcp->mc_threadid,
+ &xcp->mc_apicid, &xcp->mc_ncores,
+ &xcp->mc_ncores_active, &xcp->mc_nthreads);
+ xcp->mc_cpuid_level = c->cpuid_level;
+ xcp->mc_family = c->x86;
+ xcp->mc_vendor = c->x86_vendor;
+ xcp->mc_model = c->x86_model;
+ xcp->mc_step = c->x86_mask;
+ xcp->mc_cache_size = c->x86_cache_size;
+ xcp->mc_cache_alignment = c->x86_cache_alignment;
+ memcpy(xcp->mc_vendorid, c->x86_vendor_id, sizeof xcp->mc_vendorid);
+ memcpy(xcp->mc_brandid, c->x86_model_id, sizeof xcp->mc_brandid);
+ memcpy(xcp->mc_cpu_caps, c->x86_capability, sizeof xcp->mc_cpu_caps);
+
+ /*
+ * This part needs to run on the CPU itself.
+ */
+ xcp->mc_nmsrvals = __MC_NMSRS;
+ xcp->mc_msrvalues[0].reg = MSR_IA32_MCG_CAP;
+ rdmsrl(MSR_IA32_MCG_CAP, xcp->mc_msrvalues[0].value);
+
+ if (c->cpuid_level >= 1) {
+ cpuid(1, &junk, &ebx, &junk, &junk);
+ xcp->mc_clusterid = (ebx >> 24) & 0xff;
+ } else
+ xcp->mc_clusterid = hard_smp_processor_id();
}
void x86_mc_get_cpu_info(unsigned cpu, uint32_t *chipid, uint16_t *coreid,
- uint16_t *threadid, uint32_t *apicid,
- unsigned *ncores, unsigned *ncores_active,
- unsigned *nthreads)
-{
- struct cpuinfo_x86 *c;
-
- *apicid = cpu_physical_id(cpu);
- c = &cpu_data[cpu];
- if (c->apicid == BAD_APICID) {
- *chipid = cpu;
- *coreid = 0;
- *threadid = 0;
- if (ncores != NULL)
- *ncores = 1;
- if (ncores_active != NULL)
- *ncores_active = 1;
- if (nthreads != NULL)
- *nthreads = 1;
- } else {
- *chipid = phys_proc_id[cpu];
- if (c->x86_max_cores > 1)
- *coreid = cpu_core_id[cpu];
- else
- *coreid = 0;
- *threadid = c->apicid & ((1 << (c->x86_num_siblings - 1)) - 1);
- if (ncores != NULL)
- *ncores = c->x86_max_cores;
- if (ncores_active != NULL)
- *ncores_active = c->booted_cores;
- if (nthreads != NULL)
- *nthreads = c->x86_num_siblings;
- }
-}
-
-#define INTPOSE_NENT 50
+ uint16_t *threadid, uint32_t *apicid,
+ unsigned *ncores, unsigned *ncores_active,
+ unsigned *nthreads)
+{
+ struct cpuinfo_x86 *c;
+
+ *apicid = cpu_physical_id(cpu);
+ c = &cpu_data[cpu];
+ if (c->apicid == BAD_APICID) {
+ *chipid = cpu;
+ *coreid = 0;
+ *threadid = 0;
+ if (ncores != NULL)
+ *ncores = 1;
+ if (ncores_active != NULL)
+ *ncores_active = 1;
+ if (nthreads != NULL)
+ *nthreads = 1;
+ } else {
+ *chipid = phys_proc_id[cpu];
+ if (c->x86_max_cores > 1)
+ *coreid = cpu_core_id[cpu];
+ else
+ *coreid = 0;
+ *threadid = c->apicid & ((1 << (c->x86_num_siblings - 1)) - 1);
+ if (ncores != NULL)
+ *ncores = c->x86_max_cores;
+ if (ncores_active != NULL)
+ *ncores_active = c->booted_cores;
+ if (nthreads != NULL)
+ *nthreads = c->x86_num_siblings;
+ }
+}
+
+#define INTPOSE_NENT 50
static struct intpose_ent {
- unsigned int cpu_nr;
- uint64_t msr;
- uint64_t val;
+ unsigned int cpu_nr;
+ uint64_t msr;
+ uint64_t val;
} intpose_arr[INTPOSE_NENT];
static void intpose_init(void)
{
- static int done;
- int i;
-
- if (done++ > 0)
- return;
-
- for (i = 0; i < INTPOSE_NENT; i++) {
- intpose_arr[i].cpu_nr = -1;
- }
+ static int done;
+ int i;
+
+ if (done++ > 0)
+ return;
+
+ for (i = 0; i < INTPOSE_NENT; i++) {
+ intpose_arr[i].cpu_nr = -1;
+ }
}
struct intpose_ent *intpose_lookup(unsigned int cpu_nr, uint64_t msr,
- uint64_t *valp)
-{
- int i;
-
- for (i = 0; i < INTPOSE_NENT; i++) {
- if (intpose_arr[i].cpu_nr == cpu_nr &&
- intpose_arr[i].msr == msr) {
- if (valp != NULL)
- *valp = intpose_arr[i].val;
- return &intpose_arr[i];
- }
- }
-
- return NULL;
+ uint64_t *valp)
+{
+ int i;
+
+ for (i = 0; i < INTPOSE_NENT; i++) {
+ if (intpose_arr[i].cpu_nr == cpu_nr &&
+ intpose_arr[i].msr == msr) {
+ if (valp != NULL)
+ *valp = intpose_arr[i].val;
+ return &intpose_arr[i];
+ }
+ }
+
+ return NULL;
}
static void intpose_add(unsigned int cpu_nr, uint64_t msr, uint64_t val)
{
- struct intpose_ent *ent;
- int i;
-
- if ((ent = intpose_lookup(cpu_nr, msr, NULL)) != NULL) {
- ent->val = val;
- return;
- }
-
- for (i = 0, ent = &intpose_arr[0]; i < INTPOSE_NENT; i++, ent++) {
- if (ent->cpu_nr == -1) {
- ent->cpu_nr = cpu_nr;
- ent->msr = msr;
- ent->val = val;
- return;
- }
- }
-
- printk("intpose_add: interpose array full - request dropped\n");
+ struct intpose_ent *ent;
+ int i;
+
+ if ((ent = intpose_lookup(cpu_nr, msr, NULL)) != NULL) {
+ ent->val = val;
+ return;
+ }
+
+ for (i = 0, ent = &intpose_arr[0]; i < INTPOSE_NENT; i++, ent++) {
+ if (ent->cpu_nr == -1) {
+ ent->cpu_nr = cpu_nr;
+ ent->msr = msr;
+ ent->val = val;
+ return;
+ }
+ }
+
+ printk("intpose_add: interpose array full - request dropped\n");
}
void intpose_inval(unsigned int cpu_nr, uint64_t msr)
{
- struct intpose_ent *ent;
-
- if ((ent = intpose_lookup(cpu_nr, msr, NULL)) != NULL) {
- ent->cpu_nr = -1;
- }
-}
-
-#define IS_MCA_BANKREG(r) \
+ struct intpose_ent *ent;
+
+ if ((ent = intpose_lookup(cpu_nr, msr, NULL)) != NULL) {
+ ent->cpu_nr = -1;
+ }
+}
+
+#define IS_MCA_BANKREG(r) \
((r) >= MSR_IA32_MC0_CTL && \
(r) <= MSR_IA32_MC0_MISC + (nr_mce_banks - 1) * 4 && \
- ((r) - MSR_IA32_MC0_CTL) % 4 != 0) /* excludes MCi_CTL */
+ ((r) - MSR_IA32_MC0_CTL) % 4 != 0) /* excludes MCi_CTL */
static int x86_mc_msrinject_verify(struct xen_mc_msrinject *mci)
{
- struct cpuinfo_x86 *c;
- int i, errs = 0;
-
- c = &cpu_data[smp_processor_id()];
-
- for (i = 0; i < mci->mcinj_count; i++) {
- uint64_t reg = mci->mcinj_msr[i].reg;
- const char *reason = NULL;
-
- if (IS_MCA_BANKREG(reg)) {
- if (c->x86_vendor == X86_VENDOR_AMD) {
- /* On AMD we can set MCi_STATUS_WREN in the
- * HWCR MSR to allow non-zero writes to banks
- * MSRs not to #GP. The injector in dom0
- * should set that bit, but we detect when it
- * is necessary and set it as a courtesy to
- * avoid #GP in the hypervisor. */
- mci->mcinj_flags |=
- _MC_MSRINJ_F_REQ_HWCR_WREN;
- continue;
- } else {
- /* No alternative but to interpose, so require
- * that the injector specified as such. */
- if (!(mci->mcinj_flags &
- MC_MSRINJ_F_INTERPOSE)) {
- reason = "must specify interposition";
- }
- }
- } else {
- switch (reg) {
- /* MSRs acceptable on all x86 cpus */
- case MSR_IA32_MCG_STATUS:
- break;
-
- /* MSRs that the HV will take care of */
- case MSR_K8_HWCR:
- if (c->x86_vendor == X86_VENDOR_AMD)
- reason = "HV will operate HWCR";
- else
- reason ="only supported on AMD";
- break;
-
- default:
- reason = "not a recognized MCA MSR";
- break;
- }
- }
-
- if (reason != NULL) {
- printk("HV MSR INJECT ERROR: MSR 0x%llx %s\n",
- (unsigned long long)mci->mcinj_msr[i].reg, reason);
- errs++;
- }
- }
-
- return !errs;
+ struct cpuinfo_x86 *c;
+ int i, errs = 0;
+
+ c = &cpu_data[smp_processor_id()];
+
+ for (i = 0; i < mci->mcinj_count; i++) {
+ uint64_t reg = mci->mcinj_msr[i].reg;
+ const char *reason = NULL;
+
+ if (IS_MCA_BANKREG(reg)) {
+ if (c->x86_vendor == X86_VENDOR_AMD) {
+ /* On AMD we can set MCi_STATUS_WREN in the
+ * HWCR MSR to allow non-zero writes to banks
+ * MSRs not to #GP. The injector in dom0
+ * should set that bit, but we detect when it
+ * is necessary and set it as a courtesy to
+ * avoid #GP in the hypervisor. */
+ mci->mcinj_flags |=
+ _MC_MSRINJ_F_REQ_HWCR_WREN;
+ continue;
+ } else {
+ /* No alternative but to interpose, so require
+ * that the injector specified as such. */
+ if (!(mci->mcinj_flags &
+ MC_MSRINJ_F_INTERPOSE)) {
+ reason = "must specify interposition";
+ }
+ }
+ } else {
+ switch (reg) {
+ /* MSRs acceptable on all x86 cpus */
+ case MSR_IA32_MCG_STATUS:
+ break;
+
+ /* MSRs that the HV will take care of */
+ case MSR_K8_HWCR:
+ if (c->x86_vendor == X86_VENDOR_AMD)
+ reason = "HV will operate HWCR";
+ else
+ reason ="only supported on AMD";
+ break;
+
+ default:
+ reason = "not a recognized MCA MSR";
+ break;
+ }
+ }
+
+ if (reason != NULL) {
+ printk("HV MSR INJECT ERROR: MSR 0x%llx %s\n",
+ (unsigned long long)mci->mcinj_msr[i].reg, reason);
+ errs++;
+ }
+ }
+
+ return !errs;
}
static uint64_t x86_mc_hwcr_wren(void)
{
- uint64_t old;
-
- rdmsrl(MSR_K8_HWCR, old);
-
- if (!(old & K8_HWCR_MCi_STATUS_WREN)) {
- uint64_t new = old | K8_HWCR_MCi_STATUS_WREN;
- wrmsrl(MSR_K8_HWCR, new);
- }
-
- return old;
+ uint64_t old;
+
+ rdmsrl(MSR_K8_HWCR, old);
+
+ if (!(old & K8_HWCR_MCi_STATUS_WREN)) {
+ uint64_t new = old | K8_HWCR_MCi_STATUS_WREN;
+ wrmsrl(MSR_K8_HWCR, new);
+ }
+
+ return old;
}
static void x86_mc_hwcr_wren_restore(uint64_t hwcr)
{
- if (!(hwcr & K8_HWCR_MCi_STATUS_WREN))
- wrmsrl(MSR_K8_HWCR, hwcr);
+ if (!(hwcr & K8_HWCR_MCi_STATUS_WREN))
+ wrmsrl(MSR_K8_HWCR, hwcr);
}
static void x86_mc_msrinject(void *data)
{
- struct xen_mc_msrinject *mci = data;
- struct mcinfo_msr *msr;
- struct cpuinfo_x86 *c;
- uint64_t hwcr = 0;
- int intpose;
- int i;
-
- c = &cpu_data[smp_processor_id()];
-
- if (mci->mcinj_flags & _MC_MSRINJ_F_REQ_HWCR_WREN)
- hwcr = x86_mc_hwcr_wren();
-
- intpose = (mci->mcinj_flags & MC_MSRINJ_F_INTERPOSE) != 0;
-
- for (i = 0, msr = &mci->mcinj_msr[0];
- i < mci->mcinj_count; i++, msr++) {
- printk("HV MSR INJECT (%s) target %u actual %u MSR 0x%llx "
- "<-- 0x%llx\n",
- intpose ? "interpose" : "hardware",
- mci->mcinj_cpunr, smp_processor_id(),
- (unsigned long long)msr->reg,
- (unsigned long long)msr->value);
-
- if (intpose)
- intpose_add(mci->mcinj_cpunr, msr->reg, msr->value);
- else
- wrmsrl(msr->reg, msr->value);
- }
-
- if (mci->mcinj_flags & _MC_MSRINJ_F_REQ_HWCR_WREN)
- x86_mc_hwcr_wren_restore(hwcr);
+ struct xen_mc_msrinject *mci = data;
+ struct mcinfo_msr *msr;
+ struct cpuinfo_x86 *c;
+ uint64_t hwcr = 0;
+ int intpose;
+ int i;
+
+ c = &cpu_data[smp_processor_id()];
+
+ if (mci->mcinj_flags & _MC_MSRINJ_F_REQ_HWCR_WREN)
+ hwcr = x86_mc_hwcr_wren();
+
+ intpose = (mci->mcinj_flags & MC_MSRINJ_F_INTERPOSE) != 0;
+
+ for (i = 0, msr = &mci->mcinj_msr[0];
+ i < mci->mcinj_count; i++, msr++) {
+ printk("HV MSR INJECT (%s) target %u actual %u MSR 0x%llx "
+ "<-- 0x%llx\n",
+ intpose ? "interpose" : "hardware",
+ mci->mcinj_cpunr, smp_processor_id(),
+ (unsigned long long)msr->reg,
+ (unsigned long long)msr->value);
+
+ if (intpose)
+ intpose_add(mci->mcinj_cpunr, msr->reg, msr->value);
+ else
+ wrmsrl(msr->reg, msr->value);
+ }
+
+ if (mci->mcinj_flags & _MC_MSRINJ_F_REQ_HWCR_WREN)
+ x86_mc_hwcr_wren_restore(hwcr);
}
/*ARGSUSED*/
static void x86_mc_mceinject(void *data)
{
- printk("Simulating #MC on cpu %d\n", smp_processor_id());
- __asm__ __volatile__("int $0x12");
+ printk("Simulating #MC on cpu %d\n", smp_processor_id());
+ __asm__ __volatile__("int $0x12");
}
static void x86_cmci_inject(void *data)
{
- printk("Simulating CMCI on cpu %d\n", smp_processor_id());
- __asm__ __volatile__("int $0xf7");
+ printk("Simulating CMCI on cpu %d\n", smp_processor_id());
+ __asm__ __volatile__("int $0xf7");
}
#if BITS_PER_LONG == 64
-#define ID2COOKIE(id) ((mctelem_cookie_t)(id))
-#define COOKIE2ID(c) ((uint64_t)(c))
+#define ID2COOKIE(id) ((mctelem_cookie_t)(id))
+#define COOKIE2ID(c) ((uint64_t)(c))
#elif BITS_PER_LONG == 32
-#define ID2COOKIE(id) ((mctelem_cookie_t)(uint32_t)((id) &
0xffffffffU))
-#define COOKIE2ID(c) ((uint64_t)(uint32_t)(c))
+#define ID2COOKIE(id) ((mctelem_cookie_t)(uint32_t)((id) & 0xffffffffU))
+#define COOKIE2ID(c) ((uint64_t)(uint32_t)(c))
#elif defined(BITS_PER_LONG)
#error BITS_PER_LONG has unexpected value
@@ -1288,225 +1288,225 @@ CHECK_mcinfo_recovery;
/* Machine Check Architecture Hypercall */
long do_mca(XEN_GUEST_HANDLE(xen_mc_t) u_xen_mc)
{
- long ret = 0;
- struct xen_mc curop, *op = &curop;
- struct vcpu *v = current;
- union {
- struct xen_mc_fetch *nat;
- struct compat_mc_fetch *cmp;
- } mc_fetch;
- union {
- struct xen_mc_physcpuinfo *nat;
- struct compat_mc_physcpuinfo *cmp;
- } mc_physcpuinfo;
- uint32_t flags, cmdflags;
- int nlcpu;
- xen_mc_logical_cpu_t *log_cpus = NULL;
- mctelem_cookie_t mctc;
- mctelem_class_t which;
- unsigned int target;
- struct xen_mc_msrinject *mc_msrinject;
- struct xen_mc_mceinject *mc_mceinject;
-
- if (!IS_PRIV(v->domain) )
- return x86_mcerr(NULL, -EPERM);
-
- if ( copy_from_guest(op, u_xen_mc, 1) )
- return x86_mcerr("do_mca: failed copyin of xen_mc_t", -EFAULT);
-
- if ( op->interface_version != XEN_MCA_INTERFACE_VERSION )
- return x86_mcerr("do_mca: interface version mismatch", -EACCES);
-
- switch (op->cmd) {
- case XEN_MC_fetch:
- mc_fetch.nat = &op->u.mc_fetch;
- cmdflags = mc_fetch.nat->flags;
-
- switch (cmdflags & (XEN_MC_NONURGENT | XEN_MC_URGENT)) {
- case XEN_MC_NONURGENT:
- which = MC_NONURGENT;
- break;
-
- case XEN_MC_URGENT:
- which = MC_URGENT;
- break;
-
- default:
- return x86_mcerr("do_mca fetch: bad cmdflags", -EINVAL);
- }
-
- flags = XEN_MC_OK;
-
- if (cmdflags & XEN_MC_ACK) {
- mctelem_cookie_t cookie =
ID2COOKIE(mc_fetch.nat->fetch_id);
- mctelem_ack(which, cookie);
- } else {
- if (!is_pv_32on64_vcpu(v)
- ? guest_handle_is_null(mc_fetch.nat->data)
- : compat_handle_is_null(mc_fetch.cmp->data))
- return x86_mcerr("do_mca fetch: guest buffer "
- "invalid", -EINVAL);
-
- if ((mctc = mctelem_consume_oldest_begin(which))) {
- struct mc_info *mcip = mctelem_dataptr(mctc);
- if (!is_pv_32on64_vcpu(v)
- ? copy_to_guest(mc_fetch.nat->data, mcip, 1)
- : copy_to_compat(mc_fetch.cmp->data,
- mcip, 1)) {
- ret = -EFAULT;
- flags |= XEN_MC_FETCHFAILED;
- mc_fetch.nat->fetch_id = 0;
- } else {
- mc_fetch.nat->fetch_id =
COOKIE2ID(mctc);
- }
- mctelem_consume_oldest_end(mctc);
- } else {
- /* There is no data */
- flags |= XEN_MC_NODATA;
- mc_fetch.nat->fetch_id = 0;
- }
-
- mc_fetch.nat->flags = flags;
- if (copy_to_guest(u_xen_mc, op, 1) != 0)
- ret = -EFAULT;
- }
-
- break;
-
- case XEN_MC_notifydomain:
- return x86_mcerr("do_mca notify unsupported", -EINVAL);
-
- case XEN_MC_physcpuinfo:
- mc_physcpuinfo.nat = &op->u.mc_physcpuinfo;
- nlcpu = num_online_cpus();
-
- if (!is_pv_32on64_vcpu(v)
- ? !guest_handle_is_null(mc_physcpuinfo.nat->info)
- : !compat_handle_is_null(mc_physcpuinfo.cmp->info)) {
- if (mc_physcpuinfo.nat->ncpus <= 0)
- return x86_mcerr("do_mca cpuinfo: ncpus <= 0",
- -EINVAL);
- nlcpu = min(nlcpu, (int)mc_physcpuinfo.nat->ncpus);
- log_cpus = xmalloc_array(xen_mc_logical_cpu_t, nlcpu);
- if (log_cpus == NULL)
- return x86_mcerr("do_mca cpuinfo", -ENOMEM);
- on_each_cpu(do_mc_get_cpu_info, log_cpus, 1);
- if (!is_pv_32on64_vcpu(v)
- ? copy_to_guest(mc_physcpuinfo.nat->info,
- log_cpus, nlcpu)
- : copy_to_compat(mc_physcpuinfo.cmp->info,
- log_cpus, nlcpu))
- ret = -EFAULT;
- xfree(log_cpus);
- }
-
- mc_physcpuinfo.nat->ncpus = nlcpu;
-
- if (copy_to_guest(u_xen_mc, op, 1))
- return x86_mcerr("do_mca cpuinfo", -EFAULT);
-
- break;
-
- case XEN_MC_msrinject:
- if (nr_mce_banks == 0)
- return x86_mcerr("do_mca inject", -ENODEV);
-
- mc_msrinject = &op->u.mc_msrinject;
- target = mc_msrinject->mcinj_cpunr;
-
- if (target >= NR_CPUS)
- return x86_mcerr("do_mca inject: bad target", -EINVAL);
-
- if (!cpu_isset(target, cpu_online_map))
- return x86_mcerr("do_mca inject: target offline",
- -EINVAL);
-
- if (mc_msrinject->mcinj_count == 0)
- return 0;
-
- if (!x86_mc_msrinject_verify(mc_msrinject))
- return x86_mcerr("do_mca inject: illegal MSR", -EINVAL);
-
- add_taint(TAINT_ERROR_INJECT);
-
- on_selected_cpus(cpumask_of(target), x86_mc_msrinject,
- mc_msrinject, 1);
-
- break;
-
- case XEN_MC_mceinject:
- if (nr_mce_banks == 0)
- return x86_mcerr("do_mca #MC", -ENODEV);
-
- mc_mceinject = &op->u.mc_mceinject;
- target = mc_mceinject->mceinj_cpunr;
-
- if (target >= NR_CPUS)
- return x86_mcerr("do_mca #MC: bad target", -EINVAL);
-
- if (!cpu_isset(target, cpu_online_map))
- return x86_mcerr("do_mca #MC: target offline", -EINVAL);
-
- add_taint(TAINT_ERROR_INJECT);
+ long ret = 0;
+ struct xen_mc curop, *op = &curop;
+ struct vcpu *v = current;
+ union {
+ struct xen_mc_fetch *nat;
+ struct compat_mc_fetch *cmp;
+ } mc_fetch;
+ union {
+ struct xen_mc_physcpuinfo *nat;
+ struct compat_mc_physcpuinfo *cmp;
+ } mc_physcpuinfo;
+ uint32_t flags, cmdflags;
+ int nlcpu;
+ xen_mc_logical_cpu_t *log_cpus = NULL;
+ mctelem_cookie_t mctc;
+ mctelem_class_t which;
+ unsigned int target;
+ struct xen_mc_msrinject *mc_msrinject;
+ struct xen_mc_mceinject *mc_mceinject;
+
+ if (!IS_PRIV(v->domain) )
+ return x86_mcerr(NULL, -EPERM);
+
+ if ( copy_from_guest(op, u_xen_mc, 1) )
+ return x86_mcerr("do_mca: failed copyin of xen_mc_t", -EFAULT);
+
+ if ( op->interface_version != XEN_MCA_INTERFACE_VERSION )
+ return x86_mcerr("do_mca: interface version mismatch", -EACCES);
+
+ switch (op->cmd) {
+ case XEN_MC_fetch:
+ mc_fetch.nat = &op->u.mc_fetch;
+ cmdflags = mc_fetch.nat->flags;
+
+ switch (cmdflags & (XEN_MC_NONURGENT | XEN_MC_URGENT)) {
+ case XEN_MC_NONURGENT:
+ which = MC_NONURGENT;
+ break;
+
+ case XEN_MC_URGENT:
+ which = MC_URGENT;
+ break;
+
+ default:
+ return x86_mcerr("do_mca fetch: bad cmdflags", -EINVAL);
+ }
+
+ flags = XEN_MC_OK;
+
+ if (cmdflags & XEN_MC_ACK) {
+ mctelem_cookie_t cookie = ID2COOKIE(mc_fetch.nat->fetch_id);
+ mctelem_ack(which, cookie);
+ } else {
+ if (!is_pv_32on64_vcpu(v)
+ ? guest_handle_is_null(mc_fetch.nat->data)
+ : compat_handle_is_null(mc_fetch.cmp->data))
+ return x86_mcerr("do_mca fetch: guest buffer "
+ "invalid", -EINVAL);
+
+ if ((mctc = mctelem_consume_oldest_begin(which))) {
+ struct mc_info *mcip = mctelem_dataptr(mctc);
+ if (!is_pv_32on64_vcpu(v)
+ ? copy_to_guest(mc_fetch.nat->data, mcip, 1)
+ : copy_to_compat(mc_fetch.cmp->data,
+ mcip, 1)) {
+ ret = -EFAULT;
+ flags |= XEN_MC_FETCHFAILED;
+ mc_fetch.nat->fetch_id = 0;
+ } else {
+ mc_fetch.nat->fetch_id = COOKIE2ID(mctc);
+ }
+ mctelem_consume_oldest_end(mctc);
+ } else {
+ /* There is no data */
+ flags |= XEN_MC_NODATA;
+ mc_fetch.nat->fetch_id = 0;
+ }
+
+ mc_fetch.nat->flags = flags;
+ if (copy_to_guest(u_xen_mc, op, 1) != 0)
+ ret = -EFAULT;
+ }
+
+ break;
+
+ case XEN_MC_notifydomain:
+ return x86_mcerr("do_mca notify unsupported", -EINVAL);
+
+ case XEN_MC_physcpuinfo:
+ mc_physcpuinfo.nat = &op->u.mc_physcpuinfo;
+ nlcpu = num_online_cpus();
+
+ if (!is_pv_32on64_vcpu(v)
+ ? !guest_handle_is_null(mc_physcpuinfo.nat->info)
+ : !compat_handle_is_null(mc_physcpuinfo.cmp->info)) {
+ if (mc_physcpuinfo.nat->ncpus <= 0)
+ return x86_mcerr("do_mca cpuinfo: ncpus <= 0",
+ -EINVAL);
+ nlcpu = min(nlcpu, (int)mc_physcpuinfo.nat->ncpus);
+ log_cpus = xmalloc_array(xen_mc_logical_cpu_t, nlcpu);
+ if (log_cpus == NULL)
+ return x86_mcerr("do_mca cpuinfo", -ENOMEM);
+ on_each_cpu(do_mc_get_cpu_info, log_cpus, 1);
+ if (!is_pv_32on64_vcpu(v)
+ ? copy_to_guest(mc_physcpuinfo.nat->info,
+ log_cpus, nlcpu)
+ : copy_to_compat(mc_physcpuinfo.cmp->info,
+ log_cpus, nlcpu))
+ ret = -EFAULT;
+ xfree(log_cpus);
+ }
+
+ mc_physcpuinfo.nat->ncpus = nlcpu;
+
+ if (copy_to_guest(u_xen_mc, op, 1))
+ return x86_mcerr("do_mca cpuinfo", -EFAULT);
+
+ break;
+
+ case XEN_MC_msrinject:
+ if (nr_mce_banks == 0)
+ return x86_mcerr("do_mca inject", -ENODEV);
+
+ mc_msrinject = &op->u.mc_msrinject;
+ target = mc_msrinject->mcinj_cpunr;
+
+ if (target >= NR_CPUS)
+ return x86_mcerr("do_mca inject: bad target", -EINVAL);
+
+ if (!cpu_isset(target, cpu_online_map))
+ return x86_mcerr("do_mca inject: target offline",
+ -EINVAL);
+
+ if (mc_msrinject->mcinj_count == 0)
+ return 0;
+
+ if (!x86_mc_msrinject_verify(mc_msrinject))
+ return x86_mcerr("do_mca inject: illegal MSR", -EINVAL);
+
+ add_taint(TAINT_ERROR_INJECT);
+
+ on_selected_cpus(cpumask_of(target), x86_mc_msrinject,
+ mc_msrinject, 1);
+
+ break;
+
+ case XEN_MC_mceinject:
+ if (nr_mce_banks == 0)
+ return x86_mcerr("do_mca #MC", -ENODEV);
+
+ mc_mceinject = &op->u.mc_mceinject;
+ target = mc_mceinject->mceinj_cpunr;
+
+ if (target >= NR_CPUS)
+ return x86_mcerr("do_mca #MC: bad target", -EINVAL);
+
+ if (!cpu_isset(target, cpu_online_map))
+ return x86_mcerr("do_mca #MC: target offline", -EINVAL);
+
+ add_taint(TAINT_ERROR_INJECT);
if ( mce_broadcast )
on_each_cpu(x86_mc_mceinject, mc_mceinject, 1);
else
on_selected_cpus(cpumask_of(target), x86_mc_mceinject,
- mc_mceinject, 1);
- break;
-
- case XEN_MC_inject_v2:
- {
- cpumask_t cpumap;
-
- if (nr_mce_banks == 0)
- return x86_mcerr("do_mca #MC", -ENODEV);
-
- if ( op->u.mc_inject_v2.flags & XEN_MC_INJECT_CPU_BROADCAST )
- cpus_copy(cpumap, cpu_online_map);
- else
- {
- int gcw;
-
- cpus_clear(cpumap);
- xenctl_cpumap_to_cpumask(&cpumap,
- &op->u.mc_inject_v2.cpumap);
- gcw = cpus_weight(cpumap);
- cpus_and(cpumap, cpu_online_map, cpumap);
-
- if ( cpus_empty(cpumap) )
- return x86_mcerr("No online CPU passed\n",
-EINVAL);
- else if ( gcw != cpus_weight(cpumap) )
- dprintk(XENLOG_INFO,
- "Not all required CPUs are online\n");
- }
-
- switch (op->u.mc_inject_v2.flags & XEN_MC_INJECT_TYPE_MASK)
- {
- case XEN_MC_INJECT_TYPE_MCE:
- if ( mce_broadcast &&
- !cpus_equal(cpumap, cpu_online_map) )
- printk("Not trigger MCE on all CPUs, may
HANG!\n");
- on_selected_cpus(&cpumap, x86_mc_mceinject, NULL, 1);
- break;
- case XEN_MC_INJECT_TYPE_CMCI:
- if ( !cmci_support )
- return x86_mcerr(
- "No CMCI supported in platform\n", -EINVAL);
- on_selected_cpus(&cpumap, x86_cmci_inject, NULL, 1);
- break;
- default:
- return x86_mcerr("Wrong mca type\n", -EINVAL);
- }
- break;
- }
-
- default:
- return x86_mcerr("do_mca: bad command", -EINVAL);
- }
-
- return ret;
+ mc_mceinject, 1);
+ break;
+
+ case XEN_MC_inject_v2:
+ {
+ cpumask_t cpumap;
+
+ if (nr_mce_banks == 0)
+ return x86_mcerr("do_mca #MC", -ENODEV);
+
+ if ( op->u.mc_inject_v2.flags & XEN_MC_INJECT_CPU_BROADCAST )
+ cpus_copy(cpumap, cpu_online_map);
+ else
+ {
+ int gcw;
+
+ cpus_clear(cpumap);
+ xenctl_cpumap_to_cpumask(&cpumap,
+ &op->u.mc_inject_v2.cpumap);
+ gcw = cpus_weight(cpumap);
+ cpus_and(cpumap, cpu_online_map, cpumap);
+
+ if ( cpus_empty(cpumap) )
+ return x86_mcerr("No online CPU passed\n", -EINVAL);
+ else if ( gcw != cpus_weight(cpumap) )
+ dprintk(XENLOG_INFO,
+ "Not all required CPUs are online\n");
+ }
+
+ switch (op->u.mc_inject_v2.flags & XEN_MC_INJECT_TYPE_MASK)
+ {
+ case XEN_MC_INJECT_TYPE_MCE:
+ if ( mce_broadcast &&
+ !cpus_equal(cpumap, cpu_online_map) )
+ printk("Not trigger MCE on all CPUs, may HANG!\n");
+ on_selected_cpus(&cpumap, x86_mc_mceinject, NULL, 1);
+ break;
+ case XEN_MC_INJECT_TYPE_CMCI:
+ if ( !cmci_support )
+ return x86_mcerr(
+ "No CMCI supported in platform\n", -EINVAL);
+ on_selected_cpus(&cpumap, x86_cmci_inject, NULL, 1);
+ break;
+ default:
+ return x86_mcerr("Wrong mca type\n", -EINVAL);
+ }
+ break;
+ }
+
+ default:
+ return x86_mcerr("do_mca: bad command", -EINVAL);
+ }
+
+ return ret;
}
void mc_panic(char *s)
diff -r 05bfc5a472b6 -r 9a3f422cf980 xen/arch/x86/cpu/mcheck/mce_intel.c
--- a/xen/arch/x86/cpu/mcheck/mce_intel.c Wed Jun 09 07:51:31 2010 +0100
+++ b/xen/arch/x86/cpu/mcheck/mce_intel.c Wed Jun 09 07:54:10 2010 +0100
@@ -28,9 +28,9 @@ static int nr_intel_ext_msrs = 0;
/* Below are for MCE handling */
struct mce_softirq_barrier {
- atomic_t val;
- atomic_t ingen;
- atomic_t outgen;
+ atomic_t val;
+ atomic_t ingen;
+ atomic_t outgen;
};
static struct mce_softirq_barrier mce_inside_bar, mce_severity_bar;
@@ -594,7 +594,7 @@ static void intel_machine_check(struct c
mce_barrier_enter(&mce_trap_bar);
if (atomic_read(&found_error)) {
mce_printk(MCE_CRITICAL, "MCE: Choose one CPU "
- "to clear error finding flag\n ");
+ "to clear error finding flag\n ");
atomic_set(&found_error, 0);
}
mca_rdmsrl(MSR_IA32_MCG_STATUS, gstatus);
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|