aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips/kernel/signal32.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/mips/kernel/signal32.c')
-rw-r--r--arch/mips/kernel/signal32.c341
1 files changed, 131 insertions, 210 deletions
diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c
index c86a5ddff050..183fc7e55f34 100644
--- a/arch/mips/kernel/signal32.c
+++ b/arch/mips/kernel/signal32.c
@@ -33,6 +33,8 @@
33#include <asm/fpu.h> 33#include <asm/fpu.h>
34#include <asm/war.h> 34#include <asm/war.h>
35 35
36#include "signal-common.h"
37
36#define SI_PAD_SIZE32 ((SI_MAX_SIZE/sizeof(int)) - 3) 38#define SI_PAD_SIZE32 ((SI_MAX_SIZE/sizeof(int)) - 3)
37 39
38typedef struct compat_siginfo { 40typedef struct compat_siginfo {
@@ -102,8 +104,6 @@ typedef struct compat_siginfo {
102#define __NR_O32_rt_sigreturn 4193 104#define __NR_O32_rt_sigreturn 4193
103#define __NR_O32_restart_syscall 4253 105#define __NR_O32_restart_syscall 4253
104 106
105#define DEBUG_SIG 0
106
107#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) 107#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
108 108
109/* 32-bit compatibility types */ 109/* 32-bit compatibility types */
@@ -139,6 +139,123 @@ struct ucontext32 {
139 sigset_t32 uc_sigmask; /* mask last for extensibility */ 139 sigset_t32 uc_sigmask; /* mask last for extensibility */
140}; 140};
141 141
142#if ICACHE_REFILLS_WORKAROUND_WAR == 0
143
144struct rt_sigframe32 {
145 u32 rs_ass[4]; /* argument save space for o32 */
146 u32 rs_code[2]; /* signal trampoline */
147 compat_siginfo_t rs_info;
148 struct ucontext32 rs_uc;
149};
150
151#else /* ICACHE_REFILLS_WORKAROUND_WAR */
152
153struct rt_sigframe32 {
154 u32 rs_ass[4]; /* argument save space for o32 */
155 u32 rs_pad[2];
156 compat_siginfo_t rs_info;
157 struct ucontext32 rs_uc;
158 u32 rs_code[8] __attribute__((aligned(32))); /* signal trampoline */
159};
160
161#endif /* !ICACHE_REFILLS_WORKAROUND_WAR */
162
163/*
164 * sigcontext handlers
165 */
166static int setup_sigcontext32(struct pt_regs *regs,
167 struct sigcontext32 __user *sc)
168{
169 int err = 0;
170 int i;
171
172 err |= __put_user(regs->cp0_epc, &sc->sc_pc);
173
174 err |= __put_user(0, &sc->sc_regs[0]);
175 for (i = 1; i < 32; i++)
176 err |= __put_user(regs->regs[i], &sc->sc_regs[i]);
177
178 err |= __put_user(regs->hi, &sc->sc_mdhi);
179 err |= __put_user(regs->lo, &sc->sc_mdlo);
180 if (cpu_has_dsp) {
181 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
182 err |= __put_user(mfhi1(), &sc->sc_hi1);
183 err |= __put_user(mflo1(), &sc->sc_lo1);
184 err |= __put_user(mfhi2(), &sc->sc_hi2);
185 err |= __put_user(mflo2(), &sc->sc_lo2);
186 err |= __put_user(mfhi3(), &sc->sc_hi3);
187 err |= __put_user(mflo3(), &sc->sc_lo3);
188 }
189
190 err |= __put_user(!!used_math(), &sc->sc_used_math);
191
192 if (used_math()) {
193 /*
194 * Save FPU state to signal context. Signal handler
195 * will "inherit" current FPU state.
196 */
197 preempt_disable();
198
199 if (!is_fpu_owner()) {
200 own_fpu();
201 restore_fp(current);
202 }
203 err |= save_fp_context32(sc);
204
205 preempt_enable();
206 }
207 return err;
208}
209
210static int restore_sigcontext32(struct pt_regs *regs,
211 struct sigcontext32 __user *sc)
212{
213 u32 used_math;
214 int err = 0;
215 s32 treg;
216 int i;
217
218 /* Always make any pending restarted system calls return -EINTR */
219 current_thread_info()->restart_block.fn = do_no_restart_syscall;
220
221 err |= __get_user(regs->cp0_epc, &sc->sc_pc);
222 err |= __get_user(regs->hi, &sc->sc_mdhi);
223 err |= __get_user(regs->lo, &sc->sc_mdlo);
224 if (cpu_has_dsp) {
225 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
226 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
227 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
228 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
229 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
230 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
231 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
232 }
233
234 for (i = 1; i < 32; i++)
235 err |= __get_user(regs->regs[i], &sc->sc_regs[i]);
236
237 err |= __get_user(used_math, &sc->sc_used_math);
238 conditional_used_math(used_math);
239
240 preempt_disable();
241
242 if (used_math()) {
243 /* restore fpu context if we have used it before */
244 own_fpu();
245 err |= restore_fp_context32(sc);
246 } else {
247 /* signal handler may have used FPU. Give it up. */
248 lose_fpu();
249 }
250
251 preempt_enable();
252
253 return err;
254}
255
256/*
257 *
258 */
142extern void __put_sigset_unknown_nsig(void); 259extern void __put_sigset_unknown_nsig(void);
143extern void __get_sigset_unknown_nsig(void); 260extern void __get_sigset_unknown_nsig(void);
144 261
@@ -191,9 +308,7 @@ static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf)
191 * Atomically swap in the new signal mask, and wait for a signal. 308 * Atomically swap in the new signal mask, and wait for a signal.
192 */ 309 */
193 310
194save_static_function(sys32_sigsuspend); 311asmlinkage int sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
195__attribute_used__ noinline static int
196_sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
197{ 312{
198 compat_sigset_t __user *uset; 313 compat_sigset_t __user *uset;
199 sigset_t newset; 314 sigset_t newset;
@@ -215,9 +330,7 @@ _sys32_sigsuspend(nabi_no_regargs struct pt_regs regs)
215 return -ERESTARTNOHAND; 330 return -ERESTARTNOHAND;
216} 331}
217 332
218save_static_function(sys32_rt_sigsuspend); 333asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
219__attribute_used__ noinline static int
220_sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
221{ 334{
222 compat_sigset_t __user *uset; 335 compat_sigset_t __user *uset;
223 sigset_t newset; 336 sigset_t newset;
@@ -326,91 +439,6 @@ asmlinkage int sys32_sigaltstack(nabi_no_regargs struct pt_regs regs)
326 return ret; 439 return ret;
327} 440}
328 441
329static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 __user *sc)
330{
331 u32 used_math;
332 int err = 0;
333 s32 treg;
334
335 /* Always make any pending restarted system calls return -EINTR */
336 current_thread_info()->restart_block.fn = do_no_restart_syscall;
337
338 err |= __get_user(regs->cp0_epc, &sc->sc_pc);
339 err |= __get_user(regs->hi, &sc->sc_mdhi);
340 err |= __get_user(regs->lo, &sc->sc_mdlo);
341 if (cpu_has_dsp) {
342 err |= __get_user(treg, &sc->sc_hi1); mthi1(treg);
343 err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg);
344 err |= __get_user(treg, &sc->sc_hi2); mthi2(treg);
345 err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg);
346 err |= __get_user(treg, &sc->sc_hi3); mthi3(treg);
347 err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg);
348 err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK);
349 }
350
351#define restore_gp_reg(i) do { \
352 err |= __get_user(regs->regs[i], &sc->sc_regs[i]); \
353} while(0)
354 restore_gp_reg( 1); restore_gp_reg( 2); restore_gp_reg( 3);
355 restore_gp_reg( 4); restore_gp_reg( 5); restore_gp_reg( 6);
356 restore_gp_reg( 7); restore_gp_reg( 8); restore_gp_reg( 9);
357 restore_gp_reg(10); restore_gp_reg(11); restore_gp_reg(12);
358 restore_gp_reg(13); restore_gp_reg(14); restore_gp_reg(15);
359 restore_gp_reg(16); restore_gp_reg(17); restore_gp_reg(18);
360 restore_gp_reg(19); restore_gp_reg(20); restore_gp_reg(21);
361 restore_gp_reg(22); restore_gp_reg(23); restore_gp_reg(24);
362 restore_gp_reg(25); restore_gp_reg(26); restore_gp_reg(27);
363 restore_gp_reg(28); restore_gp_reg(29); restore_gp_reg(30);
364 restore_gp_reg(31);
365#undef restore_gp_reg
366
367 err |= __get_user(used_math, &sc->sc_used_math);
368 conditional_used_math(used_math);
369
370 preempt_disable();
371
372 if (used_math()) {
373 /* restore fpu context if we have used it before */
374 own_fpu();
375 err |= restore_fp_context32(sc);
376 } else {
377 /* signal handler may have used FPU. Give it up. */
378 lose_fpu();
379 }
380
381 preempt_enable();
382
383 return err;
384}
385
386struct sigframe {
387 u32 sf_ass[4]; /* argument save space for o32 */
388#if ICACHE_REFILLS_WORKAROUND_WAR
389 u32 sf_pad[2];
390#else
391 u32 sf_code[2]; /* signal trampoline */
392#endif
393 struct sigcontext32 sf_sc;
394 sigset_t sf_mask;
395#if ICACHE_REFILLS_WORKAROUND_WAR
396 u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */
397#endif
398};
399
400struct rt_sigframe32 {
401 u32 rs_ass[4]; /* argument save space for o32 */
402#if ICACHE_REFILLS_WORKAROUND_WAR
403 u32 rs_pad[2];
404#else
405 u32 rs_code[2]; /* signal trampoline */
406#endif
407 compat_siginfo_t rs_info;
408 struct ucontext32 rs_uc;
409#if ICACHE_REFILLS_WORKAROUND_WAR
410 u32 rs_code[8] __attribute__((aligned(32))); /* signal trampoline */
411#endif
412};
413
414int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from) 442int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
415{ 443{
416 int err; 444 int err;
@@ -463,9 +491,7 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, siginfo_t *from)
463 return err; 491 return err;
464} 492}
465 493
466save_static_function(sys32_sigreturn); 494asmlinkage void sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
467__attribute_used__ noinline static void
468_sys32_sigreturn(nabi_no_regargs struct pt_regs regs)
469{ 495{
470 struct sigframe __user *frame; 496 struct sigframe __user *frame;
471 sigset_t blocked; 497 sigset_t blocked;
@@ -499,9 +525,7 @@ badframe:
499 force_sig(SIGSEGV, current); 525 force_sig(SIGSEGV, current);
500} 526}
501 527
502save_static_function(sys32_rt_sigreturn); 528asmlinkage void sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
503__attribute_used__ noinline static void
504_sys32_rt_sigreturn(nabi_no_regargs struct pt_regs regs)
505{ 529{
506 struct rt_sigframe32 __user *frame; 530 struct rt_sigframe32 __user *frame;
507 mm_segment_t old_fs; 531 mm_segment_t old_fs;
@@ -554,89 +578,6 @@ badframe:
554 force_sig(SIGSEGV, current); 578 force_sig(SIGSEGV, current);
555} 579}
556 580
557static inline int setup_sigcontext32(struct pt_regs *regs,
558 struct sigcontext32 __user *sc)
559{
560 int err = 0;
561
562 err |= __put_user(regs->cp0_epc, &sc->sc_pc);
563 err |= __put_user(regs->cp0_status, &sc->sc_status);
564
565#define save_gp_reg(i) { \
566 err |= __put_user(regs->regs[i], &sc->sc_regs[i]); \
567} while(0)
568 __put_user(0, &sc->sc_regs[0]); save_gp_reg(1); save_gp_reg(2);
569 save_gp_reg(3); save_gp_reg(4); save_gp_reg(5); save_gp_reg(6);
570 save_gp_reg(7); save_gp_reg(8); save_gp_reg(9); save_gp_reg(10);
571 save_gp_reg(11); save_gp_reg(12); save_gp_reg(13); save_gp_reg(14);
572 save_gp_reg(15); save_gp_reg(16); save_gp_reg(17); save_gp_reg(18);
573 save_gp_reg(19); save_gp_reg(20); save_gp_reg(21); save_gp_reg(22);
574 save_gp_reg(23); save_gp_reg(24); save_gp_reg(25); save_gp_reg(26);
575 save_gp_reg(27); save_gp_reg(28); save_gp_reg(29); save_gp_reg(30);
576 save_gp_reg(31);
577#undef save_gp_reg
578
579 err |= __put_user(regs->hi, &sc->sc_mdhi);
580 err |= __put_user(regs->lo, &sc->sc_mdlo);
581 if (cpu_has_dsp) {
582 err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp);
583 err |= __put_user(mfhi1(), &sc->sc_hi1);
584 err |= __put_user(mflo1(), &sc->sc_lo1);
585 err |= __put_user(mfhi2(), &sc->sc_hi2);
586 err |= __put_user(mflo2(), &sc->sc_lo2);
587 err |= __put_user(mfhi3(), &sc->sc_hi3);
588 err |= __put_user(mflo3(), &sc->sc_lo3);
589 }
590
591 err |= __put_user(!!used_math(), &sc->sc_used_math);
592
593 if (!used_math())
594 goto out;
595
596 /*
597 * Save FPU state to signal context. Signal handler will "inherit"
598 * current FPU state.
599 */
600 preempt_disable();
601
602 if (!is_fpu_owner()) {
603 own_fpu();
604 restore_fp(current);
605 }
606 err |= save_fp_context32(sc);
607
608 preempt_enable();
609
610out:
611 return err;
612}
613
614/*
615 * Determine which stack to use..
616 */
617static inline void __user *get_sigframe(struct k_sigaction *ka,
618 struct pt_regs *regs,
619 size_t frame_size)
620{
621 unsigned long sp;
622
623 /* Default to using normal stack */
624 sp = regs->regs[29];
625
626 /*
627 * FPU emulator may have it's own trampoline active just
628 * above the user stack, 16-bytes before the next lowest
629 * 16 byte boundary. Try to avoid trashing it.
630 */
631 sp -= 32;
632
633 /* This is the X/Open sanctioned signal stack switching. */
634 if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0))
635 sp = current->sas_ss_sp + current->sas_ss_size;
636
637 return (void __user *)((sp - frame_size) & ALMASK);
638}
639
640int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs, 581int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
641 int signr, sigset_t *set) 582 int signr, sigset_t *set)
642{ 583{
@@ -647,15 +588,7 @@ int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
647 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 588 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
648 goto give_sigsegv; 589 goto give_sigsegv;
649 590
650 /* 591 err |= install_sigtramp(frame->sf_code, __NR_O32_sigreturn);
651 * Set up the return code ...
652 *
653 * li v0, __NR_O32_sigreturn
654 * syscall
655 */
656 err |= __put_user(0x24020000 + __NR_O32_sigreturn, frame->sf_code + 0);
657 err |= __put_user(0x0000000c , frame->sf_code + 1);
658 flush_cache_sigtramp((unsigned long) frame->sf_code);
659 592
660 err |= setup_sigcontext32(regs, &frame->sf_sc); 593 err |= setup_sigcontext32(regs, &frame->sf_sc);
661 err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set)); 594 err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set));
@@ -679,11 +612,10 @@ int setup_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
679 regs->regs[31] = (unsigned long) frame->sf_code; 612 regs->regs[31] = (unsigned long) frame->sf_code;
680 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; 613 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
681 614
682#if DEBUG_SIG 615 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
683 printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n",
684 current->comm, current->pid, 616 current->comm, current->pid,
685 frame, regs->cp0_epc, frame->sf_code); 617 frame, regs->cp0_epc, regs->regs[31]);
686#endif 618
687 return 0; 619 return 0;
688 620
689give_sigsegv: 621give_sigsegv:
@@ -702,17 +634,7 @@ int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
702 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) 634 if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame)))
703 goto give_sigsegv; 635 goto give_sigsegv;
704 636
705 /* Set up to return from userspace. If provided, use a stub already 637 err |= install_sigtramp(frame->rs_code, __NR_O32_rt_sigreturn);
706 in userspace. */
707 /*
708 * Set up the return code ...
709 *
710 * li v0, __NR_O32_rt_sigreturn
711 * syscall
712 */
713 err |= __put_user(0x24020000 + __NR_O32_rt_sigreturn, frame->rs_code + 0);
714 err |= __put_user(0x0000000c , frame->rs_code + 1);
715 flush_cache_sigtramp((unsigned long) frame->rs_code);
716 638
717 /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */ 639 /* Convert (siginfo_t -> compat_siginfo_t) and copy to user. */
718 err |= copy_siginfo_to_user32(&frame->rs_info, info); 640 err |= copy_siginfo_to_user32(&frame->rs_info, info);
@@ -750,11 +672,10 @@ int setup_rt_frame_32(struct k_sigaction * ka, struct pt_regs *regs,
750 regs->regs[31] = (unsigned long) frame->rs_code; 672 regs->regs[31] = (unsigned long) frame->rs_code;
751 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; 673 regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;
752 674
753#if DEBUG_SIG 675 DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n",
754 printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n",
755 current->comm, current->pid, 676 current->comm, current->pid,
756 frame, regs->cp0_epc, frame->rs_code); 677 frame, regs->cp0_epc, regs->regs[31]);
757#endif 678
758 return 0; 679 return 0;
759 680
760give_sigsegv: 681give_sigsegv: