signal.c 8.2 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
/*
 *  linux/arch/m32r/kernel/signal.c
 *
 *  Copyright (c) 2003  Hitoshi Yamamoto
 *
 *  Taken from i386 version.
 *  Copyright (C) 1991, 1992  Linus Torvalds
 *
 *  1997-11-28  Modified for POSIX.1b signals by Richard Henderson
 *  2000-06-20  Pentium III FXSR, SSE support by Gareth Hughes
 */

#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/wait.h>
#include <linux/unistd.h>
#include <linux/stddef.h>
#include <linux/personality.h>
23
#include <linux/freezer.h>
24
#include <linux/tracehook.h>
L
Linus Torvalds 已提交
25 26 27 28 29 30 31 32 33
#include <asm/cacheflush.h>
#include <asm/ucontext.h>
#include <asm/uaccess.h>

#define DEBUG_SIG 0

asmlinkage int
sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
		unsigned long r2, unsigned long r3, unsigned long r4,
34
		unsigned long r5, unsigned long r6, struct pt_regs *regs)
L
Linus Torvalds 已提交
35
{
36
	return do_sigaltstack(uss, uoss, regs->spu);
L
Linus Torvalds 已提交
37 38 39 40 41 42 43 44 45 46
}


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

struct rt_sigframe
{
	int sig;
A
Al Viro 已提交
47 48
	struct siginfo __user *pinfo;
	void __user *puc;
L
Linus Torvalds 已提交
49 50 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
	struct siginfo info;
	struct ucontext uc;
//	struct _fpstate fpstate;
};

static int
restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc,
		   int *r0_p)
{
	unsigned int err = 0;

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

#define COPY(x)		err |= __get_user(regs->x, &sc->sc_##x)
	COPY(r4);
	COPY(r5);
	COPY(r6);
	COPY(pt_regs);
	/* COPY(r0); Skip r0 */
	COPY(r1);
	COPY(r2);
	COPY(r3);
	COPY(r7);
	COPY(r8);
	COPY(r9);
	COPY(r10);
	COPY(r11);
	COPY(r12);
	COPY(acc0h);
	COPY(acc0l);
80 81
	COPY(acc1h);		/* ISA_DSP_LEVEL2 only */
	COPY(acc1l);		/* ISA_DSP_LEVEL2 only */
L
Linus Torvalds 已提交
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
	COPY(psw);
	COPY(bpc);
	COPY(bbpsw);
	COPY(bbpc);
	COPY(spu);
	COPY(fp);
	COPY(lr);
	COPY(spi);
#undef COPY

	regs->syscall_nr = -1;	/* disable syscall checks */
	err |= __get_user(*r0_p, &sc->sc_r0);

	return err;
}

asmlinkage int
sys_rt_sigreturn(unsigned long r0, unsigned long r1,
		 unsigned long r2, unsigned long r3, unsigned long r4,
101
		 unsigned long r5, unsigned long r6, struct pt_regs *regs)
L
Linus Torvalds 已提交
102
{
103
	struct rt_sigframe __user *frame = (struct rt_sigframe __user *)regs->spu;
L
Linus Torvalds 已提交
104 105 106 107 108 109 110 111
	sigset_t set;
	int result;

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

112
	set_current_blocked(&set);
L
Linus Torvalds 已提交
113

114
	if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &result))
L
Linus Torvalds 已提交
115 116
		goto badframe;

117
	if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->spu) == -EFAULT)
L
Linus Torvalds 已提交
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
		goto badframe;

	return result;

badframe:
	force_sig(SIGSEGV, current);
	return 0;
}

/*
 * Set up a signal frame.
 */

static int
setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
	         unsigned long mask)
{
	int err = 0;

#define COPY(x)	err |= __put_user(regs->x, &sc->sc_##x)
	COPY(r4);
	COPY(r5);
	COPY(r6);
	COPY(pt_regs);
	COPY(r0);
	COPY(r1);
	COPY(r2);
	COPY(r3);
	COPY(r7);
	COPY(r8);
	COPY(r9);
	COPY(r10);
	COPY(r11);
	COPY(r12);
	COPY(acc0h);
	COPY(acc0l);
154 155
	COPY(acc1h);		/* ISA_DSP_LEVEL2 only */
	COPY(acc1l);		/* ISA_DSP_LEVEL2 only */
L
Linus Torvalds 已提交
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
	COPY(psw);
	COPY(bpc);
	COPY(bbpsw);
	COPY(bbpc);
	COPY(spu);
	COPY(fp);
	COPY(lr);
	COPY(spi);
#undef COPY

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

	return err;
}

/*
 * Determine which stack to use..
 */
static inline void __user *
get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
{
	/* This is the X/Open sanctioned signal stack switching.  */
	if (ka->sa.sa_flags & SA_ONSTACK) {
		if (sas_ss_flags(sp) == 0)
			sp = current->sas_ss_sp + current->sas_ss_size;
	}

	return (void __user *)((sp - frame_size) & -8ul);
}

186
static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
L
Linus Torvalds 已提交
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
			   sigset_t *set, struct pt_regs *regs)
{
	struct rt_sigframe __user *frame;
	int err = 0;
	int signal;

	frame = get_sigframe(ka, regs->spu, sizeof(*frame));

	if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
		goto give_sigsegv;

	signal = current_thread_info()->exec_domain
		&& current_thread_info()->exec_domain->signal_invmap
		&& sig < 32
		? current_thread_info()->exec_domain->signal_invmap[sig]
		: sig;

	err |= __put_user(signal, &frame->sig);
	if (err)
		goto give_sigsegv;

	err |= __put_user(&frame->info, &frame->pinfo);
	err |= __put_user(&frame->uc, &frame->puc);
	err |= copy_siginfo_to_user(&frame->info, info);
	if (err)
		goto give_sigsegv;

	/* Create the ucontext.  */
	err |= __put_user(0, &frame->uc.uc_flags);
	err |= __put_user(0, &frame->uc.uc_link);
	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
	err |= __put_user(sas_ss_flags(regs->spu),
			  &frame->uc.uc_stack.ss_flags);
	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
	err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
	if (err)
		goto give_sigsegv;

	/* Set up to return from userspace.  */
	regs->lr = (unsigned long)ka->sa.sa_restorer;

	/* Set up registers for signal handler */
	regs->spu = (unsigned long)frame;
	regs->r0 = signal;	/* Arg for signal handler */
	regs->r1 = (unsigned long)&frame->info;
	regs->r2 = (unsigned long)&frame->uc;
	regs->bpc = (unsigned long)ka->sa.sa_handler;

	set_fs(USER_DS);

#if DEBUG_SIG
	printk("SIG deliver (%s:%d): sp=%p pc=%p\n",
		current->comm, current->pid, frame, regs->pc);
#endif

243
	return 0;
L
Linus Torvalds 已提交
244 245 246

give_sigsegv:
	force_sigsegv(sig, current);
247
	return -EFAULT;
L
Linus Torvalds 已提交
248 249
}

A
Al Viro 已提交
250 251 252
static int prev_insn(struct pt_regs *regs)
{
	u16 inst;
253
	if (get_user(inst, (u16 __user *)(regs->bpc - 2)))
A
Al Viro 已提交
254 255 256 257 258 259 260 261 262
		return -EFAULT;
	if ((inst & 0xfff0) == 0x10f0)	/* trap ? */
		regs->bpc -= 2;
	else
		regs->bpc -= 4;
	regs->syscall_nr = -1;
	return 0;
}

L
Linus Torvalds 已提交
263 264 265 266
/*
 * OK, we're invoking a handler
 */

267
static void
L
Linus Torvalds 已提交
268
handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
A
Al Viro 已提交
269
	      struct pt_regs *regs)
L
Linus Torvalds 已提交
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
{
	/* Are we from a system call? */
	if (regs->syscall_nr >= 0) {
		/* If so, check system call restarting.. */
		switch (regs->r0) {
		        case -ERESTART_RESTARTBLOCK:
			case -ERESTARTNOHAND:
				regs->r0 = -EINTR;
				break;

			case -ERESTARTSYS:
				if (!(ka->sa.sa_flags & SA_RESTART)) {
					regs->r0 = -EINTR;
					break;
				}
			/* fallthrough */
			case -ERESTARTNOINTR:
				regs->r0 = regs->orig_r0;
A
Al Viro 已提交
288
				if (prev_insn(regs) < 0)
289
					return;
L
Linus Torvalds 已提交
290 291 292 293
		}
	}

	/* Set up the stack frame */
A
Al Viro 已提交
294
	if (setup_rt_frame(sig, ka, info, sigmask_to_save(), regs))
295
		return;
L
Linus Torvalds 已提交
296

A
Al Viro 已提交
297
	signal_delivered(sig, info, ka, regs, 0);
L
Linus Torvalds 已提交
298 299 300 301 302 303 304
}

/*
 * Note that 'init' is a special process: it doesn't get signals it doesn't
 * want to handle. Thus you cannot kill init even with a SIGKILL even by
 * mistake.
 */
305
static void do_signal(struct pt_regs *regs)
L
Linus Torvalds 已提交
306 307 308 309 310 311 312 313 314 315 316 317
{
	siginfo_t info;
	int signr;
	struct k_sigaction ka;

	/*
	 * We want the common case to go fast, which
	 * is why we may in certain cases get here from
	 * kernel mode. Just return without doing anything
	 * if so.
	 */
	if (!user_mode(regs))
318
		return;
L
Linus Torvalds 已提交
319 320 321

	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
	if (signr > 0) {
S
Simon Arlott 已提交
322
		/* Re-enable any watchpoints before delivering the
L
Linus Torvalds 已提交
323 324 325 326 327 328
		 * signal to user space. The processor register will
		 * have been cleared if the watchpoint triggered
		 * inside the kernel.
		 */

		/* Whee!  Actually deliver the signal.  */
329
		handle_signal(signr, &ka, &info, regs);
330 331

		return;
L
Linus Torvalds 已提交
332 333 334 335 336 337 338 339 340
	}

	/* Did we come from a system call? */
	if (regs->syscall_nr >= 0) {
		/* Restart the system call - no handlers present */
		if (regs->r0 == -ERESTARTNOHAND ||
		    regs->r0 == -ERESTARTSYS ||
		    regs->r0 == -ERESTARTNOINTR) {
			regs->r0 = regs->orig_r0;
A
Al Viro 已提交
341
			prev_insn(regs);
342
		} else if (regs->r0 == -ERESTART_RESTARTBLOCK){
L
Linus Torvalds 已提交
343 344
			regs->r0 = regs->orig_r0;
			regs->r7 = __NR_restart_syscall;
A
Al Viro 已提交
345
			prev_insn(regs);
L
Linus Torvalds 已提交
346 347
		}
	}
A
Al Viro 已提交
348
	restore_saved_sigmask();
L
Linus Torvalds 已提交
349 350 351 352 353 354
}

/*
 * notification of userspace execution resumption
 * - triggered by current->work.notify_resume
 */
A
Al Viro 已提交
355
void do_notify_resume(struct pt_regs *regs, __u32 thread_info_flags)
L
Linus Torvalds 已提交
356 357 358 359 360 361 362
{
	/* Pending single-step? */
	if (thread_info_flags & _TIF_SINGLESTEP)
		clear_thread_flag(TIF_SINGLESTEP);

	/* deal with pending signal delivery */
	if (thread_info_flags & _TIF_SIGPENDING)
A
Al Viro 已提交
363
		do_signal(regs);
L
Linus Torvalds 已提交
364

365 366 367 368
	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
		clear_thread_flag(TIF_NOTIFY_RESUME);
		tracehook_notify_resume(regs);
	}
L
Linus Torvalds 已提交
369
}