static fastcall void intel_machine_check(struct pt_regs * regs, long error_code) { int recover=1; u32 alow, ahigh, high, low; u32 mcgstl, mcgsth; int i; struct intel_mce_extended_msrs dbg; rdmsr (MSR_IA32_MCG_STATUS, mcgstl, mcgsth); if (mcgstl & (1<<0)) /* Recoverable ? */ recover=0; printk (KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n", smp_processor_id(), mcgsth, mcgstl); if (intel_get_extended_msrs(&dbg)) { printk (KERN_DEBUG "CPU %d: EIP: %08x EFLAGS: %08x\n", smp_processor_id(), dbg.eip, dbg.eflags); printk (KERN_DEBUG "\teax: %08x ebx: %08x ecx: %08x edx: %08x\n", dbg.eax, dbg.ebx, dbg.ecx, dbg.edx); printk (KERN_DEBUG "\tesi: %08x edi: %08x ebp: %08x esp: %08x\n", dbg.esi, dbg.edi, dbg.ebp, dbg.esp); } for (i=0; i<nr_mce_banks; i++) { rdmsr (MSR_IA32_MC0_STATUS+i*4,low, high); if (high & (1<<31)) { if (high & (1<<29)) recover |= 1; if (high & (1<<25)) recover |= 2; printk (KERN_EMERG "Bank %d: %08x%08x", i, high, low); high &= ~(1<<31); if (high & (1<<27)) { rdmsr (MSR_IA32_MC0_MISC+i*4, alow, ahigh); printk ("[%08x%08x]", ahigh, alow); } if (high & (1<<26)) { rdmsr (MSR_IA32_MC0_ADDR+i*4, alow, ahigh); printk (" at %08x%08x", ahigh, alow); } printk ("\n"); } } if (recover & 2) panic ("CPU context corrupt"); if (recover & 1) panic ("Unable to continue"); printk(KERN_EMERG "Attempting to continue.\n"); /* * Do not clear the MSR_IA32_MCi_STATUS if the error is not * recoverable/continuable.This will allow BIOS to look at the MSRs * for errors if the OS could not log the error. */ for (i=0; i<nr_mce_banks; i++) { u32 msr; msr = MSR_IA32_MC0_STATUS+i*4; rdmsr (msr, low, high); if (high&(1<<31)) { /* Clear it */ wrmsr(msr, 0UL, 0UL); /* Serialize */ wmb(); add_taint(TAINT_MACHINE_CHECK); } } mcgstl &= ~(1<<2); wrmsr (MSR_IA32_MCG_STATUS,mcgstl, mcgsth); }
/* Add out_param clear_bank for Machine Check Handler Caller. * For Intel latest CPU, whether to clear the error bank status needs to * 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; bool_t uc = 0, pcc = 0, recover = 1, need_clear = 1; uint32_t mc_flags = 0; struct mc_info *mci = NULL; mctelem_class_t which = MC_URGENT; /* XXXgcc */ int errcnt = 0; int i; gstatus = mca_rdmsr(MSR_IA32_MCG_STATUS); switch (who) { 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 < nr_mce_banks; i++) { /* Skip bank if corresponding bit in bankmask is clear */ if (!mcabanks_test(i, bankmask)) continue; status = mca_rdmsr(MSR_IA32_MCx_STATUS(i)); 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 whether 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 = x86_mcinfo_reserve(mci, sizeof(*mig)); /* 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 */ { if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) intel_get_extended_msrs(mig, mci); } } } /* flag for uncorrected errors */ if (!uc && ((status & MCi_STATUS_UC) != 0)) uc = 1; /* flag processor context corrupt */ if (!pcc && ((status & MCi_STATUS_PCC) != 0)) pcc = 1; if (recover && uc) /* uc = 1, recover = 1, we need not panic. */ recover = mc_recoverable_scan(status); 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 bank */ mcabank_clear(i); 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 */ }