arch/sparc/kernel/signal_32.c

Source file repositories/reference/linux-study-clean/arch/sparc/kernel/signal_32.c

File Facts

System
Linux kernel
Corpus path
arch/sparc/kernel/signal_32.c
Extension
.c
Size
15470 bytes
Lines
566
Domain
Architecture Layer
Bucket
arch/sparc
Inferred role
Architecture Layer: implementation source
Status
source 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

struct signal_frame {
	struct sparc_stackf	ss;
	__siginfo32_t		info;
	__siginfo_fpu_t __user	*fpu_save;
	unsigned long		insns[2] __attribute__ ((aligned (8)));
	unsigned int		extramask[_NSIG_WORDS - 1];
	unsigned int		extra_size; /* Should be 0 */
	__siginfo_rwin_t __user	*rwin_save;
} __attribute__((aligned(8)));

struct rt_signal_frame {
	struct sparc_stackf	ss;
	siginfo_t		info;
	struct pt_regs		regs;
	sigset_t		mask;
	__siginfo_fpu_t __user	*fpu_save;
	unsigned int		insns[2];
	stack_t			stack;
	unsigned int		extra_size; /* Should be 0 */
	__siginfo_rwin_t __user	*rwin_save;
} __attribute__((aligned(8)));

/* Align macros */
#define SF_ALIGNEDSZ  (((sizeof(struct signal_frame) + 7) & (~7)))
#define RT_ALIGNEDSZ  (((sizeof(struct rt_signal_frame) + 7) & (~7)))

/* Checks if the fp is valid.  We always build signal frames which are
 * 16-byte aligned, therefore we can always enforce that the restore
 * frame has that property as well.
 */
static inline bool invalid_frame_pointer(void __user *fp, int fplen)
{
	if ((((unsigned long) fp) & 15) || !access_ok(fp, fplen))
		return true;

	return false;
}

asmlinkage void do_sigreturn(struct pt_regs *regs)
{
	unsigned long up_psr, pc, npc, ufp;
	struct signal_frame __user *sf;
	sigset_t set;
	__siginfo_fpu_t __user *fpu_save;
	__siginfo_rwin_t __user *rwin_save;
	int err;

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

	synchronize_user_stack();

	sf = (struct signal_frame __user *) regs->u_regs[UREG_FP];

	/* 1. Make sure we are not getting garbage from the user */
	if (invalid_frame_pointer(sf, sizeof(*sf)))
		goto segv_and_exit;

	if (get_user(ufp, &sf->info.si_regs.u_regs[UREG_FP]))
		goto segv_and_exit;

	if (ufp & 0x7)
		goto segv_and_exit;

	err = __get_user(pc,  &sf->info.si_regs.pc);
	err |= __get_user(npc, &sf->info.si_regs.npc);

	if ((pc | npc) & 3)
		goto segv_and_exit;

	/* 2. Restore the state */
	up_psr = regs->psr;
	err |= __copy_from_user(regs, &sf->info.si_regs, sizeof(struct pt_regs));

	/* User can only change condition codes and FPU enabling in %psr. */
	regs->psr = (up_psr & ~(PSR_ICC | PSR_EF))
		  | (regs->psr & (PSR_ICC | PSR_EF));

	/* Prevent syscall restart.  */
	pt_regs_clear_syscall(regs);

	err |= __get_user(fpu_save, &sf->fpu_save);
	if (fpu_save)
		err |= restore_fpu_state(regs, fpu_save);
	err |= __get_user(rwin_save, &sf->rwin_save);
	if (rwin_save)
		err |= restore_rwin_state(rwin_save);

	/* This is pretty much atomic, no amount locking would prevent
	 * the races which exist anyways.

Annotation

Implementation Notes