diff options
Diffstat (limited to 'arch/m68k')
-rw-r--r-- | arch/m68k/include/asm/sun3_pgtable.h | 5 | ||||
-rw-r--r-- | arch/m68k/include/asm/thread_info.h | 1 | ||||
-rw-r--r-- | arch/m68k/include/asm/unistd.h | 1 | ||||
-rw-r--r-- | arch/m68k/kernel/entry.S | 30 | ||||
-rw-r--r-- | arch/m68k/kernel/signal.c | 314 |
5 files changed, 141 insertions, 210 deletions
diff --git a/arch/m68k/include/asm/sun3_pgtable.h b/arch/m68k/include/asm/sun3_pgtable.h index cf5fad9b525..f55aa04161e 100644 --- a/arch/m68k/include/asm/sun3_pgtable.h +++ b/arch/m68k/include/asm/sun3_pgtable.h | |||
@@ -217,9 +217,8 @@ static inline pte_t pgoff_to_pte(unsigned off) | |||
217 | /* Find an entry in the third-level pagetable. */ | 217 | /* Find an entry in the third-level pagetable. */ |
218 | #define pte_index(address) ((address >> PAGE_SHIFT) & (PTRS_PER_PTE-1)) | 218 | #define pte_index(address) ((address >> PAGE_SHIFT) & (PTRS_PER_PTE-1)) |
219 | #define pte_offset_kernel(pmd, address) ((pte_t *) __pmd_page(*pmd) + pte_index(address)) | 219 | #define pte_offset_kernel(pmd, address) ((pte_t *) __pmd_page(*pmd) + pte_index(address)) |
220 | /* FIXME: should we bother with kmap() here? */ | 220 | #define pte_offset_map(pmd, address) ((pte_t *)page_address(pmd_page(*pmd)) + pte_index(address)) |
221 | #define pte_offset_map(pmd, address) ((pte_t *)kmap(pmd_page(*pmd)) + pte_index(address)) | 221 | #define pte_unmap(pte) do { } while (0) |
222 | #define pte_unmap(pte) kunmap(pte) | ||
223 | 222 | ||
224 | /* Macros to (de)construct the fake PTEs representing swap pages. */ | 223 | /* Macros to (de)construct the fake PTEs representing swap pages. */ |
225 | #define __swp_type(x) ((x).val & 0x7F) | 224 | #define __swp_type(x) ((x).val & 0x7F) |
diff --git a/arch/m68k/include/asm/thread_info.h b/arch/m68k/include/asm/thread_info.h index 1da5d53a00e..790988967ba 100644 --- a/arch/m68k/include/asm/thread_info.h +++ b/arch/m68k/include/asm/thread_info.h | |||
@@ -104,5 +104,6 @@ static inline struct thread_info *current_thread_info(void) | |||
104 | #define TIF_SYSCALL_TRACE 15 /* syscall trace active */ | 104 | #define TIF_SYSCALL_TRACE 15 /* syscall trace active */ |
105 | #define TIF_MEMDIE 16 /* is terminating due to OOM killer */ | 105 | #define TIF_MEMDIE 16 /* is terminating due to OOM killer */ |
106 | #define TIF_FREEZE 17 /* thread is freezing for suspend */ | 106 | #define TIF_FREEZE 17 /* thread is freezing for suspend */ |
107 | #define TIF_RESTORE_SIGMASK 18 /* restore signal mask in do_signal */ | ||
107 | 108 | ||
108 | #endif /* _ASM_M68K_THREAD_INFO_H */ | 109 | #endif /* _ASM_M68K_THREAD_INFO_H */ |
diff --git a/arch/m68k/include/asm/unistd.h b/arch/m68k/include/asm/unistd.h index b43b36beafe..26d851d385b 100644 --- a/arch/m68k/include/asm/unistd.h +++ b/arch/m68k/include/asm/unistd.h | |||
@@ -373,6 +373,7 @@ | |||
373 | #define __ARCH_WANT_SYS_SIGPENDING | 373 | #define __ARCH_WANT_SYS_SIGPENDING |
374 | #define __ARCH_WANT_SYS_SIGPROCMASK | 374 | #define __ARCH_WANT_SYS_SIGPROCMASK |
375 | #define __ARCH_WANT_SYS_RT_SIGACTION | 375 | #define __ARCH_WANT_SYS_RT_SIGACTION |
376 | #define __ARCH_WANT_SYS_RT_SIGSUSPEND | ||
376 | 377 | ||
377 | /* | 378 | /* |
378 | * "Conditional" syscalls | 379 | * "Conditional" syscalls |
diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 6360c437dcf..1559dea36e5 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S | |||
@@ -99,7 +99,10 @@ do_trace_exit: | |||
99 | jra .Lret_from_exception | 99 | jra .Lret_from_exception |
100 | 100 | ||
101 | ENTRY(ret_from_signal) | 101 | ENTRY(ret_from_signal) |
102 | RESTORE_SWITCH_STACK | 102 | tstb %curptr@(TASK_INFO+TINFO_FLAGS+2) |
103 | jge 1f | ||
104 | jbsr syscall_trace | ||
105 | 1: RESTORE_SWITCH_STACK | ||
103 | addql #4,%sp | 106 | addql #4,%sp |
104 | /* on 68040 complete pending writebacks if any */ | 107 | /* on 68040 complete pending writebacks if any */ |
105 | #ifdef CONFIG_M68040 | 108 | #ifdef CONFIG_M68040 |
@@ -174,16 +177,11 @@ do_signal_return: | |||
174 | subql #4,%sp | dummy return address | 177 | subql #4,%sp | dummy return address |
175 | SAVE_SWITCH_STACK | 178 | SAVE_SWITCH_STACK |
176 | pea %sp@(SWITCH_STACK_SIZE) | 179 | pea %sp@(SWITCH_STACK_SIZE) |
177 | clrl %sp@- | ||
178 | bsrl do_signal | 180 | bsrl do_signal |
179 | addql #8,%sp | 181 | addql #4,%sp |
180 | RESTORE_SWITCH_STACK | 182 | RESTORE_SWITCH_STACK |
181 | addql #4,%sp | 183 | addql #4,%sp |
182 | tstl %d0 | 184 | jbra resume_userspace |
183 | jeq resume_userspace | ||
184 | | when single stepping into handler stop at the first insn | ||
185 | btst #6,%curptr@(TASK_INFO+TINFO_FLAGS+2) | ||
186 | jeq resume_userspace | ||
187 | 185 | ||
188 | do_delayed_trace: | 186 | do_delayed_trace: |
189 | bclr #7,%sp@(PT_OFF_SR) | clear trace bit in SR | 187 | bclr #7,%sp@(PT_OFF_SR) | clear trace bit in SR |
@@ -290,22 +288,6 @@ ENTRY(sys_vfork) | |||
290 | RESTORE_SWITCH_STACK | 288 | RESTORE_SWITCH_STACK |
291 | rts | 289 | rts |
292 | 290 | ||
293 | ENTRY(sys_sigsuspend) | ||
294 | SAVE_SWITCH_STACK | ||
295 | pea %sp@(SWITCH_STACK_SIZE) | ||
296 | jbsr do_sigsuspend | ||
297 | addql #4,%sp | ||
298 | RESTORE_SWITCH_STACK | ||
299 | rts | ||
300 | |||
301 | ENTRY(sys_rt_sigsuspend) | ||
302 | SAVE_SWITCH_STACK | ||
303 | pea %sp@(SWITCH_STACK_SIZE) | ||
304 | jbsr do_rt_sigsuspend | ||
305 | addql #4,%sp | ||
306 | RESTORE_SWITCH_STACK | ||
307 | rts | ||
308 | |||
309 | ENTRY(sys_sigreturn) | 291 | ENTRY(sys_sigreturn) |
310 | SAVE_SWITCH_STACK | 292 | SAVE_SWITCH_STACK |
311 | jbsr do_sigreturn | 293 | jbsr do_sigreturn |
diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c index 4b387538706..d12c3b0d9e4 100644 --- a/arch/m68k/kernel/signal.c +++ b/arch/m68k/kernel/signal.c | |||
@@ -51,8 +51,6 @@ | |||
51 | 51 | ||
52 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 52 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
53 | 53 | ||
54 | asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs); | ||
55 | |||
56 | const int frame_extra_sizes[16] = { | 54 | const int frame_extra_sizes[16] = { |
57 | [1] = -1, /* sizeof(((struct frame *)0)->un.fmt1), */ | 55 | [1] = -1, /* sizeof(((struct frame *)0)->un.fmt1), */ |
58 | [2] = sizeof(((struct frame *)0)->un.fmt2), | 56 | [2] = sizeof(((struct frame *)0)->un.fmt2), |
@@ -74,51 +72,21 @@ const int frame_extra_sizes[16] = { | |||
74 | /* | 72 | /* |
75 | * Atomically swap in the new signal mask, and wait for a signal. | 73 | * Atomically swap in the new signal mask, and wait for a signal. |
76 | */ | 74 | */ |
77 | asmlinkage int do_sigsuspend(struct pt_regs *regs) | 75 | asmlinkage int |
76 | sys_sigsuspend(int unused0, int unused1, old_sigset_t mask) | ||
78 | { | 77 | { |
79 | old_sigset_t mask = regs->d3; | ||
80 | sigset_t saveset; | ||
81 | |||
82 | mask &= _BLOCKABLE; | 78 | mask &= _BLOCKABLE; |
83 | saveset = current->blocked; | 79 | spin_lock_irq(¤t->sighand->siglock); |
80 | current->saved_sigmask = current->blocked; | ||
84 | siginitset(¤t->blocked, mask); | 81 | siginitset(¤t->blocked, mask); |
85 | recalc_sigpending(); | 82 | recalc_sigpending(); |
83 | spin_unlock_irq(¤t->sighand->siglock); | ||
86 | 84 | ||
87 | regs->d0 = -EINTR; | 85 | current->state = TASK_INTERRUPTIBLE; |
88 | while (1) { | 86 | schedule(); |
89 | current->state = TASK_INTERRUPTIBLE; | 87 | set_restore_sigmask(); |
90 | schedule(); | ||
91 | if (do_signal(&saveset, regs)) | ||
92 | return -EINTR; | ||
93 | } | ||
94 | } | ||
95 | |||
96 | asmlinkage int | ||
97 | do_rt_sigsuspend(struct pt_regs *regs) | ||
98 | { | ||
99 | sigset_t __user *unewset = (sigset_t __user *)regs->d1; | ||
100 | size_t sigsetsize = (size_t)regs->d2; | ||
101 | sigset_t saveset, newset; | ||
102 | |||
103 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
104 | if (sigsetsize != sizeof(sigset_t)) | ||
105 | return -EINVAL; | ||
106 | 88 | ||
107 | if (copy_from_user(&newset, unewset, sizeof(newset))) | 89 | return -ERESTARTNOHAND; |
108 | return -EFAULT; | ||
109 | sigdelsetmask(&newset, ~_BLOCKABLE); | ||
110 | |||
111 | saveset = current->blocked; | ||
112 | current->blocked = newset; | ||
113 | recalc_sigpending(); | ||
114 | |||
115 | regs->d0 = -EINTR; | ||
116 | while (1) { | ||
117 | current->state = TASK_INTERRUPTIBLE; | ||
118 | schedule(); | ||
119 | if (do_signal(&saveset, regs)) | ||
120 | return -EINTR; | ||
121 | } | ||
122 | } | 90 | } |
123 | 91 | ||
124 | asmlinkage int | 92 | asmlinkage int |
@@ -132,10 +100,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, | |||
132 | old_sigset_t mask; | 100 | old_sigset_t mask; |
133 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || | 101 | if (!access_ok(VERIFY_READ, act, sizeof(*act)) || |
134 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || | 102 | __get_user(new_ka.sa.sa_handler, &act->sa_handler) || |
135 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) | 103 | __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) || |
104 | __get_user(new_ka.sa.sa_flags, &act->sa_flags) || | ||
105 | __get_user(mask, &act->sa_mask)) | ||
136 | return -EFAULT; | 106 | return -EFAULT; |
137 | __get_user(new_ka.sa.sa_flags, &act->sa_flags); | ||
138 | __get_user(mask, &act->sa_mask); | ||
139 | siginitset(&new_ka.sa.sa_mask, mask); | 107 | siginitset(&new_ka.sa.sa_mask, mask); |
140 | } | 108 | } |
141 | 109 | ||
@@ -144,10 +112,10 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, | |||
144 | if (!ret && oact) { | 112 | if (!ret && oact) { |
145 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || | 113 | if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || |
146 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || | 114 | __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || |
147 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) | 115 | __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) || |
116 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || | ||
117 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask)) | ||
148 | return -EFAULT; | 118 | return -EFAULT; |
149 | __put_user(old_ka.sa.sa_flags, &oact->sa_flags); | ||
150 | __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); | ||
151 | } | 119 | } |
152 | 120 | ||
153 | return ret; | 121 | return ret; |
@@ -318,36 +286,10 @@ out: | |||
318 | return err; | 286 | return err; |
319 | } | 287 | } |
320 | 288 | ||
321 | static inline int | 289 | static int mangle_kernel_stack(struct pt_regs *regs, int formatvec, |
322 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __user *fp, | 290 | void __user *fp) |
323 | int *pd0) | ||
324 | { | 291 | { |
325 | int fsize, formatvec; | 292 | int fsize = frame_extra_sizes[formatvec >> 12]; |
326 | struct sigcontext context; | ||
327 | int err; | ||
328 | |||
329 | /* Always make any pending restarted system calls return -EINTR */ | ||
330 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
331 | |||
332 | /* get previous context */ | ||
333 | if (copy_from_user(&context, usc, sizeof(context))) | ||
334 | goto badframe; | ||
335 | |||
336 | /* restore passed registers */ | ||
337 | regs->d1 = context.sc_d1; | ||
338 | regs->a0 = context.sc_a0; | ||
339 | regs->a1 = context.sc_a1; | ||
340 | regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff); | ||
341 | regs->pc = context.sc_pc; | ||
342 | regs->orig_d0 = -1; /* disable syscall checks */ | ||
343 | wrusp(context.sc_usp); | ||
344 | formatvec = context.sc_formatvec; | ||
345 | regs->format = formatvec >> 12; | ||
346 | regs->vector = formatvec & 0xfff; | ||
347 | |||
348 | err = restore_fpu_state(&context); | ||
349 | |||
350 | fsize = frame_extra_sizes[regs->format]; | ||
351 | if (fsize < 0) { | 293 | if (fsize < 0) { |
352 | /* | 294 | /* |
353 | * user process trying to return with weird frame format | 295 | * user process trying to return with weird frame format |
@@ -355,16 +297,22 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __u | |||
355 | #ifdef DEBUG | 297 | #ifdef DEBUG |
356 | printk("user process returning with weird frame format\n"); | 298 | printk("user process returning with weird frame format\n"); |
357 | #endif | 299 | #endif |
358 | goto badframe; | 300 | return 1; |
359 | } | 301 | } |
302 | if (!fsize) { | ||
303 | regs->format = formatvec >> 12; | ||
304 | regs->vector = formatvec & 0xfff; | ||
305 | } else { | ||
306 | struct switch_stack *sw = (struct switch_stack *)regs - 1; | ||
307 | unsigned long buf[fsize / 2]; /* yes, twice as much */ | ||
360 | 308 | ||
361 | /* OK. Make room on the supervisor stack for the extra junk, | 309 | /* that'll make sure that expansion won't crap over data */ |
362 | * if necessary. | 310 | if (copy_from_user(buf + fsize / 4, fp, fsize)) |
363 | */ | 311 | return 1; |
364 | 312 | ||
365 | if (fsize) { | 313 | /* point of no return */ |
366 | struct switch_stack *sw = (struct switch_stack *)regs - 1; | 314 | regs->format = formatvec >> 12; |
367 | regs->d0 = context.sc_d0; | 315 | regs->vector = formatvec & 0xfff; |
368 | #define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack)) | 316 | #define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack)) |
369 | __asm__ __volatile__ | 317 | __asm__ __volatile__ |
370 | (" movel %0,%/a0\n\t" | 318 | (" movel %0,%/a0\n\t" |
@@ -376,30 +324,50 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __u | |||
376 | " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */ | 324 | " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */ |
377 | " lsrl #2,%1\n\t" | 325 | " lsrl #2,%1\n\t" |
378 | " subql #1,%1\n\t" | 326 | " subql #1,%1\n\t" |
379 | "2: movesl %4@+,%2\n\t" | 327 | /* copy to the gap we'd made */ |
380 | "3: movel %2,%/a0@+\n\t" | 328 | "2: movel %4@+,%/a0@+\n\t" |
381 | " dbra %1,2b\n\t" | 329 | " dbra %1,2b\n\t" |
382 | " bral ret_from_signal\n" | 330 | " bral ret_from_signal\n" |
383 | "4:\n" | ||
384 | ".section __ex_table,\"a\"\n" | ||
385 | " .align 4\n" | ||
386 | " .long 2b,4b\n" | ||
387 | " .long 3b,4b\n" | ||
388 | ".previous" | ||
389 | : /* no outputs, it doesn't ever return */ | 331 | : /* no outputs, it doesn't ever return */ |
390 | : "a" (sw), "d" (fsize), "d" (frame_offset/4-1), | 332 | : "a" (sw), "d" (fsize), "d" (frame_offset/4-1), |
391 | "n" (frame_offset), "a" (fp) | 333 | "n" (frame_offset), "a" (buf + fsize/4) |
392 | : "a0"); | 334 | : "a0"); |
393 | #undef frame_offset | 335 | #undef frame_offset |
394 | /* | ||
395 | * If we ever get here an exception occurred while | ||
396 | * building the above stack-frame. | ||
397 | */ | ||
398 | goto badframe; | ||
399 | } | 336 | } |
337 | return 0; | ||
338 | } | ||
400 | 339 | ||
401 | *pd0 = context.sc_d0; | 340 | static inline int |
402 | return err; | 341 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *usc, void __user *fp) |
342 | { | ||
343 | int formatvec; | ||
344 | struct sigcontext context; | ||
345 | int err; | ||
346 | |||
347 | /* Always make any pending restarted system calls return -EINTR */ | ||
348 | current_thread_info()->restart_block.fn = do_no_restart_syscall; | ||
349 | |||
350 | /* get previous context */ | ||
351 | if (copy_from_user(&context, usc, sizeof(context))) | ||
352 | goto badframe; | ||
353 | |||
354 | /* restore passed registers */ | ||
355 | regs->d0 = context.sc_d0; | ||
356 | regs->d1 = context.sc_d1; | ||
357 | regs->a0 = context.sc_a0; | ||
358 | regs->a1 = context.sc_a1; | ||
359 | regs->sr = (regs->sr & 0xff00) | (context.sc_sr & 0xff); | ||
360 | regs->pc = context.sc_pc; | ||
361 | regs->orig_d0 = -1; /* disable syscall checks */ | ||
362 | wrusp(context.sc_usp); | ||
363 | formatvec = context.sc_formatvec; | ||
364 | |||
365 | err = restore_fpu_state(&context); | ||
366 | |||
367 | if (err || mangle_kernel_stack(regs, formatvec, fp)) | ||
368 | goto badframe; | ||
369 | |||
370 | return 0; | ||
403 | 371 | ||
404 | badframe: | 372 | badframe: |
405 | return 1; | 373 | return 1; |
@@ -407,9 +375,9 @@ badframe: | |||
407 | 375 | ||
408 | static inline int | 376 | static inline int |
409 | rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, | 377 | rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, |
410 | struct ucontext __user *uc, int *pd0) | 378 | struct ucontext __user *uc) |
411 | { | 379 | { |
412 | int fsize, temp; | 380 | int temp; |
413 | greg_t __user *gregs = uc->uc_mcontext.gregs; | 381 | greg_t __user *gregs = uc->uc_mcontext.gregs; |
414 | unsigned long usp; | 382 | unsigned long usp; |
415 | int err; | 383 | int err; |
@@ -443,65 +411,16 @@ rt_restore_ucontext(struct pt_regs *regs, struct switch_stack *sw, | |||
443 | regs->sr = (regs->sr & 0xff00) | (temp & 0xff); | 411 | regs->sr = (regs->sr & 0xff00) | (temp & 0xff); |
444 | regs->orig_d0 = -1; /* disable syscall checks */ | 412 | regs->orig_d0 = -1; /* disable syscall checks */ |
445 | err |= __get_user(temp, &uc->uc_formatvec); | 413 | err |= __get_user(temp, &uc->uc_formatvec); |
446 | regs->format = temp >> 12; | ||
447 | regs->vector = temp & 0xfff; | ||
448 | 414 | ||
449 | err |= rt_restore_fpu_state(uc); | 415 | err |= rt_restore_fpu_state(uc); |
450 | 416 | ||
451 | if (do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT) | 417 | if (err || do_sigaltstack(&uc->uc_stack, NULL, usp) == -EFAULT) |
452 | goto badframe; | 418 | goto badframe; |
453 | 419 | ||
454 | fsize = frame_extra_sizes[regs->format]; | 420 | if (mangle_kernel_stack(regs, temp, &uc->uc_extra)) |
455 | if (fsize < 0) { | ||
456 | /* | ||
457 | * user process trying to return with weird frame format | ||
458 | */ | ||
459 | #ifdef DEBUG | ||
460 | printk("user process returning with weird frame format\n"); | ||
461 | #endif | ||
462 | goto badframe; | 421 | goto badframe; |
463 | } | ||
464 | |||
465 | /* OK. Make room on the supervisor stack for the extra junk, | ||
466 | * if necessary. | ||
467 | */ | ||
468 | 422 | ||
469 | if (fsize) { | 423 | return 0; |
470 | #define frame_offset (sizeof(struct pt_regs)+sizeof(struct switch_stack)) | ||
471 | __asm__ __volatile__ | ||
472 | (" movel %0,%/a0\n\t" | ||
473 | " subl %1,%/a0\n\t" /* make room on stack */ | ||
474 | " movel %/a0,%/sp\n\t" /* set stack pointer */ | ||
475 | /* move switch_stack and pt_regs */ | ||
476 | "1: movel %0@+,%/a0@+\n\t" | ||
477 | " dbra %2,1b\n\t" | ||
478 | " lea %/sp@(%c3),%/a0\n\t" /* add offset of fmt */ | ||
479 | " lsrl #2,%1\n\t" | ||
480 | " subql #1,%1\n\t" | ||
481 | "2: movesl %4@+,%2\n\t" | ||
482 | "3: movel %2,%/a0@+\n\t" | ||
483 | " dbra %1,2b\n\t" | ||
484 | " bral ret_from_signal\n" | ||
485 | "4:\n" | ||
486 | ".section __ex_table,\"a\"\n" | ||
487 | " .align 4\n" | ||
488 | " .long 2b,4b\n" | ||
489 | " .long 3b,4b\n" | ||
490 | ".previous" | ||
491 | : /* no outputs, it doesn't ever return */ | ||
492 | : "a" (sw), "d" (fsize), "d" (frame_offset/4-1), | ||
493 | "n" (frame_offset), "a" (&uc->uc_extra) | ||
494 | : "a0"); | ||
495 | #undef frame_offset | ||
496 | /* | ||
497 | * If we ever get here an exception occurred while | ||
498 | * building the above stack-frame. | ||
499 | */ | ||
500 | goto badframe; | ||
501 | } | ||
502 | |||
503 | *pd0 = regs->d0; | ||
504 | return err; | ||
505 | 424 | ||
506 | badframe: | 425 | badframe: |
507 | return 1; | 426 | return 1; |
@@ -514,7 +433,6 @@ asmlinkage int do_sigreturn(unsigned long __unused) | |||
514 | unsigned long usp = rdusp(); | 433 | unsigned long usp = rdusp(); |
515 | struct sigframe __user *frame = (struct sigframe __user *)(usp - 4); | 434 | struct sigframe __user *frame = (struct sigframe __user *)(usp - 4); |
516 | sigset_t set; | 435 | sigset_t set; |
517 | int d0; | ||
518 | 436 | ||
519 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 437 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
520 | goto badframe; | 438 | goto badframe; |
@@ -528,9 +446,9 @@ asmlinkage int do_sigreturn(unsigned long __unused) | |||
528 | current->blocked = set; | 446 | current->blocked = set; |
529 | recalc_sigpending(); | 447 | recalc_sigpending(); |
530 | 448 | ||
531 | if (restore_sigcontext(regs, &frame->sc, frame + 1, &d0)) | 449 | if (restore_sigcontext(regs, &frame->sc, frame + 1)) |
532 | goto badframe; | 450 | goto badframe; |
533 | return d0; | 451 | return regs->d0; |
534 | 452 | ||
535 | badframe: | 453 | badframe: |
536 | force_sig(SIGSEGV, current); | 454 | force_sig(SIGSEGV, current); |
@@ -544,7 +462,6 @@ asmlinkage int do_rt_sigreturn(unsigned long __unused) | |||
544 | unsigned long usp = rdusp(); | 462 | unsigned long usp = rdusp(); |
545 | struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(usp - 4); | 463 | struct rt_sigframe __user *frame = (struct rt_sigframe __user *)(usp - 4); |
546 | sigset_t set; | 464 | sigset_t set; |
547 | int d0; | ||
548 | 465 | ||
549 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) | 466 | if (!access_ok(VERIFY_READ, frame, sizeof(*frame))) |
550 | goto badframe; | 467 | goto badframe; |
@@ -555,9 +472,9 @@ asmlinkage int do_rt_sigreturn(unsigned long __unused) | |||
555 | current->blocked = set; | 472 | current->blocked = set; |
556 | recalc_sigpending(); | 473 | recalc_sigpending(); |
557 | 474 | ||
558 | if (rt_restore_ucontext(regs, sw, &frame->uc, &d0)) | 475 | if (rt_restore_ucontext(regs, sw, &frame->uc)) |
559 | goto badframe; | 476 | goto badframe; |
560 | return d0; | 477 | return regs->d0; |
561 | 478 | ||
562 | badframe: | 479 | badframe: |
563 | force_sig(SIGSEGV, current); | 480 | force_sig(SIGSEGV, current); |
@@ -775,7 +692,7 @@ get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size) | |||
775 | return (void __user *)((usp - frame_size) & -8UL); | 692 | return (void __user *)((usp - frame_size) & -8UL); |
776 | } | 693 | } |
777 | 694 | ||
778 | static void setup_frame (int sig, struct k_sigaction *ka, | 695 | static int setup_frame (int sig, struct k_sigaction *ka, |
779 | sigset_t *set, struct pt_regs *regs) | 696 | sigset_t *set, struct pt_regs *regs) |
780 | { | 697 | { |
781 | struct sigframe __user *frame; | 698 | struct sigframe __user *frame; |
@@ -793,10 +710,8 @@ static void setup_frame (int sig, struct k_sigaction *ka, | |||
793 | 710 | ||
794 | frame = get_sigframe(ka, regs, sizeof(*frame) + fsize); | 711 | frame = get_sigframe(ka, regs, sizeof(*frame) + fsize); |
795 | 712 | ||
796 | if (fsize) { | 713 | if (fsize) |
797 | err |= copy_to_user (frame + 1, regs + 1, fsize); | 714 | err |= copy_to_user (frame + 1, regs + 1, fsize); |
798 | regs->stkadj = fsize; | ||
799 | } | ||
800 | 715 | ||
801 | err |= __put_user((current_thread_info()->exec_domain | 716 | err |= __put_user((current_thread_info()->exec_domain |
802 | && current_thread_info()->exec_domain->signal_invmap | 717 | && current_thread_info()->exec_domain->signal_invmap |
@@ -826,11 +741,21 @@ static void setup_frame (int sig, struct k_sigaction *ka, | |||
826 | 741 | ||
827 | push_cache ((unsigned long) &frame->retcode); | 742 | push_cache ((unsigned long) &frame->retcode); |
828 | 743 | ||
829 | /* Set up registers for signal handler */ | 744 | /* |
745 | * Set up registers for signal handler. All the state we are about | ||
746 | * to destroy is successfully copied to sigframe. | ||
747 | */ | ||
830 | wrusp ((unsigned long) frame); | 748 | wrusp ((unsigned long) frame); |
831 | regs->pc = (unsigned long) ka->sa.sa_handler; | 749 | regs->pc = (unsigned long) ka->sa.sa_handler; |
832 | 750 | ||
833 | adjust_stack: | 751 | /* |
752 | * This is subtle; if we build more than one sigframe, all but the | ||
753 | * first one will see frame format 0 and have fsize == 0, so we won't | ||
754 | * screw stkadj. | ||
755 | */ | ||
756 | if (fsize) | ||
757 | regs->stkadj = fsize; | ||
758 | |||
834 | /* Prepare to skip over the extra stuff in the exception frame. */ | 759 | /* Prepare to skip over the extra stuff in the exception frame. */ |
835 | if (regs->stkadj) { | 760 | if (regs->stkadj) { |
836 | struct pt_regs *tregs = | 761 | struct pt_regs *tregs = |
@@ -845,14 +770,14 @@ adjust_stack: | |||
845 | tregs->pc = regs->pc; | 770 | tregs->pc = regs->pc; |
846 | tregs->sr = regs->sr; | 771 | tregs->sr = regs->sr; |
847 | } | 772 | } |
848 | return; | 773 | return 0; |
849 | 774 | ||
850 | give_sigsegv: | 775 | give_sigsegv: |
851 | force_sigsegv(sig, current); | 776 | force_sigsegv(sig, current); |
852 | goto adjust_stack; | 777 | return err; |
853 | } | 778 | } |
854 | 779 | ||
855 | static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, | 780 | static int setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, |
856 | sigset_t *set, struct pt_regs *regs) | 781 | sigset_t *set, struct pt_regs *regs) |
857 | { | 782 | { |
858 | struct rt_sigframe __user *frame; | 783 | struct rt_sigframe __user *frame; |
@@ -869,10 +794,8 @@ static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, | |||
869 | 794 | ||
870 | frame = get_sigframe(ka, regs, sizeof(*frame)); | 795 | frame = get_sigframe(ka, regs, sizeof(*frame)); |
871 | 796 | ||
872 | if (fsize) { | 797 | if (fsize) |
873 | err |= copy_to_user (&frame->uc.uc_extra, regs + 1, fsize); | 798 | err |= copy_to_user (&frame->uc.uc_extra, regs + 1, fsize); |
874 | regs->stkadj = fsize; | ||
875 | } | ||
876 | 799 | ||
877 | err |= __put_user((current_thread_info()->exec_domain | 800 | err |= __put_user((current_thread_info()->exec_domain |
878 | && current_thread_info()->exec_domain->signal_invmap | 801 | && current_thread_info()->exec_domain->signal_invmap |
@@ -914,11 +837,21 @@ static void setup_rt_frame (int sig, struct k_sigaction *ka, siginfo_t *info, | |||
914 | 837 | ||
915 | push_cache ((unsigned long) &frame->retcode); | 838 | push_cache ((unsigned long) &frame->retcode); |
916 | 839 | ||
917 | /* Set up registers for signal handler */ | 840 | /* |
841 | * Set up registers for signal handler. All the state we are about | ||
842 | * to destroy is successfully copied to sigframe. | ||
843 | */ | ||
918 | wrusp ((unsigned long) frame); | 844 | wrusp ((unsigned long) frame); |
919 | regs->pc = (unsigned long) ka->sa.sa_handler; | 845 | regs->pc = (unsigned long) ka->sa.sa_handler; |
920 | 846 | ||
921 | adjust_stack: | 847 | /* |
848 | * This is subtle; if we build more than one sigframe, all but the | ||
849 | * first one will see frame format 0 and have fsize == 0, so we won't | ||
850 | * screw stkadj. | ||
851 | */ | ||
852 | if (fsize) | ||
853 | regs->stkadj = fsize; | ||
854 | |||
922 | /* Prepare to skip over the extra stuff in the exception frame. */ | 855 | /* Prepare to skip over the extra stuff in the exception frame. */ |
923 | if (regs->stkadj) { | 856 | if (regs->stkadj) { |
924 | struct pt_regs *tregs = | 857 | struct pt_regs *tregs = |
@@ -933,11 +866,11 @@ adjust_stack: | |||
933 | tregs->pc = regs->pc; | 866 | tregs->pc = regs->pc; |
934 | tregs->sr = regs->sr; | 867 | tregs->sr = regs->sr; |
935 | } | 868 | } |
936 | return; | 869 | return 0; |
937 | 870 | ||
938 | give_sigsegv: | 871 | give_sigsegv: |
939 | force_sigsegv(sig, current); | 872 | force_sigsegv(sig, current); |
940 | goto adjust_stack; | 873 | return err; |
941 | } | 874 | } |
942 | 875 | ||
943 | static inline void | 876 | static inline void |
@@ -995,6 +928,7 @@ static void | |||
995 | handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, | 928 | handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, |
996 | sigset_t *oldset, struct pt_regs *regs) | 929 | sigset_t *oldset, struct pt_regs *regs) |
997 | { | 930 | { |
931 | int err; | ||
998 | /* are we from a system call? */ | 932 | /* are we from a system call? */ |
999 | if (regs->orig_d0 >= 0) | 933 | if (regs->orig_d0 >= 0) |
1000 | /* If so, check system call restarting.. */ | 934 | /* If so, check system call restarting.. */ |
@@ -1002,17 +936,24 @@ handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
1002 | 936 | ||
1003 | /* set up the stack frame */ | 937 | /* set up the stack frame */ |
1004 | if (ka->sa.sa_flags & SA_SIGINFO) | 938 | if (ka->sa.sa_flags & SA_SIGINFO) |
1005 | setup_rt_frame(sig, ka, info, oldset, regs); | 939 | err = setup_rt_frame(sig, ka, info, oldset, regs); |
1006 | else | 940 | else |
1007 | setup_frame(sig, ka, oldset, regs); | 941 | err = setup_frame(sig, ka, oldset, regs); |
1008 | 942 | ||
1009 | if (ka->sa.sa_flags & SA_ONESHOT) | 943 | if (err) |
1010 | ka->sa.sa_handler = SIG_DFL; | 944 | return; |
1011 | 945 | ||
1012 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 946 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); |
1013 | if (!(ka->sa.sa_flags & SA_NODEFER)) | 947 | if (!(ka->sa.sa_flags & SA_NODEFER)) |
1014 | sigaddset(¤t->blocked,sig); | 948 | sigaddset(¤t->blocked,sig); |
1015 | recalc_sigpending(); | 949 | recalc_sigpending(); |
950 | |||
951 | if (test_thread_flag(TIF_DELAYED_TRACE)) { | ||
952 | regs->sr &= ~0x8000; | ||
953 | send_sig(SIGTRAP, current, 1); | ||
954 | } | ||
955 | |||
956 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
1016 | } | 957 | } |
1017 | 958 | ||
1018 | /* | 959 | /* |
@@ -1020,22 +961,25 @@ handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
1020 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 961 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
1021 | * mistake. | 962 | * mistake. |
1022 | */ | 963 | */ |
1023 | asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) | 964 | asmlinkage void do_signal(struct pt_regs *regs) |
1024 | { | 965 | { |
1025 | siginfo_t info; | 966 | siginfo_t info; |
1026 | struct k_sigaction ka; | 967 | struct k_sigaction ka; |
1027 | int signr; | 968 | int signr; |
969 | sigset_t *oldset; | ||
1028 | 970 | ||
1029 | current->thread.esp0 = (unsigned long) regs; | 971 | current->thread.esp0 = (unsigned long) regs; |
1030 | 972 | ||
1031 | if (!oldset) | 973 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
974 | oldset = ¤t->saved_sigmask; | ||
975 | else | ||
1032 | oldset = ¤t->blocked; | 976 | oldset = ¤t->blocked; |
1033 | 977 | ||
1034 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); | 978 | signr = get_signal_to_deliver(&info, &ka, regs, NULL); |
1035 | if (signr > 0) { | 979 | if (signr > 0) { |
1036 | /* Whee! Actually deliver the signal. */ | 980 | /* Whee! Actually deliver the signal. */ |
1037 | handle_signal(signr, &ka, &info, oldset, regs); | 981 | handle_signal(signr, &ka, &info, oldset, regs); |
1038 | return 1; | 982 | return; |
1039 | } | 983 | } |
1040 | 984 | ||
1041 | /* Did we come from a system call? */ | 985 | /* Did we come from a system call? */ |
@@ -1043,5 +987,9 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs) | |||
1043 | /* Restart the system call - no handlers present */ | 987 | /* Restart the system call - no handlers present */ |
1044 | handle_restart(regs, NULL, 0); | 988 | handle_restart(regs, NULL, 0); |
1045 | 989 | ||
1046 | return 0; | 990 | /* If there's no signal to deliver, we just restore the saved mask. */ |
991 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
992 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
993 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
994 | } | ||
1047 | } | 995 | } |