void MachineCheckException(struct pt_regs *regs) { #ifdef CONFIG_ALL_PPC unsigned long fixup; #endif /* CONFIG_ALL_PPC */ if (user_mode(regs)) { _exception(SIGSEGV, regs); return; } #if defined(CONFIG_8xx) && defined(CONFIG_PCI) /* the qspan pci read routines can cause machine checks -- Cort */ bad_page_fault(regs, regs->dar); return; #endif #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) if (debugger_fault_handler) { debugger_fault_handler(regs); return; } #endif #ifdef CONFIG_ALL_PPC /* * I/O accesses can cause machine checks on powermacs. * Check if the NIP corresponds to the address of a sync * instruction for which there is an entry in the exception * table. */ if (regs->msr & (0x80000 | 0x40000) && (fixup = search_exception_table(regs->nip)) != 0) { /* * Check that it's a sync instruction. * As the address is in the exception table * we should be able to read the instr there. */ if (*(unsigned int *)regs->nip == 0x7c0004ac) { unsigned int lsi = ((unsigned int *)regs->nip)[-1]; int rb = (lsi >> 11) & 0x1f; printk(KERN_DEBUG "%s bad port %lx at %lx\n", (lsi & 0x100)? "OUT to": "IN from", regs->gpr[rb] - _IO_BASE, regs->nip); regs->nip = fixup; return; } }
void MachineCheckException(struct pt_regs *regs) { if ( !user_mode(regs) ) { #ifdef CONFIG_MBX /* the mbx pci read routines can cause machine checks -- Cort */ bad_page_fault(regs,regs->dar); return; #endif /* CONFIG_MBX */ #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) if (debugger_fault_handler) { debugger_fault_handler(regs); return; } #endif printk("Machine check in kernel mode.\n"); printk("Caused by (from msr): "); printk("regs %p ",regs); switch( regs->msr & 0x0000F000) { case (1<<12) : printk("Machine check signal - probably due to mm fault\n" "with mmu off\n"); break; case (1<<13) : printk("Transfer error ack signal\n"); break; case (1<<14) : printk("Data parity signal\n"); break; case (1<<15) : printk("Address parity signal\n"); break; default: printk("Unknown values in msr\n"); } show_regs(regs); #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) debugger(regs); #endif print_backtrace((unsigned long *)regs->gpr[1]); instruction_dump((unsigned long *)regs->nip); panic("machine check"); } _exception(SIGSEGV, regs); }
/* * Handle a machine check. * * Note that on Power 4 and beyond Firmware Non-Maskable Interrupts (fwnmi) * should be present. If so the handler which called us tells us if the * error was recovered (never true if RI=0). * * On hardware prior to Power 4 these exceptions were asynchronous which * means we can't tell exactly where it occurred and so we can't recover. */ void MachineCheckException(struct pt_regs *regs) { #ifdef CONFIG_PPC_PSERIES struct rtas_error_log err, *errp; if (fwnmi_active) { errp = FWNMI_get_errinfo(regs); if (errp) err = *errp; FWNMI_release_errinfo(); /* frees errp */ if (errp && recover_mce(regs, err)) return; } #endif if (debugger_fault_handler(regs)) return; die("Machine check", regs, 0); /* Must die if the interrupt is not recoverable */ if (!(regs->msr & MSR_RI)) panic("Unrecoverable Machine check"); }
/* * For 600- and 800-family processors, the error_code parameter is DSISR * for a data fault, SRR1 for an instruction fault. For 400-family processors * the error_code parameter is ESR for a data fault, 0 for an instruction * fault. */ void do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code) { struct vm_area_struct * vma; struct mm_struct *mm = current->mm; siginfo_t info; int code = SEGV_MAPERR; #if defined(CONFIG_4xx) int is_write = error_code & ESR_DST; #else int is_write = 0; /* * Fortunately the bit assignments in SRR1 for an instruction * fault and DSISR for a data fault are mostly the same for the * bits we are interested in. But there are some bits which * indicate errors in DSISR but can validly be set in SRR1. */ if (regs->trap == 0x400) error_code &= 0x48200000; else is_write = error_code & 0x02000000; #endif /* CONFIG_4xx */ #if defined(CONFIG_XMON) || defined(CONFIG_KGDB) if (debugger_fault_handler && regs->trap == 0x300) { debugger_fault_handler(regs); return; } #if !defined(CONFIG_4xx) if (error_code & 0x00400000) { /* DABR match */ if (debugger_dabr_match(regs)) return; } #endif /* !CONFIG_4xx */ #endif /* CONFIG_XMON || CONFIG_KGDB */ if (in_interrupt() || mm == NULL) { bad_page_fault(regs, address); return; } down(&mm->mmap_sem); vma = find_vma(mm, address); if (!vma) goto bad_area; if (vma->vm_start <= address) goto good_area; if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; if (expand_stack(vma, address)) goto bad_area; good_area: code = SEGV_ACCERR; #if defined(CONFIG_6xx) if (error_code & 0x95700000) /* an error such as lwarx to I/O controller space, address matching DABR, eciwx, etc. */ goto bad_area; #endif /* CONFIG_6xx */ #if defined(CONFIG_8xx) /* The MPC8xx seems to always set 0x80000000, which is * "undefined". Of those that can be set, this is the only * one which seems bad. */ if (error_code & 0x10000000) /* Guarded storage error. */ goto bad_area; #endif /* CONFIG_8xx */ /* a write */ if (is_write) { if (!(vma->vm_flags & VM_WRITE)) goto bad_area; /* a read */ } else { /* protection fault */ if (error_code & 0x08000000) goto bad_area; if (!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; } /* * If for any reason at all we couldn't handle the fault, * make sure we exit gracefully rather than endlessly redo * the fault. */ switch (handle_mm_fault(mm, vma, address, is_write)) { case 1: current->min_flt++; break; case 2: current->maj_flt++; break; case 0: goto do_sigbus; default: goto out_of_memory; } up(&mm->mmap_sem); /* * keep track of tlb+htab misses that are good addrs but * just need pte's created via handle_mm_fault() * -- Cort */ pte_misses++; return; bad_area: up(&mm->mmap_sem); pte_errors++; /* User mode accesses cause a SIGSEGV */ if (user_mode(regs)) { info.si_signo = SIGSEGV; info.si_errno = 0; info.si_code = code; info.si_addr = (void *) address; force_sig_info(SIGSEGV, &info, current); return; } bad_page_fault(regs, address); return; /* * We ran out of memory, or some other thing happened to us that made * us unable to handle the page fault gracefully. */ out_of_memory: up(&mm->mmap_sem); printk("VM: killing process %s\n", current->comm); if (user_mode(regs)) do_exit(SIGKILL); bad_page_fault(regs, address); return; do_sigbus: up(&mm->mmap_sem); info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_ADRERR; info.si_addr = (void *)address; force_sig_info (SIGBUS, &info, current); if (!user_mode(regs)) bad_page_fault(regs, address); }