diff options
Diffstat (limited to 'arch/microblaze/kernel/signal.c')
-rw-r--r-- | arch/microblaze/kernel/signal.c | 109 |
1 files changed, 21 insertions, 88 deletions
diff --git a/arch/microblaze/kernel/signal.c b/arch/microblaze/kernel/signal.c index 40d36931e363..4c0e6521b114 100644 --- a/arch/microblaze/kernel/signal.c +++ b/arch/microblaze/kernel/signal.c | |||
@@ -152,8 +152,8 @@ struct rt_sigframe { | |||
152 | unsigned long tramp[2]; /* signal trampoline */ | 152 | unsigned long tramp[2]; /* signal trampoline */ |
153 | }; | 153 | }; |
154 | 154 | ||
155 | static int | 155 | static int restore_sigcontext(struct pt_regs *regs, |
156 | restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc, int *rval_p) | 156 | struct sigcontext __user *sc, int *rval_p) |
157 | { | 157 | { |
158 | unsigned int err = 0; | 158 | unsigned int err = 0; |
159 | 159 | ||
@@ -211,11 +211,10 @@ badframe: | |||
211 | 211 | ||
212 | asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) | 212 | asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) |
213 | { | 213 | { |
214 | struct rt_sigframe *frame = | 214 | struct rt_sigframe __user *frame = |
215 | (struct rt_sigframe *)(regs->r1 + STATE_SAVE_ARG_SPACE); | 215 | (struct rt_sigframe __user *)(regs->r1 + STATE_SAVE_ARG_SPACE); |
216 | 216 | ||
217 | sigset_t set; | 217 | sigset_t set; |
218 | stack_t st; | ||
219 | int rval; | 218 | int rval; |
220 | 219 | ||
221 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 220 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
@@ -233,11 +232,10 @@ asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) | |||
233 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &rval)) | 232 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext, &rval)) |
234 | goto badframe; | 233 | goto badframe; |
235 | 234 | ||
236 | if (__copy_from_user((void *)&st, &frame->uc.uc_stack, sizeof(st))) | ||
237 | goto badframe; | ||
238 | /* It is more difficult to avoid calling this function than to | 235 | /* It is more difficult to avoid calling this function than to |
239 | call it and ignore errors. */ | 236 | call it and ignore errors. */ |
240 | do_sigaltstack(&st, NULL, regs->r1); | 237 | if (do_sigaltstack(&frame->uc.uc_stack, NULL, regs->r1)) |
238 | goto badframe; | ||
241 | 239 | ||
242 | return rval; | 240 | return rval; |
243 | 241 | ||
@@ -251,7 +249,7 @@ badframe: | |||
251 | */ | 249 | */ |
252 | 250 | ||
253 | static int | 251 | static int |
254 | setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, | 252 | setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, |
255 | unsigned long mask) | 253 | unsigned long mask) |
256 | { | 254 | { |
257 | int err = 0; | 255 | int err = 0; |
@@ -278,7 +276,7 @@ setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs, | |||
278 | /* | 276 | /* |
279 | * Determine which stack to use.. | 277 | * Determine which stack to use.. |
280 | */ | 278 | */ |
281 | static inline void * | 279 | static inline void __user * |
282 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) | 280 | get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) |
283 | { | 281 | { |
284 | /* Default to using normal stack */ | 282 | /* Default to using normal stack */ |
@@ -287,87 +285,13 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) | |||
287 | if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && !on_sig_stack(sp)) | 285 | if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && !on_sig_stack(sp)) |
288 | sp = current->sas_ss_sp + current->sas_ss_size; | 286 | sp = current->sas_ss_sp + current->sas_ss_size; |
289 | 287 | ||
290 | return (void *)((sp - frame_size) & -8UL); | 288 | return (void __user *)((sp - frame_size) & -8UL); |
291 | } | ||
292 | |||
293 | static void setup_frame(int sig, struct k_sigaction *ka, | ||
294 | sigset_t *set, struct pt_regs *regs) | ||
295 | { | ||
296 | struct sigframe *frame; | ||
297 | int err = 0; | ||
298 | int signal; | ||
299 | |||
300 | frame = get_sigframe(ka, regs, sizeof(*frame)); | ||
301 | |||
302 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) | ||
303 | goto give_sigsegv; | ||
304 | |||
305 | signal = current_thread_info()->exec_domain | ||
306 | && current_thread_info()->exec_domain->signal_invmap | ||
307 | && sig < 32 | ||
308 | ? current_thread_info()->exec_domain->signal_invmap[sig] | ||
309 | : sig; | ||
310 | |||
311 | err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); | ||
312 | |||
313 | if (_NSIG_WORDS > 1) { | ||
314 | err |= __copy_to_user(frame->extramask, &set->sig[1], | ||
315 | sizeof(frame->extramask)); | ||
316 | } | ||
317 | |||
318 | /* Set up to return from userspace. If provided, use a stub | ||
319 | already in userspace. */ | ||
320 | /* minus 8 is offset to cater for "rtsd r15,8" offset */ | ||
321 | if (ka->sa.sa_flags & SA_RESTORER) { | ||
322 | regs->r15 = ((unsigned long)ka->sa.sa_restorer)-8; | ||
323 | } else { | ||
324 | /* Note, these encodings are _big endian_! */ | ||
325 | |||
326 | /* addi r12, r0, __NR_sigreturn */ | ||
327 | err |= __put_user(0x31800000 | __NR_sigreturn , | ||
328 | frame->tramp + 0); | ||
329 | /* brki r14, 0x8 */ | ||
330 | err |= __put_user(0xb9cc0008, frame->tramp + 1); | ||
331 | |||
332 | /* Return from sighandler will jump to the tramp. | ||
333 | Negative 8 offset because return is rtsd r15, 8 */ | ||
334 | regs->r15 = ((unsigned long)frame->tramp)-8; | ||
335 | |||
336 | __invalidate_cache_sigtramp((unsigned long)frame->tramp); | ||
337 | } | ||
338 | |||
339 | if (err) | ||
340 | goto give_sigsegv; | ||
341 | |||
342 | /* Set up registers for signal handler */ | ||
343 | regs->r1 = (unsigned long) frame - STATE_SAVE_ARG_SPACE; | ||
344 | |||
345 | /* Signal handler args: */ | ||
346 | regs->r5 = signal; /* Arg 0: signum */ | ||
347 | regs->r6 = (unsigned long) &frame->sc; /* arg 1: sigcontext */ | ||
348 | |||
349 | /* Offset of 4 to handle microblaze rtid r14, 0 */ | ||
350 | regs->pc = (unsigned long)ka->sa.sa_handler; | ||
351 | |||
352 | set_fs(USER_DS); | ||
353 | |||
354 | #ifdef DEBUG_SIG | ||
355 | printk(KERN_INFO "SIG deliver (%s:%d): sp=%p pc=%08lx\n", | ||
356 | current->comm, current->pid, frame, regs->pc); | ||
357 | #endif | ||
358 | |||
359 | return; | ||
360 | |||
361 | give_sigsegv: | ||
362 | if (sig == SIGSEGV) | ||
363 | ka->sa.sa_handler = SIG_DFL; | ||
364 | force_sig(SIGSEGV, current); | ||
365 | } | 289 | } |
366 | 290 | ||
367 | static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | 291 | static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, |
368 | sigset_t *set, struct pt_regs *regs) | 292 | sigset_t *set, struct pt_regs *regs) |
369 | { | 293 | { |
370 | struct rt_sigframe *frame; | 294 | struct rt_sigframe __user *frame; |
371 | int err = 0; | 295 | int err = 0; |
372 | int signal; | 296 | int signal; |
373 | 297 | ||
@@ -382,7 +306,8 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
382 | ? current_thread_info()->exec_domain->signal_invmap[sig] | 306 | ? current_thread_info()->exec_domain->signal_invmap[sig] |
383 | : sig; | 307 | : sig; |
384 | 308 | ||
385 | err |= copy_siginfo_to_user(&frame->info, info); | 309 | if (info) |
310 | err |= copy_siginfo_to_user(&frame->info, info); | ||
386 | 311 | ||
387 | /* Create the ucontext. */ | 312 | /* Create the ucontext. */ |
388 | err |= __put_user(0, &frame->uc.uc_flags); | 313 | err |= __put_user(0, &frame->uc.uc_flags); |
@@ -463,7 +388,15 @@ handle_restart(struct pt_regs *regs, struct k_sigaction *ka, int has_handler) | |||
463 | case -ERESTARTNOINTR: | 388 | case -ERESTARTNOINTR: |
464 | do_restart: | 389 | do_restart: |
465 | /* offset of 4 bytes to re-execute trap (brki) instruction */ | 390 | /* offset of 4 bytes to re-execute trap (brki) instruction */ |
391 | #ifndef CONFIG_MMU | ||
466 | regs->pc -= 4; | 392 | regs->pc -= 4; |
393 | #else | ||
394 | /* offset of 8 bytes required = 4 for rtbd | ||
395 | offset, plus 4 for size of | ||
396 | "brki r14,8" | ||
397 | instruction. */ | ||
398 | regs->pc -= 8; | ||
399 | #endif | ||
467 | break; | 400 | break; |
468 | } | 401 | } |
469 | } | 402 | } |
@@ -480,7 +413,7 @@ handle_signal(unsigned long sig, struct k_sigaction *ka, | |||
480 | if (ka->sa.sa_flags & SA_SIGINFO) | 413 | if (ka->sa.sa_flags & SA_SIGINFO) |
481 | setup_rt_frame(sig, ka, info, oldset, regs); | 414 | setup_rt_frame(sig, ka, info, oldset, regs); |
482 | else | 415 | else |
483 | setup_frame(sig, ka, oldset, regs); | 416 | setup_rt_frame(sig, ka, NULL, oldset, regs); |
484 | 417 | ||
485 | if (ka->sa.sa_flags & SA_ONESHOT) | 418 | if (ka->sa.sa_flags & SA_ONESHOT) |
486 | ka->sa.sa_handler = SIG_DFL; | 419 | ka->sa.sa_handler = SIG_DFL; |