📄 traps.c
字号:
si.si_signo = SIGFPE; si.si_errno = 0; si.si_code = code; si.si_addr = (void *) regs->iaoq[0]; force_sig_info(SIGFPE, &si, current); return -1; send_sigill: si.si_signo = SIGILL; si.si_errno = 0; si.si_code = ILL_COPROC; si.si_addr = (void *) regs->iaoq[0]; force_sig_info(SIGILL, &si, current); return -1; success: /* We absolutely have to clear the T bit and exception registers to allow the process to recover. Otherwise every subsequent floating point instruction will trap. */ sw.status.t = 0; memset(excepts, 0, sizeof(excepts)); memcpy(regs->fr, &sw, sizeof(sw)); memcpy(((char *) regs->fr) + 4,excepts , sizeof(excepts)); return 0;}int handle_toc(void){ return 0;}void default_trap(int code, struct pt_regs *regs){ printk("Trap %d on CPU %d\n", code, smp_processor_id()); show_regs(regs);}void (*cpu_lpmc) (int code, struct pt_regs *regs) = default_trap;#ifdef CONFIG_KWDBintdebug_call (void) { printk ("Debug call.\n"); return 0;}intdebug_call_leaf (void) { return 0;}#endif /* CONFIG_KWDB */extern void do_page_fault(struct pt_regs *, int, unsigned long);extern void parisc_terminate(char *, struct pt_regs *, int, unsigned long);extern void transfer_pim_to_trap_frame(struct pt_regs *);extern void pdc_console_restart(void);void handle_interruption(int code, struct pt_regs *regs){ unsigned long fault_address = 0; unsigned long fault_space = 0; struct siginfo si;#ifdef CONFIG_KWDB struct save_state ssp;#endif /* CONFIG_KWDB */ if (code == 1) pdc_console_restart(); /* switch back to pdc if HPMC */ else sti();#ifdef __LP64__ /* * FIXME: * For 32 bit processes we don't want the b bits (bits 0 & 1) * in the ior. This is more appropriately handled in the tlb * miss handlers. Changes need to be made to support addresses * >32 bits for 64 bit processes. */ regs->ior &= 0x3FFFFFFFFFFFFFFFUL;#endif#if 0 printk("interrupted with code %d, regs %p\n", code, regs); show_regs(regs);#endif switch(code) { case 1: parisc_terminate("High Priority Machine Check (HPMC)",regs,code,0); /* NOT REACHED */ case 3: /* Recovery counter trap */ regs->gr[0] &= ~PSW_R; if (regs->iasq[0]) handle_gdb_break(regs, TRAP_TRACE); /* else this must be the start of a syscall - just let it * run. */ return; case 5: flush_all_caches(); cpu_lpmc(5, regs); return; case 6: fault_address = regs->iaoq[0]; fault_space = regs->iasq[0]; break; case 9: /* Break Instruction */ handle_break(regs->iir,regs); return; case 14: /* Assist Exception Trap, i.e. floating point exception. */ die_if_kernel("Floating point exception", regs, 0); /* quiet */ handle_fpe(regs); return; case 15: case 16: /* Non-Access TLB miss faulting address is in IOR */ case 17: case 26: fault_address = regs->ior; fault_space = regs->isr; if (code == 26 && fault_space == 0) parisc_terminate("Data access rights fault in kernel",regs,code,fault_address); break; case 19: regs->gr[0] |= PSW_X; /* So we can single-step over the trap */ /* fall thru */ case 21: handle_gdb_break(regs, TRAP_HWBKPT); return; case 25: /* Taken branch trap */ regs->gr[0] &= ~PSW_T; if (regs->iasq[0]) handle_gdb_break(regs, TRAP_BRANCH); /* else this must be the start of a syscall - just let it * run. */ return;#if 0 /* def CONFIG_KWDB */ case I_TAKEN_BR: /* 25 */ mtctl(0, 15); pt_regs_to_ssp(regs, &ssp); kgdb_trap(I_TAKEN_BR, &ssp, 1); ssp_to_pt_regs(&ssp, regs); break;#endif /* CONFIG_KWDB */ case 8: die_if_kernel("Illegal instruction", regs, code); si.si_code = ILL_ILLOPC; goto give_sigill; case 10: die_if_kernel("Priviledged operation - shouldn't happen!", regs, code); si.si_code = ILL_PRVOPC; goto give_sigill; case 11: die_if_kernel("Priviledged register - shouldn't happen!", regs, code); si.si_code = ILL_PRVREG; give_sigill: si.si_signo = SIGILL; si.si_errno = 0; si.si_addr = (void *) regs->iaoq[0]; force_sig_info(SIGILL, &si, current); return; case 28: /* Unaligned just causes SIGBUS for now */ die_if_kernel("Unaligned data reference", regs, code); si.si_code = BUS_ADRALN; si.si_signo = SIGBUS; si.si_errno = 0; si.si_addr = (void *) regs->ior; force_sig_info(SIGBUS, &si, current); return; default: if (user_mode(regs)) { printk("\nhandle_interruption() pid=%d command='%s'\n", current->pid, current->comm); show_regs(regs); /* SIGBUS, for lack of a better one. */ si.si_signo = SIGBUS; si.si_code = BUS_OBJERR; si.si_errno = 0; si.si_addr = (void *) regs->ior; force_sig_info(SIGBUS, &si, current); return; } parisc_terminate("Unexpected Interruption!",regs,code,0); /* NOT REACHED */ } if (user_mode(regs)) { if (fault_space != regs->sr[7]) { if (fault_space == 0) printk("User Fault on Kernel Space "); else /* this case should never happen, but whatever... */ printk("User Fault (long pointer) "); printk("pid=%d command='%s'\n", current->pid, current->comm); show_regs(regs); si.si_signo = SIGSEGV; si.si_errno = 0; si.si_code = SEGV_MAPERR; si.si_addr = (void *) regs->ior; force_sig_info(SIGSEGV, &si, current); return; } } else { /* * The kernel should never fault on its own address space. */ if (fault_space == 0) parisc_terminate("Kernel Fault",regs,code,fault_address); }#ifdef CONFIG_KWDB debug_call_leaf ();#endif /* CONFIG_KWDB */ do_page_fault(regs, code, fault_address); /* * This should not be necessary. * However, we do not currently * implement flush_page_to_ram. * * The problem is that if we just * brought in some code through the * D-cache, the I-cache may not see * it since it hasn't been flushed * to ram. *//* flush_all_caches(); */#if 0 printk("returning %p\n", regs);/* show_regs(regs); */#endif return;}void show_stack(unsigned long sp){#if 1 if ((sp & 0xc0000000UL) == 0xc0000000UL) { __u32 *stackptr; __u32 *dumpptr; /* Stack Dump! */ stackptr = (__u32 *)sp; dumpptr = (__u32 *)(sp & ~(INIT_TASK_SIZE - 1)); printk("\nDumping Stack from %p to %p:\n",dumpptr,stackptr); while (dumpptr < stackptr) { printk("%04x %08x %08x %08x %08x %08x %08x %08x %08x\n", ((__u32)dumpptr) & 0xffff, dumpptr[0], dumpptr[1], dumpptr[2], dumpptr[3], dumpptr[4], dumpptr[5], dumpptr[6], dumpptr[7]); dumpptr += 8; } }#endif}void parisc_terminate(char *msg, struct pt_regs *regs, int code, unsigned long offset){ set_eiem(0); cli(); if (code == 1) transfer_pim_to_trap_frame(regs);#if 1 show_stack(regs->gr[30]);#endif printk("\n%s: Code=%d regs=%p (Addr=%08lx)\n",msg,code,regs,offset); show_regs(regs); for(;;) ;}void transfer_pim_to_trap_frame(struct pt_regs *regs){ register int i; extern unsigned int hpmc_pim_data[]; struct pdc_hpmc_pim_11 *pim_narrow; struct pdc_hpmc_pim_20 *pim_wide; if (boot_cpu_data.cpu_type >= pcxu) { pim_wide = (struct pdc_hpmc_pim_20 *)hpmc_pim_data; /* * Note: The following code will probably generate a * bunch of truncation error warnings from the compiler. * Could be handled with an ifdef, but perhaps there * is a better way. */ regs->gr[0] = pim_wide->cr[22]; for (i = 1; i < 32; i++) regs->gr[i] = pim_wide->gr[i]; for (i = 0; i < 32; i++) regs->fr[i] = pim_wide->fr[i]; for (i = 0; i < 8; i++) regs->sr[i] = pim_wide->sr[i]; regs->iasq[0] = pim_wide->cr[17]; regs->iasq[1] = pim_wide->iasq_back; regs->iaoq[0] = pim_wide->cr[18]; regs->iaoq[1] = pim_wide->iaoq_back; regs->cr30 = pim_wide->cr[30]; regs->sar = pim_wide->cr[11]; regs->iir = pim_wide->cr[19]; regs->isr = pim_wide->cr[20]; regs->ior = pim_wide->cr[21]; } else { pim_narrow = (struct pdc_hpmc_pim_11 *)hpmc_pim_data; regs->gr[0] = pim_narrow->cr[22]; for (i = 1; i < 32; i++) regs->gr[i] = pim_narrow->gr[i]; for (i = 0; i < 32; i++) regs->fr[i] = pim_narrow->fr[i]; for (i = 0; i < 8; i++) regs->sr[i] = pim_narrow->sr[i]; regs->iasq[0] = pim_narrow->cr[17]; regs->iasq[1] = pim_narrow->iasq_back; regs->iaoq[0] = pim_narrow->cr[18]; regs->iaoq[1] = pim_narrow->iaoq_back; regs->cr30 = pim_narrow->cr[30]; regs->sar = pim_narrow->cr[11]; regs->iir = pim_narrow->cr[19]; regs->isr = pim_narrow->cr[20]; regs->ior = pim_narrow->cr[21]; } /* * The following fields only have meaning if we came through * another path. So just zero them here. */ regs->ksp = 0; regs->kpc = 0; regs->orig_r28 = 0;}int __init check_ivt(void *iva){ int i; u32 check = 0; u32 *ivap; u32 *hpmcp; u32 length; extern void os_hpmc(void); extern void os_hpmc_end(void); if(strcmp((char *)iva, "cows can fly")) return -1; ivap = (u32 *)iva; for (i = 0; i < 8; i++) *ivap++ = 0; /* Compute Checksum for HPMC handler */ length = (u32)((unsigned long)os_hpmc_end - (unsigned long)os_hpmc); ivap[7] = length; hpmcp = (u32 *)os_hpmc; for(i=0; i<length/4; i++) check += *hpmcp++; for(i=0; i<8; i++) check += ivap[i]; ivap[5] = -check; return 0;} #ifndef __LP64__extern const void fault_vector_11;#endifextern const void fault_vector_20;void __init trap_init(void){ volatile long eiem; void *iva; printk("trap_init\n"); if (boot_cpu_data.cpu_type >= pcxu) iva = (void *) &fault_vector_20; else#ifdef __LP64__ panic("Can't boot 64-bit OS on PA1.1 processor!");#else iva = (void *) &fault_vector_11;#endif if(check_ivt(iva)) panic("IVT invalid"); mtctl(0, 30); mtctl(90000000, 16); set_eiem(-1L); mtctl(-1L, 23); asm volatile ("rsm 0,%0" : "=r" (eiem));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -