arch/x86/um/signal.c

Source file repositories/reference/linux-study-clean/arch/x86/um/signal.c

File Facts

System
Linux kernel
Corpus path
arch/x86/um/signal.c
Extension
.c
Size
12554 bytes
Lines
471
Domain
Architecture Layer
Bucket
arch/x86
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(sigreturn)
{
	unsigned long sp = PT_REGS_SP(&current->thread.regs);
	struct sigframe __user *frame = (struct sigframe __user *)(sp - 8);
	sigset_t set;
	struct sigcontext __user *sc = &frame->sc;
	int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);

	if (copy_from_user(&set.sig[0], &sc->oldmask, sizeof(set.sig[0])) ||
	    copy_from_user(&set.sig[1], frame->extramask, sig_size))
		goto segfault;

	set_current_blocked(&set);

	if (copy_sc_from_user(&current->thread.regs, sc))
		goto segfault;

	/* Avoid ERESTART handling */
	PT_REGS_SYSCALL_NR(&current->thread.regs) = -1;
	return PT_REGS_SYSCALL_RET(&current->thread.regs);

 segfault:
	force_sig(SIGSEGV);
	return 0;
}

#else

int setup_signal_stack_si(unsigned long stack_top, struct ksignal *ksig,
			  struct pt_regs *regs, sigset_t *set)
{
	unsigned long math_size = host_fp_size + FP_XSTATE_MAGIC2_SIZE;
	struct rt_sigframe __user *frame;
	int err = 0, sig = ksig->sig;
	unsigned long fp_to;

	frame = (void __user *)stack_top - sizeof(struct rt_sigframe);

	/* Add required space for math frame */
	frame = (void __user *)((unsigned long)frame - math_size);

	/* ABI requires 16 byte boundary alignment */
	frame = (void __user *)round_down((unsigned long)frame, 16);

	/* Subtract 128 for a red zone and 8 for proper alignment */
	frame = (struct rt_sigframe __user *) ((unsigned long) frame - 128 - 8);

	if (!access_ok(frame, sizeof(*frame) + math_size))
		goto out;

	if (ksig->ka.sa.sa_flags & SA_SIGINFO) {
		err |= copy_siginfo_to_user(&frame->info, &ksig->info);
		if (err)
			goto out;
	}

	/* Create the ucontext.  */
	err |= __put_user(0, &frame->uc.uc_flags);
	err |= __put_user(NULL, &frame->uc.uc_link);
	err |= __save_altstack(&frame->uc.uc_stack, PT_REGS_SP(regs));

	fp_to = (unsigned long)frame + sizeof(*frame);

	err |= copy_sc_to_user(&frame->uc.uc_mcontext,
			       (struct _xstate __user *)fp_to,
			       regs, set->sig[0]);

	err |= __put_user(fp_to, &frame->uc.uc_mcontext.fpstate);
	if (sizeof(*set) == 16) {
		err |= __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]);
		err |= __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]);
	}
	else
		err |= __copy_to_user(&frame->uc.uc_sigmask, set,
				      sizeof(*set));

	/*
	 * Set up to return from userspace.  If provided, use a stub
	 * already in userspace.
	 */
	/* x86-64 should always use SA_RESTORER. */
	if (ksig->ka.sa.sa_flags & SA_RESTORER)
		err |= __put_user((void __user *)ksig->ka.sa.sa_restorer,
				  &frame->pretcode);
	else
		/* could use a vstub here */
		return err;

	if (err)
		return err;

Annotation

Implementation Notes