📄 traps.c
字号:
#endif if ((fp->un.fmt7.wb2s & WBV_040) && !(fp->un.fmt7.wb2s & WBTT_040)) { res = do_040writeback1(fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, fp->un.fmt7.wb2d); if (res) fix_xframe040(fp, fp->un.fmt7.wb2a, fp->un.fmt7.wb2s); else fp->un.fmt7.wb2s = 0; } /* do the 2nd wb only if the first one was successful (except for a kernel wb) */ if (fp->un.fmt7.wb3s & WBV_040 && (!res || fp->un.fmt7.wb3s & 4)) { res = do_040writeback1(fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, fp->un.fmt7.wb3d); if (res) { fix_xframe040(fp, fp->un.fmt7.wb3a, fp->un.fmt7.wb3s); fp->un.fmt7.wb2s = fp->un.fmt7.wb3s; fp->un.fmt7.wb3s &= (~WBV_040); fp->un.fmt7.wb2a = fp->un.fmt7.wb3a; fp->un.fmt7.wb2d = fp->un.fmt7.wb3d; } else fp->un.fmt7.wb3s = 0; } if (res) send_fault_sig(&fp->ptregs);}/* * called from sigreturn(), must ensure userspace code didn't * manipulate exception frame to circumvent protection, then complete * pending writebacks * we just clear TM2 to turn it into an userspace access */asmlinkage void berr_040cleanup(struct frame *fp){ fp->un.fmt7.wb2s &= ~4; fp->un.fmt7.wb3s &= ~4; do_040writebacks(fp);}static inline void access_error040(struct frame *fp){ unsigned short ssw = fp->un.fmt7.ssw; unsigned long mmusr;#ifdef DEBUG printk("ssw=%#x, fa=%#lx\n", ssw, fp->un.fmt7.faddr); printk("wb1s=%#x, wb2s=%#x, wb3s=%#x\n", fp->un.fmt7.wb1s, fp->un.fmt7.wb2s, fp->un.fmt7.wb3s); printk ("wb2a=%lx, wb3a=%lx, wb2d=%lx, wb3d=%lx\n", fp->un.fmt7.wb2a, fp->un.fmt7.wb3a, fp->un.fmt7.wb2d, fp->un.fmt7.wb3d);#endif if (ssw & ATC_040) { unsigned long addr = fp->un.fmt7.faddr; unsigned long errorcode; /* * The MMU status has to be determined AFTER the address * has been corrected if there was a misaligned access (MA). */ if (ssw & MA_040) addr = (addr + 7) & -8; /* MMU error, get the MMUSR info for this access */ mmusr = probe040(!(ssw & RW_040), addr, ssw);#ifdef DEBUG printk("mmusr = %lx\n", mmusr);#endif errorcode = 1; if (!(mmusr & MMU_R_040)) { /* clear the invalid atc entry */ __flush_tlb040_one(addr); errorcode = 0; } /* despite what documentation seems to say, RMW * accesses have always both the LK and RW bits set */ if (!(ssw & RW_040) || (ssw & LK_040)) errorcode |= 2; if (do_page_fault(&fp->ptregs, addr, errorcode)) {#ifdef DEBUG printk("do_page_fault() !=0 \n");#endif if (user_mode(&fp->ptregs)){ /* delay writebacks after signal delivery */#ifdef DEBUG printk(".. was usermode - return\n");#endif return; } /* disable writeback into user space from kernel * (if do_page_fault didn't fix the mapping, * the writeback won't do good) */#ifdef DEBUG printk(".. disabling wb2\n");#endif if (fp->un.fmt7.wb2a == fp->un.fmt7.faddr) fp->un.fmt7.wb2s &= ~WBV_040; } } else if (send_fault_sig(&fp->ptregs) > 0) { printk("68040 access error, ssw=%x\n", ssw); trap_c(fp); } do_040writebacks(fp);}#endif /* CONFIG_M68040 */#if defined(CONFIG_SUN3)#include <asm/sun3mmu.h>extern int mmu_emu_handle_fault (unsigned long, int, int);/* sun3 version of bus_error030 */static inline void bus_error030 (struct frame *fp){ unsigned char buserr_type = sun3_get_buserr (); unsigned long addr, errorcode; unsigned short ssw = fp->un.fmtb.ssw; extern unsigned long _sun3_map_test_start, _sun3_map_test_end;#ifdef DEBUG if (ssw & (FC | FB)) printk ("Instruction fault at %#010lx\n", ssw & FC ? fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2 : fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr); if (ssw & DF) printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", ssw & RW ? "read" : "write", fp->un.fmtb.daddr, space_names[ssw & DFC], fp->ptregs.pc);#endif /* * Check if this page should be demand-mapped. This needs to go before * the testing for a bad kernel-space access (demand-mapping applies * to kernel accesses too). */ if ((ssw & DF) && (buserr_type & (SUN3_BUSERR_PROTERR | SUN3_BUSERR_INVALID))) { if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 0)) return; } /* Check for kernel-space pagefault (BAD). */ if (fp->ptregs.sr & PS_S) { /* kernel fault must be a data fault to user space */ if (! ((ssw & DF) && ((ssw & DFC) == USER_DATA))) { // try checking the kernel mappings before surrender if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 1)) return; /* instruction fault or kernel data fault! */ if (ssw & (FC | FB)) printk ("Instruction fault at %#010lx\n", fp->ptregs.pc); if (ssw & DF) { /* was this fault incurred testing bus mappings? */ if((fp->ptregs.pc >= (unsigned long)&_sun3_map_test_start) && (fp->ptregs.pc <= (unsigned long)&_sun3_map_test_end)) { send_fault_sig(&fp->ptregs); return; } printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", ssw & RW ? "read" : "write", fp->un.fmtb.daddr, space_names[ssw & DFC], fp->ptregs.pc); } printk ("BAD KERNEL BUSERR\n"); die_if_kernel("Oops", &fp->ptregs,0); force_sig(SIGKILL, current); return; } } else { /* user fault */ if (!(ssw & (FC | FB)) && !(ssw & DF)) /* not an instruction fault or data fault! BAD */ panic ("USER BUSERR w/o instruction or data fault"); } /* First handle the data fault, if any. */ if (ssw & DF) { addr = fp->un.fmtb.daddr;// errorcode bit 0: 0 -> no page 1 -> protection fault// errorcode bit 1: 0 -> read fault 1 -> write fault// (buserr_type & SUN3_BUSERR_PROTERR) -> protection fault// (buserr_type & SUN3_BUSERR_INVALID) -> invalid page fault if (buserr_type & SUN3_BUSERR_PROTERR) errorcode = 0x01; else if (buserr_type & SUN3_BUSERR_INVALID) errorcode = 0x00; else {#ifdef DEBUG printk ("*** unexpected busfault type=%#04x\n", buserr_type); printk ("invalid %s access at %#lx from pc %#lx\n", !(ssw & RW) ? "write" : "read", addr, fp->ptregs.pc);#endif die_if_kernel ("Oops", &fp->ptregs, buserr_type); force_sig (SIGBUS, current); return; }//todo: wtf is RM bit? --m if (!(ssw & RW) || ssw & RM) errorcode |= 0x02; /* Handle page fault. */ do_page_fault (&fp->ptregs, addr, errorcode); /* Retry the data fault now. */ return; } /* Now handle the instruction fault. */ /* Get the fault address. */ if (fp->ptregs.format == 0xA) addr = fp->ptregs.pc + 4; else addr = fp->un.fmtb.baddr; if (ssw & FC) addr -= 2; if (buserr_type & SUN3_BUSERR_INVALID) { if (!mmu_emu_handle_fault (fp->un.fmtb.daddr, 1, 0)) do_page_fault (&fp->ptregs, addr, 0); } else {#ifdef DEBUG printk ("protection fault on insn access (segv).\n");#endif force_sig (SIGSEGV, current); }}#else#if defined(CPU_M68020_OR_M68030)static inline void bus_error030 (struct frame *fp){ volatile unsigned short temp; unsigned short mmusr; unsigned long addr, errorcode; unsigned short ssw = fp->un.fmtb.ssw;#ifdef DEBUG unsigned long desc; printk ("pid = %x ", current->pid); printk ("SSW=%#06x ", ssw); if (ssw & (FC | FB)) printk ("Instruction fault at %#010lx\n", ssw & FC ? fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2 : fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr); if (ssw & DF) printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", ssw & RW ? "read" : "write", fp->un.fmtb.daddr, space_names[ssw & DFC], fp->ptregs.pc);#endif /* ++andreas: If a data fault and an instruction fault happen at the same time map in both pages. */ /* First handle the data fault, if any. */ if (ssw & DF) { addr = fp->un.fmtb.daddr;#ifdef DEBUG asm volatile ("ptestr %3,%2@,#7,%0\n\t" "pmove %%psr,%1@" : "=a&" (desc) : "a" (&temp), "a" (addr), "d" (ssw));#else asm volatile ("ptestr %2,%1@,#7\n\t" "pmove %%psr,%0@" : : "a" (&temp), "a" (addr), "d" (ssw));#endif mmusr = temp;#ifdef DEBUG printk("mmusr is %#x for addr %#lx in task %p\n", mmusr, addr, current); printk("descriptor address is %#lx, contents %#lx\n", __va(desc), *(unsigned long *)__va(desc));#endif errorcode = (mmusr & MMU_I) ? 0 : 1; if (!(ssw & RW) || (ssw & RM)) errorcode |= 2; if (mmusr & (MMU_I | MMU_WP)) { if (ssw & 4) { printk("Data %s fault at %#010lx in %s (pc=%#lx)\n", ssw & RW ? "read" : "write", fp->un.fmtb.daddr, space_names[ssw & DFC], fp->ptregs.pc); goto buserr; } /* Don't try to do anything further if an exception was handled. */ if (do_page_fault (&fp->ptregs, addr, errorcode) < 0) return; } else if (!(mmusr & MMU_I)) { /* probably a 020 cas fault */ if (!(ssw & RM) && send_fault_sig(&fp->ptregs) > 0) printk("unexpected bus error (%#x,%#x)\n", ssw, mmusr); } else if (mmusr & (MMU_B|MMU_L|MMU_S)) { printk("invalid %s access at %#lx from pc %#lx\n", !(ssw & RW) ? "write" : "read", addr, fp->ptregs.pc); die_if_kernel("Oops",&fp->ptregs,mmusr); force_sig(SIGSEGV, current); return; } else {#if 0 static volatile long tlong;#endif printk("weird %s access at %#lx from pc %#lx (ssw is %#x)\n", !(ssw & RW) ? "write" : "read", addr, fp->ptregs.pc, ssw); asm volatile ("ptestr #1,%1@,#0\n\t" "pmove %%psr,%0@" : /* no outputs */ : "a" (&temp), "a" (addr)); mmusr = temp; printk ("level 0 mmusr is %#x\n", mmusr);#if 0 asm volatile ("pmove %%tt0,%0@" : /* no outputs */ : "a" (&tlong)); printk("tt0 is %#lx, ", tlong); asm volatile ("pmove %%tt1,%0@" : /* no outputs */ : "a" (&tlong)); printk("tt1 is %#lx\n", tlong);#endif#ifdef DEBUG printk("Unknown SIGSEGV - 1\n");#endif die_if_kernel("Oops",&fp->ptregs,mmusr); force_sig(SIGSEGV, current); return; } /* setup an ATC entry for the access about to be retried */ if (!(ssw & RW) || (ssw & RM)) asm volatile ("ploadw %1,%0@" : /* no outputs */ : "a" (addr), "d" (ssw)); else asm volatile ("ploadr %1,%0@" : /* no outputs */ : "a" (addr), "d" (ssw)); } /* Now handle the instruction fault. */ if (!(ssw & (FC|FB))) return; if (fp->ptregs.sr & PS_S) { printk("Instruction fault at %#010lx\n", fp->ptregs.pc); buserr: printk ("BAD KERNEL BUSERR\n"); die_if_kernel("Oops",&fp->ptregs,0); force_sig(SIGKILL, current); return; } /* get the fault address */ if (fp->ptregs.format == 10) addr = fp->ptregs.pc + 4; else addr = fp->un.fmtb.baddr; if (ssw & FC) addr -= 2; if ((ssw & DF) && ((addr ^ fp->un.fmtb.daddr) & PAGE_MASK) == 0) /* Insn fault on same page as data fault. But we should still create the ATC entry. */ goto create_atc_entry;#ifdef DEBUG asm volatile ("ptestr #1,%2@,#7,%0\n\t" "pmove %%psr,%1@" : "=a&" (desc) : "a" (&temp), "a" (addr));#else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -