Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * This file is subject to the terms and conditions of the GNU General Public | |
3 | * License. See the file "COPYING" in the main directory of this archive | |
4 | * for more details. | |
5 | * | |
6 | * Copyright (C) 1991, 1992 Linus Torvalds | |
dda73d0b | 7 | * Copyright (C) 1994 - 2000, 2006 Ralf Baechle |
1da177e4 LT |
8 | * Copyright (C) 1999, 2000 Silicon Graphics, Inc. |
9 | */ | |
02416dcf | 10 | #include <linux/cache.h> |
431dc804 | 11 | #include <linux/compat.h> |
1da177e4 LT |
12 | #include <linux/sched.h> |
13 | #include <linux/mm.h> | |
14 | #include <linux/smp.h> | |
1da177e4 LT |
15 | #include <linux/kernel.h> |
16 | #include <linux/signal.h> | |
17 | #include <linux/syscalls.h> | |
18 | #include <linux/errno.h> | |
19 | #include <linux/wait.h> | |
20 | #include <linux/ptrace.h> | |
1da177e4 LT |
21 | #include <linux/suspend.h> |
22 | #include <linux/compiler.h> | |
faea6234 | 23 | #include <linux/uaccess.h> |
1da177e4 | 24 | |
e50c0a8f | 25 | #include <asm/abi.h> |
1da177e4 | 26 | #include <asm/asm.h> |
431dc804 | 27 | #include <asm/compat-signal.h> |
1da177e4 LT |
28 | #include <linux/bitops.h> |
29 | #include <asm/cacheflush.h> | |
30 | #include <asm/sim.h> | |
1da177e4 | 31 | #include <asm/ucontext.h> |
1da177e4 | 32 | #include <asm/fpu.h> |
02416dcf | 33 | #include <asm/war.h> |
d814c28c | 34 | #include <asm/vdso.h> |
b81947c6 | 35 | #include <asm/dsp.h> |
1da177e4 | 36 | |
36a1f2c2 FBH |
37 | #include "signal-common.h" |
38 | ||
137f6f3e RB |
39 | static int (*save_fp_context32)(struct sigcontext32 __user *sc); |
40 | static int (*restore_fp_context32)(struct sigcontext32 __user *sc); | |
41 | ||
42 | extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc); | |
43 | extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc); | |
44 | ||
45 | extern asmlinkage int fpu_emulator_save_context32(struct sigcontext32 __user *sc); | |
46 | extern asmlinkage int fpu_emulator_restore_context32(struct sigcontext32 __user *sc); | |
47 | ||
1da177e4 LT |
48 | /* |
49 | * Including <asm/unistd.h> would give use the 64-bit syscall numbers ... | |
50 | */ | |
151fd6ac | 51 | #define __NR_O32_restart_syscall 4253 |
1da177e4 | 52 | |
1da177e4 LT |
53 | /* 32-bit compatibility types */ |
54 | ||
1da177e4 LT |
55 | typedef unsigned int __sighandler32_t; |
56 | typedef void (*vfptr_t)(void); | |
57 | ||
58 | struct sigaction32 { | |
59 | unsigned int sa_flags; | |
60 | __sighandler32_t sa_handler; | |
61 | compat_sigset_t sa_mask; | |
62 | }; | |
63 | ||
64 | /* IRIX compatible stack_t */ | |
65 | typedef struct sigaltstack32 { | |
66 | s32 ss_sp; | |
67 | compat_size_t ss_size; | |
68 | int ss_flags; | |
69 | } stack32_t; | |
70 | ||
71 | struct ucontext32 { | |
72 | u32 uc_flags; | |
73 | s32 uc_link; | |
74 | stack32_t uc_stack; | |
75 | struct sigcontext32 uc_mcontext; | |
01ee6037 | 76 | compat_sigset_t uc_sigmask; /* mask last for extensibility */ |
1da177e4 LT |
77 | }; |
78 | ||
dd02f06a RB |
79 | struct sigframe32 { |
80 | u32 sf_ass[4]; /* argument save space for o32 */ | |
d814c28c | 81 | u32 sf_pad[2]; /* Was: signal trampoline */ |
dd02f06a | 82 | struct sigcontext32 sf_sc; |
755f21bb | 83 | compat_sigset_t sf_mask; |
dd02f06a RB |
84 | }; |
85 | ||
c0b9bae9 FBH |
86 | struct rt_sigframe32 { |
87 | u32 rs_ass[4]; /* argument save space for o32 */ | |
d814c28c | 88 | u32 rs_pad[2]; /* Was: signal trampoline */ |
c0b9bae9 FBH |
89 | compat_siginfo_t rs_info; |
90 | struct ucontext32 rs_uc; | |
91 | }; | |
92 | ||
9432a9ba FBH |
93 | /* |
94 | * sigcontext handlers | |
95 | */ | |
faea6234 AN |
96 | static int protected_save_fp_context32(struct sigcontext32 __user *sc) |
97 | { | |
98 | int err; | |
99 | while (1) { | |
100 | lock_fpu_owner(); | |
101 | own_fpu_inatomic(1); | |
102 | err = save_fp_context32(sc); /* this might fail */ | |
103 | unlock_fpu_owner(); | |
104 | if (likely(!err)) | |
105 | break; | |
106 | /* touch the sigcontext and try again */ | |
107 | err = __put_user(0, &sc->sc_fpregs[0]) | | |
108 | __put_user(0, &sc->sc_fpregs[31]) | | |
109 | __put_user(0, &sc->sc_fpc_csr); | |
110 | if (err) | |
111 | break; /* really bad sigcontext */ | |
112 | } | |
113 | return err; | |
114 | } | |
115 | ||
116 | static int protected_restore_fp_context32(struct sigcontext32 __user *sc) | |
117 | { | |
c726b822 | 118 | int err, tmp __maybe_unused; |
faea6234 AN |
119 | while (1) { |
120 | lock_fpu_owner(); | |
121 | own_fpu_inatomic(0); | |
122 | err = restore_fp_context32(sc); /* this might fail */ | |
123 | unlock_fpu_owner(); | |
124 | if (likely(!err)) | |
125 | break; | |
126 | /* touch the sigcontext and try again */ | |
127 | err = __get_user(tmp, &sc->sc_fpregs[0]) | | |
128 | __get_user(tmp, &sc->sc_fpregs[31]) | | |
129 | __get_user(tmp, &sc->sc_fpc_csr); | |
130 | if (err) | |
131 | break; /* really bad sigcontext */ | |
132 | } | |
133 | return err; | |
134 | } | |
135 | ||
9432a9ba FBH |
136 | static int setup_sigcontext32(struct pt_regs *regs, |
137 | struct sigcontext32 __user *sc) | |
138 | { | |
139 | int err = 0; | |
140 | int i; | |
53dc8028 | 141 | u32 used_math; |
9432a9ba FBH |
142 | |
143 | err |= __put_user(regs->cp0_epc, &sc->sc_pc); | |
9432a9ba FBH |
144 | |
145 | err |= __put_user(0, &sc->sc_regs[0]); | |
146 | for (i = 1; i < 32; i++) | |
147 | err |= __put_user(regs->regs[i], &sc->sc_regs[i]); | |
148 | ||
149 | err |= __put_user(regs->hi, &sc->sc_mdhi); | |
150 | err |= __put_user(regs->lo, &sc->sc_mdlo); | |
151 | if (cpu_has_dsp) { | |
152 | err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); | |
153 | err |= __put_user(mfhi1(), &sc->sc_hi1); | |
154 | err |= __put_user(mflo1(), &sc->sc_lo1); | |
155 | err |= __put_user(mfhi2(), &sc->sc_hi2); | |
156 | err |= __put_user(mflo2(), &sc->sc_lo2); | |
157 | err |= __put_user(mfhi3(), &sc->sc_hi3); | |
158 | err |= __put_user(mflo3(), &sc->sc_lo3); | |
159 | } | |
160 | ||
53dc8028 AN |
161 | used_math = !!used_math(); |
162 | err |= __put_user(used_math, &sc->sc_used_math); | |
9432a9ba | 163 | |
53dc8028 | 164 | if (used_math) { |
9432a9ba FBH |
165 | /* |
166 | * Save FPU state to signal context. Signal handler | |
167 | * will "inherit" current FPU state. | |
168 | */ | |
faea6234 | 169 | err |= protected_save_fp_context32(sc); |
9432a9ba FBH |
170 | } |
171 | return err; | |
172 | } | |
173 | ||
c6a2f467 AN |
174 | static int |
175 | check_and_restore_fp_context32(struct sigcontext32 __user *sc) | |
176 | { | |
177 | int err, sig; | |
178 | ||
179 | err = sig = fpcsr_pending(&sc->sc_fpc_csr); | |
180 | if (err > 0) | |
181 | err = 0; | |
faea6234 | 182 | err |= protected_restore_fp_context32(sc); |
c6a2f467 AN |
183 | return err ?: sig; |
184 | } | |
185 | ||
9432a9ba FBH |
186 | static int restore_sigcontext32(struct pt_regs *regs, |
187 | struct sigcontext32 __user *sc) | |
188 | { | |
189 | u32 used_math; | |
190 | int err = 0; | |
191 | s32 treg; | |
192 | int i; | |
193 | ||
194 | /* Always make any pending restarted system calls return -EINTR */ | |
195 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | |
196 | ||
197 | err |= __get_user(regs->cp0_epc, &sc->sc_pc); | |
198 | err |= __get_user(regs->hi, &sc->sc_mdhi); | |
199 | err |= __get_user(regs->lo, &sc->sc_mdlo); | |
200 | if (cpu_has_dsp) { | |
201 | err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); | |
202 | err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); | |
203 | err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); | |
204 | err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); | |
205 | err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); | |
206 | err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); | |
207 | err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); | |
208 | } | |
209 | ||
210 | for (i = 1; i < 32; i++) | |
211 | err |= __get_user(regs->regs[i], &sc->sc_regs[i]); | |
212 | ||
213 | err |= __get_user(used_math, &sc->sc_used_math); | |
214 | conditional_used_math(used_math); | |
215 | ||
53dc8028 | 216 | if (used_math) { |
9432a9ba | 217 | /* restore fpu context if we have used it before */ |
c6a2f467 AN |
218 | if (!err) |
219 | err = check_and_restore_fp_context32(sc); | |
9432a9ba FBH |
220 | } else { |
221 | /* signal handler may have used FPU. Give it up. */ | |
53dc8028 | 222 | lose_fpu(0); |
9432a9ba FBH |
223 | } |
224 | ||
9432a9ba FBH |
225 | return err; |
226 | } | |
227 | ||
228 | /* | |
229 | * | |
230 | */ | |
1da177e4 LT |
231 | extern void __put_sigset_unknown_nsig(void); |
232 | extern void __get_sigset_unknown_nsig(void); | |
233 | ||
9bbf28a3 | 234 | static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf) |
1da177e4 LT |
235 | { |
236 | int err = 0; | |
237 | ||
238 | if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf))) | |
239 | return -EFAULT; | |
240 | ||
241 | switch (_NSIG_WORDS) { | |
242 | default: | |
243 | __put_sigset_unknown_nsig(); | |
244 | case 2: | |
49a89efb RB |
245 | err |= __put_user(kbuf->sig[1] >> 32, &ubuf->sig[3]); |
246 | err |= __put_user(kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]); | |
1da177e4 | 247 | case 1: |
49a89efb RB |
248 | err |= __put_user(kbuf->sig[0] >> 32, &ubuf->sig[1]); |
249 | err |= __put_user(kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]); | |
1da177e4 LT |
250 | } |
251 | ||
252 | return err; | |
253 | } | |
254 | ||
9c6031cc | 255 | static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf) |
1da177e4 LT |
256 | { |
257 | int err = 0; | |
258 | unsigned long sig[4]; | |
259 | ||
260 | if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf))) | |
261 | return -EFAULT; | |
262 | ||
263 | switch (_NSIG_WORDS) { | |
264 | default: | |
265 | __get_sigset_unknown_nsig(); | |
266 | case 2: | |
49a89efb RB |
267 | err |= __get_user(sig[3], &ubuf->sig[3]); |
268 | err |= __get_user(sig[2], &ubuf->sig[2]); | |
1da177e4 LT |
269 | kbuf->sig[1] = sig[2] | (sig[3] << 32); |
270 | case 1: | |
49a89efb RB |
271 | err |= __get_user(sig[1], &ubuf->sig[1]); |
272 | err |= __get_user(sig[0], &ubuf->sig[0]); | |
1da177e4 LT |
273 | kbuf->sig[0] = sig[0] | (sig[1] << 32); |
274 | } | |
275 | ||
276 | return err; | |
277 | } | |
278 | ||
279 | /* | |
280 | * Atomically swap in the new signal mask, and wait for a signal. | |
281 | */ | |
282 | ||
f90080a0 | 283 | asmlinkage int sys32_sigsuspend(nabi_no_regargs struct pt_regs regs) |
1da177e4 | 284 | { |
9c6031cc | 285 | compat_sigset_t __user *uset; |
68fa383f | 286 | sigset_t newset; |
1da177e4 | 287 | |
9c6031cc | 288 | uset = (compat_sigset_t __user *) regs.regs[4]; |
1da177e4 LT |
289 | if (get_sigset(&newset, uset)) |
290 | return -EFAULT; | |
68f3f16d | 291 | return sigsuspend(&newset); |
1da177e4 LT |
292 | } |
293 | ||
f90080a0 | 294 | asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) |
1da177e4 | 295 | { |
9c6031cc | 296 | compat_sigset_t __user *uset; |
68fa383f | 297 | sigset_t newset; |
304416da | 298 | size_t sigsetsize; |
1da177e4 LT |
299 | |
300 | /* XXX Don't preclude handling different sized sigset_t's. */ | |
301 | sigsetsize = regs.regs[5]; | |
302 | if (sigsetsize != sizeof(compat_sigset_t)) | |
303 | return -EINVAL; | |
304 | ||
9c6031cc | 305 | uset = (compat_sigset_t __user *) regs.regs[4]; |
1da177e4 LT |
306 | if (get_sigset(&newset, uset)) |
307 | return -EFAULT; | |
68f3f16d | 308 | return sigsuspend(&newset); |
1da177e4 LT |
309 | } |
310 | ||
dbda6ac0 RB |
311 | SYSCALL_DEFINE3(32_sigaction, long, sig, const struct sigaction32 __user *, act, |
312 | struct sigaction32 __user *, oact) | |
1da177e4 LT |
313 | { |
314 | struct k_sigaction new_ka, old_ka; | |
315 | int ret; | |
316 | int err = 0; | |
317 | ||
318 | if (act) { | |
319 | old_sigset_t mask; | |
77c728c2 | 320 | s32 handler; |
1da177e4 LT |
321 | |
322 | if (!access_ok(VERIFY_READ, act, sizeof(*act))) | |
323 | return -EFAULT; | |
77c728c2 | 324 | err |= __get_user(handler, &act->sa_handler); |
9bbf28a3 | 325 | new_ka.sa.sa_handler = (void __user *)(s64)handler; |
1da177e4 LT |
326 | err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); |
327 | err |= __get_user(mask, &act->sa_mask.sig[0]); | |
328 | if (err) | |
329 | return -EFAULT; | |
330 | ||
331 | siginitset(&new_ka.sa.sa_mask, mask); | |
332 | } | |
333 | ||
334 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | |
335 | ||
336 | if (!ret && oact) { | |
337 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) | |
6254944f | 338 | return -EFAULT; |
1da177e4 LT |
339 | err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); |
340 | err |= __put_user((u32)(u64)old_ka.sa.sa_handler, | |
341 | &oact->sa_handler); | |
342 | err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig); | |
6254944f MM |
343 | err |= __put_user(0, &oact->sa_mask.sig[1]); |
344 | err |= __put_user(0, &oact->sa_mask.sig[2]); | |
345 | err |= __put_user(0, &oact->sa_mask.sig[3]); | |
346 | if (err) | |
1da177e4 LT |
347 | return -EFAULT; |
348 | } | |
349 | ||
350 | return ret; | |
351 | } | |
352 | ||
353 | asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs) | |
354 | { | |
9bbf28a3 AN |
355 | const stack32_t __user *uss = (const stack32_t __user *) regs.regs[4]; |
356 | stack32_t __user *uoss = (stack32_t __user *) regs.regs[5]; | |
1da177e4 LT |
357 | unsigned long usp = regs.regs[29]; |
358 | stack_t kss, koss; | |
359 | int ret, err = 0; | |
360 | mm_segment_t old_fs = get_fs(); | |
361 | s32 sp; | |
362 | ||
363 | if (uss) { | |
364 | if (!access_ok(VERIFY_READ, uss, sizeof(*uss))) | |
365 | return -EFAULT; | |
366 | err |= __get_user(sp, &uss->ss_sp); | |
9c6031cc | 367 | kss.ss_sp = (void __user *) (long) sp; |
1da177e4 LT |
368 | err |= __get_user(kss.ss_size, &uss->ss_size); |
369 | err |= __get_user(kss.ss_flags, &uss->ss_flags); | |
370 | if (err) | |
371 | return -EFAULT; | |
372 | } | |
373 | ||
49a89efb | 374 | set_fs(KERNEL_DS); |
9bbf28a3 AN |
375 | ret = do_sigaltstack(uss ? (stack_t __user *)&kss : NULL, |
376 | uoss ? (stack_t __user *)&koss : NULL, usp); | |
49a89efb | 377 | set_fs(old_fs); |
1da177e4 LT |
378 | |
379 | if (!ret && uoss) { | |
380 | if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss))) | |
381 | return -EFAULT; | |
9c6031cc | 382 | sp = (int) (unsigned long) koss.ss_sp; |
1da177e4 LT |
383 | err |= __put_user(sp, &uoss->ss_sp); |
384 | err |= __put_user(koss.ss_size, &uoss->ss_size); | |
385 | err |= __put_user(koss.ss_flags, &uoss->ss_flags); | |
386 | if (err) | |
387 | return -EFAULT; | |
388 | } | |
389 | return ret; | |
390 | } | |
391 | ||
9bbf28a3 | 392 | int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) |
1da177e4 LT |
393 | { |
394 | int err; | |
395 | ||
396 | if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t))) | |
397 | return -EFAULT; | |
398 | ||
399 | /* If you change siginfo_t structure, please be sure | |
400 | this code is fixed accordingly. | |
401 | It should never copy any pad contained in the structure | |
402 | to avoid security leaks, but must copy the generic | |
403 | 3 ints plus the relevant union member. | |
404 | This routine must convert siginfo from 64bit to 32bit as well | |
405 | at the same time. */ | |
406 | err = __put_user(from->si_signo, &to->si_signo); | |
407 | err |= __put_user(from->si_errno, &to->si_errno); | |
408 | err |= __put_user((short)from->si_code, &to->si_code); | |
409 | if (from->si_code < 0) | |
410 | err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); | |
411 | else { | |
412 | switch (from->si_code >> 16) { | |
a982099c RB |
413 | case __SI_TIMER >> 16: |
414 | err |= __put_user(from->si_tid, &to->si_tid); | |
415 | err |= __put_user(from->si_overrun, &to->si_overrun); | |
416 | err |= __put_user(from->si_int, &to->si_int); | |
417 | break; | |
1da177e4 LT |
418 | case __SI_CHLD >> 16: |
419 | err |= __put_user(from->si_utime, &to->si_utime); | |
420 | err |= __put_user(from->si_stime, &to->si_stime); | |
421 | err |= __put_user(from->si_status, &to->si_status); | |
422 | default: | |
423 | err |= __put_user(from->si_pid, &to->si_pid); | |
424 | err |= __put_user(from->si_uid, &to->si_uid); | |
425 | break; | |
426 | case __SI_FAULT >> 16: | |
5665a0ac | 427 | err |= __put_user((unsigned long)from->si_addr, &to->si_addr); |
1da177e4 LT |
428 | break; |
429 | case __SI_POLL >> 16: | |
430 | err |= __put_user(from->si_band, &to->si_band); | |
431 | err |= __put_user(from->si_fd, &to->si_fd); | |
432 | break; | |
433 | case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ | |
434 | case __SI_MESGQ >> 16: | |
435 | err |= __put_user(from->si_pid, &to->si_pid); | |
436 | err |= __put_user(from->si_uid, &to->si_uid); | |
437 | err |= __put_user(from->si_int, &to->si_int); | |
438 | break; | |
439 | } | |
440 | } | |
441 | return err; | |
442 | } | |
443 | ||
5d9a76cd TB |
444 | int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) |
445 | { | |
446 | memset(to, 0, sizeof *to); | |
447 | ||
448 | if (copy_from_user(to, from, 3*sizeof(int)) || | |
449 | copy_from_user(to->_sifields._pad, | |
450 | from->_sifields._pad, SI_PAD_SIZE32)) | |
451 | return -EFAULT; | |
452 | ||
453 | return 0; | |
454 | } | |
455 | ||
f90080a0 | 456 | asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs) |
1da177e4 | 457 | { |
dd02f06a | 458 | struct sigframe32 __user *frame; |
1da177e4 | 459 | sigset_t blocked; |
c6a2f467 | 460 | int sig; |
1da177e4 | 461 | |
dd02f06a | 462 | frame = (struct sigframe32 __user *) regs.regs[29]; |
1da177e4 LT |
463 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
464 | goto badframe; | |
431dc804 | 465 | if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask)) |
1da177e4 LT |
466 | goto badframe; |
467 | ||
468 | sigdelsetmask(&blocked, ~_BLOCKABLE); | |
8598f3cd | 469 | set_current_blocked(&blocked); |
1da177e4 | 470 | |
c6a2f467 AN |
471 | sig = restore_sigcontext32(®s, &frame->sf_sc); |
472 | if (sig < 0) | |
1da177e4 | 473 | goto badframe; |
c6a2f467 AN |
474 | else if (sig) |
475 | force_sig(sig, current); | |
1da177e4 LT |
476 | |
477 | /* | |
478 | * Don't let your children do this ... | |
479 | */ | |
1da177e4 LT |
480 | __asm__ __volatile__( |
481 | "move\t$29, %0\n\t" | |
482 | "j\tsyscall_exit" | |
483 | :/* no outputs */ | |
484 | :"r" (®s)); | |
485 | /* Unreached */ | |
486 | ||
487 | badframe: | |
488 | force_sig(SIGSEGV, current); | |
489 | } | |
490 | ||
f90080a0 | 491 | asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) |
1da177e4 | 492 | { |
9bbf28a3 | 493 | struct rt_sigframe32 __user *frame; |
1fcf1cc7 | 494 | mm_segment_t old_fs; |
1da177e4 LT |
495 | sigset_t set; |
496 | stack_t st; | |
497 | s32 sp; | |
c6a2f467 | 498 | int sig; |
1da177e4 | 499 | |
9bbf28a3 | 500 | frame = (struct rt_sigframe32 __user *) regs.regs[29]; |
1da177e4 LT |
501 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
502 | goto badframe; | |
431dc804 | 503 | if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask)) |
1da177e4 LT |
504 | goto badframe; |
505 | ||
506 | sigdelsetmask(&set, ~_BLOCKABLE); | |
8598f3cd | 507 | set_current_blocked(&set); |
1da177e4 | 508 | |
c6a2f467 AN |
509 | sig = restore_sigcontext32(®s, &frame->rs_uc.uc_mcontext); |
510 | if (sig < 0) | |
1da177e4 | 511 | goto badframe; |
c6a2f467 AN |
512 | else if (sig) |
513 | force_sig(sig, current); | |
1da177e4 LT |
514 | |
515 | /* The ucontext contains a stack32_t, so we must convert! */ | |
516 | if (__get_user(sp, &frame->rs_uc.uc_stack.ss_sp)) | |
517 | goto badframe; | |
9c6031cc | 518 | st.ss_sp = (void __user *)(long) sp; |
1da177e4 LT |
519 | if (__get_user(st.ss_size, &frame->rs_uc.uc_stack.ss_size)) |
520 | goto badframe; | |
521 | if (__get_user(st.ss_flags, &frame->rs_uc.uc_stack.ss_flags)) | |
522 | goto badframe; | |
523 | ||
524 | /* It is more difficult to avoid calling this function than to | |
525 | call it and ignore errors. */ | |
1fcf1cc7 | 526 | old_fs = get_fs(); |
49a89efb | 527 | set_fs(KERNEL_DS); |
9bbf28a3 | 528 | do_sigaltstack((stack_t __user *)&st, NULL, regs.regs[29]); |
49a89efb | 529 | set_fs(old_fs); |
1da177e4 LT |
530 | |
531 | /* | |
532 | * Don't let your children do this ... | |
533 | */ | |
534 | __asm__ __volatile__( | |
535 | "move\t$29, %0\n\t" | |
536 | "j\tsyscall_exit" | |
537 | :/* no outputs */ | |
538 | :"r" (®s)); | |
539 | /* Unreached */ | |
540 | ||
541 | badframe: | |
542 | force_sig(SIGSEGV, current); | |
543 | } | |
544 | ||
d814c28c DD |
545 | static int setup_frame_32(void *sig_return, struct k_sigaction *ka, |
546 | struct pt_regs *regs, int signr, sigset_t *set) | |
1da177e4 | 547 | { |
dd02f06a | 548 | struct sigframe32 __user *frame; |
1da177e4 LT |
549 | int err = 0; |
550 | ||
551 | frame = get_sigframe(ka, regs, sizeof(*frame)); | |
552 | if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) | |
553 | goto give_sigsegv; | |
554 | ||
1da177e4 | 555 | err |= setup_sigcontext32(regs, &frame->sf_sc); |
431dc804 RB |
556 | err |= __copy_conv_sigset_to_user(&frame->sf_mask, set); |
557 | ||
1da177e4 LT |
558 | if (err) |
559 | goto give_sigsegv; | |
560 | ||
561 | /* | |
562 | * Arguments to signal handler: | |
563 | * | |
564 | * a0 = signal number | |
565 | * a1 = 0 (should be cause) | |
566 | * a2 = pointer to struct sigcontext | |
567 | * | |
568 | * $25 and c0_epc point to the signal handler, $29 points to the | |
569 | * struct sigframe. | |
570 | */ | |
571 | regs->regs[ 4] = signr; | |
572 | regs->regs[ 5] = 0; | |
573 | regs->regs[ 6] = (unsigned long) &frame->sf_sc; | |
574 | regs->regs[29] = (unsigned long) frame; | |
d814c28c | 575 | regs->regs[31] = (unsigned long) sig_return; |
1da177e4 LT |
576 | regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; |
577 | ||
722bb63d | 578 | DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", |
1da177e4 | 579 | current->comm, current->pid, |
722bb63d FBH |
580 | frame, regs->cp0_epc, regs->regs[31]); |
581 | ||
7b3e2fc8 | 582 | return 0; |
1da177e4 LT |
583 | |
584 | give_sigsegv: | |
585 | force_sigsegv(signr, current); | |
7b3e2fc8 | 586 | return -EFAULT; |
1da177e4 LT |
587 | } |
588 | ||
d814c28c DD |
589 | static int setup_rt_frame_32(void *sig_return, struct k_sigaction *ka, |
590 | struct pt_regs *regs, int signr, sigset_t *set, | |
591 | siginfo_t *info) | |
1da177e4 | 592 | { |
9bbf28a3 | 593 | struct rt_sigframe32 __user *frame; |
1da177e4 LT |
594 | int err = 0; |
595 | s32 sp; | |
596 | ||
597 | frame = get_sigframe(ka, regs, sizeof(*frame)); | |
598 | if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) | |
599 | goto give_sigsegv; | |
600 | ||
1da177e4 LT |
601 | /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */ |
602 | err |= copy_siginfo_to_user32(&frame->rs_info, info); | |
603 | ||
604 | /* Create the ucontext. */ | |
605 | err |= __put_user(0, &frame->rs_uc.uc_flags); | |
606 | err |= __put_user(0, &frame->rs_uc.uc_link); | |
607 | sp = (int) (long) current->sas_ss_sp; | |
608 | err |= __put_user(sp, | |
609 | &frame->rs_uc.uc_stack.ss_sp); | |
610 | err |= __put_user(sas_ss_flags(regs->regs[29]), | |
611 | &frame->rs_uc.uc_stack.ss_flags); | |
612 | err |= __put_user(current->sas_ss_size, | |
613 | &frame->rs_uc.uc_stack.ss_size); | |
614 | err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext); | |
431dc804 | 615 | err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set); |
1da177e4 LT |
616 | |
617 | if (err) | |
618 | goto give_sigsegv; | |
619 | ||
620 | /* | |
621 | * Arguments to signal handler: | |
622 | * | |
623 | * a0 = signal number | |
624 | * a1 = 0 (should be cause) | |
625 | * a2 = pointer to ucontext | |
626 | * | |
627 | * $25 and c0_epc point to the signal handler, $29 points to | |
628 | * the struct rt_sigframe32. | |
629 | */ | |
630 | regs->regs[ 4] = signr; | |
631 | regs->regs[ 5] = (unsigned long) &frame->rs_info; | |
632 | regs->regs[ 6] = (unsigned long) &frame->rs_uc; | |
633 | regs->regs[29] = (unsigned long) frame; | |
d814c28c | 634 | regs->regs[31] = (unsigned long) sig_return; |
1da177e4 LT |
635 | regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; |
636 | ||
722bb63d | 637 | DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", |
1da177e4 | 638 | current->comm, current->pid, |
722bb63d FBH |
639 | frame, regs->cp0_epc, regs->regs[31]); |
640 | ||
7b3e2fc8 | 641 | return 0; |
1da177e4 LT |
642 | |
643 | give_sigsegv: | |
644 | force_sigsegv(signr, current); | |
7b3e2fc8 | 645 | return -EFAULT; |
1da177e4 LT |
646 | } |
647 | ||
151fd6ac RB |
648 | /* |
649 | * o32 compatibility on 64-bit kernels, without DSP ASE | |
650 | */ | |
651 | struct mips_abi mips_abi_32 = { | |
652 | .setup_frame = setup_frame_32, | |
d814c28c DD |
653 | .signal_return_offset = |
654 | offsetof(struct mips_vdso, o32_signal_trampoline), | |
151fd6ac | 655 | .setup_rt_frame = setup_rt_frame_32, |
d814c28c DD |
656 | .rt_signal_return_offset = |
657 | offsetof(struct mips_vdso, o32_rt_signal_trampoline), | |
151fd6ac RB |
658 | .restart = __NR_O32_restart_syscall |
659 | }; | |
1da177e4 | 660 | |
dbda6ac0 RB |
661 | SYSCALL_DEFINE4(32_rt_sigaction, int, sig, |
662 | const struct sigaction32 __user *, act, | |
663 | struct sigaction32 __user *, oact, unsigned int, sigsetsize) | |
1da177e4 LT |
664 | { |
665 | struct k_sigaction new_sa, old_sa; | |
666 | int ret = -EINVAL; | |
667 | ||
668 | /* XXX: Don't preclude handling different sized sigset_t's. */ | |
669 | if (sigsetsize != sizeof(sigset_t)) | |
670 | goto out; | |
671 | ||
672 | if (act) { | |
77c728c2 | 673 | s32 handler; |
1da177e4 LT |
674 | int err = 0; |
675 | ||
676 | if (!access_ok(VERIFY_READ, act, sizeof(*act))) | |
677 | return -EFAULT; | |
77c728c2 | 678 | err |= __get_user(handler, &act->sa_handler); |
9bbf28a3 | 679 | new_sa.sa.sa_handler = (void __user *)(s64)handler; |
1da177e4 LT |
680 | err |= __get_user(new_sa.sa.sa_flags, &act->sa_flags); |
681 | err |= get_sigset(&new_sa.sa.sa_mask, &act->sa_mask); | |
682 | if (err) | |
683 | return -EFAULT; | |
684 | } | |
685 | ||
686 | ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL); | |
687 | ||
688 | if (!ret && oact) { | |
689 | int err = 0; | |
690 | ||
691 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) | |
692 | return -EFAULT; | |
693 | ||
694 | err |= __put_user((u32)(u64)old_sa.sa.sa_handler, | |
695 | &oact->sa_handler); | |
696 | err |= __put_user(old_sa.sa.sa_flags, &oact->sa_flags); | |
697 | err |= put_sigset(&old_sa.sa.sa_mask, &oact->sa_mask); | |
698 | if (err) | |
699 | return -EFAULT; | |
700 | } | |
701 | out: | |
702 | return ret; | |
703 | } | |
704 | ||
dbda6ac0 RB |
705 | SYSCALL_DEFINE4(32_rt_sigprocmask, int, how, compat_sigset_t __user *, set, |
706 | compat_sigset_t __user *, oset, unsigned int, sigsetsize) | |
1da177e4 LT |
707 | { |
708 | sigset_t old_set, new_set; | |
709 | int ret; | |
710 | mm_segment_t old_fs = get_fs(); | |
711 | ||
712 | if (set && get_sigset(&new_set, set)) | |
713 | return -EFAULT; | |
714 | ||
49a89efb | 715 | set_fs(KERNEL_DS); |
9bbf28a3 AN |
716 | ret = sys_rt_sigprocmask(how, set ? (sigset_t __user *)&new_set : NULL, |
717 | oset ? (sigset_t __user *)&old_set : NULL, | |
718 | sigsetsize); | |
49a89efb | 719 | set_fs(old_fs); |
1da177e4 LT |
720 | |
721 | if (!ret && oset && put_sigset(&old_set, oset)) | |
722 | return -EFAULT; | |
723 | ||
724 | return ret; | |
725 | } | |
726 | ||
dbda6ac0 RB |
727 | SYSCALL_DEFINE2(32_rt_sigpending, compat_sigset_t __user *, uset, |
728 | unsigned int, sigsetsize) | |
1da177e4 LT |
729 | { |
730 | int ret; | |
731 | sigset_t set; | |
732 | mm_segment_t old_fs = get_fs(); | |
733 | ||
49a89efb | 734 | set_fs(KERNEL_DS); |
9bbf28a3 | 735 | ret = sys_rt_sigpending((sigset_t __user *)&set, sigsetsize); |
49a89efb | 736 | set_fs(old_fs); |
1da177e4 LT |
737 | |
738 | if (!ret && put_sigset(&set, uset)) | |
739 | return -EFAULT; | |
740 | ||
741 | return ret; | |
742 | } | |
743 | ||
dbda6ac0 RB |
744 | SYSCALL_DEFINE3(32_rt_sigqueueinfo, int, pid, int, sig, |
745 | compat_siginfo_t __user *, uinfo) | |
1da177e4 LT |
746 | { |
747 | siginfo_t info; | |
748 | int ret; | |
749 | mm_segment_t old_fs = get_fs(); | |
750 | ||
49a89efb RB |
751 | if (copy_from_user(&info, uinfo, 3*sizeof(int)) || |
752 | copy_from_user(info._sifields._pad, uinfo->_sifields._pad, SI_PAD_SIZE)) | |
1da177e4 | 753 | return -EFAULT; |
49a89efb | 754 | set_fs(KERNEL_DS); |
9bbf28a3 | 755 | ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *)&info); |
49a89efb | 756 | set_fs(old_fs); |
1da177e4 LT |
757 | return ret; |
758 | } | |
54f2da75 | 759 | |
dbda6ac0 RB |
760 | SYSCALL_DEFINE5(32_waitid, int, which, compat_pid_t, pid, |
761 | compat_siginfo_t __user *, uinfo, int, options, | |
762 | struct compat_rusage __user *, uru) | |
54f2da75 RB |
763 | { |
764 | siginfo_t info; | |
765 | struct rusage ru; | |
766 | long ret; | |
767 | mm_segment_t old_fs = get_fs(); | |
768 | ||
769 | info.si_signo = 0; | |
49a89efb | 770 | set_fs(KERNEL_DS); |
54f2da75 RB |
771 | ret = sys_waitid(which, pid, (siginfo_t __user *) &info, options, |
772 | uru ? (struct rusage __user *) &ru : NULL); | |
49a89efb | 773 | set_fs(old_fs); |
54f2da75 RB |
774 | |
775 | if (ret < 0 || info.si_signo == 0) | |
776 | return ret; | |
777 | ||
778 | if (uru && (ret = put_compat_rusage(&ru, uru))) | |
779 | return ret; | |
780 | ||
781 | BUG_ON(info.si_code & __SI_MASK); | |
782 | info.si_code |= __SI_CHLD; | |
783 | return copy_siginfo_to_user32(uinfo, &info); | |
784 | } | |
137f6f3e RB |
785 | |
786 | static int signal32_init(void) | |
787 | { | |
788 | if (cpu_has_fpu) { | |
789 | save_fp_context32 = _save_fp_context32; | |
790 | restore_fp_context32 = _restore_fp_context32; | |
791 | } else { | |
792 | save_fp_context32 = fpu_emulator_save_context32; | |
793 | restore_fp_context32 = fpu_emulator_restore_context32; | |
794 | } | |
795 | ||
796 | return 0; | |
797 | } | |
798 | ||
799 | arch_initcall(signal32_init); |