signal.c 16.6 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 *  linux/arch/arm/kernel/signal.c
 *
4
 *  Copyright (C) 1995-2009 Russell King
L
Linus Torvalds 已提交
5 6 7 8 9 10
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */
#include <linux/errno.h>
11
#include <linux/random.h>
L
Linus Torvalds 已提交
12 13
#include <linux/signal.h>
#include <linux/personality.h>
14
#include <linux/uaccess.h>
15
#include <linux/tracehook.h>
D
David A. Long 已提交
16
#include <linux/uprobes.h>
L
Linus Torvalds 已提交
17

18
#include <asm/elf.h>
L
Linus Torvalds 已提交
19
#include <asm/cacheflush.h>
20
#include <asm/traps.h>
L
Linus Torvalds 已提交
21 22
#include <asm/ucontext.h>
#include <asm/unistd.h>
23
#include <asm/vfp.h>
L
Linus Torvalds 已提交
24

25
extern const unsigned long sigreturn_codes[7];
L
Linus Torvalds 已提交
26

27 28
static unsigned long signal_return_offset;

29
#ifdef CONFIG_CRUNCH
30
static int preserve_crunch_context(struct crunch_sigframe __user *frame)
31 32 33 34 35 36 37 38 39 40 41 42
{
	char kbuf[sizeof(*frame) + 8];
	struct crunch_sigframe *kframe;

	/* the crunch context must be 64 bit aligned */
	kframe = (struct crunch_sigframe *)((unsigned long)(kbuf + 8) & ~7);
	kframe->magic = CRUNCH_MAGIC;
	kframe->size = CRUNCH_STORAGE_SIZE;
	crunch_task_copy(current_thread_info(), &kframe->storage);
	return __copy_to_user(frame, kframe, sizeof(*frame));
}

43
static int restore_crunch_context(struct crunch_sigframe __user *frame)
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
{
	char kbuf[sizeof(*frame) + 8];
	struct crunch_sigframe *kframe;

	/* the crunch context must be 64 bit aligned */
	kframe = (struct crunch_sigframe *)((unsigned long)(kbuf + 8) & ~7);
	if (__copy_from_user(kframe, frame, sizeof(*frame)))
		return -1;
	if (kframe->magic != CRUNCH_MAGIC ||
	    kframe->size != CRUNCH_STORAGE_SIZE)
		return -1;
	crunch_task_restore(current_thread_info(), &kframe->storage);
	return 0;
}
#endif

L
Linus Torvalds 已提交
60 61 62 63
#ifdef CONFIG_IWMMXT

static int preserve_iwmmxt_context(struct iwmmxt_sigframe *frame)
{
64 65
	char kbuf[sizeof(*frame) + 8];
	struct iwmmxt_sigframe *kframe;
L
Linus Torvalds 已提交
66 67

	/* the iWMMXt context must be 64 bit aligned */
68
	kframe = (struct iwmmxt_sigframe *)((unsigned long)(kbuf + 8) & ~7);
69 70
	kframe->magic = IWMMXT_MAGIC;
	kframe->size = IWMMXT_STORAGE_SIZE;
71 72
	iwmmxt_task_copy(current_thread_info(), &kframe->storage);
	return __copy_to_user(frame, kframe, sizeof(*frame));
L
Linus Torvalds 已提交
73 74 75 76
}

static int restore_iwmmxt_context(struct iwmmxt_sigframe *frame)
{
77 78 79 80 81 82 83
	char kbuf[sizeof(*frame) + 8];
	struct iwmmxt_sigframe *kframe;

	/* the iWMMXt context must be 64 bit aligned */
	kframe = (struct iwmmxt_sigframe *)((unsigned long)(kbuf + 8) & ~7);
	if (__copy_from_user(kframe, frame, sizeof(*frame)))
		return -1;
84 85
	if (kframe->magic != IWMMXT_MAGIC ||
	    kframe->size != IWMMXT_STORAGE_SIZE)
86 87 88
		return -1;
	iwmmxt_task_restore(current_thread_info(), &kframe->storage);
	return 0;
L
Linus Torvalds 已提交
89 90 91 92
}

#endif

93 94 95 96 97 98 99 100 101 102 103
#ifdef CONFIG_VFP

static int preserve_vfp_context(struct vfp_sigframe __user *frame)
{
	const unsigned long magic = VFP_MAGIC;
	const unsigned long size = VFP_STORAGE_SIZE;
	int err = 0;

	__put_user_error(magic, &frame->magic, err);
	__put_user_error(size, &frame->size, err);

104 105 106 107
	if (err)
		return -EFAULT;

	return vfp_preserve_user_clear_hwstate(&frame->ufp, &frame->ufp_exc);
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
}

static int restore_vfp_context(struct vfp_sigframe __user *frame)
{
	unsigned long magic;
	unsigned long size;
	int err = 0;

	__get_user_error(magic, &frame->magic, err);
	__get_user_error(size, &frame->size, err);

	if (err)
		return -EFAULT;
	if (magic != VFP_MAGIC || size != VFP_STORAGE_SIZE)
		return -EINVAL;

124
	return vfp_restore_user_hwstate(&frame->ufp, &frame->ufp_exc);
125 126 127 128
}

#endif

L
Linus Torvalds 已提交
129 130 131 132
/*
 * Do a signal return; undo the signal stack.  These are aligned to 64-bit.
 */
struct sigframe {
133
	struct ucontext uc;
134
	unsigned long retcode[2];
L
Linus Torvalds 已提交
135 136 137 138
};

struct rt_sigframe {
	struct siginfo info;
139
	struct sigframe sig;
L
Linus Torvalds 已提交
140 141
};

142
static int restore_sigframe(struct pt_regs *regs, struct sigframe __user *sf)
L
Linus Torvalds 已提交
143
{
144
	struct aux_sigframe __user *aux;
145 146 147 148
	sigset_t set;
	int err;

	err = __copy_from_user(&set, &sf->uc.uc_sigmask, sizeof(set));
149
	if (err == 0)
150
		set_current_blocked(&set);
L
Linus Torvalds 已提交
151

152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
	__get_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err);
	__get_user_error(regs->ARM_r1, &sf->uc.uc_mcontext.arm_r1, err);
	__get_user_error(regs->ARM_r2, &sf->uc.uc_mcontext.arm_r2, err);
	__get_user_error(regs->ARM_r3, &sf->uc.uc_mcontext.arm_r3, err);
	__get_user_error(regs->ARM_r4, &sf->uc.uc_mcontext.arm_r4, err);
	__get_user_error(regs->ARM_r5, &sf->uc.uc_mcontext.arm_r5, err);
	__get_user_error(regs->ARM_r6, &sf->uc.uc_mcontext.arm_r6, err);
	__get_user_error(regs->ARM_r7, &sf->uc.uc_mcontext.arm_r7, err);
	__get_user_error(regs->ARM_r8, &sf->uc.uc_mcontext.arm_r8, err);
	__get_user_error(regs->ARM_r9, &sf->uc.uc_mcontext.arm_r9, err);
	__get_user_error(regs->ARM_r10, &sf->uc.uc_mcontext.arm_r10, err);
	__get_user_error(regs->ARM_fp, &sf->uc.uc_mcontext.arm_fp, err);
	__get_user_error(regs->ARM_ip, &sf->uc.uc_mcontext.arm_ip, err);
	__get_user_error(regs->ARM_sp, &sf->uc.uc_mcontext.arm_sp, err);
	__get_user_error(regs->ARM_lr, &sf->uc.uc_mcontext.arm_lr, err);
	__get_user_error(regs->ARM_pc, &sf->uc.uc_mcontext.arm_pc, err);
	__get_user_error(regs->ARM_cpsr, &sf->uc.uc_mcontext.arm_cpsr, err);
L
Linus Torvalds 已提交
169 170 171

	err |= !valid_user_regs(regs);

172
	aux = (struct aux_sigframe __user *) sf->uc.uc_regspace;
173 174 175 176
#ifdef CONFIG_CRUNCH
	if (err == 0)
		err |= restore_crunch_context(&aux->crunch);
#endif
L
Linus Torvalds 已提交
177 178 179 180 181
#ifdef CONFIG_IWMMXT
	if (err == 0 && test_thread_flag(TIF_USING_IWMMXT))
		err |= restore_iwmmxt_context(&aux->iwmmxt);
#endif
#ifdef CONFIG_VFP
182 183
	if (err == 0)
		err |= restore_vfp_context(&aux->vfp);
L
Linus Torvalds 已提交
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
#endif

	return err;
}

asmlinkage int sys_sigreturn(struct pt_regs *regs)
{
	struct sigframe __user *frame;

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

	/*
	 * Since we stacked the signal on a 64-bit boundary,
	 * then 'sp' should be word aligned here.  If it's
	 * not, then the user is trying to mess with us.
	 */
	if (regs->ARM_sp & 7)
		goto badframe;

	frame = (struct sigframe __user *)regs->ARM_sp;

	if (!access_ok(VERIFY_READ, frame, sizeof (*frame)))
		goto badframe;

209
	if (restore_sigframe(regs, frame))
L
Linus Torvalds 已提交
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
		goto badframe;

	return regs->ARM_r0;

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

asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
{
	struct rt_sigframe __user *frame;

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

	/*
	 * Since we stacked the signal on a 64-bit boundary,
	 * then 'sp' should be word aligned here.  If it's
	 * not, then the user is trying to mess with us.
	 */
	if (regs->ARM_sp & 7)
		goto badframe;

	frame = (struct rt_sigframe __user *)regs->ARM_sp;

	if (!access_ok(VERIFY_READ, frame, sizeof (*frame)))
		goto badframe;

239
	if (restore_sigframe(regs, &frame->sig))
L
Linus Torvalds 已提交
240 241
		goto badframe;

A
Al Viro 已提交
242
	if (restore_altstack(&frame->sig.uc.uc_stack))
L
Linus Torvalds 已提交
243 244 245 246 247 248 249 250 251 252
		goto badframe;

	return regs->ARM_r0;

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

static int
253
setup_sigframe(struct sigframe __user *sf, struct pt_regs *regs, sigset_t *set)
L
Linus Torvalds 已提交
254
{
255
	struct aux_sigframe __user *aux;
L
Linus Torvalds 已提交
256 257
	int err = 0;

258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281
	__put_user_error(regs->ARM_r0, &sf->uc.uc_mcontext.arm_r0, err);
	__put_user_error(regs->ARM_r1, &sf->uc.uc_mcontext.arm_r1, err);
	__put_user_error(regs->ARM_r2, &sf->uc.uc_mcontext.arm_r2, err);
	__put_user_error(regs->ARM_r3, &sf->uc.uc_mcontext.arm_r3, err);
	__put_user_error(regs->ARM_r4, &sf->uc.uc_mcontext.arm_r4, err);
	__put_user_error(regs->ARM_r5, &sf->uc.uc_mcontext.arm_r5, err);
	__put_user_error(regs->ARM_r6, &sf->uc.uc_mcontext.arm_r6, err);
	__put_user_error(regs->ARM_r7, &sf->uc.uc_mcontext.arm_r7, err);
	__put_user_error(regs->ARM_r8, &sf->uc.uc_mcontext.arm_r8, err);
	__put_user_error(regs->ARM_r9, &sf->uc.uc_mcontext.arm_r9, err);
	__put_user_error(regs->ARM_r10, &sf->uc.uc_mcontext.arm_r10, err);
	__put_user_error(regs->ARM_fp, &sf->uc.uc_mcontext.arm_fp, err);
	__put_user_error(regs->ARM_ip, &sf->uc.uc_mcontext.arm_ip, err);
	__put_user_error(regs->ARM_sp, &sf->uc.uc_mcontext.arm_sp, err);
	__put_user_error(regs->ARM_lr, &sf->uc.uc_mcontext.arm_lr, err);
	__put_user_error(regs->ARM_pc, &sf->uc.uc_mcontext.arm_pc, err);
	__put_user_error(regs->ARM_cpsr, &sf->uc.uc_mcontext.arm_cpsr, err);

	__put_user_error(current->thread.trap_no, &sf->uc.uc_mcontext.trap_no, err);
	__put_user_error(current->thread.error_code, &sf->uc.uc_mcontext.error_code, err);
	__put_user_error(current->thread.address, &sf->uc.uc_mcontext.fault_address, err);
	__put_user_error(set->sig[0], &sf->uc.uc_mcontext.oldmask, err);

	err |= __copy_to_user(&sf->uc.uc_sigmask, set, sizeof(*set));
L
Linus Torvalds 已提交
282

283
	aux = (struct aux_sigframe __user *) sf->uc.uc_regspace;
284 285 286 287
#ifdef CONFIG_CRUNCH
	if (err == 0)
		err |= preserve_crunch_context(&aux->crunch);
#endif
L
Linus Torvalds 已提交
288 289 290 291 292
#ifdef CONFIG_IWMMXT
	if (err == 0 && test_thread_flag(TIF_USING_IWMMXT))
		err |= preserve_iwmmxt_context(&aux->iwmmxt);
#endif
#ifdef CONFIG_VFP
293 294
	if (err == 0)
		err |= preserve_vfp_context(&aux->vfp);
L
Linus Torvalds 已提交
295
#endif
296
	__put_user_error(0, &aux->end_magic, err);
L
Linus Torvalds 已提交
297 298 299 300 301

	return err;
}

static inline void __user *
302
get_sigframe(struct ksignal *ksig, struct pt_regs *regs, int framesize)
L
Linus Torvalds 已提交
303
{
304
	unsigned long sp = sigsp(regs->ARM_sp, ksig);
L
Linus Torvalds 已提交
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320
	void __user *frame;

	/*
	 * ATPCS B01 mandates 8-byte alignment
	 */
	frame = (void __user *)((sp - framesize) & ~7);

	/*
	 * Check that we can actually write to the signal frame.
	 */
	if (!access_ok(VERIFY_WRITE, frame, framesize))
		frame = NULL;

	return frame;
}

321 322 323 324 325 326 327 328 329 330 331
/*
 * translate the signal
 */
static inline int map_sig(int sig)
{
	struct thread_info *thread = current_thread_info();
	if (sig < 32 && thread->exec_domain && thread->exec_domain->signal_invmap)
		sig = thread->exec_domain->signal_invmap[sig];
	return sig;
}

L
Linus Torvalds 已提交
332
static int
333 334
setup_return(struct pt_regs *regs, struct ksignal *ksig,
	     unsigned long __user *rc, void __user *frame)
L
Linus Torvalds 已提交
335
{
336
	unsigned long handler = (unsigned long)ksig->ka.sa.sa_handler;
L
Linus Torvalds 已提交
337 338
	unsigned long retcode;
	int thumb = 0;
339 340 341
	unsigned long cpsr = regs->ARM_cpsr & ~(PSR_f | PSR_E_BIT);

	cpsr |= PSR_ENDSTATE;
L
Linus Torvalds 已提交
342 343 344 345

	/*
	 * Maybe we need to deliver a 32-bit signal to a 26-bit task.
	 */
346
	if (ksig->ka.sa.sa_flags & SA_THIRTYTWO)
L
Linus Torvalds 已提交
347 348 349 350 351 352 353 354 355 356
		cpsr = (cpsr & ~MODE_MASK) | USR_MODE;

#ifdef CONFIG_ARM_THUMB
	if (elf_hwcap & HWCAP_THUMB) {
		/*
		 * The LSB of the handler determines if we're going to
		 * be using THUMB or ARM mode for this signal handler.
		 */
		thumb = handler & 1;

357
#if __LINUX_ARM_ARCH__ >= 7
358 359 360 361 362 363 364
		/*
		 * Clear the If-Then Thumb-2 execution state
		 * ARM spec requires this to be all 000s in ARM mode
		 * Snapdragon S4/Krait misbehaves on a Thumb=>ARM
		 * signal transition without this.
		 */
		cpsr &= ~PSR_IT_MASK;
365
#endif
366 367 368

		if (thumb) {
			cpsr |= PSR_T_BIT;
369
		} else
L
Linus Torvalds 已提交
370 371 372 373
			cpsr &= ~PSR_T_BIT;
	}
#endif

374 375
	if (ksig->ka.sa.sa_flags & SA_RESTORER) {
		retcode = (unsigned long)ksig->ka.sa.sa_restorer;
L
Linus Torvalds 已提交
376
	} else {
377
		unsigned int idx = thumb << 1;
L
Linus Torvalds 已提交
378

379
		if (ksig->ka.sa.sa_flags & SA_SIGINFO)
380
			idx += 3;
L
Linus Torvalds 已提交
381

382 383 384 385
		/*
		 * Put the sigreturn code on the stack no matter which return
		 * mechanism we use in order to remain ABI compliant
		 */
386 387
		if (__put_user(sigreturn_codes[idx],   rc) ||
		    __put_user(sigreturn_codes[idx+1], rc+1))
L
Linus Torvalds 已提交
388 389
			return 1;

390 391
#ifdef CONFIG_MMU
		if (cpsr & MODE32_BIT) {
392 393
			struct mm_struct *mm = current->mm;

394
			/*
395 396 397
			 * 32-bit code can use the signal return page
			 * except when the MPU has protected the vectors
			 * page from PL0
398
			 */
399 400
			retcode = mm->context.sigpage + signal_return_offset +
				  (idx << 2) + thumb;
401 402 403
		} else
#endif
		{
404 405 406 407 408
			/*
			 * Ensure that the instruction cache sees
			 * the return code written onto the stack.
			 */
			flush_icache_range((unsigned long)rc,
409
					   (unsigned long)(rc + 2));
410 411 412

			retcode = ((unsigned long)rc) + thumb;
		}
L
Linus Torvalds 已提交
413 414
	}

415
	regs->ARM_r0 = map_sig(ksig->sig);
L
Linus Torvalds 已提交
416 417 418 419 420 421 422 423 424
	regs->ARM_sp = (unsigned long)frame;
	regs->ARM_lr = retcode;
	regs->ARM_pc = handler;
	regs->ARM_cpsr = cpsr;

	return 0;
}

static int
425
setup_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
L
Linus Torvalds 已提交
426
{
427
	struct sigframe __user *frame = get_sigframe(ksig, regs, sizeof(*frame));
L
Linus Torvalds 已提交
428 429 430 431 432
	int err = 0;

	if (!frame)
		return 1;

433 434 435 436
	/*
	 * Set uc.uc_flags to a value which sc.trap_no would never have.
	 */
	__put_user_error(0x5ac3c35a, &frame->uc.uc_flags, err);
L
Linus Torvalds 已提交
437

438
	err |= setup_sigframe(frame, regs, set);
L
Linus Torvalds 已提交
439
	if (err == 0)
440
		err = setup_return(regs, ksig, frame->retcode, frame);
L
Linus Torvalds 已提交
441 442 443 444 445

	return err;
}

static int
446
setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
L
Linus Torvalds 已提交
447
{
448
	struct rt_sigframe __user *frame = get_sigframe(ksig, regs, sizeof(*frame));
L
Linus Torvalds 已提交
449 450 451 452 453
	int err = 0;

	if (!frame)
		return 1;

454
	err |= copy_siginfo_to_user(&frame->info, &ksig->info);
L
Linus Torvalds 已提交
455

456 457
	__put_user_error(0, &frame->sig.uc.uc_flags, err);
	__put_user_error(NULL, &frame->sig.uc.uc_link, err);
L
Linus Torvalds 已提交
458

A
Al Viro 已提交
459
	err |= __save_altstack(&frame->sig.uc.uc_stack, regs->ARM_sp);
460
	err |= setup_sigframe(&frame->sig, regs, set);
L
Linus Torvalds 已提交
461
	if (err == 0)
462
		err = setup_return(regs, ksig, frame->sig.retcode, frame);
L
Linus Torvalds 已提交
463 464 465 466 467 468 469 470

	if (err == 0) {
		/*
		 * For realtime signals we must also set the second and third
		 * arguments for the signal handler.
		 *   -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06
		 */
		regs->ARM_r1 = (unsigned long)&frame->info;
471
		regs->ARM_r2 = (unsigned long)&frame->sig.uc;
L
Linus Torvalds 已提交
472 473 474 475 476 477 478 479
	}

	return err;
}

/*
 * OK, we're invoking a handler
 */	
480
static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
L
Linus Torvalds 已提交
481
{
A
Al Viro 已提交
482
	sigset_t *oldset = sigmask_to_save();
L
Linus Torvalds 已提交
483 484 485 486 487
	int ret;

	/*
	 * Set up the stack frame
	 */
488 489
	if (ksig->ka.sa.sa_flags & SA_SIGINFO)
		ret = setup_rt_frame(ksig, oldset, regs);
L
Linus Torvalds 已提交
490
	else
491
		ret = setup_frame(ksig, oldset, regs);
L
Linus Torvalds 已提交
492 493 494 495 496 497

	/*
	 * Check that the resulting registers are actually sane.
	 */
	ret |= !valid_user_regs(regs);

498
	signal_setup_done(ret, ksig, 0);
L
Linus Torvalds 已提交
499 500 501 502 503 504 505 506 507 508 509
}

/*
 * 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.
 *
 * Note that we go through the signals twice: once to check the signals that
 * the kernel can handle, and then we build all the user-level signal handling
 * stack-frames in one go after that.
 */
510
static int do_signal(struct pt_regs *regs, int syscall)
L
Linus Torvalds 已提交
511
{
512
	unsigned int retval = 0, continue_addr = 0, restart_addr = 0;
513
	struct ksignal ksig;
514
	int restart = 0;
L
Linus Torvalds 已提交
515

516 517 518 519 520 521 522 523 524 525 526 527 528
	/*
	 * If we were from a system call, check for system call restarting...
	 */
	if (syscall) {
		continue_addr = regs->ARM_pc;
		restart_addr = continue_addr - (thumb_mode(regs) ? 2 : 4);
		retval = regs->ARM_r0;

		/*
		 * Prepare for system call restart.  We do this here so that a
		 * debugger will see the already changed PSW.
		 */
		switch (retval) {
529
		case -ERESTART_RESTARTBLOCK:
530
			restart -= 2;
531 532 533
		case -ERESTARTNOHAND:
		case -ERESTARTSYS:
		case -ERESTARTNOINTR:
534
			restart++;
535 536 537 538 539 540 541 542 543 544
			regs->ARM_r0 = regs->ARM_ORIG_r0;
			regs->ARM_pc = restart_addr;
			break;
		}
	}

	/*
	 * Get the signal to deliver.  When running under ptrace, at this
	 * point the debugger may change all our registers ...
	 */
545 546 547 548 549
	/*
	 * Depending on the signal settings we may need to revert the
	 * decision to restart the system call.  But skip this if a
	 * debugger has chosen to restart at a different PC.
	 */
550 551 552
	if (get_signal(&ksig)) {
		/* handler */
		if (unlikely(restart) && regs->ARM_pc == restart_addr) {
553 554
			if (retval == -ERESTARTNOHAND ||
			    retval == -ERESTART_RESTARTBLOCK
555
			    || (retval == -ERESTARTSYS
556
				&& !(ksig.ka.sa.sa_flags & SA_RESTART))) {
557 558 559 560
				regs->ARM_r0 = -EINTR;
				regs->ARM_pc = continue_addr;
			}
		}
561 562 563 564 565 566 567 568
		handle_signal(&ksig, regs);
	} else {
		/* no handler */
		restore_saved_sigmask();
		if (unlikely(restart) && regs->ARM_pc == restart_addr) {
			regs->ARM_pc = continue_addr;
			return restart;
		}
L
Linus Torvalds 已提交
569
	}
570
	return 0;
L
Linus Torvalds 已提交
571 572
}

573
asmlinkage int
574
do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
L
Linus Torvalds 已提交
575
{
576 577 578 579 580
	do {
		if (likely(thread_flags & _TIF_NEED_RESCHED)) {
			schedule();
		} else {
			if (unlikely(!user_mode(regs)))
581
				return 0;
582 583
			local_irq_enable();
			if (thread_flags & _TIF_SIGPENDING) {
584 585
				int restart = do_signal(regs, syscall);
				if (unlikely(restart)) {
586 587 588 589 590
					/*
					 * Restart without handlers.
					 * Deal with it without leaving
					 * the kernel space.
					 */
591
					return restart;
592
				}
593
				syscall = 0;
D
David A. Long 已提交
594 595
			} else if (thread_flags & _TIF_UPROBE) {
				uprobe_notify_resume(regs);
596 597 598 599 600 601 602 603
			} else {
				clear_thread_flag(TIF_NOTIFY_RESUME);
				tracehook_notify_resume(regs);
			}
		}
		local_irq_disable();
		thread_flags = current_thread_info()->flags;
	} while (thread_flags & _TIF_WORK_MASK);
604
	return 0;
L
Linus Torvalds 已提交
605
}
606 607 608

struct page *get_signal_page(void)
{
609 610 611 612
	unsigned long ptr;
	unsigned offset;
	struct page *page;
	void *addr;
613

614
	page = alloc_pages(GFP_KERNEL, 0);
615

616 617
	if (!page)
		return NULL;
618

619
	addr = page_address(page);
620

621 622 623
	/* Give the signal return code some randomness */
	offset = 0x200 + (get_random_int() & 0x7fc);
	signal_return_offset = offset;
624

625 626 627 628 629
	/*
	 * Copy signal return handlers into the vector page, and
	 * set sigreturn to be a pointer to these.
	 */
	memcpy(addr + offset, sigreturn_codes, sizeof(sigreturn_codes));
630

631 632
	ptr = (unsigned long)addr + offset;
	flush_icache_range(ptr, ptr + sizeof(sigreturn_codes));
633

634
	return page;
635
}