📄 traps.c
字号:
#define CE_STATUS_UDBH_UE (1UL << (43 + 9))#define CE_STATUS_UDBH_CE (1UL << (43 + 8))#define CE_STATUS_UDBH_ESYNDR (0xffUL << 43)#define CE_STATUS_UDBH_SHIFT 43#define CE_STATUS_UDBL_UE (1UL << (33 + 9))#define CE_STATUS_UDBL_CE (1UL << (33 + 8))#define CE_STATUS_UDBL_ESYNDR (0xffUL << 33)#define CE_STATUS_UDBL_SHIFT 33#define CE_STATUS_AFSR_MASK (0x1ffffffffUL)#define CE_STATUS_AFSR_ME (1UL << 32)#define CE_STATUS_AFSR_PRIV (1UL << 31)#define CE_STATUS_AFSR_ISAP (1UL << 30)#define CE_STATUS_AFSR_ETP (1UL << 29)#define CE_STATUS_AFSR_IVUE (1UL << 28)#define CE_STATUS_AFSR_TO (1UL << 27)#define CE_STATUS_AFSR_BERR (1UL << 26)#define CE_STATUS_AFSR_LDP (1UL << 25)#define CE_STATUS_AFSR_CP (1UL << 24)#define CE_STATUS_AFSR_WP (1UL << 23)#define CE_STATUS_AFSR_EDP (1UL << 22)#define CE_STATUS_AFSR_UE (1UL << 21)#define CE_STATUS_AFSR_CE (1UL << 20)#define CE_STATUS_AFSR_ETS (0xfUL << 16)#define CE_STATUS_AFSR_ETS_SHIFT 16#define CE_STATUS_AFSR_PSYND (0xffffUL << 0)#define CE_STATUS_AFSR_PSYND_SHIFT 0/* Layout of Ecache TAG Parity Syndrome of AFSR */#define AFSR_ETSYNDROME_7_0 0x1UL /* E$-tag bus bits <7:0> */#define AFSR_ETSYNDROME_15_8 0x2UL /* E$-tag bus bits <15:8> */#define AFSR_ETSYNDROME_21_16 0x4UL /* E$-tag bus bits <21:16> */#define AFSR_ETSYNDROME_24_22 0x8UL /* E$-tag bus bits <24:22> */static char *syndrome_unknown = "<Unknown>";asmlinkage void cee_log(unsigned long ce_status, unsigned long afar, struct pt_regs *regs){ char memmod_str[64]; char *p; unsigned short scode, udb_reg; printk(KERN_WARNING "CPU[%d]: Correctable ECC Error " "AFSR[%lx] AFAR[%016lx] UDBL[%lx] UDBH[%lx]\n", smp_processor_id(), (ce_status & CE_STATUS_AFSR_MASK), afar, ((ce_status >> CE_STATUS_UDBL_SHIFT) & 0x3ffUL), ((ce_status >> CE_STATUS_UDBH_SHIFT) & 0x3ffUL)); udb_reg = ((ce_status >> CE_STATUS_UDBL_SHIFT) & 0x3ffUL); if (udb_reg & (1 << 8)) { scode = ecc_syndrome_table[udb_reg & 0xff]; if (prom_getunumber(scode, afar, memmod_str, sizeof(memmod_str)) == -1) p = syndrome_unknown; else p = memmod_str; printk(KERN_WARNING "CPU[%d]: UDBL Syndrome[%x] " "Memory Module \"%s\"\n", smp_processor_id(), scode, p); } udb_reg = ((ce_status >> CE_STATUS_UDBH_SHIFT) & 0x3ffUL); if (udb_reg & (1 << 8)) { scode = ecc_syndrome_table[udb_reg & 0xff]; if (prom_getunumber(scode, afar, memmod_str, sizeof(memmod_str)) == -1) p = syndrome_unknown; else p = memmod_str; printk(KERN_WARNING "CPU[%d]: UDBH Syndrome[%x] " "Memory Module \"%s\"\n", smp_processor_id(), scode, p); }}void do_fpe_common(struct pt_regs *regs){ if(regs->tstate & TSTATE_PRIV) { regs->tpc = regs->tnpc; regs->tnpc += 4; } else { unsigned long fsr = current->thread.xfsr[0]; siginfo_t info; info.si_signo = SIGFPE; info.si_errno = 0; info.si_addr = (void *)regs->tpc; info.si_trapno = 0; info.si_code = __SI_FAULT; if ((fsr & 0x1c000) == (1 << 14)) { if (fsr & 0x10) info.si_code = FPE_FLTINV; else if (fsr & 0x08) info.si_code = FPE_FLTOVF; else if (fsr & 0x04) info.si_code = FPE_FLTUND; else if (fsr & 0x02) info.si_code = FPE_FLTDIV; else if (fsr & 0x01) info.si_code = FPE_FLTRES; } force_sig_info(SIGFPE, &info, current); }}void do_fpieee(struct pt_regs *regs){#ifdef DEBUG_FPU printk("fpieee %016lx\n", current->thread.xfsr[0]);#endif do_fpe_common(regs);}extern int do_mathemu(struct pt_regs *, struct fpustate *);void do_fpother(struct pt_regs *regs){ struct fpustate *f = FPUSTATE; int ret = 0; switch ((current->thread.xfsr[0] & 0x1c000)) { case (2 << 14): /* unfinished_FPop */ case (3 << 14): /* unimplemented_FPop */ ret = do_mathemu(regs, f); break; } if (ret) return;#ifdef DEBUG_FPU printk("fpother %016lx\n", current->thread.xfsr[0]);#endif do_fpe_common(regs);}void do_tof(struct pt_regs *regs){ siginfo_t info; if(regs->tstate & TSTATE_PRIV) die_if_kernel("Penguin overflow trap from kernel mode", regs); info.si_signo = SIGEMT; info.si_errno = 0; info.si_code = EMT_TAGOVF; info.si_addr = (void *)regs->tpc; info.si_trapno = 0; force_sig_info(SIGEMT, &info, current);}void do_div0(struct pt_regs *regs){ siginfo_t info; info.si_signo = SIGFPE; info.si_errno = 0; info.si_code = FPE_INTDIV; info.si_addr = (void *)regs->tpc; info.si_trapno = 0; force_sig_info(SIGFPE, &info, current);}void instruction_dump (unsigned int *pc){ int i; if((((unsigned long) pc) & 3)) return; printk("Instruction DUMP:"); for(i = -3; i < 6; i++) printk("%c%08x%c",i?' ':'<',pc[i],i?' ':'>'); printk("\n");}void user_instruction_dump (unsigned int *pc){ int i; unsigned int buf[9]; if((((unsigned long) pc) & 3)) return; if(copy_from_user(buf, pc - 3, sizeof(buf))) return; printk("Instruction DUMP:"); for(i = 0; i < 9; i++) printk("%c%08x%c",i==3?' ':'<',buf[i],i==3?' ':'>'); printk("\n");}void die_if_kernel(char *str, struct pt_regs *regs){ extern void __show_regs(struct pt_regs * regs); extern void smp_report_regs(void); int count = 0; struct reg_window *lastrw; /* Amuse the user. */ printk(" \\|/ ____ \\|/\n"" \"@'/ .. \\`@\"\n"" /_| \\__/ |_\\\n"" \\__U_/\n"); printk("%s(%d): %s\n", current->comm, current->pid, str); __asm__ __volatile__("flushw"); __show_regs(regs); if(regs->tstate & TSTATE_PRIV) { struct reg_window *rw = (struct reg_window *) (regs->u_regs[UREG_FP] + STACK_BIAS); /* Stop the back trace when we hit userland or we * find some badly aligned kernel stack. */ lastrw = (struct reg_window *)current; while(rw && count++ < 30 && rw >= lastrw && (char *) rw < ((char *) current) + sizeof (union task_union) && !(((unsigned long) rw) & 0x7)) { printk("Caller[%016lx]\n", rw->ins[7]); lastrw = rw; rw = (struct reg_window *) (rw->ins[6] + STACK_BIAS); } instruction_dump ((unsigned int *) regs->tpc); } else user_instruction_dump ((unsigned int *) regs->tpc);#ifdef CONFIG_SMP smp_report_regs();#endif if(regs->tstate & TSTATE_PRIV) do_exit(SIGKILL); do_exit(SIGSEGV);}extern int handle_popc(u32 insn, struct pt_regs *regs);extern int handle_ldf_stq(u32 insn, struct pt_regs *regs);void do_illegal_instruction(struct pt_regs *regs){ unsigned long pc = regs->tpc; unsigned long tstate = regs->tstate; u32 insn; siginfo_t info; if(tstate & TSTATE_PRIV) die_if_kernel("Kernel illegal instruction", regs); if(current->thread.flags & SPARC_FLAG_32BIT) pc = (u32)pc; if (get_user(insn, (u32 *)pc) != -EFAULT) { if ((insn & 0xc1ffc000) == 0x81700000) /* POPC */ { if (handle_popc(insn, regs)) return; } else if ((insn & 0xc1580000) == 0xc1100000) /* LDQ/STQ */ { if (handle_ldf_stq(insn, regs)) return; } } info.si_signo = SIGILL; info.si_errno = 0; info.si_code = ILL_ILLOPC; info.si_addr = (void *)pc; info.si_trapno = 0; force_sig_info(SIGILL, &info, current);}void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr){ siginfo_t info; if(regs->tstate & TSTATE_PRIV) { extern void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn, unsigned long sfar, unsigned long sfsr); return kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc), sfar, sfsr); } info.si_signo = SIGBUS; info.si_errno = 0; info.si_code = BUS_ADRALN; info.si_addr = (void *)sfar; info.si_trapno = 0; force_sig_info(SIGBUS, &info, current);}void do_privop(struct pt_regs *regs){ siginfo_t info; info.si_signo = SIGILL; info.si_errno = 0; info.si_code = ILL_PRVOPC; info.si_addr = (void *)regs->tpc; info.si_trapno = 0; force_sig_info(SIGILL, &info, current);}void do_privact(struct pt_regs *regs){ do_privop(regs);}/* Trap level 1 stuff or other traps we should never see... */void do_cee(struct pt_regs *regs){ die_if_kernel("TL0: Cache Error Exception", regs);}void do_cee_tl1(struct pt_regs *regs){ die_if_kernel("TL1: Cache Error Exception", regs);}void do_dae_tl1(struct pt_regs *regs){ die_if_kernel("TL1: Data Access Exception", regs);}void do_iae_tl1(struct pt_regs *regs){ die_if_kernel("TL1: Instruction Access Exception", regs);}void do_div0_tl1(struct pt_regs *regs){ die_if_kernel("TL1: DIV0 Exception", regs);}void do_fpdis_tl1(struct pt_regs *regs){ die_if_kernel("TL1: FPU Disabled", regs);}void do_fpieee_tl1(struct pt_regs *regs){ die_if_kernel("TL1: FPU IEEE Exception", regs);}void do_fpother_tl1(struct pt_regs *regs){ die_if_kernel("TL1: FPU Other Exception", regs);}void do_ill_tl1(struct pt_regs *regs){ die_if_kernel("TL1: Illegal Instruction Exception", regs);}void do_irq_tl1(struct pt_regs *regs){ die_if_kernel("TL1: IRQ Exception", regs);}void do_lddfmna_tl1(struct pt_regs *regs){ die_if_kernel("TL1: LDDF Exception", regs);}void do_stdfmna_tl1(struct pt_regs *regs){ die_if_kernel("TL1: STDF Exception", regs);}void do_paw(struct pt_regs *regs){ die_if_kernel("TL0: Phys Watchpoint Exception", regs);}void do_paw_tl1(struct pt_regs *regs){ die_if_kernel("TL1: Phys Watchpoint Exception", regs);}void do_vaw(struct pt_regs *regs){ die_if_kernel("TL0: Virt Watchpoint Exception", regs);}void do_vaw_tl1(struct pt_regs *regs){ die_if_kernel("TL1: Virt Watchpoint Exception", regs);}void do_tof_tl1(struct pt_regs *regs){ die_if_kernel("TL1: Tag Overflow Exception", regs);}#ifdef CONFIG_EC_FLUSH_TRAPvoid cache_flush_trap(struct pt_regs *regs){#ifndef CONFIG_SMP unsigned node = linux_cpus[get_cpuid()].prom_node;#else#error cache_flush_trap not supported on sparc64/SMP yet#endif#if 0/* Broken */ int size = prom_getintdefault(node, "ecache-size", 512*1024); int i, j; unsigned long addr; struct page *page, *end; regs->tpc = regs->tnpc; regs->tnpc = regs->tnpc + 4; if (!capable(CAP_SYS_ADMIN)) return; size >>= PAGE_SHIFT; addr = PAGE_OFFSET - PAGE_SIZE; page = mem_map - 1; end = mem_map + max_mapnr; for (i = 0; i < size; i++) { do { addr += PAGE_SIZE; page++; if (page >= end) return; } while (!PageReserved(page)); /* E-Cache line size is 64B. Let us pollute it :)) */ for (j = 0; j < PAGE_SIZE; j += 64) __asm__ __volatile__ ("ldx [%0 + %1], %%g1" : : "r" (j), "r" (addr) : "g1"); }#endif}#endifvoid do_getpsr(struct pt_regs *regs){ regs->u_regs[UREG_I0] = tstate_to_psr(regs->tstate); regs->tpc = regs->tnpc; regs->tnpc += 4;}void trap_init(void){ /* Attach to the address space of init_task. */ atomic_inc(&init_mm.mm_count); current->active_mm = &init_mm; /* NOTE: Other cpus have this done as they are started * up on SMP. */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -