void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) { if (kernel_mode(regs)) die("Exception in kernel mode", regs, signr); force_sig_fault(signr, code, (void __user *)addr, current); }
void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) { siginfo_t info; if (kernel_mode(regs)) { die("Exception in kernel mode", regs, signr); } info.si_signo = signr; info.si_errno = 0; info.si_code = code; info.si_addr = (void __user *) addr; force_sig_info(signr, &info, current); }
asmlinkage void do_notify_resume(struct pt_regs *regs, int in_syscall) { /* * We want the common case to go fast, which * is why we may in certain cases get here from * kernel mode. Just return without doing anything * if so. */ if (kernel_mode(regs)) return; if (test_thread_flag(TIF_SIGPENDING)) do_signal(regs, in_syscall); if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME)) tracehook_notify_resume(regs); }
/* * Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. * * Note that we go through the signals twice: once to check the signals that * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that. */ int do_signal(struct pt_regs *regs, sigset_t *oldset, int in_syscall) { siginfo_t info; int signr; struct k_sigaction ka; #ifdef DEBUG_SIG printk(KERN_INFO "do signal: %p %p %d\n", regs, oldset, in_syscall); printk(KERN_INFO "do signal2: %lx %lx %ld [%lx]\n", regs->pc, regs->r1, regs->r12, current_thread_info()->flags); #endif /* * We want the common case to go fast, which * is why we may in certain cases get here from * kernel mode. Just return without doing anything * if so. */ if (kernel_mode(regs)) return 1; if (!oldset) oldset = ¤t->blocked; signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { /* Whee! Actually deliver the signal. */ if (in_syscall) handle_restart(regs, &ka, 1); handle_signal(signr, &ka, &info, oldset, regs); return 1; } if (in_syscall) handle_restart(regs, NULL, 0); /* Did we come from a system call? */ return 0; }
int copy_thread(unsigned long clone_flags, unsigned long usp, unsigned long unused, struct task_struct *p, struct pt_regs *regs) { struct pt_regs *childregs = task_pt_regs(p); struct thread_info *ti = task_thread_info(p); *childregs = *regs; if (user_mode(regs)) childregs->r1 = usp; else childregs->r1 = ((unsigned long) ti) + THREAD_SIZE; #ifndef CONFIG_MMU memset(&ti->cpu_context, 0, sizeof(struct cpu_context)); ti->cpu_context.r1 = (unsigned long)childregs; ti->cpu_context.msr = (unsigned long)childregs->msr; #else /* if creating a kernel thread then update the current reg (we don't * want to use the parent's value when restoring by POP_STATE) */ if (kernel_mode(regs)) /* save new current on stack to use POP_STATE */ childregs->CURRENT_TASK = (unsigned long)p; /* if returning to user then use the parent's value of this register */ /* if we're creating a new kernel thread then just zeroing all * the registers. That's OK for a brand new thread.*/ /* Pls. note that some of them will be restored in POP_STATE */ if (kernel_mode(regs)) memset(&ti->cpu_context, 0, sizeof(struct cpu_context)); /* if this thread is created for fork/vfork/clone, then we want to * restore all the parent's context */ /* in addition to the registers which will be restored by POP_STATE */ else { ti->cpu_context = *(struct cpu_context *)regs; childregs->msr |= MSR_UMS; } /* FIXME STATE_SAVE_PT_OFFSET; */ ti->cpu_context.r1 = (unsigned long)childregs; /* we should consider the fact that childregs is a copy of the parent * regs which were saved immediately after entering the kernel state * before enabling VM. This MSR will be restored in switch_to and * RETURN() and we want to have the right machine state there * specifically this state must have INTs disabled before and enabled * after performing rtbd * compose the right MSR for RETURN(). It will work for switch_to also * excepting for VM and UMS * don't touch UMS , CARRY and cache bits * right now MSR is a copy of parent one */ childregs->msr |= MSR_BIP; childregs->msr &= ~MSR_EIP; childregs->msr |= MSR_IE; childregs->msr &= ~MSR_VM; childregs->msr |= MSR_VMS; childregs->msr |= MSR_EE; /* exceptions will be enabled*/ ti->cpu_context.msr = (childregs->msr|MSR_VM); ti->cpu_context.msr &= ~MSR_UMS; /* switch_to to kernel mode */ ti->cpu_context.msr &= ~MSR_IE; #endif ti->cpu_context.r15 = (unsigned long)ret_from_fork - 8; /* * r21 is the thread reg, r10 is 6th arg to clone * which contains TLS area */ if (clone_flags & CLONE_SETTLS) childregs->r21 = childregs->r10; return 0; }
asmlinkage void full_exception(struct pt_regs *regs, unsigned int type, int fsr, int addr) { #ifdef CONFIG_MMU addr = regs->pc; #endif #if 0 printk(KERN_WARNING "Exception %02x in %s mode, FSR=%08x PC=%08x " \ "ESR=%08x\n", type, user_mode(regs) ? "user" : "kernel", fsr, (unsigned int) regs->pc, (unsigned int) regs->esr); #endif switch (type & 0x1F) { case MICROBLAZE_ILL_OPCODE_EXCEPTION: if (user_mode(regs)) { pr_debug("Illegal opcode exception in user mode\n"); _exception(SIGILL, regs, ILL_ILLOPC, addr); return; } printk(KERN_WARNING "Illegal opcode exception " \ "in kernel mode.\n"); die("opcode exception", regs, SIGBUS); break; case MICROBLAZE_IBUS_EXCEPTION: if (user_mode(regs)) { pr_debug("Instruction bus error exception in user mode\n"); _exception(SIGBUS, regs, BUS_ADRERR, addr); return; } printk(KERN_WARNING "Instruction bus error exception " \ "in kernel mode.\n"); die("bus exception", regs, SIGBUS); break; case MICROBLAZE_DBUS_EXCEPTION: if (user_mode(regs)) { pr_debug("Data bus error exception in user mode\n"); _exception(SIGBUS, regs, BUS_ADRERR, addr); return; } printk(KERN_WARNING "Data bus error exception " \ "in kernel mode.\n"); die("bus exception", regs, SIGBUS); break; case MICROBLAZE_DIV_ZERO_EXCEPTION: if (user_mode(regs)) { pr_debug("Divide by zero exception in user mode\n"); _exception(SIGILL, regs, FPE_INTDIV, addr); return; } printk(KERN_WARNING "Divide by zero exception " \ "in kernel mode.\n"); die("Divide by zero exception", regs, SIGBUS); break; case MICROBLAZE_FPU_EXCEPTION: pr_debug("FPU exception\n"); /* IEEE FP exception */ /* I removed fsr variable and use code var for storing fsr */ if (fsr & FSR_IO) fsr = FPE_FLTINV; else if (fsr & FSR_OF) fsr = FPE_FLTOVF; else if (fsr & FSR_UF) fsr = FPE_FLTUND; else if (fsr & FSR_DZ) fsr = FPE_FLTDIV; else if (fsr & FSR_DO) fsr = FPE_FLTRES; _exception(SIGFPE, regs, fsr, addr); break; #ifdef CONFIG_MMU case MICROBLAZE_PRIVILEGED_EXCEPTION: pr_debug("Privileged exception\n"); _exception(SIGILL, regs, ILL_PRVOPC, addr); break; #endif default: /* FIXME what to do in unexpected exception */ printk(KERN_WARNING "Unexpected exception %02x " "PC=%08x in %s mode\n", type, (unsigned int) addr, kernel_mode(regs) ? "kernel" : "user"); } return; }