do_signal

/*
 * 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.
 */
static void do_signal(struct pt_regs *regs)
{
    unsigned long continue_addr = 0, restart_addr = 0;
    int retval = 0;
    struct ksignal ksig;
    bool syscall = in_syscall(regs);

    /*
     * If we were from a system call, check for system call restarting...
     */
    if (syscall) {
        continue_addr = regs->pc;
        restart_addr = continue_addr - (compat_thumb_mode(regs) ? 2 : 4);
        retval = regs->regs[0];

        /*
         * Avoid additional syscall restarting via ret_to_user.
         */
        forget_syscall(regs);

        /*
         * Prepare for system call restart. We do this here so that a
         * debugger will see the already changed PC.
         */
        switch (retval) {
        case -ERESTARTNOHAND:
        case -ERESTARTSYS:
        case -ERESTARTNOINTR:
        case -ERESTART_RESTARTBLOCK:
            regs->regs[0] = regs->orig_x0;
            regs->pc = restart_addr;
            break;
        }
    }

    /*
     * Get the signal to deliver. When running under ptrace, at this point
     * the debugger may change all of our registers.
     */
    if (get_signal(&ksig)) {
        /*
         * Depending on the signal settings, we may need to revert the
         * decision to restart the system call, but skip this if a
         * debugger has chosen to restart at a different PC.
         */
        if (regs->pc == restart_addr &&
            (retval == -ERESTARTNOHAND ||
             retval == -ERESTART_RESTARTBLOCK ||
             (retval == -ERESTARTSYS &&
              !(ksig.ka.sa.sa_flags & SA_RESTART)))) {
            regs->regs[0] = -EINTR;
            regs->pc = continue_addr;
        } //如果驱动返回-ERESTART_RESTARTBLOCK,pc就不是restart_addr了,如果驱动返回                 -ERESTARTSYS,同时SA_RESTART是1,那pc还是restart_addr ;不过前提get_signal返回true,不然ERESTART_RESTARTBLOCK好像也可以restart

        handle_signal(&ksig, regs);
        return;
    }

    /*
     * Handle restarting a different system call. As above, if a debugger
     * has chosen to restart at a different PC, ignore the restart.
     */
    if (syscall && regs->pc == restart_addr) {
        if (retval == -ERESTART_RESTARTBLOCK)
            setup_restart_syscall(regs);
        user_rewind_single_step(current);
    }

    restore_saved_sigmask();
}

asmlinkage void do_notify_resume(struct pt_regs *regs,
                 unsigned long thread_flags)
{
    /*
     * The assembly code enters us with IRQs off, but it hasn't
     * informed the tracing code of that for efficiency reasons.
     * Update the trace code with the current status.
     */
    trace_hardirqs_off();

    do {
        /* Check valid user FS if needed */
        addr_limit_user_check();

        if (thread_flags & _TIF_NEED_RESCHED) {
            /* Unmask Debug and SError for the next task */
            local_daif_restore(DAIF_PROCCTX_NOIRQ);

            schedule();
        } else {
            local_daif_restore(DAIF_PROCCTX);

            if (thread_flags & _TIF_UPROBE)
                uprobe_notify_resume(regs);

            if (thread_flags & _TIF_SIGPENDING)
                do_signal(regs);

            if (thread_flags & _TIF_NOTIFY_RESUME) {
                clear_thread_flag(TIF_NOTIFY_RESUME);
                tracehook_notify_resume(regs);
                rseq_handle_notify_resume(NULL, regs);
            }

            if (thread_flags & _TIF_FOREIGN_FPSTATE)
                fpsimd_restore_current_state();
        }

        local_daif_mask();
        thread_flags = READ_ONCE(current_thread_info()->flags);
    } while (thread_flags & _TIF_WORK_MASK);
}

/*
 * Ok, we need to do extra processing, enter the slow path.
 */
work_pending:
    mov    x0, sp                // 'regs'
    bl    do_notify_resume
#ifdef CONFIG_TRACE_IRQFLAGS
    bl    trace_hardirqs_on        // enabled while in userspace
#endif
    ldr    x1, [tsk, #TSK_TI_FLAGS]    // re-check for single-step
    b    finish_ret_to_user
/*
 * "slow" syscall return path.
 */
ret_to_user:
    disable_daif
    gic_prio_kentry_setup tmp=x3
    ldr    x1, [tsk, #TSK_TI_FLAGS]
    and    x2, x1, #_TIF_WORK_MASK
    cbnz    x2, work_pending
finish_ret_to_user:
    enable_step_tsk x1, x2
#ifdef CONFIG_GCC_PLUGIN_STACKLEAK
    bl    stackleak_erase
#endif
    kernel_exit 0
ENDPROC(ret_to_user)

/**
 *  sys_restart_syscall - restart a system call
 */
SYSCALL_DEFINE0(restart_syscall)
{
    struct restart_block *restart = &current->restart_block;
    return restart->fn(restart);
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值