Blame view

arch/mips/kernel/signal.c 18.1 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
  /*
   * This file is subject to the terms and conditions of the GNU General Public
   * License.  See the file "COPYING" in the main directory of this archive
   * for more details.
   *
   * Copyright (C) 1991, 1992  Linus Torvalds
   * Copyright (C) 1994 - 2000  Ralf Baechle
   * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
   */
02416dcf5   Ralf Baechle   Redo RM9000 worka...
10
  #include <linux/cache.h>
1f717929e   Ralf Baechle   MIPS: Handle __pu...
11
  #include <linux/irqflags.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
15
  #include <linux/sched.h>
  #include <linux/mm.h>
  #include <linux/personality.h>
  #include <linux/smp.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
18
19
20
21
22
  #include <linux/kernel.h>
  #include <linux/signal.h>
  #include <linux/errno.h>
  #include <linux/wait.h>
  #include <linux/ptrace.h>
  #include <linux/unistd.h>
  #include <linux/compiler.h>
dbda6ac08   Ralf Baechle   MIPS: CVE-2009-00...
23
  #include <linux/syscalls.h>
faea62346   Atsushi Nemoto   [MIPS] Retry {sav...
24
  #include <linux/uaccess.h>
733e5e4b4   David Howells   KEYS: Add missing...
25
  #include <linux/tracehook.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26

e50c0a8fa   Ralf Baechle   Support the MIPS3...
27
  #include <asm/abi.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
31
32
  #include <asm/asm.h>
  #include <linux/bitops.h>
  #include <asm/cacheflush.h>
  #include <asm/fpu.h>
  #include <asm/sim.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
  #include <asm/ucontext.h>
  #include <asm/cpu-features.h>
02416dcf5   Ralf Baechle   Redo RM9000 worka...
35
  #include <asm/war.h>
d814c28ce   David Daney   MIPS: Move signal...
36
  #include <asm/vdso.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
  
  #include "signal-common.h"
137f6f3e2   Ralf Baechle   MIPS: Cleanup sig...
39
40
41
42
43
44
45
46
  static int (*save_fp_context)(struct sigcontext __user *sc);
  static int (*restore_fp_context)(struct sigcontext __user *sc);
  
  extern asmlinkage int _save_fp_context(struct sigcontext __user *sc);
  extern asmlinkage int _restore_fp_context(struct sigcontext __user *sc);
  
  extern asmlinkage int fpu_emulator_save_context(struct sigcontext __user *sc);
  extern asmlinkage int fpu_emulator_restore_context(struct sigcontext __user *sc);
666805834   Ralf Baechle   [MIPS] signal: Mo...
47
48
  struct sigframe {
  	u32 sf_ass[4];		/* argument save space for o32 */
d814c28ce   David Daney   MIPS: Move signal...
49
  	u32 sf_pad[2];		/* Was: signal trampoline */
666805834   Ralf Baechle   [MIPS] signal: Mo...
50
51
52
  	struct sigcontext sf_sc;
  	sigset_t sf_mask;
  };
c0b9bae9d   Franck Bui-Huu   [MIPS] signal: cl...
53
54
  struct rt_sigframe {
  	u32 rs_ass[4];		/* argument save space for o32 */
d814c28ce   David Daney   MIPS: Move signal...
55
  	u32 rs_pad[2];		/* Was: signal trampoline */
c0b9bae9d   Franck Bui-Huu   [MIPS] signal: cl...
56
57
58
  	struct siginfo rs_info;
  	struct ucontext rs_uc;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
  /*
c3fc4ab36   Franck Bui-Huu   [MIPS] signal: do...
60
61
   * Helper routines
   */
faea62346   Atsushi Nemoto   [MIPS] Retry {sav...
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
  static int protected_save_fp_context(struct sigcontext __user *sc)
  {
  	int err;
  	while (1) {
  		lock_fpu_owner();
  		own_fpu_inatomic(1);
  		err = save_fp_context(sc); /* this might fail */
  		unlock_fpu_owner();
  		if (likely(!err))
  			break;
  		/* touch the sigcontext and try again */
  		err = __put_user(0, &sc->sc_fpregs[0]) |
  			__put_user(0, &sc->sc_fpregs[31]) |
  			__put_user(0, &sc->sc_fpc_csr);
  		if (err)
  			break;	/* really bad sigcontext */
  	}
  	return err;
  }
  
  static int protected_restore_fp_context(struct sigcontext __user *sc)
  {
c726b8221   David Daney   MIPS: Fix GCC-4.6...
84
  	int err, tmp __maybe_unused;
faea62346   Atsushi Nemoto   [MIPS] Retry {sav...
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
  	while (1) {
  		lock_fpu_owner();
  		own_fpu_inatomic(0);
  		err = restore_fp_context(sc); /* this might fail */
  		unlock_fpu_owner();
  		if (likely(!err))
  			break;
  		/* touch the sigcontext and try again */
  		err = __get_user(tmp, &sc->sc_fpregs[0]) |
  			__get_user(tmp, &sc->sc_fpregs[31]) |
  			__get_user(tmp, &sc->sc_fpc_csr);
  		if (err)
  			break;	/* really bad sigcontext */
  	}
  	return err;
  }
c3fc4ab36   Franck Bui-Huu   [MIPS] signal: do...
101
102
103
104
  int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
  {
  	int err = 0;
  	int i;
53dc80287   Atsushi Nemoto   [MIPS] FPU owners...
105
  	unsigned int used_math;
c3fc4ab36   Franck Bui-Huu   [MIPS] signal: do...
106
107
108
109
110
111
  
  	err |= __put_user(regs->cp0_epc, &sc->sc_pc);
  
  	err |= __put_user(0, &sc->sc_regs[0]);
  	for (i = 1; i < 32; i++)
  		err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
9693a8537   Franck Bui-Huu   [MIPS] Add basic ...
112
113
114
  #ifdef CONFIG_CPU_HAS_SMARTMIPS
  	err |= __put_user(regs->acx, &sc->sc_acx);
  #endif
c3fc4ab36   Franck Bui-Huu   [MIPS] signal: do...
115
116
117
118
119
120
121
122
123
124
125
  	err |= __put_user(regs->hi, &sc->sc_mdhi);
  	err |= __put_user(regs->lo, &sc->sc_mdlo);
  	if (cpu_has_dsp) {
  		err |= __put_user(mfhi1(), &sc->sc_hi1);
  		err |= __put_user(mflo1(), &sc->sc_lo1);
  		err |= __put_user(mfhi2(), &sc->sc_hi2);
  		err |= __put_user(mflo2(), &sc->sc_lo2);
  		err |= __put_user(mfhi3(), &sc->sc_hi3);
  		err |= __put_user(mflo3(), &sc->sc_lo3);
  		err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
  	}
53dc80287   Atsushi Nemoto   [MIPS] FPU owners...
126
127
  	used_math = !!used_math();
  	err |= __put_user(used_math, &sc->sc_used_math);
c3fc4ab36   Franck Bui-Huu   [MIPS] signal: do...
128

53dc80287   Atsushi Nemoto   [MIPS] FPU owners...
129
  	if (used_math) {
c3fc4ab36   Franck Bui-Huu   [MIPS] signal: do...
130
131
132
133
  		/*
  		 * Save FPU state to signal context. Signal handler
  		 * will "inherit" current FPU state.
  		 */
faea62346   Atsushi Nemoto   [MIPS] Retry {sav...
134
  		err |= protected_save_fp_context(sc);
c3fc4ab36   Franck Bui-Huu   [MIPS] signal: do...
135
136
137
  	}
  	return err;
  }
c6a2f4679   Atsushi Nemoto   [MIPS] Check FCSR...
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
  int fpcsr_pending(unsigned int __user *fpcsr)
  {
  	int err, sig = 0;
  	unsigned int csr, enabled;
  
  	err = __get_user(csr, fpcsr);
  	enabled = FPU_CSR_UNI_X | ((csr & FPU_CSR_ALL_E) << 5);
  	/*
  	 * If the signal handler set some FPU exceptions, clear it and
  	 * send SIGFPE.
  	 */
  	if (csr & enabled) {
  		csr &= ~enabled;
  		err |= __put_user(csr, fpcsr);
  		sig = SIGFPE;
  	}
  	return err ?: sig;
  }
  
  static int
  check_and_restore_fp_context(struct sigcontext __user *sc)
  {
  	int err, sig;
  
  	err = sig = fpcsr_pending(&sc->sc_fpc_csr);
  	if (err > 0)
  		err = 0;
faea62346   Atsushi Nemoto   [MIPS] Retry {sav...
165
  	err |= protected_restore_fp_context(sc);
c6a2f4679   Atsushi Nemoto   [MIPS] Check FCSR...
166
167
  	return err ?: sig;
  }
c3fc4ab36   Franck Bui-Huu   [MIPS] signal: do...
168
169
170
171
172
173
174
175
176
177
178
  int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
  {
  	unsigned int used_math;
  	unsigned long treg;
  	int err = 0;
  	int i;
  
  	/* Always make any pending restarted system calls return -EINTR */
  	current_thread_info()->restart_block.fn = do_no_restart_syscall;
  
  	err |= __get_user(regs->cp0_epc, &sc->sc_pc);
9693a8537   Franck Bui-Huu   [MIPS] Add basic ...
179
180
181
182
  
  #ifdef CONFIG_CPU_HAS_SMARTMIPS
  	err |= __get_user(regs->acx, &sc->sc_acx);
  #endif
c3fc4ab36   Franck Bui-Huu   [MIPS] signal: do...
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
  	err |= __get_user(regs->hi, &sc->sc_mdhi);
  	err |= __get_user(regs->lo, &sc->sc_mdlo);
  	if (cpu_has_dsp) {
  		err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
  		err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
  		err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
  		err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
  		err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
  		err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
  		err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
  	}
  
  	for (i = 1; i < 32; i++)
  		err |= __get_user(regs->regs[i], &sc->sc_regs[i]);
  
  	err |= __get_user(used_math, &sc->sc_used_math);
  	conditional_used_math(used_math);
53dc80287   Atsushi Nemoto   [MIPS] FPU owners...
200
  	if (used_math) {
c3fc4ab36   Franck Bui-Huu   [MIPS] signal: do...
201
  		/* restore fpu context if we have used it before */
c6a2f4679   Atsushi Nemoto   [MIPS] Check FCSR...
202
203
  		if (!err)
  			err = check_and_restore_fp_context(sc);
c3fc4ab36   Franck Bui-Huu   [MIPS] signal: do...
204
205
  	} else {
  		/* signal handler may have used FPU.  Give it up. */
53dc80287   Atsushi Nemoto   [MIPS] FPU owners...
206
  		lose_fpu(0);
c3fc4ab36   Franck Bui-Huu   [MIPS] signal: do...
207
  	}
c3fc4ab36   Franck Bui-Huu   [MIPS] signal: do...
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
  	return err;
  }
  
  void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs,
  			  size_t frame_size)
  {
  	unsigned long sp;
  
  	/* Default to using normal stack */
  	sp = regs->regs[29];
  
  	/*
  	 * FPU emulator may have it's own trampoline active just
  	 * above the user stack, 16-bytes before the next lowest
  	 * 16 byte boundary.  Try to avoid trashing it.
  	 */
  	sp -= 32;
  
  	/* This is the X/Open sanctioned signal stack switching.  */
  	if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0))
  		sp = current->sas_ss_sp + current->sas_ss_size;
  
  	return (void __user *)((sp - frame_size) & (ICACHE_REFILLS_WORKAROUND_WAR ? ~(cpu_icache_line_size()-1) : ALMASK));
  }
c3fc4ab36   Franck Bui-Huu   [MIPS] signal: do...
232
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
234
235
236
   * Atomically swap in the new signal mask, and wait for a signal.
   */
  
  #ifdef CONFIG_TRAD_SIGNALS
f90080a05   Franck Bui-Huu   [MIPS] signal: do...
237
  asmlinkage int sys_sigsuspend(nabi_no_regargs struct pt_regs regs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238
  {
7b3e2fc84   Ralf Baechle   [MIPS] Add suppor...
239
  	sigset_t newset;
fe00f943e   Ralf Baechle   Sparseify MIPS.
240
  	sigset_t __user *uset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241

fe00f943e   Ralf Baechle   Sparseify MIPS.
242
  	uset = (sigset_t __user *) regs.regs[4];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
244
245
246
247
  	if (copy_from_user(&newset, uset, sizeof(sigset_t)))
  		return -EFAULT;
  	sigdelsetmask(&newset, ~_BLOCKABLE);
  
  	spin_lock_irq(&current->sighand->siglock);
7b3e2fc84   Ralf Baechle   [MIPS] Add suppor...
248
  	current->saved_sigmask = current->blocked;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
249
250
251
  	current->blocked = newset;
  	recalc_sigpending();
  	spin_unlock_irq(&current->sighand->siglock);
7b3e2fc84   Ralf Baechle   [MIPS] Add suppor...
252
253
254
255
  	current->state = TASK_INTERRUPTIBLE;
  	schedule();
  	set_thread_flag(TIF_RESTORE_SIGMASK);
  	return -ERESTARTNOHAND;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
  }
  #endif
f90080a05   Franck Bui-Huu   [MIPS] signal: do...
258
  asmlinkage int sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
  {
7b3e2fc84   Ralf Baechle   [MIPS] Add suppor...
260
  	sigset_t newset;
fe00f943e   Ralf Baechle   Sparseify MIPS.
261
  	sigset_t __user *unewset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
262
263
264
265
266
267
  	size_t sigsetsize;
  
  	/* XXX Don't preclude handling different sized sigset_t's.  */
  	sigsetsize = regs.regs[5];
  	if (sigsetsize != sizeof(sigset_t))
  		return -EINVAL;
fe00f943e   Ralf Baechle   Sparseify MIPS.
268
  	unewset = (sigset_t __user *) regs.regs[4];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
269
270
271
272
273
  	if (copy_from_user(&newset, unewset, sizeof(newset)))
  		return -EFAULT;
  	sigdelsetmask(&newset, ~_BLOCKABLE);
  
  	spin_lock_irq(&current->sighand->siglock);
7b3e2fc84   Ralf Baechle   [MIPS] Add suppor...
274
  	current->saved_sigmask = current->blocked;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275
  	current->blocked = newset;
e0daad449   Ralf Baechle   [MIPS] Whitespace...
276
  	recalc_sigpending();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
  	spin_unlock_irq(&current->sighand->siglock);
7b3e2fc84   Ralf Baechle   [MIPS] Add suppor...
278
279
280
281
  	current->state = TASK_INTERRUPTIBLE;
  	schedule();
  	set_thread_flag(TIF_RESTORE_SIGMASK);
  	return -ERESTARTNOHAND;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
284
  }
  
  #ifdef CONFIG_TRAD_SIGNALS
dbda6ac08   Ralf Baechle   MIPS: CVE-2009-00...
285
286
  SYSCALL_DEFINE3(sigaction, int, sig, const struct sigaction __user *, act,
  	struct sigaction __user *, oact)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
  {
  	struct k_sigaction new_ka, old_ka;
  	int ret;
  	int err = 0;
  
  	if (act) {
  		old_sigset_t mask;
  
  		if (!access_ok(VERIFY_READ, act, sizeof(*act)))
  			return -EFAULT;
  		err |= __get_user(new_ka.sa.sa_handler, &act->sa_handler);
  		err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags);
  		err |= __get_user(mask, &act->sa_mask.sig[0]);
  		if (err)
  			return -EFAULT;
  
  		siginitset(&new_ka.sa.sa_mask, mask);
  	}
  
  	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
  
  	if (!ret && oact) {
  		if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
e0daad449   Ralf Baechle   [MIPS] Whitespace...
310
  			return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
  		err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
  		err |= __put_user(old_ka.sa.sa_handler, &oact->sa_handler);
  		err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
  		err |= __put_user(0, &oact->sa_mask.sig[1]);
  		err |= __put_user(0, &oact->sa_mask.sig[2]);
  		err |= __put_user(0, &oact->sa_mask.sig[3]);
  		if (err)
  			return -EFAULT;
  	}
  
  	return ret;
  }
  #endif
  
  asmlinkage int sys_sigaltstack(nabi_no_regargs struct pt_regs regs)
  {
fe00f943e   Ralf Baechle   Sparseify MIPS.
327
328
  	const stack_t __user *uss = (const stack_t __user *) regs.regs[4];
  	stack_t __user *uoss = (stack_t __user *) regs.regs[5];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
329
330
331
332
  	unsigned long usp = regs.regs[29];
  
  	return do_sigaltstack(uss, uoss, usp);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
333
  #ifdef CONFIG_TRAD_SIGNALS
f90080a05   Franck Bui-Huu   [MIPS] signal: do...
334
  asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
335
  {
9bbf28a36   Atsushi Nemoto   [MIPS] Sparse: Ad...
336
  	struct sigframe __user *frame;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
  	sigset_t blocked;
c6a2f4679   Atsushi Nemoto   [MIPS] Check FCSR...
338
  	int sig;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339

9bbf28a36   Atsushi Nemoto   [MIPS] Sparse: Ad...
340
  	frame = (struct sigframe __user *) regs.regs[29];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
342
343
344
345
346
347
348
349
350
  	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
  		goto badframe;
  	if (__copy_from_user(&blocked, &frame->sf_mask, sizeof(blocked)))
  		goto badframe;
  
  	sigdelsetmask(&blocked, ~_BLOCKABLE);
  	spin_lock_irq(&current->sighand->siglock);
  	current->blocked = blocked;
  	recalc_sigpending();
  	spin_unlock_irq(&current->sighand->siglock);
c6a2f4679   Atsushi Nemoto   [MIPS] Check FCSR...
351
352
  	sig = restore_sigcontext(&regs, &frame->sf_sc);
  	if (sig < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
  		goto badframe;
c6a2f4679   Atsushi Nemoto   [MIPS] Check FCSR...
354
355
  	else if (sig)
  		force_sig(sig, current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356
357
358
359
  
  	/*
  	 * Don't let your children do this ...
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
361
362
363
364
365
366
367
368
369
370
  	__asm__ __volatile__(
  		"move\t$29, %0
  \t"
  		"j\tsyscall_exit"
  		:/* no outputs */
  		:"r" (&regs));
  	/* Unreached */
  
  badframe:
  	force_sig(SIGSEGV, current);
  }
e50c0a8fa   Ralf Baechle   Support the MIPS3...
371
  #endif /* CONFIG_TRAD_SIGNALS */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372

f90080a05   Franck Bui-Huu   [MIPS] signal: do...
373
  asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
374
  {
9bbf28a36   Atsushi Nemoto   [MIPS] Sparse: Ad...
375
  	struct rt_sigframe __user *frame;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
  	sigset_t set;
c6a2f4679   Atsushi Nemoto   [MIPS] Check FCSR...
377
  	int sig;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
378

9bbf28a36   Atsushi Nemoto   [MIPS] Sparse: Ad...
379
  	frame = (struct rt_sigframe __user *) regs.regs[29];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
382
383
384
385
386
387
388
389
  	if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
  		goto badframe;
  	if (__copy_from_user(&set, &frame->rs_uc.uc_sigmask, sizeof(set)))
  		goto badframe;
  
  	sigdelsetmask(&set, ~_BLOCKABLE);
  	spin_lock_irq(&current->sighand->siglock);
  	current->blocked = set;
  	recalc_sigpending();
  	spin_unlock_irq(&current->sighand->siglock);
c6a2f4679   Atsushi Nemoto   [MIPS] Check FCSR...
390
391
  	sig = restore_sigcontext(&regs, &frame->rs_uc.uc_mcontext);
  	if (sig < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
  		goto badframe;
c6a2f4679   Atsushi Nemoto   [MIPS] Check FCSR...
393
394
  	else if (sig)
  		force_sig(sig, current);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
397
  	/* It is more difficult to avoid calling this function than to
  	   call it and ignore errors.  */
4bfb8c5c8   Al Viro   MIPS: do_sigaltst...
398
  	do_sigaltstack(&frame->rs_uc.uc_stack, NULL, regs.regs[29]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
  
  	/*
  	 * Don't let your children do this ...
  	 */
  	__asm__ __volatile__(
  		"move\t$29, %0
  \t"
  		"j\tsyscall_exit"
  		:/* no outputs */
  		:"r" (&regs));
  	/* Unreached */
  
  badframe:
  	force_sig(SIGSEGV, current);
  }
  
  #ifdef CONFIG_TRAD_SIGNALS
d814c28ce   David Daney   MIPS: Move signal...
416
417
  static int setup_frame(void *sig_return, struct k_sigaction *ka,
  		       struct pt_regs *regs, int signr, sigset_t *set)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
418
  {
9bbf28a36   Atsushi Nemoto   [MIPS] Sparse: Ad...
419
  	struct sigframe __user *frame;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
422
423
424
  	int err = 0;
  
  	frame = get_sigframe(ka, regs, sizeof(*frame));
  	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
  		goto give_sigsegv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
  	err |= setup_sigcontext(regs, &frame->sf_sc);
  	err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set));
  	if (err)
  		goto give_sigsegv;
  
  	/*
  	 * Arguments to signal handler:
  	 *
  	 *   a0 = signal number
  	 *   a1 = 0 (should be cause)
  	 *   a2 = pointer to struct sigcontext
  	 *
  	 * $25 and c0_epc point to the signal handler, $29 points to the
  	 * struct sigframe.
  	 */
  	regs->regs[ 4] = signr;
  	regs->regs[ 5] = 0;
  	regs->regs[ 6] = (unsigned long) &frame->sf_sc;
  	regs->regs[29] = (unsigned long) frame;
d814c28ce   David Daney   MIPS: Move signal...
444
  	regs->regs[31] = (unsigned long) sig_return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
  	regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
722bb63de   Franck Bui-Huu   [MIPS] signal: fa...
446
447
  	DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
448
  	       current->comm, current->pid,
722bb63de   Franck Bui-Huu   [MIPS] signal: fa...
449
  	       frame, regs->cp0_epc, regs->regs[31]);
e0daad449   Ralf Baechle   [MIPS] Whitespace...
450
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
452
453
  
  give_sigsegv:
  	force_sigsegv(signr, current);
7b3e2fc84   Ralf Baechle   [MIPS] Add suppor...
454
  	return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
456
  }
  #endif
d814c28ce   David Daney   MIPS: Move signal...
457
458
459
  static int setup_rt_frame(void *sig_return, struct k_sigaction *ka,
  			  struct pt_regs *regs,	int signr, sigset_t *set,
  			  siginfo_t *info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
460
  {
9bbf28a36   Atsushi Nemoto   [MIPS] Sparse: Ad...
461
  	struct rt_sigframe __user *frame;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
462
463
464
465
466
  	int err = 0;
  
  	frame = get_sigframe(ka, regs, sizeof(*frame));
  	if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
  		goto give_sigsegv;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
467
468
469
470
471
  	/* Create siginfo.  */
  	err |= copy_siginfo_to_user(&frame->rs_info, info);
  
  	/* Create the ucontext.  */
  	err |= __put_user(0, &frame->rs_uc.uc_flags);
5665a0ac5   Atsushi Nemoto   [MIPS] Fix minor ...
472
  	err |= __put_user(NULL, &frame->rs_uc.uc_link);
9c6031cc9   Atsushi Nemoto   [MIPS] Signal cle...
473
  	err |= __put_user((void __user *)current->sas_ss_sp,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
  	                  &frame->rs_uc.uc_stack.ss_sp);
  	err |= __put_user(sas_ss_flags(regs->regs[29]),
  	                  &frame->rs_uc.uc_stack.ss_flags);
  	err |= __put_user(current->sas_ss_size,
  	                  &frame->rs_uc.uc_stack.ss_size);
  	err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext);
  	err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set));
  
  	if (err)
  		goto give_sigsegv;
  
  	/*
  	 * Arguments to signal handler:
  	 *
  	 *   a0 = signal number
  	 *   a1 = 0 (should be cause)
  	 *   a2 = pointer to ucontext
  	 *
  	 * $25 and c0_epc point to the signal handler, $29 points to
  	 * the struct rt_sigframe.
  	 */
  	regs->regs[ 4] = signr;
  	regs->regs[ 5] = (unsigned long) &frame->rs_info;
  	regs->regs[ 6] = (unsigned long) &frame->rs_uc;
  	regs->regs[29] = (unsigned long) frame;
d814c28ce   David Daney   MIPS: Move signal...
499
  	regs->regs[31] = (unsigned long) sig_return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
  	regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
722bb63de   Franck Bui-Huu   [MIPS] signal: fa...
501
502
  	DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
503
504
  	       current->comm, current->pid,
  	       frame, regs->cp0_epc, regs->regs[31]);
722bb63de   Franck Bui-Huu   [MIPS] signal: fa...
505

7b3e2fc84   Ralf Baechle   [MIPS] Add suppor...
506
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
508
509
  
  give_sigsegv:
  	force_sigsegv(signr, current);
7b3e2fc84   Ralf Baechle   [MIPS] Add suppor...
510
  	return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
  }
151fd6acd   Ralf Baechle   [MIPS] signals: S...
512
513
514
  struct mips_abi mips_abi = {
  #ifdef CONFIG_TRAD_SIGNALS
  	.setup_frame	= setup_frame,
d814c28ce   David Daney   MIPS: Move signal...
515
  	.signal_return_offset = offsetof(struct mips_vdso, signal_trampoline),
151fd6acd   Ralf Baechle   [MIPS] signals: S...
516
517
  #endif
  	.setup_rt_frame	= setup_rt_frame,
d814c28ce   David Daney   MIPS: Move signal...
518
519
  	.rt_signal_return_offset =
  		offsetof(struct mips_vdso, rt_signal_trampoline),
151fd6acd   Ralf Baechle   [MIPS] signals: S...
520
521
  	.restart	= __NR_restart_syscall
  };
e692eb30f   Franck Bui-Huu   [MIPS] signal: do...
522
  static int handle_signal(unsigned long sig, siginfo_t *info,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
524
  	struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs)
  {
129bc8f78   Ralf Baechle   Setup_frame is no...
525
  	int ret;
d814c28ce   David Daney   MIPS: Move signal...
526
527
  	struct mips_abi *abi = current->thread.abi;
  	void *vdso = current->mm->context.vdso;
129bc8f78   Ralf Baechle   Setup_frame is no...
528

8f5a00eb4   Al Viro   MIPS: Sanitize re...
529
530
531
532
  	if (regs->regs[0]) {
  		switch(regs->regs[2]) {
  		case ERESTART_RESTARTBLOCK:
  		case ERESTARTNOHAND:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
534
  			regs->regs[2] = EINTR;
  			break;
8f5a00eb4   Al Viro   MIPS: Sanitize re...
535
536
537
538
539
540
541
542
543
544
  		case ERESTARTSYS:
  			if (!(ka->sa.sa_flags & SA_RESTART)) {
  				regs->regs[2] = EINTR;
  				break;
  			}
  		/* fallthrough */
  		case ERESTARTNOINTR:
  			regs->regs[7] = regs->regs[26];
  			regs->regs[2] = regs->regs[0];
  			regs->cp0_epc -= 4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546

8f5a00eb4   Al Viro   MIPS: Sanitize re...
547
548
  		regs->regs[0] = 0;		/* Don't deal with this again.  */
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549

e50c0a8fa   Ralf Baechle   Support the MIPS3...
550
  	if (sig_uses_siginfo(ka))
d814c28ce   David Daney   MIPS: Move signal...
551
552
  		ret = abi->setup_rt_frame(vdso + abi->rt_signal_return_offset,
  					  ka, regs, sig, oldset, info);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
553
  	else
d814c28ce   David Daney   MIPS: Move signal...
554
555
  		ret = abi->setup_frame(vdso + abi->signal_return_offset,
  				       ka, regs, sig, oldset);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556

062ab57b2   Al Viro   MIPS: Don't block...
557
558
  	if (ret)
  		return ret;
69be8f189   Steven Rostedt   [PATCH] convert s...
559
  	spin_lock_irq(&current->sighand->siglock);
21a151d8c   Ralf Baechle   [MIPS] checkfiles...
560
  	sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
69be8f189   Steven Rostedt   [PATCH] convert s...
561
  	if (!(ka->sa.sa_flags & SA_NODEFER))
21a151d8c   Ralf Baechle   [MIPS] checkfiles...
562
  		sigaddset(&current->blocked, sig);
69be8f189   Steven Rostedt   [PATCH] convert s...
563
564
  	recalc_sigpending();
  	spin_unlock_irq(&current->sighand->siglock);
129bc8f78   Ralf Baechle   Setup_frame is no...
565
566
  
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
567
  }
151fd6acd   Ralf Baechle   [MIPS] signals: S...
568
  static void do_signal(struct pt_regs *regs)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
569
570
  {
  	struct k_sigaction ka;
7b3e2fc84   Ralf Baechle   [MIPS] Add suppor...
571
  	sigset_t *oldset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
572
573
  	siginfo_t info;
  	int signr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
575
576
577
578
579
  	/*
  	 * 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))
40ac5d479   Ralf Baechle   [MIPS] Make do_si...
580
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
581

7b3e2fc84   Ralf Baechle   [MIPS] Add suppor...
582
583
584
  	if (test_thread_flag(TIF_RESTORE_SIGMASK))
  		oldset = &current->saved_sigmask;
  	else
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
587
  		oldset = &current->blocked;
  
  	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
7b3e2fc84   Ralf Baechle   [MIPS] Add suppor...
588
589
590
591
592
593
594
595
596
597
598
599
  	if (signr > 0) {
  		/* Whee!  Actually deliver the signal.  */
  		if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
  			/*
  			 * A signal was successfully delivered; the saved
  			 * sigmask will have been stored in the signal frame,
  			 * and will be restored by sigreturn, so we can simply
  			 * clear the TIF_RESTORE_SIGMASK flag.
  			 */
  			if (test_thread_flag(TIF_RESTORE_SIGMASK))
  				clear_thread_flag(TIF_RESTORE_SIGMASK);
  		}
45887e12f   Ralf Baechle   [MIPS] Add missin...
600
601
  
  		return;
7b3e2fc84   Ralf Baechle   [MIPS] Add suppor...
602
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604
605
606
607
  	if (regs->regs[0]) {
  		if (regs->regs[2] == ERESTARTNOHAND ||
  		    regs->regs[2] == ERESTARTSYS ||
  		    regs->regs[2] == ERESTARTNOINTR) {
8f5a00eb4   Al Viro   MIPS: Sanitize re...
608
  			regs->regs[2] = regs->regs[0];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
  			regs->regs[7] = regs->regs[26];
8f5a00eb4   Al Viro   MIPS: Sanitize re...
610
  			regs->cp0_epc -= 4;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
612
  		}
  		if (regs->regs[2] == ERESTART_RESTARTBLOCK) {
151fd6acd   Ralf Baechle   [MIPS] signals: S...
613
  			regs->regs[2] = current->thread.abi->restart;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614
615
616
  			regs->regs[7] = regs->regs[26];
  			regs->cp0_epc -= 4;
  		}
13fdd31ab   Ralf Baechle   [MIPS] Avoid doub...
617
  		regs->regs[0] = 0;	/* Don't deal with this again.  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
618
  	}
7b3e2fc84   Ralf Baechle   [MIPS] Add suppor...
619
620
621
622
623
624
625
626
627
  
  	/*
  	 * If there's no signal to deliver, we just put the saved sigmask
  	 * back
  	 */
  	if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
  		clear_thread_flag(TIF_RESTORE_SIGMASK);
  		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
628
629
630
631
  }
  
  /*
   * notification of userspace execution resumption
7b3e2fc84   Ralf Baechle   [MIPS] Add suppor...
632
   * - triggered by the TIF_WORK_MASK flags
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
633
   */
7b3e2fc84   Ralf Baechle   [MIPS] Add suppor...
634
  asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
636
  	__u32 thread_info_flags)
  {
1f717929e   Ralf Baechle   MIPS: Handle __pu...
637
  	local_irq_enable();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
638
  	/* deal with pending signal delivery */
7b3e2fc84   Ralf Baechle   [MIPS] Add suppor...
639
  	if (thread_info_flags & (_TIF_SIGPENDING | _TIF_RESTORE_SIGMASK))
151fd6acd   Ralf Baechle   [MIPS] signals: S...
640
  		do_signal(regs);
d0420c83f   David Howells   KEYS: Extend TIF_...
641
642
643
644
  
  	if (thread_info_flags & _TIF_NOTIFY_RESUME) {
  		clear_thread_flag(TIF_NOTIFY_RESUME);
  		tracehook_notify_resume(regs);
ee18d64c1   David Howells   KEYS: Add a keyct...
645
646
  		if (current->replacement_session_keyring)
  			key_replace_session_keyring();
d0420c83f   David Howells   KEYS: Extend TIF_...
647
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
  }
137f6f3e2   Ralf Baechle   MIPS: Cleanup sig...
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
  
  #ifdef CONFIG_SMP
  static int smp_save_fp_context(struct sigcontext __user *sc)
  {
  	return raw_cpu_has_fpu
  	       ? _save_fp_context(sc)
  	       : fpu_emulator_save_context(sc);
  }
  
  static int smp_restore_fp_context(struct sigcontext __user *sc)
  {
  	return raw_cpu_has_fpu
  	       ? _restore_fp_context(sc)
  	       : fpu_emulator_restore_context(sc);
  }
  #endif
  
  static int signal_setup(void)
  {
  #ifdef CONFIG_SMP
  	/* For now just do the cpu_has_fpu check when the functions are invoked */
  	save_fp_context = smp_save_fp_context;
  	restore_fp_context = smp_restore_fp_context;
  #else
  	if (cpu_has_fpu) {
  		save_fp_context = _save_fp_context;
  		restore_fp_context = _restore_fp_context;
  	} else {
  		save_fp_context = fpu_emulator_save_context;
  		restore_fp_context = fpu_emulator_restore_context;
  	}
  #endif
  
  	return 0;
  }
  
  arch_initcall(signal_setup);