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/s390/kernel/compat_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/s390/kernel/compat_signal.c')
-rw-r--r-- | arch/s390/kernel/compat_signal.c | 648 |
1 files changed, 648 insertions, 0 deletions
diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c new file mode 100644 index 000000000000..d05d65ac9694 --- /dev/null +++ b/arch/s390/kernel/compat_signal.c | |||
@@ -0,0 +1,648 @@ | |||
1 | /* | ||
2 | * arch/s390/kernel/signal32.c | ||
3 | * | ||
4 | * S390 version | ||
5 | * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation | ||
6 | * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) | ||
7 | * Gerhard Tonn (ton@de.ibm.com) | ||
8 | * | ||
9 | * Copyright (C) 1991, 1992 Linus Torvalds | ||
10 | * | ||
11 | * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson | ||
12 | */ | ||
13 | |||
14 | #include <linux/config.h> | ||
15 | #include <linux/compat.h> | ||
16 | #include <linux/sched.h> | ||
17 | #include <linux/mm.h> | ||
18 | #include <linux/smp.h> | ||
19 | #include <linux/smp_lock.h> | ||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/signal.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/wait.h> | ||
24 | #include <linux/ptrace.h> | ||
25 | #include <linux/unistd.h> | ||
26 | #include <linux/stddef.h> | ||
27 | #include <linux/tty.h> | ||
28 | #include <linux/personality.h> | ||
29 | #include <linux/binfmts.h> | ||
30 | #include <asm/ucontext.h> | ||
31 | #include <asm/uaccess.h> | ||
32 | #include <asm/lowcore.h> | ||
33 | #include "compat_linux.h" | ||
34 | #include "compat_ptrace.h" | ||
35 | |||
36 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | ||
37 | |||
38 | typedef struct | ||
39 | { | ||
40 | __u8 callee_used_stack[__SIGNAL_FRAMESIZE32]; | ||
41 | struct sigcontext32 sc; | ||
42 | _sigregs32 sregs; | ||
43 | int signo; | ||
44 | __u8 retcode[S390_SYSCALL_SIZE]; | ||
45 | } sigframe32; | ||
46 | |||
47 | typedef struct | ||
48 | { | ||
49 | __u8 callee_used_stack[__SIGNAL_FRAMESIZE32]; | ||
50 | __u8 retcode[S390_SYSCALL_SIZE]; | ||
51 | compat_siginfo_t info; | ||
52 | struct ucontext32 uc; | ||
53 | } rt_sigframe32; | ||
54 | |||
55 | asmlinkage int FASTCALL(do_signal(struct pt_regs *regs, sigset_t *oldset)); | ||
56 | |||
57 | int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) | ||
58 | { | ||
59 | int err; | ||
60 | |||
61 | if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t))) | ||
62 | return -EFAULT; | ||
63 | |||
64 | /* If you change siginfo_t structure, please be sure | ||
65 | this code is fixed accordingly. | ||
66 | It should never copy any pad contained in the structure | ||
67 | to avoid security leaks, but must copy the generic | ||
68 | 3 ints plus the relevant union member. | ||
69 | This routine must convert siginfo from 64bit to 32bit as well | ||
70 | at the same time. */ | ||
71 | err = __put_user(from->si_signo, &to->si_signo); | ||
72 | err |= __put_user(from->si_errno, &to->si_errno); | ||
73 | err |= __put_user((short)from->si_code, &to->si_code); | ||
74 | if (from->si_code < 0) | ||
75 | err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); | ||
76 | else { | ||
77 | switch (from->si_code >> 16) { | ||
78 | case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ | ||
79 | case __SI_MESGQ >> 16: | ||
80 | err |= __put_user(from->si_int, &to->si_int); | ||
81 | /* fallthrough */ | ||
82 | case __SI_KILL >> 16: | ||
83 | err |= __put_user(from->si_pid, &to->si_pid); | ||
84 | err |= __put_user(from->si_uid, &to->si_uid); | ||
85 | break; | ||
86 | case __SI_CHLD >> 16: | ||
87 | err |= __put_user(from->si_pid, &to->si_pid); | ||
88 | err |= __put_user(from->si_uid, &to->si_uid); | ||
89 | err |= __put_user(from->si_utime, &to->si_utime); | ||
90 | err |= __put_user(from->si_stime, &to->si_stime); | ||
91 | err |= __put_user(from->si_status, &to->si_status); | ||
92 | break; | ||
93 | case __SI_FAULT >> 16: | ||
94 | err |= __put_user((unsigned long) from->si_addr, | ||
95 | &to->si_addr); | ||
96 | break; | ||
97 | case __SI_POLL >> 16: | ||
98 | err |= __put_user(from->si_band, &to->si_band); | ||
99 | err |= __put_user(from->si_fd, &to->si_fd); | ||
100 | break; | ||
101 | case __SI_TIMER >> 16: | ||
102 | err |= __put_user(from->si_tid, &to->si_tid); | ||
103 | err |= __put_user(from->si_overrun, &to->si_overrun); | ||
104 | err |= __put_user(from->si_int, &to->si_int); | ||
105 | break; | ||
106 | default: | ||
107 | break; | ||
108 | } | ||
109 | } | ||
110 | return err; | ||
111 | } | ||
112 | |||
113 | int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) | ||
114 | { | ||
115 | int err; | ||
116 | u32 tmp; | ||
117 | |||
118 | if (!access_ok (VERIFY_READ, from, sizeof(compat_siginfo_t))) | ||
119 | return -EFAULT; | ||
120 | |||
121 | err = __get_user(to->si_signo, &from->si_signo); | ||
122 | err |= __get_user(to->si_errno, &from->si_errno); | ||
123 | err |= __get_user(to->si_code, &from->si_code); | ||
124 | |||
125 | if (to->si_code < 0) | ||
126 | err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); | ||
127 | else { | ||
128 | switch (to->si_code >> 16) { | ||
129 | case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ | ||
130 | case __SI_MESGQ >> 16: | ||
131 | err |= __get_user(to->si_int, &from->si_int); | ||
132 | /* fallthrough */ | ||
133 | case __SI_KILL >> 16: | ||
134 | err |= __get_user(to->si_pid, &from->si_pid); | ||
135 | err |= __get_user(to->si_uid, &from->si_uid); | ||
136 | break; | ||
137 | case __SI_CHLD >> 16: | ||
138 | err |= __get_user(to->si_pid, &from->si_pid); | ||
139 | err |= __get_user(to->si_uid, &from->si_uid); | ||
140 | err |= __get_user(to->si_utime, &from->si_utime); | ||
141 | err |= __get_user(to->si_stime, &from->si_stime); | ||
142 | err |= __get_user(to->si_status, &from->si_status); | ||
143 | break; | ||
144 | case __SI_FAULT >> 16: | ||
145 | err |= __get_user(tmp, &from->si_addr); | ||
146 | to->si_addr = (void *)(u64) (tmp & PSW32_ADDR_INSN); | ||
147 | break; | ||
148 | case __SI_POLL >> 16: | ||
149 | err |= __get_user(to->si_band, &from->si_band); | ||
150 | err |= __get_user(to->si_fd, &from->si_fd); | ||
151 | break; | ||
152 | case __SI_TIMER >> 16: | ||
153 | err |= __get_user(to->si_tid, &from->si_tid); | ||
154 | err |= __get_user(to->si_overrun, &from->si_overrun); | ||
155 | err |= __get_user(to->si_int, &from->si_int); | ||
156 | break; | ||
157 | default: | ||
158 | break; | ||
159 | } | ||
160 | } | ||
161 | return err; | ||
162 | } | ||
163 | |||
164 | /* | ||
165 | * Atomically swap in the new signal mask, and wait for a signal. | ||
166 | */ | ||
167 | asmlinkage int | ||
168 | sys32_sigsuspend(struct pt_regs * regs,int history0, int history1, old_sigset_t mask) | ||
169 | { | ||
170 | sigset_t saveset; | ||
171 | |||
172 | mask &= _BLOCKABLE; | ||
173 | spin_lock_irq(¤t->sighand->siglock); | ||
174 | saveset = current->blocked; | ||
175 | siginitset(¤t->blocked, mask); | ||
176 | recalc_sigpending(); | ||
177 | spin_unlock_irq(¤t->sighand->siglock); | ||
178 | regs->gprs[2] = -EINTR; | ||
179 | |||
180 | while (1) { | ||
181 | set_current_state(TASK_INTERRUPTIBLE); | ||
182 | schedule(); | ||
183 | if (do_signal(regs, &saveset)) | ||
184 | return -EINTR; | ||
185 | } | ||
186 | } | ||
187 | |||
188 | asmlinkage int | ||
189 | sys32_rt_sigsuspend(struct pt_regs * regs, compat_sigset_t __user *unewset, | ||
190 | size_t sigsetsize) | ||
191 | { | ||
192 | sigset_t saveset, newset; | ||
193 | compat_sigset_t set32; | ||
194 | |||
195 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
196 | if (sigsetsize != sizeof(sigset_t)) | ||
197 | return -EINVAL; | ||
198 | |||
199 | if (copy_from_user(&set32, unewset, sizeof(set32))) | ||
200 | return -EFAULT; | ||
201 | switch (_NSIG_WORDS) { | ||
202 | case 4: newset.sig[3] = set32.sig[6] + (((long)set32.sig[7]) << 32); | ||
203 | case 3: newset.sig[2] = set32.sig[4] + (((long)set32.sig[5]) << 32); | ||
204 | case 2: newset.sig[1] = set32.sig[2] + (((long)set32.sig[3]) << 32); | ||
205 | case 1: newset.sig[0] = set32.sig[0] + (((long)set32.sig[1]) << 32); | ||
206 | } | ||
207 | sigdelsetmask(&newset, ~_BLOCKABLE); | ||
208 | |||
209 | spin_lock_irq(¤t->sighand->siglock); | ||
210 | saveset = current->blocked; | ||
211 | current->blocked = newset; | ||
212 | recalc_sigpending(); | ||
213 | spin_unlock_irq(¤t->sighand->siglock); | ||
214 | regs->gprs[2] = -EINTR; | ||
215 | |||
216 | while (1) { | ||
217 | set_current_state(TASK_INTERRUPTIBLE); | ||
218 | schedule(); | ||
219 | if (do_signal(regs, &saveset)) | ||
220 | return -EINTR; | ||
221 | } | ||
222 | } | ||
223 | |||
224 | asmlinkage long | ||
225 | sys32_sigaction(int sig, const struct old_sigaction32 __user *act, | ||
226 | struct old_sigaction32 __user *oact) | ||
227 | { | ||
228 | struct k_sigaction new_ka, old_ka; | ||
229 | unsigned long sa_handler, sa_restorer; | ||
230 | int ret; | ||
231 | |||
232 | if (act) { | ||
233 | compat_old_sigset_t mask; | ||
234 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | ||
235 | __get_user(sa_handler, &act->sa_handler) || | ||
236 | __get_user(sa_restorer, &act->sa_restorer)) | ||
237 | return -EFAULT; | ||
238 | new_ka.sa.sa_handler = (__sighandler_t) sa_handler; | ||
239 | new_ka.sa.sa_restorer = (void (*)(void)) sa_restorer; | ||
240 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); | ||
241 | __get_user(mask, &act->sa_mask); | ||
242 | siginitset(&new_ka.sa.sa_mask, mask); | ||
243 | } | ||
244 | |||
245 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | ||
246 | |||
247 | if (!ret && oact) { | ||
248 | sa_handler = (unsigned long) old_ka.sa.sa_handler; | ||
249 | sa_restorer = (unsigned long) old_ka.sa.sa_restorer; | ||
250 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | ||
251 | __put_user(sa_handler, &oact->sa_handler) || | ||
252 | __put_user(sa_restorer, &oact->sa_restorer)) | ||
253 | return -EFAULT; | ||
254 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | ||
255 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | ||
256 | } | ||
257 | |||
258 | return ret; | ||
259 | } | ||
260 | |||
261 | int | ||
262 | do_sigaction(int sig, const struct k_sigaction *act, struct k_sigaction *oact); | ||
263 | |||
264 | asmlinkage long | ||
265 | sys32_rt_sigaction(int sig, const struct sigaction32 __user *act, | ||
266 | struct sigaction32 __user *oact, size_t sigsetsize) | ||
267 | { | ||
268 | struct k_sigaction new_ka, old_ka; | ||
269 | unsigned long sa_handler; | ||
270 | int ret; | ||
271 | compat_sigset_t set32; | ||
272 | |||
273 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
274 | if (sigsetsize != sizeof(compat_sigset_t)) | ||
275 | return -EINVAL; | ||
276 | |||
277 | if (act) { | ||
278 | ret = get_user(sa_handler, &act->sa_handler); | ||
279 | ret |= __copy_from_user(&set32, &act->sa_mask, | ||
280 | sizeof(compat_sigset_t)); | ||
281 | switch (_NSIG_WORDS) { | ||
282 | case 4: new_ka.sa.sa_mask.sig[3] = set32.sig[6] | ||
283 | | (((long)set32.sig[7]) << 32); | ||
284 | case 3: new_ka.sa.sa_mask.sig[2] = set32.sig[4] | ||
285 | | (((long)set32.sig[5]) << 32); | ||
286 | case 2: new_ka.sa.sa_mask.sig[1] = set32.sig[2] | ||
287 | | (((long)set32.sig[3]) << 32); | ||
288 | case 1: new_ka.sa.sa_mask.sig[0] = set32.sig[0] | ||
289 | | (((long)set32.sig[1]) << 32); | ||
290 | } | ||
291 | ret |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); | ||
292 | |||
293 | if (ret) | ||
294 | return -EFAULT; | ||
295 | new_ka.sa.sa_handler = (__sighandler_t) sa_handler; | ||
296 | } | ||
297 | |||
298 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | ||
299 | |||
300 | if (!ret && oact) { | ||
301 | switch (_NSIG_WORDS) { | ||
302 | case 4: | ||
303 | set32.sig[7] = (old_ka.sa.sa_mask.sig[3] >> 32); | ||
304 | set32.sig[6] = old_ka.sa.sa_mask.sig[3]; | ||
305 | case 3: | ||
306 | set32.sig[5] = (old_ka.sa.sa_mask.sig[2] >> 32); | ||
307 | set32.sig[4] = old_ka.sa.sa_mask.sig[2]; | ||
308 | case 2: | ||
309 | set32.sig[3] = (old_ka.sa.sa_mask.sig[1] >> 32); | ||
310 | set32.sig[2] = old_ka.sa.sa_mask.sig[1]; | ||
311 | case 1: | ||
312 | set32.sig[1] = (old_ka.sa.sa_mask.sig[0] >> 32); | ||
313 | set32.sig[0] = old_ka.sa.sa_mask.sig[0]; | ||
314 | } | ||
315 | ret = put_user((unsigned long)old_ka.sa.sa_handler, &oact->sa_handler); | ||
316 | ret |= __copy_to_user(&oact->sa_mask, &set32, | ||
317 | sizeof(compat_sigset_t)); | ||
318 | ret |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | ||
319 | } | ||
320 | |||
321 | return ret; | ||
322 | } | ||
323 | |||
324 | asmlinkage long | ||
325 | sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss, | ||
326 | struct pt_regs *regs) | ||
327 | { | ||
328 | stack_t kss, koss; | ||
329 | unsigned long ss_sp; | ||
330 | int ret, err = 0; | ||
331 | mm_segment_t old_fs = get_fs(); | ||
332 | |||
333 | if (uss) { | ||
334 | if (!access_ok(VERIFY_READ, uss, sizeof(*uss))) | ||
335 | return -EFAULT; | ||
336 | err |= __get_user(ss_sp, &uss->ss_sp); | ||
337 | err |= __get_user(kss.ss_size, &uss->ss_size); | ||
338 | err |= __get_user(kss.ss_flags, &uss->ss_flags); | ||
339 | if (err) | ||
340 | return -EFAULT; | ||
341 | kss.ss_sp = (void *) ss_sp; | ||
342 | } | ||
343 | |||
344 | set_fs (KERNEL_DS); | ||
345 | ret = do_sigaltstack((stack_t __user *) (uss ? &kss : NULL), | ||
346 | (stack_t __user *) (uoss ? &koss : NULL), | ||
347 | regs->gprs[15]); | ||
348 | set_fs (old_fs); | ||
349 | |||
350 | if (!ret && uoss) { | ||
351 | if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss))) | ||
352 | return -EFAULT; | ||
353 | ss_sp = (unsigned long) koss.ss_sp; | ||
354 | err |= __put_user(ss_sp, &uoss->ss_sp); | ||
355 | err |= __put_user(koss.ss_size, &uoss->ss_size); | ||
356 | err |= __put_user(koss.ss_flags, &uoss->ss_flags); | ||
357 | if (err) | ||
358 | return -EFAULT; | ||
359 | } | ||
360 | return ret; | ||
361 | } | ||
362 | |||
363 | static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs) | ||
364 | { | ||
365 | _s390_regs_common32 regs32; | ||
366 | int err, i; | ||
367 | |||
368 | regs32.psw.mask = PSW32_MASK_MERGE(PSW32_USER_BITS, | ||
369 | (__u32)(regs->psw.mask >> 32)); | ||
370 | regs32.psw.addr = PSW32_ADDR_AMODE31 | (__u32) regs->psw.addr; | ||
371 | for (i = 0; i < NUM_GPRS; i++) | ||
372 | regs32.gprs[i] = (__u32) regs->gprs[i]; | ||
373 | save_access_regs(current->thread.acrs); | ||
374 | memcpy(regs32.acrs, current->thread.acrs, sizeof(regs32.acrs)); | ||
375 | err = __copy_to_user(&sregs->regs, ®s32, sizeof(regs32)); | ||
376 | if (err) | ||
377 | return err; | ||
378 | save_fp_regs(¤t->thread.fp_regs); | ||
379 | /* s390_fp_regs and _s390_fp_regs32 are the same ! */ | ||
380 | return __copy_to_user(&sregs->fpregs, ¤t->thread.fp_regs, | ||
381 | sizeof(_s390_fp_regs32)); | ||
382 | } | ||
383 | |||
384 | static int restore_sigregs32(struct pt_regs *regs,_sigregs32 __user *sregs) | ||
385 | { | ||
386 | _s390_regs_common32 regs32; | ||
387 | int err, i; | ||
388 | |||
389 | /* Alwys make any pending restarted system call return -EINTR */ | ||
390 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
391 | |||
392 | err = __copy_from_user(®s32, &sregs->regs, sizeof(regs32)); | ||
393 | if (err) | ||
394 | return err; | ||
395 | regs->psw.mask = PSW_MASK_MERGE(regs->psw.mask, | ||
396 | (__u64)regs32.psw.mask << 32); | ||
397 | regs->psw.addr = (__u64)(regs32.psw.addr & PSW32_ADDR_INSN); | ||
398 | for (i = 0; i < NUM_GPRS; i++) | ||
399 | regs->gprs[i] = (__u64) regs32.gprs[i]; | ||
400 | memcpy(current->thread.acrs, regs32.acrs, sizeof(current->thread.acrs)); | ||
401 | restore_access_regs(current->thread.acrs); | ||
402 | |||
403 | err = __copy_from_user(¤t->thread.fp_regs, &sregs->fpregs, | ||
404 | sizeof(_s390_fp_regs32)); | ||
405 | current->thread.fp_regs.fpc &= FPC_VALID_MASK; | ||
406 | if (err) | ||
407 | return err; | ||
408 | |||
409 | restore_fp_regs(¤t->thread.fp_regs); | ||
410 | regs->trap = -1; /* disable syscall checks */ | ||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | asmlinkage long sys32_sigreturn(struct pt_regs *regs) | ||
415 | { | ||
416 | sigframe32 __user *frame = (sigframe32 __user *)regs->gprs[15]; | ||
417 | sigset_t set; | ||
418 | |||
419 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
420 | goto badframe; | ||
421 | if (__copy_from_user(&set.sig, &frame->sc.oldmask, _SIGMASK_COPY_SIZE32)) | ||
422 | goto badframe; | ||
423 | |||
424 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
425 | spin_lock_irq(¤t->sighand->siglock); | ||
426 | current->blocked = set; | ||
427 | recalc_sigpending(); | ||
428 | spin_unlock_irq(¤t->sighand->siglock); | ||
429 | |||
430 | if (restore_sigregs32(regs, &frame->sregs)) | ||
431 | goto badframe; | ||
432 | |||
433 | return regs->gprs[2]; | ||
434 | |||
435 | badframe: | ||
436 | force_sig(SIGSEGV, current); | ||
437 | return 0; | ||
438 | } | ||
439 | |||
440 | asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs) | ||
441 | { | ||
442 | rt_sigframe32 __user *frame = (rt_sigframe32 __user *)regs->gprs[15]; | ||
443 | sigset_t set; | ||
444 | stack_t st; | ||
445 | __u32 ss_sp; | ||
446 | int err; | ||
447 | mm_segment_t old_fs = get_fs(); | ||
448 | |||
449 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | ||
450 | goto badframe; | ||
451 | if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) | ||
452 | goto badframe; | ||
453 | |||
454 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
455 | spin_lock_irq(¤t->sighand->siglock); | ||
456 | current->blocked = set; | ||
457 | recalc_sigpending(); | ||
458 | spin_unlock_irq(¤t->sighand->siglock); | ||
459 | |||
460 | if (restore_sigregs32(regs, &frame->uc.uc_mcontext)) | ||
461 | goto badframe; | ||
462 | |||
463 | err = __get_user(ss_sp, &frame->uc.uc_stack.ss_sp); | ||
464 | st.ss_sp = (void *) A((unsigned long)ss_sp); | ||
465 | err |= __get_user(st.ss_size, &frame->uc.uc_stack.ss_size); | ||
466 | err |= __get_user(st.ss_flags, &frame->uc.uc_stack.ss_flags); | ||
467 | if (err) | ||
468 | goto badframe; | ||
469 | |||
470 | /* It is more difficult to avoid calling this function than to | ||
471 | call it and ignore errors. */ | ||
472 | set_fs (KERNEL_DS); | ||
473 | do_sigaltstack((stack_t __user *)&st, NULL, regs->gprs[15]); | ||
474 | set_fs (old_fs); | ||
475 | |||
476 | return regs->gprs[2]; | ||
477 | |||
478 | badframe: | ||
479 | force_sig(SIGSEGV, current); | ||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | /* | ||
484 | * Set up a signal frame. | ||
485 | */ | ||
486 | |||
487 | |||
488 | /* | ||
489 | * Determine which stack to use.. | ||
490 | */ | ||
491 | static inline void __user * | ||
492 | get_sigframe(struct k_sigaction *ka, struct pt_regs * regs, size_t frame_size) | ||
493 | { | ||
494 | unsigned long sp; | ||
495 | |||
496 | /* Default to using normal stack */ | ||
497 | sp = (unsigned long) A(regs->gprs[15]); | ||
498 | |||
499 | /* This is the X/Open sanctioned signal stack switching. */ | ||
500 | if (ka->sa.sa_flags & SA_ONSTACK) { | ||
501 | if (! on_sig_stack(sp)) | ||
502 | sp = current->sas_ss_sp + current->sas_ss_size; | ||
503 | } | ||
504 | |||
505 | /* This is the legacy signal stack switching. */ | ||
506 | else if (!user_mode(regs) && | ||
507 | !(ka->sa.sa_flags & SA_RESTORER) && | ||
508 | ka->sa.sa_restorer) { | ||
509 | sp = (unsigned long) ka->sa.sa_restorer; | ||
510 | } | ||
511 | |||
512 | return (void __user *)((sp - frame_size) & -8ul); | ||
513 | } | ||
514 | |||
515 | static inline int map_signal(int sig) | ||
516 | { | ||
517 | if (current_thread_info()->exec_domain | ||
518 | && current_thread_info()->exec_domain->signal_invmap | ||
519 | && sig < 32) | ||
520 | return current_thread_info()->exec_domain->signal_invmap[sig]; | ||
521 | else | ||
522 | return sig; | ||
523 | } | ||
524 | |||
525 | static void setup_frame32(int sig, struct k_sigaction *ka, | ||
526 | sigset_t *set, struct pt_regs * regs) | ||
527 | { | ||
528 | sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(sigframe32)); | ||
529 | if (!access_ok(VERIFY_WRITE, frame, sizeof(sigframe32))) | ||
530 | goto give_sigsegv; | ||
531 | |||
532 | if (__copy_to_user(&frame->sc.oldmask, &set->sig, _SIGMASK_COPY_SIZE32)) | ||
533 | goto give_sigsegv; | ||
534 | |||
535 | if (save_sigregs32(regs, &frame->sregs)) | ||
536 | goto give_sigsegv; | ||
537 | if (__put_user((unsigned long) &frame->sregs, &frame->sc.sregs)) | ||
538 | goto give_sigsegv; | ||
539 | |||
540 | /* Set up to return from userspace. If provided, use a stub | ||
541 | already in userspace. */ | ||
542 | if (ka->sa.sa_flags & SA_RESTORER) { | ||
543 | regs->gprs[14] = (__u64) ka->sa.sa_restorer; | ||
544 | } else { | ||
545 | regs->gprs[14] = (__u64) frame->retcode; | ||
546 | if (__put_user(S390_SYSCALL_OPCODE | __NR_sigreturn, | ||
547 | (u16 __user *)(frame->retcode))) | ||
548 | goto give_sigsegv; | ||
549 | } | ||
550 | |||
551 | /* Set up backchain. */ | ||
552 | if (__put_user(regs->gprs[15], (unsigned int __user *) frame)) | ||
553 | goto give_sigsegv; | ||
554 | |||
555 | /* Set up registers for signal handler */ | ||
556 | regs->gprs[15] = (__u64) frame; | ||
557 | regs->psw.addr = (__u64) ka->sa.sa_handler; | ||
558 | |||
559 | regs->gprs[2] = map_signal(sig); | ||
560 | regs->gprs[3] = (__u64) &frame->sc; | ||
561 | |||
562 | /* We forgot to include these in the sigcontext. | ||
563 | To avoid breaking binary compatibility, they are passed as args. */ | ||
564 | regs->gprs[4] = current->thread.trap_no; | ||
565 | regs->gprs[5] = current->thread.prot_addr; | ||
566 | |||
567 | /* Place signal number on stack to allow backtrace from handler. */ | ||
568 | if (__put_user(regs->gprs[2], (int __user *) &frame->signo)) | ||
569 | goto give_sigsegv; | ||
570 | return; | ||
571 | |||
572 | give_sigsegv: | ||
573 | force_sigsegv(sig, current); | ||
574 | } | ||
575 | |||
576 | static void setup_rt_frame32(int sig, struct k_sigaction *ka, siginfo_t *info, | ||
577 | sigset_t *set, struct pt_regs * regs) | ||
578 | { | ||
579 | int err = 0; | ||
580 | rt_sigframe32 __user *frame = get_sigframe(ka, regs, sizeof(rt_sigframe32)); | ||
581 | if (!access_ok(VERIFY_WRITE, frame, sizeof(rt_sigframe32))) | ||
582 | goto give_sigsegv; | ||
583 | |||
584 | if (copy_siginfo_to_user32(&frame->info, info)) | ||
585 | goto give_sigsegv; | ||
586 | |||
587 | /* Create the ucontext. */ | ||
588 | err |= __put_user(0, &frame->uc.uc_flags); | ||
589 | err |= __put_user(0, &frame->uc.uc_link); | ||
590 | err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); | ||
591 | err |= __put_user(sas_ss_flags(regs->gprs[15]), | ||
592 | &frame->uc.uc_stack.ss_flags); | ||
593 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | ||
594 | err |= save_sigregs32(regs, &frame->uc.uc_mcontext); | ||
595 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | ||
596 | if (err) | ||
597 | goto give_sigsegv; | ||
598 | |||
599 | /* Set up to return from userspace. If provided, use a stub | ||
600 | already in userspace. */ | ||
601 | if (ka->sa.sa_flags & SA_RESTORER) { | ||
602 | regs->gprs[14] = (__u64) ka->sa.sa_restorer; | ||
603 | } else { | ||
604 | regs->gprs[14] = (__u64) frame->retcode; | ||
605 | err |= __put_user(S390_SYSCALL_OPCODE | __NR_rt_sigreturn, | ||
606 | (u16 __user *)(frame->retcode)); | ||
607 | } | ||
608 | |||
609 | /* Set up backchain. */ | ||
610 | if (__put_user(regs->gprs[15], (unsigned int __user *) frame)) | ||
611 | goto give_sigsegv; | ||
612 | |||
613 | /* Set up registers for signal handler */ | ||
614 | regs->gprs[15] = (__u64) frame; | ||
615 | regs->psw.addr = (__u64) ka->sa.sa_handler; | ||
616 | |||
617 | regs->gprs[2] = map_signal(sig); | ||
618 | regs->gprs[3] = (__u64) &frame->info; | ||
619 | regs->gprs[4] = (__u64) &frame->uc; | ||
620 | return; | ||
621 | |||
622 | give_sigsegv: | ||
623 | force_sigsegv(sig, current); | ||
624 | } | ||
625 | |||
626 | /* | ||
627 | * OK, we're invoking a handler | ||
628 | */ | ||
629 | |||
630 | void | ||
631 | handle_signal32(unsigned long sig, struct k_sigaction *ka, | ||
632 | siginfo_t *info, sigset_t *oldset, struct pt_regs * regs) | ||
633 | { | ||
634 | /* Set up the stack frame */ | ||
635 | if (ka->sa.sa_flags & SA_SIGINFO) | ||
636 | setup_rt_frame32(sig, ka, info, oldset, regs); | ||
637 | else | ||
638 | setup_frame32(sig, ka, oldset, regs); | ||
639 | |||
640 | if (!(ka->sa.sa_flags & SA_NODEFER)) { | ||
641 | spin_lock_irq(¤t->sighand->siglock); | ||
642 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | ||
643 | sigaddset(¤t->blocked,sig); | ||
644 | recalc_sigpending(); | ||
645 | spin_unlock_irq(¤t->sighand->siglock); | ||
646 | } | ||
647 | } | ||
648 | |||