diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/sparc/kernel/signal.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/sparc/kernel/signal.c')
-rw-r--r-- | arch/sparc/kernel/signal.c | 1181 |
1 files changed, 1181 insertions, 0 deletions
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c new file mode 100644 index 000000000000..011ff35057a5 --- /dev/null +++ b/arch/sparc/kernel/signal.c | |||
@@ -0,0 +1,1181 @@ | |||
1 | /* $Id: signal.c,v 1.110 2002/02/08 03:57:14 davem Exp $ | ||
2 | * linux/arch/sparc/kernel/signal.c | ||
3 | * | ||
4 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
5 | * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) | ||
6 | * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) | ||
7 | * Copyright (C) 1997 Eddie C. Dost (ecd@skynet.be) | ||
8 | */ | ||
9 | |||
10 | #include <linux/config.h> | ||
11 | #include <linux/sched.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/signal.h> | ||
14 | #include <linux/errno.h> | ||
15 | #include <linux/wait.h> | ||
16 | #include <linux/ptrace.h> | ||
17 | #include <linux/unistd.h> | ||
18 | #include <linux/mm.h> | ||
19 | #include <linux/tty.h> | ||
20 | #include <linux/smp.h> | ||
21 | #include <linux/smp_lock.h> | ||
22 | #include <linux/binfmts.h> /* do_coredum */ | ||
23 | #include <linux/bitops.h> | ||
24 | |||
25 | #include <asm/uaccess.h> | ||
26 | #include <asm/ptrace.h> | ||
27 | #include <asm/svr4.h> | ||
28 | #include <asm/pgalloc.h> | ||
29 | #include <asm/pgtable.h> | ||
30 | #include <asm/cacheflush.h> /* flush_sig_insns */ | ||
31 | |||
32 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | ||
33 | |||
34 | extern void fpsave(unsigned long *fpregs, unsigned long *fsr, | ||
35 | void *fpqueue, unsigned long *fpqdepth); | ||
36 | extern void fpload(unsigned long *fpregs, unsigned long *fsr); | ||
37 | |||
38 | asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, | ||
39 | unsigned long orig_o0, int restart_syscall); | ||
40 | |||
41 | /* Signal frames: the original one (compatible with SunOS): | ||
42 | * | ||
43 | * Set up a signal frame... Make the stack look the way SunOS | ||
44 | * expects it to look which is basically: | ||
45 | * | ||
46 | * ---------------------------------- <-- %sp at signal time | ||
47 | * Struct sigcontext | ||
48 | * Signal address | ||
49 | * Ptr to sigcontext area above | ||
50 | * Signal code | ||
51 | * The signal number itself | ||
52 | * One register window | ||
53 | * ---------------------------------- <-- New %sp | ||
54 | */ | ||
55 | struct signal_sframe { | ||
56 | struct reg_window sig_window; | ||
57 | int sig_num; | ||
58 | int sig_code; | ||
59 | struct sigcontext __user *sig_scptr; | ||
60 | int sig_address; | ||
61 | struct sigcontext sig_context; | ||
62 | unsigned int extramask[_NSIG_WORDS - 1]; | ||
63 | }; | ||
64 | |||
65 | /* | ||
66 | * And the new one, intended to be used for Linux applications only | ||
67 | * (we have enough in there to work with clone). | ||
68 | * All the interesting bits are in the info field. | ||
69 | */ | ||
70 | |||
71 | struct new_signal_frame { | ||
72 | struct sparc_stackf ss; | ||
73 | __siginfo_t info; | ||
74 | __siginfo_fpu_t __user *fpu_save; | ||
75 | unsigned long insns[2] __attribute__ ((aligned (8))); | ||
76 | unsigned int extramask[_NSIG_WORDS - 1]; | ||
77 | unsigned int extra_size; /* Should be 0 */ | ||
78 | __siginfo_fpu_t fpu_state; | ||
79 | }; | ||
80 | |||
81 | struct rt_signal_frame { | ||
82 | struct sparc_stackf ss; | ||
83 | siginfo_t info; | ||
84 | struct pt_regs regs; | ||
85 | sigset_t mask; | ||
86 | __siginfo_fpu_t __user *fpu_save; | ||
87 | unsigned int insns[2]; | ||
88 | stack_t stack; | ||
89 | unsigned int extra_size; /* Should be 0 */ | ||
90 | __siginfo_fpu_t fpu_state; | ||
91 | }; | ||
92 | |||
93 | /* Align macros */ | ||
94 | #define SF_ALIGNEDSZ (((sizeof(struct signal_sframe) + 7) & (~7))) | ||
95 | #define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame) + 7) & (~7))) | ||
96 | #define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame) + 7) & (~7))) | ||
97 | |||
98 | /* | ||
99 | * atomically swap in the new signal mask, and wait for a signal. | ||
100 | * This is really tricky on the Sparc, watch out... | ||
101 | */ | ||
102 | asmlinkage void _sigpause_common(old_sigset_t set, struct pt_regs *regs) | ||
103 | { | ||
104 | sigset_t saveset; | ||
105 | |||
106 | set &= _BLOCKABLE; | ||
107 | spin_lock_irq(¤t->sighand->siglock); | ||
108 | saveset = current->blocked; | ||
109 | siginitset(¤t->blocked, set); | ||
110 | recalc_sigpending(); | ||
111 | spin_unlock_irq(¤t->sighand->siglock); | ||
112 | |||
113 | regs->pc = regs->npc; | ||
114 | regs->npc += 4; | ||
115 | |||
116 | /* Condition codes and return value where set here for sigpause, | ||
117 | * and so got used by setup_frame, which again causes sigreturn() | ||
118 | * to return -EINTR. | ||
119 | */ | ||
120 | while (1) { | ||
121 | current->state = TASK_INTERRUPTIBLE; | ||
122 | schedule(); | ||
123 | /* | ||
124 | * Return -EINTR and set condition code here, | ||
125 | * so the interrupted system call actually returns | ||
126 | * these. | ||
127 | */ | ||
128 | regs->psr |= PSR_C; | ||
129 | regs->u_regs[UREG_I0] = EINTR; | ||
130 | if (do_signal(&saveset, regs, 0, 0)) | ||
131 | return; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | asmlinkage void do_sigpause(unsigned int set, struct pt_regs *regs) | ||
136 | { | ||
137 | _sigpause_common(set, regs); | ||
138 | } | ||
139 | |||
140 | asmlinkage void do_sigsuspend (struct pt_regs *regs) | ||
141 | { | ||
142 | _sigpause_common(regs->u_regs[UREG_I0], regs); | ||
143 | } | ||
144 | |||
145 | asmlinkage void do_rt_sigsuspend(sigset_t __user *uset, size_t sigsetsize, | ||
146 | struct pt_regs *regs) | ||
147 | { | ||
148 | sigset_t oldset, set; | ||
149 | |||
150 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
151 | if (sigsetsize != sizeof(sigset_t)) { | ||
152 | regs->psr |= PSR_C; | ||
153 | regs->u_regs[UREG_I0] = EINVAL; | ||
154 | return; | ||
155 | } | ||
156 | |||
157 | if (copy_from_user(&set, uset, sizeof(set))) { | ||
158 | regs->psr |= PSR_C; | ||
159 | regs->u_regs[UREG_I0] = EFAULT; | ||
160 | return; | ||
161 | } | ||
162 | |||
163 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
164 | spin_lock_irq(¤t->sighand->siglock); | ||
165 | oldset = current->blocked; | ||
166 | current->blocked = set; | ||
167 | recalc_sigpending(); | ||
168 | spin_unlock_irq(¤t->sighand->siglock); | ||
169 | |||
170 | regs->pc = regs->npc; | ||
171 | regs->npc += 4; | ||
172 | |||
173 | /* Condition codes and return value where set here for sigpause, | ||
174 | * and so got used by setup_frame, which again causes sigreturn() | ||
175 | * to return -EINTR. | ||
176 | */ | ||
177 | while (1) { | ||
178 | current->state = TASK_INTERRUPTIBLE; | ||
179 | schedule(); | ||
180 | /* | ||
181 | * Return -EINTR and set condition code here, | ||
182 | * so the interrupted system call actually returns | ||
183 | * these. | ||
184 | */ | ||
185 | regs->psr |= PSR_C; | ||
186 | regs->u_regs[UREG_I0] = EINTR; | ||
187 | if (do_signal(&oldset, regs, 0, 0)) | ||
188 | return; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | static inline int | ||
193 | restore_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) | ||
194 | { | ||
195 | int err; | ||
196 | #ifdef CONFIG_SMP | ||
197 | if (test_tsk_thread_flag(current, TIF_USEDFPU)) | ||
198 | regs->psr &= ~PSR_EF; | ||
199 | #else | ||
200 | if (current == last_task_used_math) { | ||
201 | last_task_used_math = NULL; | ||
202 | regs->psr &= ~PSR_EF; | ||
203 | } | ||
204 | #endif | ||
205 | set_used_math(); | ||
206 | clear_tsk_thread_flag(current, TIF_USEDFPU); | ||
207 | |||
208 | if (!access_ok(VERIFY_READ, fpu, sizeof(*fpu))) | ||
209 | return -EFAULT; | ||
210 | |||
211 | err = __copy_from_user(¤t->thread.float_regs[0], &fpu->si_float_regs[0], | ||
212 | (sizeof(unsigned long) * 32)); | ||
213 | err |= __get_user(current->thread.fsr, &fpu->si_fsr); | ||
214 | err |= __get_user(current->thread.fpqdepth, &fpu->si_fpqdepth); | ||
215 | if (current->thread.fpqdepth != 0) | ||
216 | err |= __copy_from_user(¤t->thread.fpqueue[0], | ||
217 | &fpu->si_fpqueue[0], | ||
218 | ((sizeof(unsigned long) + | ||
219 | (sizeof(unsigned long *)))*16)); | ||
220 | return err; | ||
221 | } | ||
222 | |||
223 | static inline void do_new_sigreturn (struct pt_regs *regs) | ||
224 | { | ||
225 | struct new_signal_frame __user *sf; | ||
226 | unsigned long up_psr, pc, npc; | ||
227 | sigset_t set; | ||
228 | __siginfo_fpu_t __user *fpu_save; | ||
229 | int err; | ||
230 | |||
231 | sf = (struct new_signal_frame __user *) regs->u_regs[UREG_FP]; | ||
232 | |||
233 | /* 1. Make sure we are not getting garbage from the user */ | ||
234 | if (!access_ok(VERIFY_READ, sf, sizeof(*sf))) | ||
235 | goto segv_and_exit; | ||
236 | |||
237 | if (((unsigned long) sf) & 3) | ||
238 | goto segv_and_exit; | ||
239 | |||
240 | err = __get_user(pc, &sf->info.si_regs.pc); | ||
241 | err |= __get_user(npc, &sf->info.si_regs.npc); | ||
242 | |||
243 | if ((pc | npc) & 3) | ||
244 | goto segv_and_exit; | ||
245 | |||
246 | /* 2. Restore the state */ | ||
247 | up_psr = regs->psr; | ||
248 | err |= __copy_from_user(regs, &sf->info.si_regs, sizeof(struct pt_regs)); | ||
249 | |||
250 | /* User can only change condition codes and FPU enabling in %psr. */ | ||
251 | regs->psr = (up_psr & ~(PSR_ICC | PSR_EF)) | ||
252 | | (regs->psr & (PSR_ICC | PSR_EF)); | ||
253 | |||
254 | err |= __get_user(fpu_save, &sf->fpu_save); | ||
255 | |||
256 | if (fpu_save) | ||
257 | err |= restore_fpu_state(regs, fpu_save); | ||
258 | |||
259 | /* This is pretty much atomic, no amount locking would prevent | ||
260 | * the races which exist anyways. | ||
261 | */ | ||
262 | err |= __get_user(set.sig[0], &sf->info.si_mask); | ||
263 | err |= __copy_from_user(&set.sig[1], &sf->extramask, | ||
264 | (_NSIG_WORDS-1) * sizeof(unsigned int)); | ||
265 | |||
266 | if (err) | ||
267 | goto segv_and_exit; | ||
268 | |||
269 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
270 | spin_lock_irq(¤t->sighand->siglock); | ||
271 | current->blocked = set; | ||
272 | recalc_sigpending(); | ||
273 | spin_unlock_irq(¤t->sighand->siglock); | ||
274 | return; | ||
275 | |||
276 | segv_and_exit: | ||
277 | force_sig(SIGSEGV, current); | ||
278 | } | ||
279 | |||
280 | asmlinkage void do_sigreturn(struct pt_regs *regs) | ||
281 | { | ||
282 | struct sigcontext __user *scptr; | ||
283 | unsigned long pc, npc, psr; | ||
284 | sigset_t set; | ||
285 | int err; | ||
286 | |||
287 | /* Always make any pending restarted system calls return -EINTR */ | ||
288 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
289 | |||
290 | synchronize_user_stack(); | ||
291 | |||
292 | if (current->thread.new_signal) { | ||
293 | do_new_sigreturn(regs); | ||
294 | return; | ||
295 | } | ||
296 | |||
297 | scptr = (struct sigcontext __user *) regs->u_regs[UREG_I0]; | ||
298 | |||
299 | /* Check sanity of the user arg. */ | ||
300 | if (!access_ok(VERIFY_READ, scptr, sizeof(struct sigcontext)) || | ||
301 | (((unsigned long) scptr) & 3)) | ||
302 | goto segv_and_exit; | ||
303 | |||
304 | err = __get_user(pc, &scptr->sigc_pc); | ||
305 | err |= __get_user(npc, &scptr->sigc_npc); | ||
306 | |||
307 | if ((pc | npc) & 3) | ||
308 | goto segv_and_exit; | ||
309 | |||
310 | /* This is pretty much atomic, no amount locking would prevent | ||
311 | * the races which exist anyways. | ||
312 | */ | ||
313 | err |= __get_user(set.sig[0], &scptr->sigc_mask); | ||
314 | /* Note that scptr + 1 points to extramask */ | ||
315 | err |= __copy_from_user(&set.sig[1], scptr + 1, | ||
316 | (_NSIG_WORDS - 1) * sizeof(unsigned int)); | ||
317 | |||
318 | if (err) | ||
319 | goto segv_and_exit; | ||
320 | |||
321 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
322 | spin_lock_irq(¤t->sighand->siglock); | ||
323 | current->blocked = set; | ||
324 | recalc_sigpending(); | ||
325 | spin_unlock_irq(¤t->sighand->siglock); | ||
326 | |||
327 | regs->pc = pc; | ||
328 | regs->npc = npc; | ||
329 | |||
330 | err = __get_user(regs->u_regs[UREG_FP], &scptr->sigc_sp); | ||
331 | err |= __get_user(regs->u_regs[UREG_I0], &scptr->sigc_o0); | ||
332 | err |= __get_user(regs->u_regs[UREG_G1], &scptr->sigc_g1); | ||
333 | |||
334 | /* User can only change condition codes in %psr. */ | ||
335 | err |= __get_user(psr, &scptr->sigc_psr); | ||
336 | if (err) | ||
337 | goto segv_and_exit; | ||
338 | |||
339 | regs->psr &= ~(PSR_ICC); | ||
340 | regs->psr |= (psr & PSR_ICC); | ||
341 | return; | ||
342 | |||
343 | segv_and_exit: | ||
344 | force_sig(SIGSEGV, current); | ||
345 | } | ||
346 | |||
347 | asmlinkage void do_rt_sigreturn(struct pt_regs *regs) | ||
348 | { | ||
349 | struct rt_signal_frame __user *sf; | ||
350 | unsigned int psr, pc, npc; | ||
351 | __siginfo_fpu_t __user *fpu_save; | ||
352 | mm_segment_t old_fs; | ||
353 | sigset_t set; | ||
354 | stack_t st; | ||
355 | int err; | ||
356 | |||
357 | synchronize_user_stack(); | ||
358 | sf = (struct rt_signal_frame __user *) regs->u_regs[UREG_FP]; | ||
359 | if (!access_ok(VERIFY_READ, sf, sizeof(*sf)) || | ||
360 | (((unsigned long) sf) & 0x03)) | ||
361 | goto segv; | ||
362 | |||
363 | err = __get_user(pc, &sf->regs.pc); | ||
364 | err |= __get_user(npc, &sf->regs.npc); | ||
365 | err |= ((pc | npc) & 0x03); | ||
366 | |||
367 | err |= __get_user(regs->y, &sf->regs.y); | ||
368 | err |= __get_user(psr, &sf->regs.psr); | ||
369 | |||
370 | err |= __copy_from_user(®s->u_regs[UREG_G1], | ||
371 | &sf->regs.u_regs[UREG_G1], 15 * sizeof(u32)); | ||
372 | |||
373 | regs->psr = (regs->psr & ~PSR_ICC) | (psr & PSR_ICC); | ||
374 | |||
375 | err |= __get_user(fpu_save, &sf->fpu_save); | ||
376 | |||
377 | if (fpu_save) | ||
378 | err |= restore_fpu_state(regs, fpu_save); | ||
379 | err |= __copy_from_user(&set, &sf->mask, sizeof(sigset_t)); | ||
380 | |||
381 | err |= __copy_from_user(&st, &sf->stack, sizeof(stack_t)); | ||
382 | |||
383 | if (err) | ||
384 | goto segv; | ||
385 | |||
386 | regs->pc = pc; | ||
387 | regs->npc = npc; | ||
388 | |||
389 | /* It is more difficult to avoid calling this function than to | ||
390 | * call it and ignore errors. | ||
391 | */ | ||
392 | old_fs = get_fs(); | ||
393 | set_fs(KERNEL_DS); | ||
394 | do_sigaltstack((const stack_t __user *) &st, NULL, (unsigned long)sf); | ||
395 | set_fs(old_fs); | ||
396 | |||
397 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
398 | spin_lock_irq(¤t->sighand->siglock); | ||
399 | current->blocked = set; | ||
400 | recalc_sigpending(); | ||
401 | spin_unlock_irq(¤t->sighand->siglock); | ||
402 | return; | ||
403 | segv: | ||
404 | force_sig(SIGSEGV, current); | ||
405 | } | ||
406 | |||
407 | /* Checks if the fp is valid */ | ||
408 | static inline int invalid_frame_pointer(void __user *fp, int fplen) | ||
409 | { | ||
410 | if ((((unsigned long) fp) & 7) || | ||
411 | !__access_ok((unsigned long)fp, fplen) || | ||
412 | ((sparc_cpu_model == sun4 || sparc_cpu_model == sun4c) && | ||
413 | ((unsigned long) fp < 0xe0000000 && (unsigned long) fp >= 0x20000000))) | ||
414 | return 1; | ||
415 | |||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | static inline void __user *get_sigframe(struct sigaction *sa, struct pt_regs *regs, unsigned long framesize) | ||
420 | { | ||
421 | unsigned long sp; | ||
422 | |||
423 | sp = regs->u_regs[UREG_FP]; | ||
424 | |||
425 | /* This is the X/Open sanctioned signal stack switching. */ | ||
426 | if (sa->sa_flags & SA_ONSTACK) { | ||
427 | if (!on_sig_stack(sp) && !((current->sas_ss_sp + current->sas_ss_size) & 7)) | ||
428 | sp = current->sas_ss_sp + current->sas_ss_size; | ||
429 | } | ||
430 | return (void __user *)(sp - framesize); | ||
431 | } | ||
432 | |||
433 | static inline void | ||
434 | setup_frame(struct sigaction *sa, struct pt_regs *regs, int signr, sigset_t *oldset, siginfo_t *info) | ||
435 | { | ||
436 | struct signal_sframe __user *sframep; | ||
437 | struct sigcontext __user *sc; | ||
438 | int window = 0, err; | ||
439 | unsigned long pc = regs->pc; | ||
440 | unsigned long npc = regs->npc; | ||
441 | struct thread_info *tp = current_thread_info(); | ||
442 | void __user *sig_address; | ||
443 | int sig_code; | ||
444 | |||
445 | synchronize_user_stack(); | ||
446 | sframep = (struct signal_sframe __user *) | ||
447 | get_sigframe(sa, regs, SF_ALIGNEDSZ); | ||
448 | if (invalid_frame_pointer(sframep, sizeof(*sframep))){ | ||
449 | /* Don't change signal code and address, so that | ||
450 | * post mortem debuggers can have a look. | ||
451 | */ | ||
452 | goto sigill_and_return; | ||
453 | } | ||
454 | |||
455 | sc = &sframep->sig_context; | ||
456 | |||
457 | /* We've already made sure frame pointer isn't in kernel space... */ | ||
458 | err = __put_user((sas_ss_flags(regs->u_regs[UREG_FP]) == SS_ONSTACK), | ||
459 | &sc->sigc_onstack); | ||
460 | err |= __put_user(oldset->sig[0], &sc->sigc_mask); | ||
461 | err |= __copy_to_user(sframep->extramask, &oldset->sig[1], | ||
462 | (_NSIG_WORDS - 1) * sizeof(unsigned int)); | ||
463 | err |= __put_user(regs->u_regs[UREG_FP], &sc->sigc_sp); | ||
464 | err |= __put_user(pc, &sc->sigc_pc); | ||
465 | err |= __put_user(npc, &sc->sigc_npc); | ||
466 | err |= __put_user(regs->psr, &sc->sigc_psr); | ||
467 | err |= __put_user(regs->u_regs[UREG_G1], &sc->sigc_g1); | ||
468 | err |= __put_user(regs->u_regs[UREG_I0], &sc->sigc_o0); | ||
469 | err |= __put_user(tp->w_saved, &sc->sigc_oswins); | ||
470 | if (tp->w_saved) | ||
471 | for (window = 0; window < tp->w_saved; window++) { | ||
472 | put_user((char *)tp->rwbuf_stkptrs[window], | ||
473 | &sc->sigc_spbuf[window]); | ||
474 | err |= __copy_to_user(&sc->sigc_wbuf[window], | ||
475 | &tp->reg_window[window], | ||
476 | sizeof(struct reg_window)); | ||
477 | } | ||
478 | else | ||
479 | err |= __copy_to_user(sframep, (char *) regs->u_regs[UREG_FP], | ||
480 | sizeof(struct reg_window)); | ||
481 | |||
482 | tp->w_saved = 0; /* So process is allowed to execute. */ | ||
483 | |||
484 | err |= __put_user(signr, &sframep->sig_num); | ||
485 | sig_address = NULL; | ||
486 | sig_code = 0; | ||
487 | if (SI_FROMKERNEL (info) && (info->si_code & __SI_MASK) == __SI_FAULT) { | ||
488 | sig_address = info->si_addr; | ||
489 | switch (signr) { | ||
490 | case SIGSEGV: | ||
491 | switch (info->si_code) { | ||
492 | case SEGV_MAPERR: sig_code = SUBSIG_NOMAPPING; break; | ||
493 | default: sig_code = SUBSIG_PROTECTION; break; | ||
494 | } | ||
495 | break; | ||
496 | case SIGILL: | ||
497 | switch (info->si_code) { | ||
498 | case ILL_ILLOPC: sig_code = SUBSIG_ILLINST; break; | ||
499 | case ILL_PRVOPC: sig_code = SUBSIG_PRIVINST; break; | ||
500 | case ILL_ILLTRP: sig_code = SUBSIG_BADTRAP(info->si_trapno); break; | ||
501 | default: sig_code = SUBSIG_STACK; break; | ||
502 | } | ||
503 | break; | ||
504 | case SIGFPE: | ||
505 | switch (info->si_code) { | ||
506 | case FPE_INTDIV: sig_code = SUBSIG_IDIVZERO; break; | ||
507 | case FPE_INTOVF: sig_code = SUBSIG_FPINTOVFL; break; | ||
508 | case FPE_FLTDIV: sig_code = SUBSIG_FPDIVZERO; break; | ||
509 | case FPE_FLTOVF: sig_code = SUBSIG_FPOVFLOW; break; | ||
510 | case FPE_FLTUND: sig_code = SUBSIG_FPUNFLOW; break; | ||
511 | case FPE_FLTRES: sig_code = SUBSIG_FPINEXACT; break; | ||
512 | case FPE_FLTINV: sig_code = SUBSIG_FPOPERROR; break; | ||
513 | default: sig_code = SUBSIG_FPERROR; break; | ||
514 | } | ||
515 | break; | ||
516 | case SIGBUS: | ||
517 | switch (info->si_code) { | ||
518 | case BUS_ADRALN: sig_code = SUBSIG_ALIGNMENT; break; | ||
519 | case BUS_ADRERR: sig_code = SUBSIG_MISCERROR; break; | ||
520 | default: sig_code = SUBSIG_BUSTIMEOUT; break; | ||
521 | } | ||
522 | break; | ||
523 | case SIGEMT: | ||
524 | switch (info->si_code) { | ||
525 | case EMT_TAGOVF: sig_code = SUBSIG_TAG; break; | ||
526 | } | ||
527 | break; | ||
528 | case SIGSYS: | ||
529 | if (info->si_code == (__SI_FAULT|0x100)) { | ||
530 | /* See sys_sunos.c */ | ||
531 | sig_code = info->si_trapno; | ||
532 | break; | ||
533 | } | ||
534 | default: | ||
535 | sig_address = NULL; | ||
536 | } | ||
537 | } | ||
538 | err |= __put_user((unsigned long)sig_address, &sframep->sig_address); | ||
539 | err |= __put_user(sig_code, &sframep->sig_code); | ||
540 | err |= __put_user(sc, &sframep->sig_scptr); | ||
541 | if (err) | ||
542 | goto sigsegv; | ||
543 | |||
544 | regs->u_regs[UREG_FP] = (unsigned long) sframep; | ||
545 | regs->pc = (unsigned long) sa->sa_handler; | ||
546 | regs->npc = (regs->pc + 4); | ||
547 | return; | ||
548 | |||
549 | sigill_and_return: | ||
550 | do_exit(SIGILL); | ||
551 | sigsegv: | ||
552 | force_sigsegv(signr, current); | ||
553 | } | ||
554 | |||
555 | |||
556 | static inline int | ||
557 | save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) | ||
558 | { | ||
559 | int err = 0; | ||
560 | #ifdef CONFIG_SMP | ||
561 | if (test_tsk_thread_flag(current, TIF_USEDFPU)) { | ||
562 | put_psr(get_psr() | PSR_EF); | ||
563 | fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr, | ||
564 | ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth); | ||
565 | regs->psr &= ~(PSR_EF); | ||
566 | clear_tsk_thread_flag(current, TIF_USEDFPU); | ||
567 | } | ||
568 | #else | ||
569 | if (current == last_task_used_math) { | ||
570 | put_psr(get_psr() | PSR_EF); | ||
571 | fpsave(¤t->thread.float_regs[0], ¤t->thread.fsr, | ||
572 | ¤t->thread.fpqueue[0], ¤t->thread.fpqdepth); | ||
573 | last_task_used_math = NULL; | ||
574 | regs->psr &= ~(PSR_EF); | ||
575 | } | ||
576 | #endif | ||
577 | err |= __copy_to_user(&fpu->si_float_regs[0], | ||
578 | ¤t->thread.float_regs[0], | ||
579 | (sizeof(unsigned long) * 32)); | ||
580 | err |= __put_user(current->thread.fsr, &fpu->si_fsr); | ||
581 | err |= __put_user(current->thread.fpqdepth, &fpu->si_fpqdepth); | ||
582 | if (current->thread.fpqdepth != 0) | ||
583 | err |= __copy_to_user(&fpu->si_fpqueue[0], | ||
584 | ¤t->thread.fpqueue[0], | ||
585 | ((sizeof(unsigned long) + | ||
586 | (sizeof(unsigned long *)))*16)); | ||
587 | clear_used_math(); | ||
588 | return err; | ||
589 | } | ||
590 | |||
591 | static inline void | ||
592 | new_setup_frame(struct k_sigaction *ka, struct pt_regs *regs, | ||
593 | int signo, sigset_t *oldset) | ||
594 | { | ||
595 | struct new_signal_frame __user *sf; | ||
596 | int sigframe_size, err; | ||
597 | |||
598 | /* 1. Make sure everything is clean */ | ||
599 | synchronize_user_stack(); | ||
600 | |||
601 | sigframe_size = NF_ALIGNEDSZ; | ||
602 | if (!used_math()) | ||
603 | sigframe_size -= sizeof(__siginfo_fpu_t); | ||
604 | |||
605 | sf = (struct new_signal_frame __user *) | ||
606 | get_sigframe(&ka->sa, regs, sigframe_size); | ||
607 | |||
608 | if (invalid_frame_pointer(sf, sigframe_size)) | ||
609 | goto sigill_and_return; | ||
610 | |||
611 | if (current_thread_info()->w_saved != 0) | ||
612 | goto sigill_and_return; | ||
613 | |||
614 | /* 2. Save the current process state */ | ||
615 | err = __copy_to_user(&sf->info.si_regs, regs, sizeof(struct pt_regs)); | ||
616 | |||
617 | err |= __put_user(0, &sf->extra_size); | ||
618 | |||
619 | if (used_math()) { | ||
620 | err |= save_fpu_state(regs, &sf->fpu_state); | ||
621 | err |= __put_user(&sf->fpu_state, &sf->fpu_save); | ||
622 | } else { | ||
623 | err |= __put_user(0, &sf->fpu_save); | ||
624 | } | ||
625 | |||
626 | err |= __put_user(oldset->sig[0], &sf->info.si_mask); | ||
627 | err |= __copy_to_user(sf->extramask, &oldset->sig[1], | ||
628 | (_NSIG_WORDS - 1) * sizeof(unsigned int)); | ||
629 | err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP], | ||
630 | sizeof(struct reg_window)); | ||
631 | if (err) | ||
632 | goto sigsegv; | ||
633 | |||
634 | /* 3. signal handler back-trampoline and parameters */ | ||
635 | regs->u_regs[UREG_FP] = (unsigned long) sf; | ||
636 | regs->u_regs[UREG_I0] = signo; | ||
637 | regs->u_regs[UREG_I1] = (unsigned long) &sf->info; | ||
638 | regs->u_regs[UREG_I2] = (unsigned long) &sf->info; | ||
639 | |||
640 | /* 4. signal handler */ | ||
641 | regs->pc = (unsigned long) ka->sa.sa_handler; | ||
642 | regs->npc = (regs->pc + 4); | ||
643 | |||
644 | /* 5. return to kernel instructions */ | ||
645 | if (ka->ka_restorer) | ||
646 | regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; | ||
647 | else { | ||
648 | regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2); | ||
649 | |||
650 | /* mov __NR_sigreturn, %g1 */ | ||
651 | err |= __put_user(0x821020d8, &sf->insns[0]); | ||
652 | |||
653 | /* t 0x10 */ | ||
654 | err |= __put_user(0x91d02010, &sf->insns[1]); | ||
655 | if (err) | ||
656 | goto sigsegv; | ||
657 | |||
658 | /* Flush instruction space. */ | ||
659 | flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); | ||
660 | } | ||
661 | return; | ||
662 | |||
663 | sigill_and_return: | ||
664 | do_exit(SIGILL); | ||
665 | sigsegv: | ||
666 | force_sigsegv(signo, current); | ||
667 | } | ||
668 | |||
669 | static inline void | ||
670 | new_setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, | ||
671 | int signo, sigset_t *oldset, siginfo_t *info) | ||
672 | { | ||
673 | struct rt_signal_frame __user *sf; | ||
674 | int sigframe_size; | ||
675 | unsigned int psr; | ||
676 | int err; | ||
677 | |||
678 | synchronize_user_stack(); | ||
679 | sigframe_size = RT_ALIGNEDSZ; | ||
680 | if (!used_math()) | ||
681 | sigframe_size -= sizeof(__siginfo_fpu_t); | ||
682 | sf = (struct rt_signal_frame __user *) | ||
683 | get_sigframe(&ka->sa, regs, sigframe_size); | ||
684 | if (invalid_frame_pointer(sf, sigframe_size)) | ||
685 | goto sigill; | ||
686 | if (current_thread_info()->w_saved != 0) | ||
687 | goto sigill; | ||
688 | |||
689 | err = __put_user(regs->pc, &sf->regs.pc); | ||
690 | err |= __put_user(regs->npc, &sf->regs.npc); | ||
691 | err |= __put_user(regs->y, &sf->regs.y); | ||
692 | psr = regs->psr; | ||
693 | if (used_math()) | ||
694 | psr |= PSR_EF; | ||
695 | err |= __put_user(psr, &sf->regs.psr); | ||
696 | err |= __copy_to_user(&sf->regs.u_regs, regs->u_regs, sizeof(regs->u_regs)); | ||
697 | err |= __put_user(0, &sf->extra_size); | ||
698 | |||
699 | if (psr & PSR_EF) { | ||
700 | err |= save_fpu_state(regs, &sf->fpu_state); | ||
701 | err |= __put_user(&sf->fpu_state, &sf->fpu_save); | ||
702 | } else { | ||
703 | err |= __put_user(0, &sf->fpu_save); | ||
704 | } | ||
705 | err |= __copy_to_user(&sf->mask, &oldset->sig[0], sizeof(sigset_t)); | ||
706 | |||
707 | /* Setup sigaltstack */ | ||
708 | err |= __put_user(current->sas_ss_sp, &sf->stack.ss_sp); | ||
709 | err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &sf->stack.ss_flags); | ||
710 | err |= __put_user(current->sas_ss_size, &sf->stack.ss_size); | ||
711 | |||
712 | err |= __copy_to_user(sf, (char *) regs->u_regs[UREG_FP], | ||
713 | sizeof(struct reg_window)); | ||
714 | |||
715 | err |= copy_siginfo_to_user(&sf->info, info); | ||
716 | |||
717 | if (err) | ||
718 | goto sigsegv; | ||
719 | |||
720 | regs->u_regs[UREG_FP] = (unsigned long) sf; | ||
721 | regs->u_regs[UREG_I0] = signo; | ||
722 | regs->u_regs[UREG_I1] = (unsigned long) &sf->info; | ||
723 | regs->u_regs[UREG_I2] = (unsigned long) &sf->regs; | ||
724 | |||
725 | regs->pc = (unsigned long) ka->sa.sa_handler; | ||
726 | regs->npc = (regs->pc + 4); | ||
727 | |||
728 | if (ka->ka_restorer) | ||
729 | regs->u_regs[UREG_I7] = (unsigned long)ka->ka_restorer; | ||
730 | else { | ||
731 | regs->u_regs[UREG_I7] = (unsigned long)(&(sf->insns[0]) - 2); | ||
732 | |||
733 | /* mov __NR_sigreturn, %g1 */ | ||
734 | err |= __put_user(0x821020d8, &sf->insns[0]); | ||
735 | |||
736 | /* t 0x10 */ | ||
737 | err |= __put_user(0x91d02010, &sf->insns[1]); | ||
738 | if (err) | ||
739 | goto sigsegv; | ||
740 | |||
741 | /* Flush instruction space. */ | ||
742 | flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); | ||
743 | } | ||
744 | return; | ||
745 | |||
746 | sigill: | ||
747 | do_exit(SIGILL); | ||
748 | sigsegv: | ||
749 | force_sigsegv(signo, current); | ||
750 | } | ||
751 | |||
752 | /* Setup a Solaris stack frame */ | ||
753 | static inline void | ||
754 | setup_svr4_frame(struct sigaction *sa, unsigned long pc, unsigned long npc, | ||
755 | struct pt_regs *regs, int signr, sigset_t *oldset) | ||
756 | { | ||
757 | svr4_signal_frame_t __user *sfp; | ||
758 | svr4_gregset_t __user *gr; | ||
759 | svr4_siginfo_t __user *si; | ||
760 | svr4_mcontext_t __user *mc; | ||
761 | svr4_gwindows_t __user *gw; | ||
762 | svr4_ucontext_t __user *uc; | ||
763 | svr4_sigset_t setv; | ||
764 | struct thread_info *tp = current_thread_info(); | ||
765 | int window = 0, err; | ||
766 | |||
767 | synchronize_user_stack(); | ||
768 | sfp = (svr4_signal_frame_t __user *) | ||
769 | get_sigframe(sa, regs, SVR4_SF_ALIGNED + sizeof(struct reg_window)); | ||
770 | |||
771 | if (invalid_frame_pointer(sfp, sizeof(*sfp))) | ||
772 | goto sigill_and_return; | ||
773 | |||
774 | /* Start with a clean frame pointer and fill it */ | ||
775 | err = __clear_user(sfp, sizeof(*sfp)); | ||
776 | |||
777 | /* Setup convenience variables */ | ||
778 | si = &sfp->si; | ||
779 | uc = &sfp->uc; | ||
780 | gw = &sfp->gw; | ||
781 | mc = &uc->mcontext; | ||
782 | gr = &mc->greg; | ||
783 | |||
784 | /* FIXME: where am I supposed to put this? | ||
785 | * sc->sigc_onstack = old_status; | ||
786 | * anyways, it does not look like it is used for anything at all. | ||
787 | */ | ||
788 | setv.sigbits[0] = oldset->sig[0]; | ||
789 | setv.sigbits[1] = oldset->sig[1]; | ||
790 | if (_NSIG_WORDS >= 4) { | ||
791 | setv.sigbits[2] = oldset->sig[2]; | ||
792 | setv.sigbits[3] = oldset->sig[3]; | ||
793 | err |= __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t)); | ||
794 | } else | ||
795 | err |= __copy_to_user(&uc->sigmask, &setv, | ||
796 | 2 * sizeof(unsigned int)); | ||
797 | |||
798 | /* Store registers */ | ||
799 | err |= __put_user(regs->pc, &((*gr)[SVR4_PC])); | ||
800 | err |= __put_user(regs->npc, &((*gr)[SVR4_NPC])); | ||
801 | err |= __put_user(regs->psr, &((*gr)[SVR4_PSR])); | ||
802 | err |= __put_user(regs->y, &((*gr)[SVR4_Y])); | ||
803 | |||
804 | /* Copy g[1..7] and o[0..7] registers */ | ||
805 | err |= __copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs[UREG_G1], | ||
806 | sizeof(long) * 7); | ||
807 | err |= __copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs[UREG_I0], | ||
808 | sizeof(long) * 8); | ||
809 | |||
810 | /* Setup sigaltstack */ | ||
811 | err |= __put_user(current->sas_ss_sp, &uc->stack.sp); | ||
812 | err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags); | ||
813 | err |= __put_user(current->sas_ss_size, &uc->stack.size); | ||
814 | |||
815 | /* Save the currently window file: */ | ||
816 | |||
817 | /* 1. Link sfp->uc->gwins to our windows */ | ||
818 | err |= __put_user(gw, &mc->gwin); | ||
819 | |||
820 | /* 2. Number of windows to restore at setcontext(): */ | ||
821 | err |= __put_user(tp->w_saved, &gw->count); | ||
822 | |||
823 | /* 3. Save each valid window | ||
824 | * Currently, it makes a copy of the windows from the kernel copy. | ||
825 | * David's code for SunOS, makes the copy but keeps the pointer to | ||
826 | * the kernel. My version makes the pointer point to a userland | ||
827 | * copy of those. Mhm, I wonder if I shouldn't just ignore those | ||
828 | * on setcontext and use those that are on the kernel, the signal | ||
829 | * handler should not be modyfing those, mhm. | ||
830 | * | ||
831 | * These windows are just used in case synchronize_user_stack failed | ||
832 | * to flush the user windows. | ||
833 | */ | ||
834 | for (window = 0; window < tp->w_saved; window++) { | ||
835 | err |= __put_user((int __user *) &(gw->win[window]), &gw->winptr[window]); | ||
836 | err |= __copy_to_user(&gw->win[window], | ||
837 | &tp->reg_window[window], | ||
838 | sizeof(svr4_rwindow_t)); | ||
839 | err |= __put_user(0, gw->winptr[window]); | ||
840 | } | ||
841 | |||
842 | /* 4. We just pay attention to the gw->count field on setcontext */ | ||
843 | tp->w_saved = 0; /* So process is allowed to execute. */ | ||
844 | |||
845 | /* Setup the signal information. Solaris expects a bunch of | ||
846 | * information to be passed to the signal handler, we don't provide | ||
847 | * that much currently, should use siginfo. | ||
848 | */ | ||
849 | err |= __put_user(signr, &si->siginfo.signo); | ||
850 | err |= __put_user(SVR4_SINOINFO, &si->siginfo.code); | ||
851 | if (err) | ||
852 | goto sigsegv; | ||
853 | |||
854 | regs->u_regs[UREG_FP] = (unsigned long) sfp; | ||
855 | regs->pc = (unsigned long) sa->sa_handler; | ||
856 | regs->npc = (regs->pc + 4); | ||
857 | |||
858 | /* Arguments passed to signal handler */ | ||
859 | if (regs->u_regs[14]){ | ||
860 | struct reg_window __user *rw = (struct reg_window __user *) | ||
861 | regs->u_regs[14]; | ||
862 | |||
863 | err |= __put_user(signr, &rw->ins[0]); | ||
864 | err |= __put_user(si, &rw->ins[1]); | ||
865 | err |= __put_user(uc, &rw->ins[2]); | ||
866 | err |= __put_user(sfp, &rw->ins[6]); /* frame pointer */ | ||
867 | if (err) | ||
868 | goto sigsegv; | ||
869 | |||
870 | regs->u_regs[UREG_I0] = signr; | ||
871 | regs->u_regs[UREG_I1] = (unsigned long) si; | ||
872 | regs->u_regs[UREG_I2] = (unsigned long) uc; | ||
873 | } | ||
874 | return; | ||
875 | |||
876 | sigill_and_return: | ||
877 | do_exit(SIGILL); | ||
878 | sigsegv: | ||
879 | force_sigsegv(signr, current); | ||
880 | } | ||
881 | |||
882 | asmlinkage int svr4_getcontext(svr4_ucontext_t __user *uc, struct pt_regs *regs) | ||
883 | { | ||
884 | svr4_gregset_t __user *gr; | ||
885 | svr4_mcontext_t __user *mc; | ||
886 | svr4_sigset_t setv; | ||
887 | int err = 0; | ||
888 | |||
889 | synchronize_user_stack(); | ||
890 | |||
891 | if (current_thread_info()->w_saved) | ||
892 | return -EFAULT; | ||
893 | |||
894 | err = clear_user(uc, sizeof(*uc)); | ||
895 | if (err) | ||
896 | return -EFAULT; | ||
897 | |||
898 | /* Setup convenience variables */ | ||
899 | mc = &uc->mcontext; | ||
900 | gr = &mc->greg; | ||
901 | |||
902 | setv.sigbits[0] = current->blocked.sig[0]; | ||
903 | setv.sigbits[1] = current->blocked.sig[1]; | ||
904 | if (_NSIG_WORDS >= 4) { | ||
905 | setv.sigbits[2] = current->blocked.sig[2]; | ||
906 | setv.sigbits[3] = current->blocked.sig[3]; | ||
907 | err |= __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t)); | ||
908 | } else | ||
909 | err |= __copy_to_user(&uc->sigmask, &setv, | ||
910 | 2 * sizeof(unsigned int)); | ||
911 | |||
912 | /* Store registers */ | ||
913 | err |= __put_user(regs->pc, &uc->mcontext.greg[SVR4_PC]); | ||
914 | err |= __put_user(regs->npc, &uc->mcontext.greg[SVR4_NPC]); | ||
915 | err |= __put_user(regs->psr, &uc->mcontext.greg[SVR4_PSR]); | ||
916 | err |= __put_user(regs->y, &uc->mcontext.greg[SVR4_Y]); | ||
917 | |||
918 | /* Copy g[1..7] and o[0..7] registers */ | ||
919 | err |= __copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs[UREG_G1], | ||
920 | sizeof(uint) * 7); | ||
921 | err |= __copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs[UREG_I0], | ||
922 | sizeof(uint) * 8); | ||
923 | |||
924 | /* Setup sigaltstack */ | ||
925 | err |= __put_user(current->sas_ss_sp, &uc->stack.sp); | ||
926 | err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags); | ||
927 | err |= __put_user(current->sas_ss_size, &uc->stack.size); | ||
928 | |||
929 | /* The register file is not saved | ||
930 | * we have already stuffed all of it with sync_user_stack | ||
931 | */ | ||
932 | return (err ? -EFAULT : 0); | ||
933 | } | ||
934 | |||
935 | /* Set the context for a svr4 application, this is Solaris way to sigreturn */ | ||
936 | asmlinkage int svr4_setcontext(svr4_ucontext_t __user *c, struct pt_regs *regs) | ||
937 | { | ||
938 | svr4_gregset_t __user *gr; | ||
939 | unsigned long pc, npc, psr; | ||
940 | mm_segment_t old_fs; | ||
941 | sigset_t set; | ||
942 | svr4_sigset_t setv; | ||
943 | int err; | ||
944 | stack_t st; | ||
945 | |||
946 | /* Fixme: restore windows, or is this already taken care of in | ||
947 | * svr4_setup_frame when sync_user_windows is done? | ||
948 | */ | ||
949 | flush_user_windows(); | ||
950 | |||
951 | if (current_thread_info()->w_saved) | ||
952 | goto sigsegv_and_return; | ||
953 | |||
954 | if (((unsigned long) c) & 3) | ||
955 | goto sigsegv_and_return; | ||
956 | |||
957 | if (!__access_ok((unsigned long)c, sizeof(*c))) | ||
958 | goto sigsegv_and_return; | ||
959 | |||
960 | /* Check for valid PC and nPC */ | ||
961 | gr = &c->mcontext.greg; | ||
962 | err = __get_user(pc, &((*gr)[SVR4_PC])); | ||
963 | err |= __get_user(npc, &((*gr)[SVR4_NPC])); | ||
964 | |||
965 | if ((pc | npc) & 3) | ||
966 | goto sigsegv_and_return; | ||
967 | |||
968 | /* Retrieve information from passed ucontext */ | ||
969 | /* note that nPC is ored a 1, this is used to inform entry.S */ | ||
970 | /* that we don't want it to mess with our PC and nPC */ | ||
971 | |||
972 | /* This is pretty much atomic, no amount locking would prevent | ||
973 | * the races which exist anyways. | ||
974 | */ | ||
975 | err |= __copy_from_user(&setv, &c->sigmask, sizeof(svr4_sigset_t)); | ||
976 | |||
977 | err |= __get_user(st.ss_sp, &c->stack.sp); | ||
978 | err |= __get_user(st.ss_flags, &c->stack.flags); | ||
979 | err |= __get_user(st.ss_size, &c->stack.size); | ||
980 | |||
981 | if (err) | ||
982 | goto sigsegv_and_return; | ||
983 | |||
984 | /* It is more difficult to avoid calling this function than to | ||
985 | call it and ignore errors. */ | ||
986 | old_fs = get_fs(); | ||
987 | set_fs(KERNEL_DS); | ||
988 | do_sigaltstack((const stack_t __user *) &st, NULL, | ||
989 | regs->u_regs[UREG_I6]); | ||
990 | set_fs(old_fs); | ||
991 | |||
992 | set.sig[0] = setv.sigbits[0]; | ||
993 | set.sig[1] = setv.sigbits[1]; | ||
994 | if (_NSIG_WORDS >= 4) { | ||
995 | set.sig[2] = setv.sigbits[2]; | ||
996 | set.sig[3] = setv.sigbits[3]; | ||
997 | } | ||
998 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
999 | spin_lock_irq(¤t->sighand->siglock); | ||
1000 | current->blocked = set; | ||
1001 | recalc_sigpending(); | ||
1002 | spin_unlock_irq(¤t->sighand->siglock); | ||
1003 | regs->pc = pc; | ||
1004 | regs->npc = npc | 1; | ||
1005 | err |= __get_user(regs->y, &((*gr)[SVR4_Y])); | ||
1006 | err |= __get_user(psr, &((*gr)[SVR4_PSR])); | ||
1007 | regs->psr &= ~(PSR_ICC); | ||
1008 | regs->psr |= (psr & PSR_ICC); | ||
1009 | |||
1010 | /* Restore g[1..7] and o[0..7] registers */ | ||
1011 | err |= __copy_from_user(®s->u_regs[UREG_G1], &(*gr)[SVR4_G1], | ||
1012 | sizeof(long) * 7); | ||
1013 | err |= __copy_from_user(®s->u_regs[UREG_I0], &(*gr)[SVR4_O0], | ||
1014 | sizeof(long) * 8); | ||
1015 | return (err ? -EFAULT : 0); | ||
1016 | |||
1017 | sigsegv_and_return: | ||
1018 | force_sig(SIGSEGV, current); | ||
1019 | return -EFAULT; | ||
1020 | } | ||
1021 | |||
1022 | static inline void | ||
1023 | handle_signal(unsigned long signr, struct k_sigaction *ka, | ||
1024 | siginfo_t *info, sigset_t *oldset, struct pt_regs *regs, | ||
1025 | int svr4_signal) | ||
1026 | { | ||
1027 | if (svr4_signal) | ||
1028 | setup_svr4_frame(&ka->sa, regs->pc, regs->npc, regs, signr, oldset); | ||
1029 | else { | ||
1030 | if (ka->sa.sa_flags & SA_SIGINFO) | ||
1031 | new_setup_rt_frame(ka, regs, signr, oldset, info); | ||
1032 | else if (current->thread.new_signal) | ||
1033 | new_setup_frame(ka, regs, signr, oldset); | ||
1034 | else | ||
1035 | setup_frame(&ka->sa, regs, signr, oldset, info); | ||
1036 | } | ||
1037 | if (!(ka->sa.sa_flags & SA_NOMASK)) { | ||
1038 | spin_lock_irq(¤t->sighand->siglock); | ||
1039 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | ||
1040 | sigaddset(¤t->blocked, signr); | ||
1041 | recalc_sigpending(); | ||
1042 | spin_unlock_irq(¤t->sighand->siglock); | ||
1043 | } | ||
1044 | } | ||
1045 | |||
1046 | static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, | ||
1047 | struct sigaction *sa) | ||
1048 | { | ||
1049 | switch(regs->u_regs[UREG_I0]) { | ||
1050 | case ERESTART_RESTARTBLOCK: | ||
1051 | case ERESTARTNOHAND: | ||
1052 | no_system_call_restart: | ||
1053 | regs->u_regs[UREG_I0] = EINTR; | ||
1054 | regs->psr |= PSR_C; | ||
1055 | break; | ||
1056 | case ERESTARTSYS: | ||
1057 | if (!(sa->sa_flags & SA_RESTART)) | ||
1058 | goto no_system_call_restart; | ||
1059 | /* fallthrough */ | ||
1060 | case ERESTARTNOINTR: | ||
1061 | regs->u_regs[UREG_I0] = orig_i0; | ||
1062 | regs->pc -= 4; | ||
1063 | regs->npc -= 4; | ||
1064 | } | ||
1065 | } | ||
1066 | |||
1067 | /* Note that 'init' is a special process: it doesn't get signals it doesn't | ||
1068 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | ||
1069 | * mistake. | ||
1070 | */ | ||
1071 | asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, | ||
1072 | unsigned long orig_i0, int restart_syscall) | ||
1073 | { | ||
1074 | siginfo_t info; | ||
1075 | struct sparc_deliver_cookie cookie; | ||
1076 | struct k_sigaction ka; | ||
1077 | int signr; | ||
1078 | |||
1079 | /* | ||
1080 | * XXX Disable svr4 signal handling until solaris emulation works. | ||
1081 | * It is buggy - Anton | ||
1082 | */ | ||
1083 | #define SVR4_SIGNAL_BROKEN 1 | ||
1084 | #ifdef SVR4_SIGNAL_BROKEN | ||
1085 | int svr4_signal = 0; | ||
1086 | #else | ||
1087 | int svr4_signal = current->personality == PER_SVR4; | ||
1088 | #endif | ||
1089 | |||
1090 | cookie.restart_syscall = restart_syscall; | ||
1091 | cookie.orig_i0 = orig_i0; | ||
1092 | |||
1093 | if (!oldset) | ||
1094 | oldset = ¤t->blocked; | ||
1095 | |||
1096 | signr = get_signal_to_deliver(&info, &ka, regs, &cookie); | ||
1097 | if (signr > 0) { | ||
1098 | if (cookie.restart_syscall) | ||
1099 | syscall_restart(cookie.orig_i0, regs, &ka.sa); | ||
1100 | handle_signal(signr, &ka, &info, oldset, | ||
1101 | regs, svr4_signal); | ||
1102 | return 1; | ||
1103 | } | ||
1104 | if (cookie.restart_syscall && | ||
1105 | (regs->u_regs[UREG_I0] == ERESTARTNOHAND || | ||
1106 | regs->u_regs[UREG_I0] == ERESTARTSYS || | ||
1107 | regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { | ||
1108 | /* replay the system call when we are done */ | ||
1109 | regs->u_regs[UREG_I0] = cookie.orig_i0; | ||
1110 | regs->pc -= 4; | ||
1111 | regs->npc -= 4; | ||
1112 | } | ||
1113 | if (cookie.restart_syscall && | ||
1114 | regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { | ||
1115 | regs->u_regs[UREG_G1] = __NR_restart_syscall; | ||
1116 | regs->pc -= 4; | ||
1117 | regs->npc -= 4; | ||
1118 | } | ||
1119 | return 0; | ||
1120 | } | ||
1121 | |||
1122 | asmlinkage int | ||
1123 | do_sys_sigstack(struct sigstack __user *ssptr, struct sigstack __user *ossptr, | ||
1124 | unsigned long sp) | ||
1125 | { | ||
1126 | int ret = -EFAULT; | ||
1127 | |||
1128 | /* First see if old state is wanted. */ | ||
1129 | if (ossptr) { | ||
1130 | if (put_user(current->sas_ss_sp + current->sas_ss_size, | ||
1131 | &ossptr->the_stack) || | ||
1132 | __put_user(on_sig_stack(sp), &ossptr->cur_status)) | ||
1133 | goto out; | ||
1134 | } | ||
1135 | |||
1136 | /* Now see if we want to update the new state. */ | ||
1137 | if (ssptr) { | ||
1138 | char *ss_sp; | ||
1139 | |||
1140 | if (get_user(ss_sp, &ssptr->the_stack)) | ||
1141 | goto out; | ||
1142 | /* If the current stack was set with sigaltstack, don't | ||
1143 | swap stacks while we are on it. */ | ||
1144 | ret = -EPERM; | ||
1145 | if (current->sas_ss_sp && on_sig_stack(sp)) | ||
1146 | goto out; | ||
1147 | |||
1148 | /* Since we don't know the extent of the stack, and we don't | ||
1149 | track onstack-ness, but rather calculate it, we must | ||
1150 | presume a size. Ho hum this interface is lossy. */ | ||
1151 | current->sas_ss_sp = (unsigned long)ss_sp - SIGSTKSZ; | ||
1152 | current->sas_ss_size = SIGSTKSZ; | ||
1153 | } | ||
1154 | ret = 0; | ||
1155 | out: | ||
1156 | return ret; | ||
1157 | } | ||
1158 | |||
1159 | void ptrace_signal_deliver(struct pt_regs *regs, void *cookie) | ||
1160 | { | ||
1161 | struct sparc_deliver_cookie *cp = cookie; | ||
1162 | |||
1163 | if (cp->restart_syscall && | ||
1164 | (regs->u_regs[UREG_I0] == ERESTARTNOHAND || | ||
1165 | regs->u_regs[UREG_I0] == ERESTARTSYS || | ||
1166 | regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { | ||
1167 | /* replay the system call when we are done */ | ||
1168 | regs->u_regs[UREG_I0] = cp->orig_i0; | ||
1169 | regs->pc -= 4; | ||
1170 | regs->npc -= 4; | ||
1171 | cp->restart_syscall = 0; | ||
1172 | } | ||
1173 | |||
1174 | if (cp->restart_syscall && | ||
1175 | regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { | ||
1176 | regs->u_regs[UREG_G1] = __NR_restart_syscall; | ||
1177 | regs->pc -= 4; | ||
1178 | regs->npc -= 4; | ||
1179 | cp->restart_syscall = 0; | ||
1180 | } | ||
1181 | } | ||