arch/riscv/kernel/signal.c

Source file repositories/reference/linux-study-clean/arch/riscv/kernel/signal.c

File Facts

System
Linux kernel
Corpus path
arch/riscv/kernel/signal.c
Extension
.c
Size
16802 bytes
Lines
590
Domain
Architecture Layer
Bucket
arch/riscv
Inferred role
Architecture Layer: syscall or user/kernel boundary
Status
core implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

SYSCALL_DEFINE0(rt_sigreturn)
{
	struct pt_regs *regs = current_pt_regs();
	struct rt_sigframe __user *frame;
	struct task_struct *task;
	sigset_t set;
	size_t frame_size = get_rt_frame_size(false);

	/* Always make any pending restarted system calls return -EINTR */
	current->restart_block.fn = do_no_restart_syscall;

	frame = (struct rt_sigframe __user *)regs->sp;

	if (!access_ok(frame, frame_size))
		goto badframe;

	if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
		goto badframe;

	set_current_blocked(&set);

	if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
		goto badframe;

	if (restore_altstack(&frame->uc.uc_stack))
		goto badframe;

	regs->cause = -1UL;

	return regs->a0;

badframe:
	task = current;
	if (show_unhandled_signals) {
		pr_info_ratelimited(
			"%s[%d]: bad frame in %s: frame=%p pc=%p sp=%p\n",
			task->comm, task_pid_nr(task), __func__,
			frame, (void *)regs->epc, (void *)regs->sp);
	}
	force_sig(SIGSEGV);
	return 0;
}

static long setup_sigcontext(struct rt_sigframe __user *frame,
	struct pt_regs *regs)
{
	struct sigcontext __user *sc = &frame->uc.uc_mcontext;
	struct __riscv_ctx_hdr __user *sc_ext_ptr = &sc->sc_extdesc.hdr;
	struct arch_ext_priv *arch_ext;
	long err, i, ext_size;

	/* sc_regs is structured the same as the start of pt_regs */
	err = __copy_to_user(&sc->sc_regs, regs, sizeof(sc->sc_regs));
	/* Save the floating-point state. */
	if (has_fpu())
		err |= save_fp_state(regs, &sc->sc_fpregs);
	/* Save the vector state. */
	for (i = 0; i < nr_arch_exts; i++) {
		arch_ext = &arch_ext_list[i];
		if (!arch_ext->save)
			continue;

		ext_size = arch_ext->save(regs, sc_ext_ptr + 1);
		if (ext_size <= 0) {
			err |= ext_size;
		} else {
			err |= __put_user(arch_ext->magic, &sc_ext_ptr->magic);
			err |= __put_user(ext_size, &sc_ext_ptr->size);
			sc_ext_ptr = (void __user *)sc_ext_ptr + ext_size;
		}
	}
	/* Write zero to fp-reserved space and check it on restore_sigcontext */
	err |= __put_user(0, &sc->sc_extdesc.reserved);
	/* And put END __riscv_ctx_hdr at the end. */
	err |= __put_user(END_MAGIC, &sc_ext_ptr->magic);
	err |= __put_user(END_HDR_SIZE, &sc_ext_ptr->size);

	return err;
}

static inline void __user *get_sigframe(struct ksignal *ksig,
	struct pt_regs *regs, size_t framesize)
{
	unsigned long sp;
	/* Default to using normal stack */
	sp = regs->sp;

	/*
	 * If we are on the alternate signal stack and would overflow it, don't.
	 * Return an always-bogus address instead so we will die with SIGSEGV.

Annotation

Implementation Notes