signal.c 8.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * Copyright (C) 2003 PathScale, Inc.
 * Licensed under the GPL
 */

#include "linux/stddef.h"
#include "linux/errno.h"
#include "linux/personality.h"
#include "linux/ptrace.h"
#include "asm/current.h"
#include "asm/uaccess.h"
#include "asm/sigcontext.h"
#include "asm/ptrace.h"
#include "asm/arch/ucontext.h"
#include "sysdep/ptrace.h"
#include "frame_kern.h"
#include "skas.h"

19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
void copy_sc(union uml_pt_regs *regs, void *from)
{
	struct sigcontext *sc = from;

#define GETREG(regs, regno, sc, regname) \
       (regs)->skas.regs[(regno) / sizeof(unsigned long)] = (sc)->regname

       GETREG(regs, R8, sc, r8);
       GETREG(regs, R9, sc, r9);
       GETREG(regs, R10, sc, r10);
       GETREG(regs, R11, sc, r11);
       GETREG(regs, R12, sc, r12);
       GETREG(regs, R13, sc, r13);
       GETREG(regs, R14, sc, r14);
       GETREG(regs, R15, sc, r15);
       GETREG(regs, RDI, sc, rdi);
       GETREG(regs, RSI, sc, rsi);
       GETREG(regs, RBP, sc, rbp);
       GETREG(regs, RBX, sc, rbx);
       GETREG(regs, RDX, sc, rdx);
       GETREG(regs, RAX, sc, rax);
       GETREG(regs, RCX, sc, rcx);
       GETREG(regs, RSP, sc, rsp);
       GETREG(regs, RIP, sc, rip);
       GETREG(regs, EFLAGS, sc, eflags);
       GETREG(regs, CS, sc, cs);

#undef GETREG
}

L
Linus Torvalds 已提交
49
static int copy_sc_from_user_skas(struct pt_regs *regs,
A
Al Viro 已提交
50
                                 struct sigcontext __user *from)
L
Linus Torvalds 已提交
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
{
       int err = 0;

#define GETREG(regs, regno, sc, regname) \
       __get_user((regs)->regs.skas.regs[(regno) / sizeof(unsigned long)], \
                  &(sc)->regname)

       err |= GETREG(regs, R8, from, r8);
       err |= GETREG(regs, R9, from, r9);
       err |= GETREG(regs, R10, from, r10);
       err |= GETREG(regs, R11, from, r11);
       err |= GETREG(regs, R12, from, r12);
       err |= GETREG(regs, R13, from, r13);
       err |= GETREG(regs, R14, from, r14);
       err |= GETREG(regs, R15, from, r15);
       err |= GETREG(regs, RDI, from, rdi);
       err |= GETREG(regs, RSI, from, rsi);
       err |= GETREG(regs, RBP, from, rbp);
       err |= GETREG(regs, RBX, from, rbx);
       err |= GETREG(regs, RDX, from, rdx);
       err |= GETREG(regs, RAX, from, rax);
       err |= GETREG(regs, RCX, from, rcx);
       err |= GETREG(regs, RSP, from, rsp);
       err |= GETREG(regs, RIP, from, rip);
       err |= GETREG(regs, EFLAGS, from, eflags);
       err |= GETREG(regs, CS, from, cs);

#undef GETREG

J
Jeff Dike 已提交
80
       return err;
L
Linus Torvalds 已提交
81 82
}

A
Al Viro 已提交
83 84
int copy_sc_to_user_skas(struct sigcontext __user *to,
			 struct _fpstate __user *to_fp,
85 86
			 struct pt_regs *regs, unsigned long mask,
			 unsigned long sp)
L
Linus Torvalds 已提交
87
{
88
        struct faultinfo * fi = &current->thread.arch.faultinfo;
L
Linus Torvalds 已提交
89 90 91 92 93 94 95 96 97 98 99 100
	int err = 0;

	err |= __put_user(0, &to->gs);
	err |= __put_user(0, &to->fs);

#define PUTREG(regs, regno, sc, regname) \
       __put_user((regs)->regs.skas.regs[(regno) / sizeof(unsigned long)], \
                  &(sc)->regname)

	err |= PUTREG(regs, RDI, to, rdi);
	err |= PUTREG(regs, RSI, to, rsi);
	err |= PUTREG(regs, RBP, to, rbp);
101 102 103 104 105
        /* Must use orignal RSP, which is passed in, rather than what's in
         * the pt_regs, because that's already been updated to point at the
         * signal frame.
         */
	err |= __put_user(sp, &to->rsp);
L
Linus Torvalds 已提交
106 107 108 109 110 111 112 113 114 115 116 117 118
	err |= PUTREG(regs, RBX, to, rbx);
	err |= PUTREG(regs, RDX, to, rdx);
	err |= PUTREG(regs, RCX, to, rcx);
	err |= PUTREG(regs, RAX, to, rax);
	err |= PUTREG(regs, R8, to, r8);
	err |= PUTREG(regs, R9, to, r9);
	err |= PUTREG(regs, R10, to, r10);
	err |= PUTREG(regs, R11, to, r11);
	err |= PUTREG(regs, R12, to, r12);
	err |= PUTREG(regs, R13, to, r13);
	err |= PUTREG(regs, R14, to, r14);
	err |= PUTREG(regs, R15, to, r15);
	err |= PUTREG(regs, CS, to, cs); /* XXX x86_64 doesn't do this */
119 120 121 122 123

        err |= __put_user(fi->cr2, &to->cr2);
        err |= __put_user(fi->error_code, &to->err);
        err |= __put_user(fi->trap_no, &to->trapno);

L
Linus Torvalds 已提交
124 125 126 127 128 129 130 131 132 133 134 135 136
	err |= PUTREG(regs, RIP, to, rip);
	err |= PUTREG(regs, EFLAGS, to, eflags);
#undef PUTREG

	err |= __put_user(mask, &to->oldmask);

	return(err);
}

static int copy_sc_from_user(struct pt_regs *to, void __user *from)
{
       int ret;

J
Jeff Dike 已提交
137
       ret = copy_sc_from_user_skas(to, from);
L
Linus Torvalds 已提交
138 139 140
       return(ret);
}

A
Al Viro 已提交
141 142
static int copy_sc_to_user(struct sigcontext __user *to,
			   struct _fpstate __user *fp,
143 144
			   struct pt_regs *from, unsigned long mask,
			   unsigned long sp)
L
Linus Torvalds 已提交
145
{
J
Jeff Dike 已提交
146
       return copy_sc_to_user_skas(to, fp, from, mask, sp);
L
Linus Torvalds 已提交
147 148 149 150
}

struct rt_sigframe
{
A
Al Viro 已提交
151
       char __user *pretcode;
L
Linus Torvalds 已提交
152 153 154 155 156 157 158 159 160 161 162 163
       struct ucontext uc;
       struct siginfo info;
};

#define round_down(m, n) (((m) / (n)) * (n))

int setup_signal_stack_si(unsigned long stack_top, int sig,
			  struct k_sigaction *ka, struct pt_regs * regs,
			  siginfo_t *info, sigset_t *set)
{
	struct rt_sigframe __user *frame;
	struct _fpstate __user *fp = NULL;
164
	unsigned long save_sp = PT_REGS_RSP(regs);
L
Linus Torvalds 已提交
165 166 167 168
	int err = 0;
	struct task_struct *me = current;

	frame = (struct rt_sigframe __user *)
169 170 171
		round_down(stack_top - sizeof(struct rt_sigframe), 16);
	/* Subtract 128 for a red zone and 8 for proper alignment */
        frame = (struct rt_sigframe __user *) ((unsigned long) frame - 128 - 8);
L
Linus Torvalds 已提交
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188

	if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate)))
		goto out;

#if 0 /* XXX */
	if (save_i387(fp) < 0)
		err |= -1;
#endif
	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
		goto out;

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

189 190 191 192 193 194 195 196 197 198
	/* Update SP now because the page fault handler refuses to extend
	 * the stack if the faulting address is too far below the current
	 * SP, which frame now certainly is.  If there's an error, the original
	 * value is restored on the way out.
	 * When writing the sigcontext to the stack, we have to write the
	 * original value, so that's passed to copy_sc_to_user, which does
	 * the right thing with it.
	 */
	PT_REGS_RSP(regs) = (unsigned long) frame;

L
Linus Torvalds 已提交
199 200 201 202
	/* Create the ucontext.  */
	err |= __put_user(0, &frame->uc.uc_flags);
	err |= __put_user(0, &frame->uc.uc_link);
	err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
203
	err |= __put_user(sas_ss_flags(save_sp),
L
Linus Torvalds 已提交
204 205
			  &frame->uc.uc_stack.ss_flags);
	err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
206 207
	err |= copy_sc_to_user(&frame->uc.uc_mcontext, fp, regs, set->sig[0],
		save_sp);
L
Linus Torvalds 已提交
208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223
	err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate);
	if (sizeof(*set) == 16) {
		__put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]);
		__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 (ka->sa.sa_flags & SA_RESTORER)
		err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
	else
		/* could use a vstub here */
224
		goto restore_sp;
L
Linus Torvalds 已提交
225 226

	if (err)
227
		goto restore_sp;
L
Linus Torvalds 已提交
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245

	/* Set up registers for signal handler */
	{
		struct exec_domain *ed = current_thread_info()->exec_domain;
		if (unlikely(ed && ed->signal_invmap && sig < 32))
			sig = ed->signal_invmap[sig];
	}

	PT_REGS_RDI(regs) = sig;
	/* In case the signal handler was declared without prototypes */
	PT_REGS_RAX(regs) = 0;

	/* This also works for non SA_SIGINFO handlers because they expect the
	   next argument after the signal number on the stack. */
	PT_REGS_RSI(regs) = (unsigned long) &frame->info;
	PT_REGS_RDX(regs) = (unsigned long) &frame->uc;
	PT_REGS_RIP(regs) = (unsigned long) ka->sa.sa_handler;
 out:
246 247 248 249 250
	return err;

restore_sp:
	PT_REGS_RSP(regs) = save_sp;
	return err;
L
Linus Torvalds 已提交
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
}

long sys_rt_sigreturn(struct pt_regs *regs)
{
	unsigned long sp = PT_REGS_SP(&current->thread.regs);
	struct rt_sigframe __user *frame =
		(struct rt_sigframe __user *)(sp - 8);
	struct ucontext __user *uc = &frame->uc;
	sigset_t set;

	if(copy_from_user(&set, &uc->uc_sigmask, sizeof(set)))
		goto segfault;

	sigdelsetmask(&set, ~_BLOCKABLE);

	spin_lock_irq(&current->sighand->siglock);
	current->blocked = set;
	recalc_sigpending();
	spin_unlock_irq(&current->sighand->siglock);

	if(copy_sc_from_user(&current->thread.regs, &uc->uc_mcontext))
		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, current);
	return 0;
}
/*
 * Overrides for Emacs so that we follow Linus's tabbing style.
 * Emacs will notice this stuff at the end of the file and automatically
 * adjust the settings for this buffer only.  This must remain at the end
 * of the file.
 * ---------------------------------------------------------------------------
 * Local variables:
 * c-file-style: "linux"
 * End:
 */