/* * Find out which address space caused the exception. * Access register mode is impossible, ignore space == 3. */ static inline enum fault_type get_fault_type(struct pt_regs *regs) { unsigned long trans_exc_code; trans_exc_code = regs->int_parm_long & 3; if (likely(trans_exc_code == 0)) { /* primary space exception */ if (IS_ENABLED(CONFIG_PGSTE) && test_pt_regs_flag(regs, PIF_GUEST_FAULT)) return GMAP_FAULT; if (current->thread.mm_segment == USER_DS) return USER_FAULT; return KERNEL_FAULT; } if (trans_exc_code == 2) { /* secondary space exception */ if (current->thread.mm_segment & 1) { if (current->thread.mm_segment == USER_DS_SACF) return USER_FAULT; return KERNEL_FAULT; } return VDSO_FAULT; } /* home space exception -> access via kernel ASCE */ return KERNEL_FAULT; }
/* * 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. */ void do_signal(struct pt_regs *regs) { siginfo_t info; int signr; struct k_sigaction ka; sigset_t *oldset = sigmask_to_save(); /* * Get signal to deliver. When running under ptrace, at this point * the debugger may change all our registers, including the system * call information. */ current_thread_info()->system_call = test_pt_regs_flag(regs, PIF_SYSCALL) ? regs->int_code : 0; signr = get_signal_to_deliver(&info, &ka, regs, NULL); if (signr > 0) { /* Whee! Actually deliver the signal. */ if (current_thread_info()->system_call) { regs->int_code = current_thread_info()->system_call; /* Check for system call restarting. */ switch (regs->gprs[2]) { case -ERESTART_RESTARTBLOCK: case -ERESTARTNOHAND: regs->gprs[2] = -EINTR; break; case -ERESTARTSYS: if (!(ka.sa.sa_flags & SA_RESTART)) { regs->gprs[2] = -EINTR; break; } /* fallthrough */ case -ERESTARTNOINTR: regs->gprs[2] = regs->orig_gpr2; regs->psw.addr = __rewind_psw(regs->psw, regs->int_code >> 16); break; } } /* No longer in a system call */ clear_pt_regs_flag(regs, PIF_SYSCALL); if (is_compat_task()) handle_signal32(signr, &ka, &info, oldset, regs); else handle_signal(signr, &ka, &info, oldset, regs); return; }