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 | */ | |
70342287 | 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 | ||
1da177e4 | 58 | struct ucontext32 { |
70342287 RB |
59 | u32 uc_flags; |
60 | s32 uc_link; | |
ea536ad4 | 61 | compat_stack_t uc_stack; |
1da177e4 | 62 | struct sigcontext32 uc_mcontext; |
70342287 | 63 | compat_sigset_t uc_sigmask; /* mask last for extensibility */ |
1da177e4 LT |
64 | }; |
65 | ||
dd02f06a RB |
66 | struct sigframe32 { |
67 | u32 sf_ass[4]; /* argument save space for o32 */ | |
d814c28c | 68 | u32 sf_pad[2]; /* Was: signal trampoline */ |
dd02f06a | 69 | struct sigcontext32 sf_sc; |
755f21bb | 70 | compat_sigset_t sf_mask; |
dd02f06a RB |
71 | }; |
72 | ||
c0b9bae9 FBH |
73 | struct rt_sigframe32 { |
74 | u32 rs_ass[4]; /* argument save space for o32 */ | |
d814c28c | 75 | u32 rs_pad[2]; /* Was: signal trampoline */ |
c0b9bae9 FBH |
76 | compat_siginfo_t rs_info; |
77 | struct ucontext32 rs_uc; | |
78 | }; | |
79 | ||
9432a9ba FBH |
80 | /* |
81 | * sigcontext handlers | |
82 | */ | |
faea6234 AN |
83 | static int protected_save_fp_context32(struct sigcontext32 __user *sc) |
84 | { | |
85 | int err; | |
86 | while (1) { | |
87 | lock_fpu_owner(); | |
88 | own_fpu_inatomic(1); | |
89 | err = save_fp_context32(sc); /* this might fail */ | |
90 | unlock_fpu_owner(); | |
91 | if (likely(!err)) | |
92 | break; | |
93 | /* touch the sigcontext and try again */ | |
94 | err = __put_user(0, &sc->sc_fpregs[0]) | | |
95 | __put_user(0, &sc->sc_fpregs[31]) | | |
96 | __put_user(0, &sc->sc_fpc_csr); | |
97 | if (err) | |
98 | break; /* really bad sigcontext */ | |
99 | } | |
100 | return err; | |
101 | } | |
102 | ||
103 | static int protected_restore_fp_context32(struct sigcontext32 __user *sc) | |
104 | { | |
c726b822 | 105 | int err, tmp __maybe_unused; |
faea6234 AN |
106 | while (1) { |
107 | lock_fpu_owner(); | |
108 | own_fpu_inatomic(0); | |
109 | err = restore_fp_context32(sc); /* this might fail */ | |
110 | unlock_fpu_owner(); | |
111 | if (likely(!err)) | |
112 | break; | |
113 | /* touch the sigcontext and try again */ | |
114 | err = __get_user(tmp, &sc->sc_fpregs[0]) | | |
115 | __get_user(tmp, &sc->sc_fpregs[31]) | | |
116 | __get_user(tmp, &sc->sc_fpc_csr); | |
117 | if (err) | |
118 | break; /* really bad sigcontext */ | |
119 | } | |
120 | return err; | |
121 | } | |
122 | ||
9432a9ba FBH |
123 | static int setup_sigcontext32(struct pt_regs *regs, |
124 | struct sigcontext32 __user *sc) | |
125 | { | |
126 | int err = 0; | |
127 | int i; | |
53dc8028 | 128 | u32 used_math; |
9432a9ba FBH |
129 | |
130 | err |= __put_user(regs->cp0_epc, &sc->sc_pc); | |
9432a9ba FBH |
131 | |
132 | err |= __put_user(0, &sc->sc_regs[0]); | |
133 | for (i = 1; i < 32; i++) | |
134 | err |= __put_user(regs->regs[i], &sc->sc_regs[i]); | |
135 | ||
136 | err |= __put_user(regs->hi, &sc->sc_mdhi); | |
137 | err |= __put_user(regs->lo, &sc->sc_mdlo); | |
138 | if (cpu_has_dsp) { | |
139 | err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); | |
140 | err |= __put_user(mfhi1(), &sc->sc_hi1); | |
141 | err |= __put_user(mflo1(), &sc->sc_lo1); | |
142 | err |= __put_user(mfhi2(), &sc->sc_hi2); | |
143 | err |= __put_user(mflo2(), &sc->sc_lo2); | |
144 | err |= __put_user(mfhi3(), &sc->sc_hi3); | |
145 | err |= __put_user(mflo3(), &sc->sc_lo3); | |
146 | } | |
147 | ||
53dc8028 AN |
148 | used_math = !!used_math(); |
149 | err |= __put_user(used_math, &sc->sc_used_math); | |
9432a9ba | 150 | |
53dc8028 | 151 | if (used_math) { |
9432a9ba FBH |
152 | /* |
153 | * Save FPU state to signal context. Signal handler | |
154 | * will "inherit" current FPU state. | |
155 | */ | |
faea6234 | 156 | err |= protected_save_fp_context32(sc); |
9432a9ba FBH |
157 | } |
158 | return err; | |
159 | } | |
160 | ||
c6a2f467 AN |
161 | static int |
162 | check_and_restore_fp_context32(struct sigcontext32 __user *sc) | |
163 | { | |
164 | int err, sig; | |
165 | ||
166 | err = sig = fpcsr_pending(&sc->sc_fpc_csr); | |
167 | if (err > 0) | |
168 | err = 0; | |
faea6234 | 169 | err |= protected_restore_fp_context32(sc); |
c6a2f467 AN |
170 | return err ?: sig; |
171 | } | |
172 | ||
9432a9ba FBH |
173 | static int restore_sigcontext32(struct pt_regs *regs, |
174 | struct sigcontext32 __user *sc) | |
175 | { | |
176 | u32 used_math; | |
177 | int err = 0; | |
178 | s32 treg; | |
179 | int i; | |
180 | ||
181 | /* Always make any pending restarted system calls return -EINTR */ | |
182 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | |
183 | ||
184 | err |= __get_user(regs->cp0_epc, &sc->sc_pc); | |
185 | err |= __get_user(regs->hi, &sc->sc_mdhi); | |
186 | err |= __get_user(regs->lo, &sc->sc_mdlo); | |
187 | if (cpu_has_dsp) { | |
188 | err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); | |
189 | err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); | |
190 | err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); | |
191 | err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); | |
192 | err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); | |
193 | err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); | |
194 | err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); | |
195 | } | |
196 | ||
197 | for (i = 1; i < 32; i++) | |
198 | err |= __get_user(regs->regs[i], &sc->sc_regs[i]); | |
199 | ||
200 | err |= __get_user(used_math, &sc->sc_used_math); | |
201 | conditional_used_math(used_math); | |
202 | ||
53dc8028 | 203 | if (used_math) { |
9432a9ba | 204 | /* restore fpu context if we have used it before */ |
c6a2f467 AN |
205 | if (!err) |
206 | err = check_and_restore_fp_context32(sc); | |
9432a9ba FBH |
207 | } else { |
208 | /* signal handler may have used FPU. Give it up. */ | |
53dc8028 | 209 | lose_fpu(0); |
9432a9ba FBH |
210 | } |
211 | ||
9432a9ba FBH |
212 | return err; |
213 | } | |
214 | ||
215 | /* | |
216 | * | |
217 | */ | |
1da177e4 LT |
218 | extern void __put_sigset_unknown_nsig(void); |
219 | extern void __get_sigset_unknown_nsig(void); | |
220 | ||
9bbf28a3 | 221 | static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf) |
1da177e4 LT |
222 | { |
223 | int err = 0; | |
224 | ||
225 | if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf))) | |
226 | return -EFAULT; | |
227 | ||
228 | switch (_NSIG_WORDS) { | |
229 | default: | |
230 | __put_sigset_unknown_nsig(); | |
231 | case 2: | |
49a89efb RB |
232 | err |= __put_user(kbuf->sig[1] >> 32, &ubuf->sig[3]); |
233 | err |= __put_user(kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]); | |
1da177e4 | 234 | case 1: |
49a89efb RB |
235 | err |= __put_user(kbuf->sig[0] >> 32, &ubuf->sig[1]); |
236 | err |= __put_user(kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]); | |
1da177e4 LT |
237 | } |
238 | ||
239 | return err; | |
240 | } | |
241 | ||
9c6031cc | 242 | static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf) |
1da177e4 LT |
243 | { |
244 | int err = 0; | |
245 | unsigned long sig[4]; | |
246 | ||
247 | if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf))) | |
248 | return -EFAULT; | |
249 | ||
250 | switch (_NSIG_WORDS) { | |
251 | default: | |
252 | __get_sigset_unknown_nsig(); | |
253 | case 2: | |
49a89efb RB |
254 | err |= __get_user(sig[3], &ubuf->sig[3]); |
255 | err |= __get_user(sig[2], &ubuf->sig[2]); | |
1da177e4 LT |
256 | kbuf->sig[1] = sig[2] | (sig[3] << 32); |
257 | case 1: | |
49a89efb RB |
258 | err |= __get_user(sig[1], &ubuf->sig[1]); |
259 | err |= __get_user(sig[0], &ubuf->sig[0]); | |
1da177e4 LT |
260 | kbuf->sig[0] = sig[0] | (sig[1] << 32); |
261 | } | |
262 | ||
263 | return err; | |
264 | } | |
265 | ||
266 | /* | |
267 | * Atomically swap in the new signal mask, and wait for a signal. | |
268 | */ | |
269 | ||
1910f4ab | 270 | asmlinkage int sys32_sigsuspend(compat_sigset_t __user *uset) |
1da177e4 | 271 | { |
1910f4ab | 272 | return compat_sys_rt_sigsuspend(uset, sizeof(compat_sigset_t)); |
1da177e4 LT |
273 | } |
274 | ||
aa584802 AV |
275 | SYSCALL_DEFINE3(32_sigaction, long, sig, const struct compat_sigaction __user *, act, |
276 | struct compat_sigaction __user *, oact) | |
1da177e4 LT |
277 | { |
278 | struct k_sigaction new_ka, old_ka; | |
279 | int ret; | |
280 | int err = 0; | |
281 | ||
282 | if (act) { | |
283 | old_sigset_t mask; | |
77c728c2 | 284 | s32 handler; |
1da177e4 LT |
285 | |
286 | if (!access_ok(VERIFY_READ, act, sizeof(*act))) | |
287 | return -EFAULT; | |
77c728c2 | 288 | err |= __get_user(handler, &act->sa_handler); |
9bbf28a3 | 289 | new_ka.sa.sa_handler = (void __user *)(s64)handler; |
1da177e4 LT |
290 | err |= __get_user(new_ka.sa.sa_flags, &act->sa_flags); |
291 | err |= __get_user(mask, &act->sa_mask.sig[0]); | |
292 | if (err) | |
293 | return -EFAULT; | |
294 | ||
295 | siginitset(&new_ka.sa.sa_mask, mask); | |
296 | } | |
297 | ||
298 | ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); | |
299 | ||
300 | if (!ret && oact) { | |
301 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) | |
6254944f | 302 | return -EFAULT; |
1da177e4 LT |
303 | err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); |
304 | err |= __put_user((u32)(u64)old_ka.sa.sa_handler, | |
70342287 | 305 | &oact->sa_handler); |
1da177e4 | 306 | err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig); |
6254944f MM |
307 | err |= __put_user(0, &oact->sa_mask.sig[1]); |
308 | err |= __put_user(0, &oact->sa_mask.sig[2]); | |
309 | err |= __put_user(0, &oact->sa_mask.sig[3]); | |
310 | if (err) | |
1da177e4 LT |
311 | return -EFAULT; |
312 | } | |
313 | ||
314 | return ret; | |
315 | } | |
316 | ||
9bbf28a3 | 317 | int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) |
1da177e4 LT |
318 | { |
319 | int err; | |
320 | ||
321 | if (!access_ok (VERIFY_WRITE, to, sizeof(compat_siginfo_t))) | |
322 | return -EFAULT; | |
323 | ||
324 | /* If you change siginfo_t structure, please be sure | |
325 | this code is fixed accordingly. | |
326 | It should never copy any pad contained in the structure | |
327 | to avoid security leaks, but must copy the generic | |
328 | 3 ints plus the relevant union member. | |
329 | This routine must convert siginfo from 64bit to 32bit as well | |
330 | at the same time. */ | |
331 | err = __put_user(from->si_signo, &to->si_signo); | |
332 | err |= __put_user(from->si_errno, &to->si_errno); | |
333 | err |= __put_user((short)from->si_code, &to->si_code); | |
334 | if (from->si_code < 0) | |
335 | err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE); | |
336 | else { | |
337 | switch (from->si_code >> 16) { | |
a982099c RB |
338 | case __SI_TIMER >> 16: |
339 | err |= __put_user(from->si_tid, &to->si_tid); | |
340 | err |= __put_user(from->si_overrun, &to->si_overrun); | |
341 | err |= __put_user(from->si_int, &to->si_int); | |
342 | break; | |
1da177e4 LT |
343 | case __SI_CHLD >> 16: |
344 | err |= __put_user(from->si_utime, &to->si_utime); | |
345 | err |= __put_user(from->si_stime, &to->si_stime); | |
346 | err |= __put_user(from->si_status, &to->si_status); | |
347 | default: | |
348 | err |= __put_user(from->si_pid, &to->si_pid); | |
349 | err |= __put_user(from->si_uid, &to->si_uid); | |
350 | break; | |
351 | case __SI_FAULT >> 16: | |
5665a0ac | 352 | err |= __put_user((unsigned long)from->si_addr, &to->si_addr); |
1da177e4 LT |
353 | break; |
354 | case __SI_POLL >> 16: | |
355 | err |= __put_user(from->si_band, &to->si_band); | |
356 | err |= __put_user(from->si_fd, &to->si_fd); | |
357 | break; | |
358 | case __SI_RT >> 16: /* This is not generated by the kernel as of now. */ | |
359 | case __SI_MESGQ >> 16: | |
360 | err |= __put_user(from->si_pid, &to->si_pid); | |
361 | err |= __put_user(from->si_uid, &to->si_uid); | |
362 | err |= __put_user(from->si_int, &to->si_int); | |
363 | break; | |
364 | } | |
365 | } | |
366 | return err; | |
367 | } | |
368 | ||
5d9a76cd TB |
369 | int copy_siginfo_from_user32(siginfo_t *to, compat_siginfo_t __user *from) |
370 | { | |
371 | memset(to, 0, sizeof *to); | |
372 | ||
373 | if (copy_from_user(to, from, 3*sizeof(int)) || | |
374 | copy_from_user(to->_sifields._pad, | |
375 | from->_sifields._pad, SI_PAD_SIZE32)) | |
376 | return -EFAULT; | |
377 | ||
378 | return 0; | |
379 | } | |
380 | ||
f90080a0 | 381 | asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs) |
1da177e4 | 382 | { |
dd02f06a | 383 | struct sigframe32 __user *frame; |
1da177e4 | 384 | sigset_t blocked; |
c6a2f467 | 385 | int sig; |
1da177e4 | 386 | |
dd02f06a | 387 | frame = (struct sigframe32 __user *) regs.regs[29]; |
1da177e4 LT |
388 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
389 | goto badframe; | |
431dc804 | 390 | if (__copy_conv_sigset_from_user(&blocked, &frame->sf_mask)) |
1da177e4 LT |
391 | goto badframe; |
392 | ||
8598f3cd | 393 | set_current_blocked(&blocked); |
1da177e4 | 394 | |
c6a2f467 AN |
395 | sig = restore_sigcontext32(®s, &frame->sf_sc); |
396 | if (sig < 0) | |
1da177e4 | 397 | goto badframe; |
c6a2f467 AN |
398 | else if (sig) |
399 | force_sig(sig, current); | |
1da177e4 LT |
400 | |
401 | /* | |
402 | * Don't let your children do this ... | |
403 | */ | |
1da177e4 LT |
404 | __asm__ __volatile__( |
405 | "move\t$29, %0\n\t" | |
406 | "j\tsyscall_exit" | |
407 | :/* no outputs */ | |
408 | :"r" (®s)); | |
409 | /* Unreached */ | |
410 | ||
411 | badframe: | |
412 | force_sig(SIGSEGV, current); | |
413 | } | |
414 | ||
f90080a0 | 415 | asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs) |
1da177e4 | 416 | { |
9bbf28a3 | 417 | struct rt_sigframe32 __user *frame; |
1da177e4 | 418 | sigset_t set; |
c6a2f467 | 419 | int sig; |
1da177e4 | 420 | |
9bbf28a3 | 421 | frame = (struct rt_sigframe32 __user *) regs.regs[29]; |
1da177e4 LT |
422 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
423 | goto badframe; | |
431dc804 | 424 | if (__copy_conv_sigset_from_user(&set, &frame->rs_uc.uc_sigmask)) |
1da177e4 LT |
425 | goto badframe; |
426 | ||
8598f3cd | 427 | set_current_blocked(&set); |
1da177e4 | 428 | |
c6a2f467 AN |
429 | sig = restore_sigcontext32(®s, &frame->rs_uc.uc_mcontext); |
430 | if (sig < 0) | |
1da177e4 | 431 | goto badframe; |
c6a2f467 AN |
432 | else if (sig) |
433 | force_sig(sig, current); | |
1da177e4 | 434 | |
ea536ad4 | 435 | if (compat_restore_altstack(&frame->rs_uc.uc_stack)) |
1da177e4 | 436 | goto badframe; |
1da177e4 LT |
437 | |
438 | /* | |
439 | * Don't let your children do this ... | |
440 | */ | |
441 | __asm__ __volatile__( | |
442 | "move\t$29, %0\n\t" | |
443 | "j\tsyscall_exit" | |
444 | :/* no outputs */ | |
445 | :"r" (®s)); | |
446 | /* Unreached */ | |
447 | ||
448 | badframe: | |
449 | force_sig(SIGSEGV, current); | |
450 | } | |
451 | ||
d814c28c DD |
452 | static int setup_frame_32(void *sig_return, struct k_sigaction *ka, |
453 | struct pt_regs *regs, int signr, sigset_t *set) | |
1da177e4 | 454 | { |
dd02f06a | 455 | struct sigframe32 __user *frame; |
1da177e4 LT |
456 | int err = 0; |
457 | ||
458 | frame = get_sigframe(ka, regs, sizeof(*frame)); | |
459 | if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) | |
460 | goto give_sigsegv; | |
461 | ||
1da177e4 | 462 | err |= setup_sigcontext32(regs, &frame->sf_sc); |
431dc804 RB |
463 | err |= __copy_conv_sigset_to_user(&frame->sf_mask, set); |
464 | ||
1da177e4 LT |
465 | if (err) |
466 | goto give_sigsegv; | |
467 | ||
468 | /* | |
469 | * Arguments to signal handler: | |
470 | * | |
471 | * a0 = signal number | |
472 | * a1 = 0 (should be cause) | |
473 | * a2 = pointer to struct sigcontext | |
474 | * | |
475 | * $25 and c0_epc point to the signal handler, $29 points to the | |
476 | * struct sigframe. | |
477 | */ | |
478 | regs->regs[ 4] = signr; | |
479 | regs->regs[ 5] = 0; | |
480 | regs->regs[ 6] = (unsigned long) &frame->sf_sc; | |
481 | regs->regs[29] = (unsigned long) frame; | |
d814c28c | 482 | regs->regs[31] = (unsigned long) sig_return; |
1da177e4 LT |
483 | regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; |
484 | ||
722bb63d | 485 | DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", |
1da177e4 | 486 | current->comm, current->pid, |
722bb63d FBH |
487 | frame, regs->cp0_epc, regs->regs[31]); |
488 | ||
7b3e2fc8 | 489 | return 0; |
1da177e4 LT |
490 | |
491 | give_sigsegv: | |
492 | force_sigsegv(signr, current); | |
7b3e2fc8 | 493 | return -EFAULT; |
1da177e4 LT |
494 | } |
495 | ||
d814c28c DD |
496 | static int setup_rt_frame_32(void *sig_return, struct k_sigaction *ka, |
497 | struct pt_regs *regs, int signr, sigset_t *set, | |
498 | siginfo_t *info) | |
1da177e4 | 499 | { |
9bbf28a3 | 500 | struct rt_sigframe32 __user *frame; |
1da177e4 | 501 | int err = 0; |
1da177e4 LT |
502 | |
503 | frame = get_sigframe(ka, regs, sizeof(*frame)); | |
504 | if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) | |
505 | goto give_sigsegv; | |
506 | ||
1da177e4 LT |
507 | /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */ |
508 | err |= copy_siginfo_to_user32(&frame->rs_info, info); | |
509 | ||
70342287 | 510 | /* Create the ucontext. */ |
1da177e4 LT |
511 | err |= __put_user(0, &frame->rs_uc.uc_flags); |
512 | err |= __put_user(0, &frame->rs_uc.uc_link); | |
ea536ad4 | 513 | err |= __compat_save_altstack(&frame->rs_uc.uc_stack, regs->regs[29]); |
1da177e4 | 514 | err |= setup_sigcontext32(regs, &frame->rs_uc.uc_mcontext); |
431dc804 | 515 | err |= __copy_conv_sigset_to_user(&frame->rs_uc.uc_sigmask, set); |
1da177e4 LT |
516 | |
517 | if (err) | |
518 | goto give_sigsegv; | |
519 | ||
520 | /* | |
521 | * Arguments to signal handler: | |
522 | * | |
523 | * a0 = signal number | |
524 | * a1 = 0 (should be cause) | |
525 | * a2 = pointer to ucontext | |
526 | * | |
527 | * $25 and c0_epc point to the signal handler, $29 points to | |
528 | * the struct rt_sigframe32. | |
529 | */ | |
530 | regs->regs[ 4] = signr; | |
531 | regs->regs[ 5] = (unsigned long) &frame->rs_info; | |
532 | regs->regs[ 6] = (unsigned long) &frame->rs_uc; | |
533 | regs->regs[29] = (unsigned long) frame; | |
d814c28c | 534 | regs->regs[31] = (unsigned long) sig_return; |
1da177e4 LT |
535 | regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; |
536 | ||
722bb63d | 537 | DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", |
1da177e4 | 538 | current->comm, current->pid, |
722bb63d FBH |
539 | frame, regs->cp0_epc, regs->regs[31]); |
540 | ||
7b3e2fc8 | 541 | return 0; |
1da177e4 LT |
542 | |
543 | give_sigsegv: | |
544 | force_sigsegv(signr, current); | |
7b3e2fc8 | 545 | return -EFAULT; |
1da177e4 LT |
546 | } |
547 | ||
151fd6ac RB |
548 | /* |
549 | * o32 compatibility on 64-bit kernels, without DSP ASE | |
550 | */ | |
551 | struct mips_abi mips_abi_32 = { | |
552 | .setup_frame = setup_frame_32, | |
d814c28c DD |
553 | .signal_return_offset = |
554 | offsetof(struct mips_vdso, o32_signal_trampoline), | |
70342287 | 555 | .setup_rt_frame = setup_rt_frame_32, |
d814c28c DD |
556 | .rt_signal_return_offset = |
557 | offsetof(struct mips_vdso, o32_rt_signal_trampoline), | |
151fd6ac RB |
558 | .restart = __NR_O32_restart_syscall |
559 | }; | |
1da177e4 | 560 | |
137f6f3e RB |
561 | static int signal32_init(void) |
562 | { | |
563 | if (cpu_has_fpu) { | |
564 | save_fp_context32 = _save_fp_context32; | |
565 | restore_fp_context32 = _restore_fp_context32; | |
566 | } else { | |
567 | save_fp_context32 = fpu_emulator_save_context32; | |
568 | restore_fp_context32 = fpu_emulator_restore_context32; | |
569 | } | |
570 | ||
571 | return 0; | |
572 | } | |
573 | ||
574 | arch_initcall(signal32_init); |