diff options
Diffstat (limited to 'arch/mips/kernel/signal.c')
-rw-r--r-- | arch/mips/kernel/signal.c | 236 |
1 files changed, 174 insertions, 62 deletions
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index b9d358e05214..54398af2371f 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c | |||
@@ -34,18 +34,174 @@ | |||
34 | 34 | ||
35 | #include "signal-common.h" | 35 | #include "signal-common.h" |
36 | 36 | ||
37 | #define DEBUG_SIG 0 | ||
38 | |||
39 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 37 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
40 | 38 | ||
39 | #if ICACHE_REFILLS_WORKAROUND_WAR == 0 | ||
40 | |||
41 | struct rt_sigframe { | ||
42 | u32 rs_ass[4]; /* argument save space for o32 */ | ||
43 | u32 rs_code[2]; /* signal trampoline */ | ||
44 | struct siginfo rs_info; | ||
45 | struct ucontext rs_uc; | ||
46 | }; | ||
47 | |||
48 | #else | ||
49 | |||
50 | struct rt_sigframe { | ||
51 | u32 rs_ass[4]; /* argument save space for o32 */ | ||
52 | u32 rs_pad[2]; | ||
53 | struct siginfo rs_info; | ||
54 | struct ucontext rs_uc; | ||
55 | u32 rs_code[8] ____cacheline_aligned; /* signal trampoline */ | ||
56 | }; | ||
57 | |||
58 | #endif | ||
59 | |||
60 | /* | ||
61 | * Helper routines | ||
62 | */ | ||
63 | int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | ||
64 | { | ||
65 | int err = 0; | ||
66 | int i; | ||
67 | |||
68 | err |= __put_user(regs->cp0_epc, &sc->sc_pc); | ||
69 | |||
70 | err |= __put_user(0, &sc->sc_regs[0]); | ||
71 | for (i = 1; i < 32; i++) | ||
72 | err |= __put_user(regs->regs[i], &sc->sc_regs[i]); | ||
73 | |||
74 | err |= __put_user(regs->hi, &sc->sc_mdhi); | ||
75 | err |= __put_user(regs->lo, &sc->sc_mdlo); | ||
76 | if (cpu_has_dsp) { | ||
77 | err |= __put_user(mfhi1(), &sc->sc_hi1); | ||
78 | err |= __put_user(mflo1(), &sc->sc_lo1); | ||
79 | err |= __put_user(mfhi2(), &sc->sc_hi2); | ||
80 | err |= __put_user(mflo2(), &sc->sc_lo2); | ||
81 | err |= __put_user(mfhi3(), &sc->sc_hi3); | ||
82 | err |= __put_user(mflo3(), &sc->sc_lo3); | ||
83 | err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); | ||
84 | } | ||
85 | |||
86 | err |= __put_user(!!used_math(), &sc->sc_used_math); | ||
87 | |||
88 | if (used_math()) { | ||
89 | /* | ||
90 | * Save FPU state to signal context. Signal handler | ||
91 | * will "inherit" current FPU state. | ||
92 | */ | ||
93 | preempt_disable(); | ||
94 | |||
95 | if (!is_fpu_owner()) { | ||
96 | own_fpu(); | ||
97 | restore_fp(current); | ||
98 | } | ||
99 | err |= save_fp_context(sc); | ||
100 | |||
101 | preempt_enable(); | ||
102 | } | ||
103 | return err; | ||
104 | } | ||
105 | |||
106 | int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | ||
107 | { | ||
108 | unsigned int used_math; | ||
109 | unsigned long treg; | ||
110 | int err = 0; | ||
111 | int i; | ||
112 | |||
113 | /* Always make any pending restarted system calls return -EINTR */ | ||
114 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
115 | |||
116 | err |= __get_user(regs->cp0_epc, &sc->sc_pc); | ||
117 | err |= __get_user(regs->hi, &sc->sc_mdhi); | ||
118 | err |= __get_user(regs->lo, &sc->sc_mdlo); | ||
119 | if (cpu_has_dsp) { | ||
120 | err |= __get_user(treg, &sc->sc_hi1); mthi1(treg); | ||
121 | err |= __get_user(treg, &sc->sc_lo1); mtlo1(treg); | ||
122 | err |= __get_user(treg, &sc->sc_hi2); mthi2(treg); | ||
123 | err |= __get_user(treg, &sc->sc_lo2); mtlo2(treg); | ||
124 | err |= __get_user(treg, &sc->sc_hi3); mthi3(treg); | ||
125 | err |= __get_user(treg, &sc->sc_lo3); mtlo3(treg); | ||
126 | err |= __get_user(treg, &sc->sc_dsp); wrdsp(treg, DSP_MASK); | ||
127 | } | ||
128 | |||
129 | for (i = 1; i < 32; i++) | ||
130 | err |= __get_user(regs->regs[i], &sc->sc_regs[i]); | ||
131 | |||
132 | err |= __get_user(used_math, &sc->sc_used_math); | ||
133 | conditional_used_math(used_math); | ||
134 | |||
135 | preempt_disable(); | ||
136 | |||
137 | if (used_math()) { | ||
138 | /* restore fpu context if we have used it before */ | ||
139 | own_fpu(); | ||
140 | err |= restore_fp_context(sc); | ||
141 | } else { | ||
142 | /* signal handler may have used FPU. Give it up. */ | ||
143 | lose_fpu(); | ||
144 | } | ||
145 | |||
146 | preempt_enable(); | ||
147 | |||
148 | return err; | ||
149 | } | ||
150 | |||
151 | void __user *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, | ||
152 | size_t frame_size) | ||
153 | { | ||
154 | unsigned long sp; | ||
155 | |||
156 | /* Default to using normal stack */ | ||
157 | sp = regs->regs[29]; | ||
158 | |||
159 | /* | ||
160 | * FPU emulator may have it's own trampoline active just | ||
161 | * above the user stack, 16-bytes before the next lowest | ||
162 | * 16 byte boundary. Try to avoid trashing it. | ||
163 | */ | ||
164 | sp -= 32; | ||
165 | |||
166 | /* This is the X/Open sanctioned signal stack switching. */ | ||
167 | if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) | ||
168 | sp = current->sas_ss_sp + current->sas_ss_size; | ||
169 | |||
170 | return (void __user *)((sp - frame_size) & (ICACHE_REFILLS_WORKAROUND_WAR ? ~(cpu_icache_line_size()-1) : ALMASK)); | ||
171 | } | ||
172 | |||
173 | int install_sigtramp(unsigned int __user *tramp, unsigned int syscall) | ||
174 | { | ||
175 | int err; | ||
176 | |||
177 | /* | ||
178 | * Set up the return code ... | ||
179 | * | ||
180 | * li v0, __NR__foo_sigreturn | ||
181 | * syscall | ||
182 | */ | ||
183 | |||
184 | err = __put_user(0x24020000 + syscall, tramp + 0); | ||
185 | err |= __put_user(0x0000000c , tramp + 1); | ||
186 | if (ICACHE_REFILLS_WORKAROUND_WAR) { | ||
187 | err |= __put_user(0, tramp + 2); | ||
188 | err |= __put_user(0, tramp + 3); | ||
189 | err |= __put_user(0, tramp + 4); | ||
190 | err |= __put_user(0, tramp + 5); | ||
191 | err |= __put_user(0, tramp + 6); | ||
192 | err |= __put_user(0, tramp + 7); | ||
193 | } | ||
194 | flush_cache_sigtramp((unsigned long) tramp); | ||
195 | |||
196 | return err; | ||
197 | } | ||
198 | |||
41 | /* | 199 | /* |
42 | * Atomically swap in the new signal mask, and wait for a signal. | 200 | * Atomically swap in the new signal mask, and wait for a signal. |
43 | */ | 201 | */ |
44 | 202 | ||
45 | #ifdef CONFIG_TRAD_SIGNALS | 203 | #ifdef CONFIG_TRAD_SIGNALS |
46 | save_static_function(sys_sigsuspend); | 204 | asmlinkage int sys_sigsuspend(nabi_no_regargs struct pt_regs regs) |
47 | __attribute_used__ noinline static int | ||
48 | _sys_sigsuspend(nabi_no_regargs struct pt_regs regs) | ||
49 | { | 205 | { |
50 | sigset_t newset; | 206 | sigset_t newset; |
51 | sigset_t __user *uset; | 207 | sigset_t __user *uset; |
@@ -68,9 +224,7 @@ _sys_sigsuspend(nabi_no_regargs struct pt_regs regs) | |||
68 | } | 224 | } |
69 | #endif | 225 | #endif |
70 | 226 | ||
71 | save_static_function(sys_rt_sigsuspend); | 227 | asmlinkage int sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) |
72 | __attribute_used__ noinline static int | ||
73 | _sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) | ||
74 | { | 228 | { |
75 | sigset_t newset; | 229 | sigset_t newset; |
76 | sigset_t __user *unewset; | 230 | sigset_t __user *unewset; |
@@ -89,7 +243,7 @@ _sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs) | |||
89 | spin_lock_irq(¤t->sighand->siglock); | 243 | spin_lock_irq(¤t->sighand->siglock); |
90 | current->saved_sigmask = current->blocked; | 244 | current->saved_sigmask = current->blocked; |
91 | current->blocked = newset; | 245 | current->blocked = newset; |
92 | recalc_sigpending(); | 246 | recalc_sigpending(); |
93 | spin_unlock_irq(¤t->sighand->siglock); | 247 | spin_unlock_irq(¤t->sighand->siglock); |
94 | 248 | ||
95 | current->state = TASK_INTERRUPTIBLE; | 249 | current->state = TASK_INTERRUPTIBLE; |
@@ -124,7 +278,7 @@ asmlinkage int sys_sigaction(int sig, const struct sigaction __user *act, | |||
124 | 278 | ||
125 | if (!ret && oact) { | 279 | if (!ret && oact) { |
126 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) | 280 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact))) |
127 | return -EFAULT; | 281 | return -EFAULT; |
128 | err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | 282 | err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags); |
129 | err |= __put_user(old_ka.sa.sa_handler, &oact->sa_handler); | 283 | err |= __put_user(old_ka.sa.sa_handler, &oact->sa_handler); |
130 | err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig); | 284 | err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig); |
@@ -148,45 +302,8 @@ asmlinkage int sys_sigaltstack(nabi_no_regargs struct pt_regs regs) | |||
148 | return do_sigaltstack(uss, uoss, usp); | 302 | return do_sigaltstack(uss, uoss, usp); |
149 | } | 303 | } |
150 | 304 | ||
151 | /* | ||
152 | * Horribly complicated - with the bloody RM9000 workarounds enabled | ||
153 | * the signal trampolines is moving to the end of the structure so we can | ||
154 | * increase the alignment without breaking software compatibility. | ||
155 | */ | ||
156 | #ifdef CONFIG_TRAD_SIGNALS | 305 | #ifdef CONFIG_TRAD_SIGNALS |
157 | struct sigframe { | 306 | asmlinkage void sys_sigreturn(nabi_no_regargs struct pt_regs regs) |
158 | u32 sf_ass[4]; /* argument save space for o32 */ | ||
159 | #if ICACHE_REFILLS_WORKAROUND_WAR | ||
160 | u32 sf_pad[2]; | ||
161 | #else | ||
162 | u32 sf_code[2]; /* signal trampoline */ | ||
163 | #endif | ||
164 | struct sigcontext sf_sc; | ||
165 | sigset_t sf_mask; | ||
166 | #if ICACHE_REFILLS_WORKAROUND_WAR | ||
167 | u32 sf_code[8] ____cacheline_aligned; /* signal trampoline */ | ||
168 | #endif | ||
169 | }; | ||
170 | #endif | ||
171 | |||
172 | struct rt_sigframe { | ||
173 | u32 rs_ass[4]; /* argument save space for o32 */ | ||
174 | #if ICACHE_REFILLS_WORKAROUND_WAR | ||
175 | u32 rs_pad[2]; | ||
176 | #else | ||
177 | u32 rs_code[2]; /* signal trampoline */ | ||
178 | #endif | ||
179 | struct siginfo rs_info; | ||
180 | struct ucontext rs_uc; | ||
181 | #if ICACHE_REFILLS_WORKAROUND_WAR | ||
182 | u32 rs_code[8] ____cacheline_aligned; /* signal trampoline */ | ||
183 | #endif | ||
184 | }; | ||
185 | |||
186 | #ifdef CONFIG_TRAD_SIGNALS | ||
187 | save_static_function(sys_sigreturn); | ||
188 | __attribute_used__ noinline static void | ||
189 | _sys_sigreturn(nabi_no_regargs struct pt_regs regs) | ||
190 | { | 307 | { |
191 | struct sigframe __user *frame; | 308 | struct sigframe __user *frame; |
192 | sigset_t blocked; | 309 | sigset_t blocked; |
@@ -221,9 +338,7 @@ badframe: | |||
221 | } | 338 | } |
222 | #endif /* CONFIG_TRAD_SIGNALS */ | 339 | #endif /* CONFIG_TRAD_SIGNALS */ |
223 | 340 | ||
224 | save_static_function(sys_rt_sigreturn); | 341 | asmlinkage void sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs) |
225 | __attribute_used__ noinline static void | ||
226 | _sys_rt_sigreturn(nabi_no_regargs struct pt_regs regs) | ||
227 | { | 342 | { |
228 | struct rt_sigframe __user *frame; | 343 | struct rt_sigframe __user *frame; |
229 | sigset_t set; | 344 | sigset_t set; |
@@ -275,7 +390,7 @@ int setup_frame(struct k_sigaction * ka, struct pt_regs *regs, | |||
275 | if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) | 390 | if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) |
276 | goto give_sigsegv; | 391 | goto give_sigsegv; |
277 | 392 | ||
278 | install_sigtramp(frame->sf_code, __NR_sigreturn); | 393 | err |= install_sigtramp(frame->sf_code, __NR_sigreturn); |
279 | 394 | ||
280 | err |= setup_sigcontext(regs, &frame->sf_sc); | 395 | err |= setup_sigcontext(regs, &frame->sf_sc); |
281 | err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set)); | 396 | err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set)); |
@@ -299,12 +414,10 @@ int setup_frame(struct k_sigaction * ka, struct pt_regs *regs, | |||
299 | regs->regs[31] = (unsigned long) frame->sf_code; | 414 | regs->regs[31] = (unsigned long) frame->sf_code; |
300 | regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; | 415 | regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; |
301 | 416 | ||
302 | #if DEBUG_SIG | 417 | DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", |
303 | printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n", | ||
304 | current->comm, current->pid, | 418 | current->comm, current->pid, |
305 | frame, regs->cp0_epc, frame->regs[31]); | 419 | frame, regs->cp0_epc, regs->regs[31]); |
306 | #endif | 420 | return 0; |
307 | return 0; | ||
308 | 421 | ||
309 | give_sigsegv: | 422 | give_sigsegv: |
310 | force_sigsegv(signr, current); | 423 | force_sigsegv(signr, current); |
@@ -322,7 +435,7 @@ int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, | |||
322 | if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) | 435 | if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) |
323 | goto give_sigsegv; | 436 | goto give_sigsegv; |
324 | 437 | ||
325 | install_sigtramp(frame->rs_code, __NR_rt_sigreturn); | 438 | err |= install_sigtramp(frame->rs_code, __NR_rt_sigreturn); |
326 | 439 | ||
327 | /* Create siginfo. */ | 440 | /* Create siginfo. */ |
328 | err |= copy_siginfo_to_user(&frame->rs_info, info); | 441 | err |= copy_siginfo_to_user(&frame->rs_info, info); |
@@ -359,11 +472,10 @@ int setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, | |||
359 | regs->regs[31] = (unsigned long) frame->rs_code; | 472 | regs->regs[31] = (unsigned long) frame->rs_code; |
360 | regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; | 473 | regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler; |
361 | 474 | ||
362 | #if DEBUG_SIG | 475 | DEBUGP("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%lx\n", |
363 | printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n", | ||
364 | current->comm, current->pid, | 476 | current->comm, current->pid, |
365 | frame, regs->cp0_epc, regs->regs[31]); | 477 | frame, regs->cp0_epc, regs->regs[31]); |
366 | #endif | 478 | |
367 | return 0; | 479 | return 0; |
368 | 480 | ||
369 | give_sigsegv: | 481 | give_sigsegv: |
@@ -371,7 +483,7 @@ give_sigsegv: | |||
371 | return -EFAULT; | 483 | return -EFAULT; |
372 | } | 484 | } |
373 | 485 | ||
374 | static inline int handle_signal(unsigned long sig, siginfo_t *info, | 486 | static int handle_signal(unsigned long sig, siginfo_t *info, |
375 | struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs) | 487 | struct k_sigaction *ka, sigset_t *oldset, struct pt_regs *regs) |
376 | { | 488 | { |
377 | int ret; | 489 | int ret; |