arch/powerpc/kernel/signal_64.c

Source file repositories/reference/linux-study-clean/arch/powerpc/kernel/signal_64.c

File Facts

System
Linux kernel
Corpus path
arch/powerpc/kernel/signal_64.c
Extension
.c
Size
30995 bytes
Lines
978
Domain
Architecture Layer
Bucket
arch/powerpc
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_DEFINE3(swapcontext, struct ucontext __user *, old_ctx,
		struct ucontext __user *, new_ctx, long, ctx_size)
{
	sigset_t set;
	unsigned long new_msr = 0;
	int ctx_has_vsx_region = 0;

	if (new_ctx &&
	    get_user(new_msr, &new_ctx->uc_mcontext.gp_regs[PT_MSR]))
		return -EFAULT;
	/*
	 * Check that the context is not smaller than the original
	 * size (with VMX but without VSX)
	 */
	if (ctx_size < UCONTEXTSIZEWITHOUTVSX)
		return -EINVAL;
	/*
	 * If the new context state sets the MSR VSX bits but
	 * it doesn't provide VSX state.
	 */
	if ((ctx_size < sizeof(struct ucontext)) &&
	    (new_msr & MSR_VSX))
		return -EINVAL;
	/* Does the context have enough room to store VSX data? */
	if (ctx_size >= sizeof(struct ucontext))
		ctx_has_vsx_region = 1;

	if (old_ctx != NULL) {
		prepare_setup_sigcontext(current);
		if (!user_write_access_begin(old_ctx, ctx_size))
			return -EFAULT;

		unsafe_setup_sigcontext(&old_ctx->uc_mcontext, current, 0, NULL,
					0, ctx_has_vsx_region, efault_out);
		unsafe_copy_to_user(&old_ctx->uc_sigmask, &current->blocked,
				    sizeof(sigset_t), efault_out);

		user_write_access_end();
	}
	if (new_ctx == NULL)
		return 0;
	if (!access_ok(new_ctx, ctx_size) ||
	    fault_in_readable((char __user *)new_ctx, ctx_size))
		return -EFAULT;

	/*
	 * If we get a fault copying the context into the kernel's
	 * image of the user's registers, we can't just return -EFAULT
	 * because the user's registers will be corrupted.  For instance
	 * the NIP value may have been updated but not some of the
	 * other registers.  Given that we have done the access_ok
	 * and successfully read the first and last bytes of the region
	 * above, this should only happen in an out-of-memory situation
	 * or if another thread unmaps the region containing the context.
	 * We kill the task with a SIGSEGV in this situation.
	 */

	if (__get_user_sigset(&set, &new_ctx->uc_sigmask)) {
		force_exit_sig(SIGSEGV);
		return -EFAULT;
	}
	set_current_blocked(&set);

	if (!user_read_access_begin(new_ctx, ctx_size))
		return -EFAULT;
	if (__unsafe_restore_sigcontext(current, NULL, 0, &new_ctx->uc_mcontext)) {
		user_read_access_end();
		force_exit_sig(SIGSEGV);
		return -EFAULT;
	}
	user_read_access_end();

	/* This returns like rt_sigreturn */
	set_thread_flag(TIF_RESTOREALL);

	return 0;

efault_out:
	user_write_access_end();
	return -EFAULT;
}


/*
 * Do a signal return; undo the signal stack.
 */

SYSCALL_DEFINE0(rt_sigreturn)
{
	struct pt_regs *regs = current_pt_regs();

Annotation

Implementation Notes