diff options
author | David Woodhouse <dwmw2@infradead.org> | 2005-11-15 13:52:18 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-01-08 22:49:01 -0500 |
commit | 401d1f029bebb7153ca704997772113dc36d9527 (patch) | |
tree | 01a3d649ac591d7a1fb910ce29a7223ffb629f9a | |
parent | 1cd8e506209223ed10da805d99be55e268f4023c (diff) |
[PATCH] syscall entry/exit revamp
This cleanup patch speeds up the null syscall path on ppc64 by about 3%,
and brings the ppc32 and ppc64 code slightly closer together.
The ppc64 code was checking current_thread_info()->flags twice in the
syscall exit path; once for TIF_SYSCALL_T_OR_A before disabling
interrupts, and then again for TIF_SIGPENDING|TIF_NEED_RESCHED etc after
disabling interrupts. Now we do the same as ppc32 -- check the flags
only once in the fast path, and re-enable interrupts if necessary in the
ptrace case.
The patch abolishes the 'syscall_noerror' member of struct thread_info
and replaces it with a TIF_NOERROR bit in the flags, which is handled in
the slow path. This shortens the syscall entry code, which no longer
needs to clear syscall_noerror.
The patch adds a TIF_SAVE_NVGPRS flag which causes the syscall exit slow
path to save the non-volatile GPRs into a signal frame. This removes the
need for the assembly wrappers around sys_sigsuspend(),
sys_rt_sigsuspend(), et al which existed solely to save those registers
in advance. It also means I don't have to add new wrappers for ppoll()
and pselect(), which is what I was supposed to be doing when I got
distracted into this...
Finally, it unifies the ppc64 and ppc32 methods of handling syscall exit
directly into a signal handler (as required by sigsuspend et al) by
introducing a TIF_RESTOREALL flag which causes _all_ the registers to be
reloaded from the pt_regs by taking the ret_from_exception path, instead
of the normal syscall exit path which stomps on the callee-saved GPRs.
It appears to pass an LTP test run on ppc64, and passes basic testing on
ppc32 too. Brief tests of ptrace functionality with strace and gdb also
appear OK. I wouldn't send it to Linus for 2.6.15 just yet though :)
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r-- | arch/powerpc/kernel/asm-offsets.c | 4 | ||||
-rw-r--r-- | arch/powerpc/kernel/entry_32.S | 167 | ||||
-rw-r--r-- | arch/powerpc/kernel/entry_64.S | 214 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal_32.c | 59 | ||||
-rw-r--r-- | arch/powerpc/kernel/signal_64.c | 23 | ||||
-rw-r--r-- | arch/powerpc/kernel/systbl.S | 10 | ||||
-rw-r--r-- | include/asm-powerpc/ptrace.h | 2 | ||||
-rw-r--r-- | include/asm-powerpc/thread_info.h | 12 |
8 files changed, 269 insertions, 222 deletions
diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index 91538d2445bf..3bf89d1a2de6 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c | |||
@@ -92,9 +92,9 @@ int main(void) | |||
92 | 92 | ||
93 | DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); | 93 | DEFINE(TI_FLAGS, offsetof(struct thread_info, flags)); |
94 | DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); | 94 | DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count)); |
95 | DEFINE(TI_SC_NOERR, offsetof(struct thread_info, syscall_noerror)); | 95 | DEFINE(TI_SIGFRAME, offsetof(struct thread_info, nvgprs_frame)); |
96 | #ifdef CONFIG_PPC32 | ||
97 | DEFINE(TI_TASK, offsetof(struct thread_info, task)); | 96 | DEFINE(TI_TASK, offsetof(struct thread_info, task)); |
97 | #ifdef CONFIG_PPC32 | ||
98 | DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); | 98 | DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain)); |
99 | DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); | 99 | DEFINE(TI_CPU, offsetof(struct thread_info, cpu)); |
100 | #endif /* CONFIG_PPC32 */ | 100 | #endif /* CONFIG_PPC32 */ |
diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 2e99ae41723c..8fed9538f188 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S | |||
@@ -200,8 +200,6 @@ _GLOBAL(DoSyscall) | |||
200 | bl do_show_syscall | 200 | bl do_show_syscall |
201 | #endif /* SHOW_SYSCALLS */ | 201 | #endif /* SHOW_SYSCALLS */ |
202 | rlwinm r10,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ | 202 | rlwinm r10,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ |
203 | li r11,0 | ||
204 | stb r11,TI_SC_NOERR(r10) | ||
205 | lwz r11,TI_FLAGS(r10) | 203 | lwz r11,TI_FLAGS(r10) |
206 | andi. r11,r11,_TIF_SYSCALL_T_OR_A | 204 | andi. r11,r11,_TIF_SYSCALL_T_OR_A |
207 | bne- syscall_dotrace | 205 | bne- syscall_dotrace |
@@ -222,25 +220,21 @@ ret_from_syscall: | |||
222 | bl do_show_syscall_exit | 220 | bl do_show_syscall_exit |
223 | #endif | 221 | #endif |
224 | mr r6,r3 | 222 | mr r6,r3 |
225 | li r11,-_LAST_ERRNO | ||
226 | cmplw 0,r3,r11 | ||
227 | rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ | 223 | rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ |
228 | blt+ 30f | ||
229 | lbz r11,TI_SC_NOERR(r12) | ||
230 | cmpwi r11,0 | ||
231 | bne 30f | ||
232 | neg r3,r3 | ||
233 | lwz r10,_CCR(r1) /* Set SO bit in CR */ | ||
234 | oris r10,r10,0x1000 | ||
235 | stw r10,_CCR(r1) | ||
236 | |||
237 | /* disable interrupts so current_thread_info()->flags can't change */ | 224 | /* disable interrupts so current_thread_info()->flags can't change */ |
238 | 30: LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */ | 225 | LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */ |
239 | SYNC | 226 | SYNC |
240 | MTMSRD(r10) | 227 | MTMSRD(r10) |
241 | lwz r9,TI_FLAGS(r12) | 228 | lwz r9,TI_FLAGS(r12) |
242 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED) | 229 | li r8,-_LAST_ERRNO |
230 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL) | ||
243 | bne- syscall_exit_work | 231 | bne- syscall_exit_work |
232 | cmplw 0,r3,r8 | ||
233 | blt+ syscall_exit_cont | ||
234 | lwz r11,_CCR(r1) /* Load CR */ | ||
235 | neg r3,r3 | ||
236 | oris r11,r11,0x1000 /* Set SO bit in CR */ | ||
237 | stw r11,_CCR(r1) | ||
244 | syscall_exit_cont: | 238 | syscall_exit_cont: |
245 | #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) | 239 | #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) |
246 | /* If the process has its own DBCR0 value, load it up. The single | 240 | /* If the process has its own DBCR0 value, load it up. The single |
@@ -292,46 +286,113 @@ syscall_dotrace: | |||
292 | b syscall_dotrace_cont | 286 | b syscall_dotrace_cont |
293 | 287 | ||
294 | syscall_exit_work: | 288 | syscall_exit_work: |
295 | stw r6,RESULT(r1) /* Save result */ | 289 | andi. r0,r9,_TIF_RESTOREALL |
290 | bne- 2f | ||
291 | cmplw 0,r3,r8 | ||
292 | blt+ 1f | ||
293 | andi. r0,r9,_TIF_NOERROR | ||
294 | bne- 1f | ||
295 | lwz r11,_CCR(r1) /* Load CR */ | ||
296 | neg r3,r3 | ||
297 | oris r11,r11,0x1000 /* Set SO bit in CR */ | ||
298 | stw r11,_CCR(r1) | ||
299 | |||
300 | 1: stw r6,RESULT(r1) /* Save result */ | ||
296 | stw r3,GPR3(r1) /* Update return value */ | 301 | stw r3,GPR3(r1) /* Update return value */ |
297 | andi. r0,r9,_TIF_SYSCALL_T_OR_A | 302 | 2: andi. r0,r9,(_TIF_PERSYSCALL_MASK) |
298 | beq 5f | 303 | beq 4f |
299 | ori r10,r10,MSR_EE | 304 | |
300 | SYNC | 305 | /* Clear per-syscall TIF flags if any are set, but _leave_ |
301 | MTMSRD(r10) /* re-enable interrupts */ | 306 | _TIF_SAVE_NVGPRS set in r9 since we haven't dealt with that |
307 | yet. */ | ||
308 | |||
309 | li r11,_TIF_PERSYSCALL_MASK | ||
310 | addi r12,r12,TI_FLAGS | ||
311 | 3: lwarx r8,0,r12 | ||
312 | andc r8,r8,r11 | ||
313 | #ifdef CONFIG_IBM405_ERR77 | ||
314 | dcbt 0,r12 | ||
315 | #endif | ||
316 | stwcx. r8,0,r12 | ||
317 | bne- 3b | ||
318 | subi r12,r12,TI_FLAGS | ||
319 | |||
320 | 4: /* Anything which requires enabling interrupts? */ | ||
321 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SAVE_NVGPRS) | ||
322 | beq 7f | ||
323 | |||
324 | /* Save NVGPRS if they're not saved already */ | ||
302 | lwz r4,_TRAP(r1) | 325 | lwz r4,_TRAP(r1) |
303 | andi. r4,r4,1 | 326 | andi. r4,r4,1 |
304 | beq 4f | 327 | beq 5f |
305 | SAVE_NVGPRS(r1) | 328 | SAVE_NVGPRS(r1) |
306 | li r4,0xc00 | 329 | li r4,0xc00 |
307 | stw r4,_TRAP(r1) | 330 | stw r4,_TRAP(r1) |
308 | 4: | 331 | |
332 | /* Re-enable interrupts */ | ||
333 | 5: ori r10,r10,MSR_EE | ||
334 | SYNC | ||
335 | MTMSRD(r10) | ||
336 | |||
337 | andi. r0,r9,_TIF_SAVE_NVGPRS | ||
338 | bne save_user_nvgprs | ||
339 | |||
340 | save_user_nvgprs_cont: | ||
341 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) | ||
342 | beq 7f | ||
343 | |||
309 | addi r3,r1,STACK_FRAME_OVERHEAD | 344 | addi r3,r1,STACK_FRAME_OVERHEAD |
310 | bl do_syscall_trace_leave | 345 | bl do_syscall_trace_leave |
311 | REST_NVGPRS(r1) | 346 | REST_NVGPRS(r1) |
312 | 2: | 347 | |
313 | lwz r3,GPR3(r1) | 348 | 6: lwz r3,GPR3(r1) |
314 | LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */ | 349 | LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */ |
315 | SYNC | 350 | SYNC |
316 | MTMSRD(r10) /* disable interrupts again */ | 351 | MTMSRD(r10) /* disable interrupts again */ |
317 | rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ | 352 | rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ |
318 | lwz r9,TI_FLAGS(r12) | 353 | lwz r9,TI_FLAGS(r12) |
319 | 5: | 354 | 7: |
320 | andi. r0,r9,_TIF_NEED_RESCHED | 355 | andi. r0,r9,_TIF_NEED_RESCHED |
321 | bne 1f | 356 | bne 8f |
322 | lwz r5,_MSR(r1) | 357 | lwz r5,_MSR(r1) |
323 | andi. r5,r5,MSR_PR | 358 | andi. r5,r5,MSR_PR |
324 | beq syscall_exit_cont | 359 | beq ret_from_except |
325 | andi. r0,r9,_TIF_SIGPENDING | 360 | andi. r0,r9,_TIF_SIGPENDING |
326 | beq syscall_exit_cont | 361 | beq ret_from_except |
327 | b do_user_signal | 362 | b do_user_signal |
328 | 1: | 363 | 8: |
329 | ori r10,r10,MSR_EE | 364 | ori r10,r10,MSR_EE |
330 | SYNC | 365 | SYNC |
331 | MTMSRD(r10) /* re-enable interrupts */ | 366 | MTMSRD(r10) /* re-enable interrupts */ |
332 | bl schedule | 367 | bl schedule |
333 | b 2b | 368 | b 6b |
369 | |||
370 | save_user_nvgprs: | ||
371 | ld r8,TI_SIGFRAME(r12) | ||
372 | |||
373 | .macro savewords start, end | ||
374 | 1: stw \start,4*(\start)(r8) | ||
375 | .section __ex_table,"a" | ||
376 | .align 2 | ||
377 | .long 1b,save_user_nvgprs_fault | ||
378 | .previous | ||
379 | .if \end - \start | ||
380 | savewords "(\start+1)",\end | ||
381 | .endif | ||
382 | .endm | ||
383 | savewords 14,31 | ||
384 | b save_user_nvgprs_cont | ||
385 | |||
386 | |||
387 | save_user_nvgprs_fault: | ||
388 | li r3,11 /* SIGSEGV */ | ||
389 | ld r4,TI_TASK(r12) | ||
390 | bl force_sigsegv | ||
334 | 391 | ||
392 | rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ | ||
393 | ld r9,TI_FLAGS(r12) | ||
394 | b save_user_nvgprs_cont | ||
395 | |||
335 | #ifdef SHOW_SYSCALLS | 396 | #ifdef SHOW_SYSCALLS |
336 | do_show_syscall: | 397 | do_show_syscall: |
337 | #ifdef SHOW_SYSCALLS_TASK | 398 | #ifdef SHOW_SYSCALLS_TASK |
@@ -401,28 +462,10 @@ show_syscalls_task: | |||
401 | #endif /* SHOW_SYSCALLS */ | 462 | #endif /* SHOW_SYSCALLS */ |
402 | 463 | ||
403 | /* | 464 | /* |
404 | * The sigsuspend and rt_sigsuspend system calls can call do_signal | 465 | * The fork/clone functions need to copy the full register set into |
405 | * and thus put the process into the stopped state where we might | 466 | * the child process. Therefore we need to save all the nonvolatile |
406 | * want to examine its user state with ptrace. Therefore we need | 467 | * registers (r13 - r31) before calling the C code. |
407 | * to save all the nonvolatile registers (r13 - r31) before calling | ||
408 | * the C code. | ||
409 | */ | 468 | */ |
410 | .globl ppc_sigsuspend | ||
411 | ppc_sigsuspend: | ||
412 | SAVE_NVGPRS(r1) | ||
413 | lwz r0,_TRAP(r1) | ||
414 | rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */ | ||
415 | stw r0,_TRAP(r1) /* register set saved */ | ||
416 | b sys_sigsuspend | ||
417 | |||
418 | .globl ppc_rt_sigsuspend | ||
419 | ppc_rt_sigsuspend: | ||
420 | SAVE_NVGPRS(r1) | ||
421 | lwz r0,_TRAP(r1) | ||
422 | rlwinm r0,r0,0,0,30 | ||
423 | stw r0,_TRAP(r1) | ||
424 | b sys_rt_sigsuspend | ||
425 | |||
426 | .globl ppc_fork | 469 | .globl ppc_fork |
427 | ppc_fork: | 470 | ppc_fork: |
428 | SAVE_NVGPRS(r1) | 471 | SAVE_NVGPRS(r1) |
@@ -447,14 +490,6 @@ ppc_clone: | |||
447 | stw r0,_TRAP(r1) /* register set saved */ | 490 | stw r0,_TRAP(r1) /* register set saved */ |
448 | b sys_clone | 491 | b sys_clone |
449 | 492 | ||
450 | .globl ppc_swapcontext | ||
451 | ppc_swapcontext: | ||
452 | SAVE_NVGPRS(r1) | ||
453 | lwz r0,_TRAP(r1) | ||
454 | rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */ | ||
455 | stw r0,_TRAP(r1) /* register set saved */ | ||
456 | b sys_swapcontext | ||
457 | |||
458 | /* | 493 | /* |
459 | * Top-level page fault handling. | 494 | * Top-level page fault handling. |
460 | * This is in assembler because if do_page_fault tells us that | 495 | * This is in assembler because if do_page_fault tells us that |
@@ -626,16 +661,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_601) | |||
626 | .long ret_from_except | 661 | .long ret_from_except |
627 | #endif | 662 | #endif |
628 | 663 | ||
629 | .globl sigreturn_exit | ||
630 | sigreturn_exit: | ||
631 | subi r1,r3,STACK_FRAME_OVERHEAD | ||
632 | rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ | ||
633 | lwz r9,TI_FLAGS(r12) | ||
634 | andi. r0,r9,_TIF_SYSCALL_T_OR_A | ||
635 | beq+ ret_from_except_full | ||
636 | bl do_syscall_trace_leave | ||
637 | /* fall through */ | ||
638 | |||
639 | .globl ret_from_except_full | 664 | .globl ret_from_except_full |
640 | ret_from_except_full: | 665 | ret_from_except_full: |
641 | REST_NVGPRS(r1) | 666 | REST_NVGPRS(r1) |
@@ -658,7 +683,7 @@ user_exc_return: /* r10 contains MSR_KERNEL here */ | |||
658 | /* Check current_thread_info()->flags */ | 683 | /* Check current_thread_info()->flags */ |
659 | rlwinm r9,r1,0,0,(31-THREAD_SHIFT) | 684 | rlwinm r9,r1,0,0,(31-THREAD_SHIFT) |
660 | lwz r9,TI_FLAGS(r9) | 685 | lwz r9,TI_FLAGS(r9) |
661 | andi. r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED) | 686 | andi. r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL) |
662 | bne do_work | 687 | bne do_work |
663 | 688 | ||
664 | restore_user: | 689 | restore_user: |
diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index bce33a38399f..0bff31f166dd 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S | |||
@@ -113,9 +113,7 @@ system_call_common: | |||
113 | addi r9,r1,STACK_FRAME_OVERHEAD | 113 | addi r9,r1,STACK_FRAME_OVERHEAD |
114 | #endif | 114 | #endif |
115 | clrrdi r11,r1,THREAD_SHIFT | 115 | clrrdi r11,r1,THREAD_SHIFT |
116 | li r12,0 | ||
117 | ld r10,TI_FLAGS(r11) | 116 | ld r10,TI_FLAGS(r11) |
118 | stb r12,TI_SC_NOERR(r11) | ||
119 | andi. r11,r10,_TIF_SYSCALL_T_OR_A | 117 | andi. r11,r10,_TIF_SYSCALL_T_OR_A |
120 | bne- syscall_dotrace | 118 | bne- syscall_dotrace |
121 | syscall_dotrace_cont: | 119 | syscall_dotrace_cont: |
@@ -144,24 +142,12 @@ system_call: /* label this so stack traces look sane */ | |||
144 | bctrl /* Call handler */ | 142 | bctrl /* Call handler */ |
145 | 143 | ||
146 | syscall_exit: | 144 | syscall_exit: |
145 | std r3,RESULT(r1) | ||
147 | #ifdef SHOW_SYSCALLS | 146 | #ifdef SHOW_SYSCALLS |
148 | std r3,GPR3(r1) | ||
149 | bl .do_show_syscall_exit | 147 | bl .do_show_syscall_exit |
150 | ld r3,GPR3(r1) | 148 | ld r3,RESULT(r1) |
151 | #endif | 149 | #endif |
152 | std r3,RESULT(r1) | ||
153 | ld r5,_CCR(r1) | ||
154 | li r10,-_LAST_ERRNO | ||
155 | cmpld r3,r10 | ||
156 | clrrdi r12,r1,THREAD_SHIFT | 150 | clrrdi r12,r1,THREAD_SHIFT |
157 | bge- syscall_error | ||
158 | syscall_error_cont: | ||
159 | |||
160 | /* check for syscall tracing or audit */ | ||
161 | ld r9,TI_FLAGS(r12) | ||
162 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) | ||
163 | bne- syscall_exit_trace | ||
164 | syscall_exit_trace_cont: | ||
165 | 151 | ||
166 | /* disable interrupts so current_thread_info()->flags can't change, | 152 | /* disable interrupts so current_thread_info()->flags can't change, |
167 | and so that we don't get interrupted after loading SRR0/1. */ | 153 | and so that we don't get interrupted after loading SRR0/1. */ |
@@ -173,8 +159,13 @@ syscall_exit_trace_cont: | |||
173 | rotldi r10,r10,16 | 159 | rotldi r10,r10,16 |
174 | mtmsrd r10,1 | 160 | mtmsrd r10,1 |
175 | ld r9,TI_FLAGS(r12) | 161 | ld r9,TI_FLAGS(r12) |
176 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED) | 162 | li r11,-_LAST_ERRNO |
163 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL|_TIF_SAVE_NVGPRS|_TIF_NOERROR) | ||
177 | bne- syscall_exit_work | 164 | bne- syscall_exit_work |
165 | cmpld r3,r11 | ||
166 | ld r5,_CCR(r1) | ||
167 | bge- syscall_error | ||
168 | syscall_error_cont: | ||
178 | ld r7,_NIP(r1) | 169 | ld r7,_NIP(r1) |
179 | stdcx. r0,0,r1 /* to clear the reservation */ | 170 | stdcx. r0,0,r1 /* to clear the reservation */ |
180 | andi. r6,r8,MSR_PR | 171 | andi. r6,r8,MSR_PR |
@@ -193,21 +184,12 @@ syscall_exit_trace_cont: | |||
193 | rfid | 184 | rfid |
194 | b . /* prevent speculative execution */ | 185 | b . /* prevent speculative execution */ |
195 | 186 | ||
196 | syscall_enosys: | 187 | syscall_error: |
197 | li r3,-ENOSYS | ||
198 | std r3,RESULT(r1) | ||
199 | clrrdi r12,r1,THREAD_SHIFT | ||
200 | ld r5,_CCR(r1) | ||
201 | |||
202 | syscall_error: | ||
203 | lbz r11,TI_SC_NOERR(r12) | ||
204 | cmpwi 0,r11,0 | ||
205 | bne- syscall_error_cont | ||
206 | neg r3,r3 | ||
207 | oris r5,r5,0x1000 /* Set SO bit in CR */ | 188 | oris r5,r5,0x1000 /* Set SO bit in CR */ |
189 | neg r3,r3 | ||
208 | std r5,_CCR(r1) | 190 | std r5,_CCR(r1) |
209 | b syscall_error_cont | 191 | b syscall_error_cont |
210 | 192 | ||
211 | /* Traced system call support */ | 193 | /* Traced system call support */ |
212 | syscall_dotrace: | 194 | syscall_dotrace: |
213 | bl .save_nvgprs | 195 | bl .save_nvgprs |
@@ -225,21 +207,69 @@ syscall_dotrace: | |||
225 | ld r10,TI_FLAGS(r10) | 207 | ld r10,TI_FLAGS(r10) |
226 | b syscall_dotrace_cont | 208 | b syscall_dotrace_cont |
227 | 209 | ||
228 | syscall_exit_trace: | 210 | syscall_enosys: |
229 | std r3,GPR3(r1) | 211 | li r3,-ENOSYS |
230 | bl .save_nvgprs | 212 | b syscall_exit |
213 | |||
214 | syscall_exit_work: | ||
215 | /* If TIF_RESTOREALL is set, don't scribble on either r3 or ccr. | ||
216 | If TIF_NOERROR is set, just save r3 as it is. */ | ||
217 | |||
218 | andi. r0,r9,_TIF_RESTOREALL | ||
219 | bne- 2f | ||
220 | cmpld r3,r11 /* r10 is -LAST_ERRNO */ | ||
221 | blt+ 1f | ||
222 | andi. r0,r9,_TIF_NOERROR | ||
223 | bne- 1f | ||
224 | ld r5,_CCR(r1) | ||
225 | neg r3,r3 | ||
226 | oris r5,r5,0x1000 /* Set SO bit in CR */ | ||
227 | std r5,_CCR(r1) | ||
228 | 1: std r3,GPR3(r1) | ||
229 | 2: andi. r0,r9,(_TIF_PERSYSCALL_MASK) | ||
230 | beq 4f | ||
231 | |||
232 | /* Clear per-syscall TIF flags if any are set, but _leave_ | ||
233 | _TIF_SAVE_NVGPRS set in r9 since we haven't dealt with that | ||
234 | yet. */ | ||
235 | |||
236 | li r11,_TIF_PERSYSCALL_MASK | ||
237 | addi r12,r12,TI_FLAGS | ||
238 | 3: ldarx r10,0,r12 | ||
239 | andc r10,r10,r11 | ||
240 | stdcx. r10,0,r12 | ||
241 | bne- 3b | ||
242 | subi r12,r12,TI_FLAGS | ||
243 | |||
244 | 4: bl save_nvgprs | ||
245 | /* Anything else left to do? */ | ||
246 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SAVE_NVGPRS) | ||
247 | beq .ret_from_except_lite | ||
248 | |||
249 | /* Re-enable interrupts */ | ||
250 | mfmsr r10 | ||
251 | ori r10,r10,MSR_EE | ||
252 | mtmsrd r10,1 | ||
253 | |||
254 | andi. r0,r9,_TIF_SAVE_NVGPRS | ||
255 | bne save_user_nvgprs | ||
256 | |||
257 | /* If tracing, re-enable interrupts and do it */ | ||
258 | save_user_nvgprs_cont: | ||
259 | andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) | ||
260 | beq 5f | ||
261 | |||
231 | addi r3,r1,STACK_FRAME_OVERHEAD | 262 | addi r3,r1,STACK_FRAME_OVERHEAD |
232 | bl .do_syscall_trace_leave | 263 | bl .do_syscall_trace_leave |
233 | REST_NVGPRS(r1) | 264 | REST_NVGPRS(r1) |
234 | ld r3,GPR3(r1) | ||
235 | ld r5,_CCR(r1) | ||
236 | clrrdi r12,r1,THREAD_SHIFT | 265 | clrrdi r12,r1,THREAD_SHIFT |
237 | b syscall_exit_trace_cont | ||
238 | 266 | ||
239 | /* Stuff to do on exit from a system call. */ | 267 | /* Disable interrupts again and handle other work if any */ |
240 | syscall_exit_work: | 268 | 5: mfmsr r10 |
241 | std r3,GPR3(r1) | 269 | rldicl r10,r10,48,1 |
242 | std r5,_CCR(r1) | 270 | rotldi r10,r10,16 |
271 | mtmsrd r10,1 | ||
272 | |||
243 | b .ret_from_except_lite | 273 | b .ret_from_except_lite |
244 | 274 | ||
245 | /* Save non-volatile GPRs, if not already saved. */ | 275 | /* Save non-volatile GPRs, if not already saved. */ |
@@ -252,6 +282,52 @@ _GLOBAL(save_nvgprs) | |||
252 | std r0,_TRAP(r1) | 282 | std r0,_TRAP(r1) |
253 | blr | 283 | blr |
254 | 284 | ||
285 | |||
286 | save_user_nvgprs: | ||
287 | ld r10,TI_SIGFRAME(r12) | ||
288 | andi. r0,r9,_TIF_32BIT | ||
289 | beq- save_user_nvgprs_64 | ||
290 | |||
291 | /* 32-bit save to userspace */ | ||
292 | |||
293 | .macro savewords start, end | ||
294 | 1: stw \start,4*(\start)(r10) | ||
295 | .section __ex_table,"a" | ||
296 | .align 3 | ||
297 | .llong 1b,save_user_nvgprs_fault | ||
298 | .previous | ||
299 | .if \end - \start | ||
300 | savewords "(\start+1)",\end | ||
301 | .endif | ||
302 | .endm | ||
303 | savewords 14,31 | ||
304 | b save_user_nvgprs_cont | ||
305 | |||
306 | save_user_nvgprs_64: | ||
307 | /* 64-bit save to userspace */ | ||
308 | |||
309 | .macro savelongs start, end | ||
310 | 1: std \start,8*(\start)(r10) | ||
311 | .section __ex_table,"a" | ||
312 | .align 3 | ||
313 | .llong 1b,save_user_nvgprs_fault | ||
314 | .previous | ||
315 | .if \end - \start | ||
316 | savelongs "(\start+1)",\end | ||
317 | .endif | ||
318 | .endm | ||
319 | savelongs 14,31 | ||
320 | b save_user_nvgprs_cont | ||
321 | |||
322 | save_user_nvgprs_fault: | ||
323 | li r3,11 /* SIGSEGV */ | ||
324 | ld r4,TI_TASK(r12) | ||
325 | bl .force_sigsegv | ||
326 | |||
327 | clrrdi r12,r1,THREAD_SHIFT | ||
328 | ld r9,TI_FLAGS(r12) | ||
329 | b save_user_nvgprs_cont | ||
330 | |||
255 | /* | 331 | /* |
256 | * The sigsuspend and rt_sigsuspend system calls can call do_signal | 332 | * The sigsuspend and rt_sigsuspend system calls can call do_signal |
257 | * and thus put the process into the stopped state where we might | 333 | * and thus put the process into the stopped state where we might |
@@ -260,35 +336,6 @@ _GLOBAL(save_nvgprs) | |||
260 | * the C code. Similarly, fork, vfork and clone need the full | 336 | * the C code. Similarly, fork, vfork and clone need the full |
261 | * register state on the stack so that it can be copied to the child. | 337 | * register state on the stack so that it can be copied to the child. |
262 | */ | 338 | */ |
263 | _GLOBAL(ppc32_sigsuspend) | ||
264 | bl .save_nvgprs | ||
265 | bl .compat_sys_sigsuspend | ||
266 | b 70f | ||
267 | |||
268 | _GLOBAL(ppc64_rt_sigsuspend) | ||
269 | bl .save_nvgprs | ||
270 | bl .sys_rt_sigsuspend | ||
271 | b 70f | ||
272 | |||
273 | _GLOBAL(ppc32_rt_sigsuspend) | ||
274 | bl .save_nvgprs | ||
275 | bl .compat_sys_rt_sigsuspend | ||
276 | 70: cmpdi 0,r3,0 | ||
277 | /* If it returned an error, we need to return via syscall_exit to set | ||
278 | the SO bit in cr0 and potentially stop for ptrace. */ | ||
279 | bne syscall_exit | ||
280 | /* If sigsuspend() returns zero, we are going into a signal handler. We | ||
281 | may need to call audit_syscall_exit() to mark the exit from sigsuspend() */ | ||
282 | #ifdef CONFIG_AUDITSYSCALL | ||
283 | ld r3,PACACURRENT(r13) | ||
284 | ld r4,AUDITCONTEXT(r3) | ||
285 | cmpdi 0,r4,0 | ||
286 | beq .ret_from_except /* No audit_context: Leave immediately. */ | ||
287 | li r4, 2 /* AUDITSC_FAILURE */ | ||
288 | li r5,-4 /* It's always -EINTR */ | ||
289 | bl .audit_syscall_exit | ||
290 | #endif | ||
291 | b .ret_from_except | ||
292 | 339 | ||
293 | _GLOBAL(ppc_fork) | 340 | _GLOBAL(ppc_fork) |
294 | bl .save_nvgprs | 341 | bl .save_nvgprs |
@@ -305,37 +352,6 @@ _GLOBAL(ppc_clone) | |||
305 | bl .sys_clone | 352 | bl .sys_clone |
306 | b syscall_exit | 353 | b syscall_exit |
307 | 354 | ||
308 | _GLOBAL(ppc32_swapcontext) | ||
309 | bl .save_nvgprs | ||
310 | bl .compat_sys_swapcontext | ||
311 | b 80f | ||
312 | |||
313 | _GLOBAL(ppc64_swapcontext) | ||
314 | bl .save_nvgprs | ||
315 | bl .sys_swapcontext | ||
316 | b 80f | ||
317 | |||
318 | _GLOBAL(ppc32_sigreturn) | ||
319 | bl .compat_sys_sigreturn | ||
320 | b 80f | ||
321 | |||
322 | _GLOBAL(ppc32_rt_sigreturn) | ||
323 | bl .compat_sys_rt_sigreturn | ||
324 | b 80f | ||
325 | |||
326 | _GLOBAL(ppc64_rt_sigreturn) | ||
327 | bl .sys_rt_sigreturn | ||
328 | |||
329 | 80: cmpdi 0,r3,0 | ||
330 | blt syscall_exit | ||
331 | clrrdi r4,r1,THREAD_SHIFT | ||
332 | ld r4,TI_FLAGS(r4) | ||
333 | andi. r4,r4,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) | ||
334 | beq+ 81f | ||
335 | addi r3,r1,STACK_FRAME_OVERHEAD | ||
336 | bl .do_syscall_trace_leave | ||
337 | 81: b .ret_from_except | ||
338 | |||
339 | _GLOBAL(ret_from_fork) | 355 | _GLOBAL(ret_from_fork) |
340 | bl .schedule_tail | 356 | bl .schedule_tail |
341 | REST_NVGPRS(r1) | 357 | REST_NVGPRS(r1) |
diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 5a2eba60dd39..c9d02751127f 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c | |||
@@ -76,7 +76,6 @@ | |||
76 | * registers from *regs. This is what we need | 76 | * registers from *regs. This is what we need |
77 | * to do when a signal has been delivered. | 77 | * to do when a signal has been delivered. |
78 | */ | 78 | */ |
79 | #define sigreturn_exit(regs) return 0 | ||
80 | 79 | ||
81 | #define GP_REGS_SIZE min(sizeof(elf_gregset_t32), sizeof(struct pt_regs32)) | 80 | #define GP_REGS_SIZE min(sizeof(elf_gregset_t32), sizeof(struct pt_regs32)) |
82 | #undef __SIGNAL_FRAMESIZE | 81 | #undef __SIGNAL_FRAMESIZE |
@@ -156,9 +155,17 @@ static inline int save_general_regs(struct pt_regs *regs, | |||
156 | elf_greg_t64 *gregs = (elf_greg_t64 *)regs; | 155 | elf_greg_t64 *gregs = (elf_greg_t64 *)regs; |
157 | int i; | 156 | int i; |
158 | 157 | ||
159 | for (i = 0; i <= PT_RESULT; i ++) | 158 | if (!FULL_REGS(regs)) { |
159 | set_thread_flag(TIF_SAVE_NVGPRS); | ||
160 | current_thread_info()->nvgprs_frame = frame->mc_gregs; | ||
161 | } | ||
162 | |||
163 | for (i = 0; i <= PT_RESULT; i ++) { | ||
164 | if (i == 14 && !FULL_REGS(regs)) | ||
165 | i = 32; | ||
160 | if (__put_user((unsigned int)gregs[i], &frame->mc_gregs[i])) | 166 | if (__put_user((unsigned int)gregs[i], &frame->mc_gregs[i])) |
161 | return -EFAULT; | 167 | return -EFAULT; |
168 | } | ||
162 | return 0; | 169 | return 0; |
163 | } | 170 | } |
164 | 171 | ||
@@ -179,8 +186,6 @@ static inline int restore_general_regs(struct pt_regs *regs, | |||
179 | 186 | ||
180 | #else /* CONFIG_PPC64 */ | 187 | #else /* CONFIG_PPC64 */ |
181 | 188 | ||
182 | extern void sigreturn_exit(struct pt_regs *); | ||
183 | |||
184 | #define GP_REGS_SIZE min(sizeof(elf_gregset_t), sizeof(struct pt_regs)) | 189 | #define GP_REGS_SIZE min(sizeof(elf_gregset_t), sizeof(struct pt_regs)) |
185 | 190 | ||
186 | static inline int put_sigset_t(sigset_t __user *uset, sigset_t *set) | 191 | static inline int put_sigset_t(sigset_t __user *uset, sigset_t *set) |
@@ -256,8 +261,10 @@ long sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7, | |||
256 | while (1) { | 261 | while (1) { |
257 | current->state = TASK_INTERRUPTIBLE; | 262 | current->state = TASK_INTERRUPTIBLE; |
258 | schedule(); | 263 | schedule(); |
259 | if (do_signal(&saveset, regs)) | 264 | if (do_signal(&saveset, regs)) { |
260 | sigreturn_exit(regs); | 265 | set_thread_flag(TIF_RESTOREALL); |
266 | return 0; | ||
267 | } | ||
261 | } | 268 | } |
262 | } | 269 | } |
263 | 270 | ||
@@ -292,8 +299,10 @@ long sys_rt_sigsuspend( | |||
292 | while (1) { | 299 | while (1) { |
293 | current->state = TASK_INTERRUPTIBLE; | 300 | current->state = TASK_INTERRUPTIBLE; |
294 | schedule(); | 301 | schedule(); |
295 | if (do_signal(&saveset, regs)) | 302 | if (do_signal(&saveset, regs)) { |
296 | sigreturn_exit(regs); | 303 | set_thread_flag(TIF_RESTOREALL); |
304 | return 0; | ||
305 | } | ||
297 | } | 306 | } |
298 | } | 307 | } |
299 | 308 | ||
@@ -391,9 +400,6 @@ struct rt_sigframe { | |||
391 | static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, | 400 | static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, |
392 | int sigret) | 401 | int sigret) |
393 | { | 402 | { |
394 | #ifdef CONFIG_PPC32 | ||
395 | CHECK_FULL_REGS(regs); | ||
396 | #endif | ||
397 | /* Make sure floating point registers are stored in regs */ | 403 | /* Make sure floating point registers are stored in regs */ |
398 | flush_fp_to_thread(current); | 404 | flush_fp_to_thread(current); |
399 | 405 | ||
@@ -828,12 +834,6 @@ static int handle_rt_signal(unsigned long sig, struct k_sigaction *ka, | |||
828 | regs->gpr[6] = (unsigned long) rt_sf; | 834 | regs->gpr[6] = (unsigned long) rt_sf; |
829 | regs->nip = (unsigned long) ka->sa.sa_handler; | 835 | regs->nip = (unsigned long) ka->sa.sa_handler; |
830 | regs->trap = 0; | 836 | regs->trap = 0; |
831 | #ifdef CONFIG_PPC64 | ||
832 | regs->result = 0; | ||
833 | |||
834 | if (test_thread_flag(TIF_SINGLESTEP)) | ||
835 | ptrace_notify(SIGTRAP); | ||
836 | #endif | ||
837 | return 1; | 837 | return 1; |
838 | 838 | ||
839 | badframe: | 839 | badframe: |
@@ -911,8 +911,8 @@ long sys_swapcontext(struct ucontext __user *old_ctx, | |||
911 | */ | 911 | */ |
912 | if (do_setcontext(new_ctx, regs, 0)) | 912 | if (do_setcontext(new_ctx, regs, 0)) |
913 | do_exit(SIGSEGV); | 913 | do_exit(SIGSEGV); |
914 | sigreturn_exit(regs); | 914 | |
915 | /* doesn't actually return back to here */ | 915 | set_thread_flag(TIF_RESTOREALL); |
916 | return 0; | 916 | return 0; |
917 | } | 917 | } |
918 | 918 | ||
@@ -945,12 +945,11 @@ long sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, | |||
945 | * nobody does any... | 945 | * nobody does any... |
946 | */ | 946 | */ |
947 | compat_sys_sigaltstack((u32)(u64)&rt_sf->uc.uc_stack, 0, 0, 0, 0, 0, regs); | 947 | compat_sys_sigaltstack((u32)(u64)&rt_sf->uc.uc_stack, 0, 0, 0, 0, 0, regs); |
948 | return (int)regs->result; | ||
949 | #else | 948 | #else |
950 | do_sigaltstack(&rt_sf->uc.uc_stack, NULL, regs->gpr[1]); | 949 | do_sigaltstack(&rt_sf->uc.uc_stack, NULL, regs->gpr[1]); |
951 | sigreturn_exit(regs); /* doesn't return here */ | ||
952 | return 0; | ||
953 | #endif | 950 | #endif |
951 | set_thread_flag(TIF_RESTOREALL); | ||
952 | return 0; | ||
954 | 953 | ||
955 | bad: | 954 | bad: |
956 | force_sig(SIGSEGV, current); | 955 | force_sig(SIGSEGV, current); |
@@ -1041,9 +1040,7 @@ int sys_debug_setcontext(struct ucontext __user *ctx, | |||
1041 | */ | 1040 | */ |
1042 | do_sigaltstack(&ctx->uc_stack, NULL, regs->gpr[1]); | 1041 | do_sigaltstack(&ctx->uc_stack, NULL, regs->gpr[1]); |
1043 | 1042 | ||
1044 | sigreturn_exit(regs); | 1043 | set_thread_flag(TIF_RESTOREALL); |
1045 | /* doesn't actually return back to here */ | ||
1046 | |||
1047 | out: | 1044 | out: |
1048 | return 0; | 1045 | return 0; |
1049 | } | 1046 | } |
@@ -1107,12 +1104,6 @@ static int handle_signal(unsigned long sig, struct k_sigaction *ka, | |||
1107 | regs->gpr[4] = (unsigned long) sc; | 1104 | regs->gpr[4] = (unsigned long) sc; |
1108 | regs->nip = (unsigned long) ka->sa.sa_handler; | 1105 | regs->nip = (unsigned long) ka->sa.sa_handler; |
1109 | regs->trap = 0; | 1106 | regs->trap = 0; |
1110 | #ifdef CONFIG_PPC64 | ||
1111 | regs->result = 0; | ||
1112 | |||
1113 | if (test_thread_flag(TIF_SINGLESTEP)) | ||
1114 | ptrace_notify(SIGTRAP); | ||
1115 | #endif | ||
1116 | 1107 | ||
1117 | return 1; | 1108 | return 1; |
1118 | 1109 | ||
@@ -1160,12 +1151,8 @@ long sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, | |||
1160 | || restore_user_regs(regs, sr, 1)) | 1151 | || restore_user_regs(regs, sr, 1)) |
1161 | goto badframe; | 1152 | goto badframe; |
1162 | 1153 | ||
1163 | #ifdef CONFIG_PPC64 | 1154 | set_thread_flag(TIF_RESTOREALL); |
1164 | return (int)regs->result; | ||
1165 | #else | ||
1166 | sigreturn_exit(regs); /* doesn't return */ | ||
1167 | return 0; | 1155 | return 0; |
1168 | #endif | ||
1169 | 1156 | ||
1170 | badframe: | 1157 | badframe: |
1171 | force_sig(SIGSEGV, current); | 1158 | force_sig(SIGSEGV, current); |
diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 1decf2785530..5462bef898f6 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c | |||
@@ -96,8 +96,10 @@ long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, int p3, int | |||
96 | while (1) { | 96 | while (1) { |
97 | current->state = TASK_INTERRUPTIBLE; | 97 | current->state = TASK_INTERRUPTIBLE; |
98 | schedule(); | 98 | schedule(); |
99 | if (do_signal(&saveset, regs)) | 99 | if (do_signal(&saveset, regs)) { |
100 | set_thread_flag(TIF_RESTOREALL); | ||
100 | return 0; | 101 | return 0; |
102 | } | ||
101 | } | 103 | } |
102 | } | 104 | } |
103 | 105 | ||
@@ -152,6 +154,14 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, | |||
152 | err |= __put_user(0, &sc->v_regs); | 154 | err |= __put_user(0, &sc->v_regs); |
153 | #endif /* CONFIG_ALTIVEC */ | 155 | #endif /* CONFIG_ALTIVEC */ |
154 | err |= __put_user(&sc->gp_regs, &sc->regs); | 156 | err |= __put_user(&sc->gp_regs, &sc->regs); |
157 | if (!FULL_REGS(regs)) { | ||
158 | /* Zero out the unsaved GPRs to avoid information | ||
159 | leak, and set TIF_SAVE_NVGPRS to ensure that the | ||
160 | registers do actually get saved later. */ | ||
161 | memset(®s->gpr[14], 0, 18 * sizeof(unsigned long)); | ||
162 | set_thread_flag(TIF_SAVE_NVGPRS); | ||
163 | current_thread_info()->nvgprs_frame = &sc->gp_regs; | ||
164 | } | ||
155 | err |= __copy_to_user(&sc->gp_regs, regs, GP_REGS_SIZE); | 165 | err |= __copy_to_user(&sc->gp_regs, regs, GP_REGS_SIZE); |
156 | err |= __copy_to_user(&sc->fp_regs, ¤t->thread.fpr, FP_REGS_SIZE); | 166 | err |= __copy_to_user(&sc->fp_regs, ¤t->thread.fpr, FP_REGS_SIZE); |
157 | err |= __put_user(signr, &sc->signal); | 167 | err |= __put_user(signr, &sc->signal); |
@@ -340,6 +350,7 @@ int sys_swapcontext(struct ucontext __user *old_ctx, | |||
340 | do_exit(SIGSEGV); | 350 | do_exit(SIGSEGV); |
341 | 351 | ||
342 | /* This returns like rt_sigreturn */ | 352 | /* This returns like rt_sigreturn */ |
353 | set_thread_flag(TIF_RESTOREALL); | ||
343 | return 0; | 354 | return 0; |
344 | } | 355 | } |
345 | 356 | ||
@@ -372,7 +383,8 @@ int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5, | |||
372 | */ | 383 | */ |
373 | do_sigaltstack(&uc->uc_stack, NULL, regs->gpr[1]); | 384 | do_sigaltstack(&uc->uc_stack, NULL, regs->gpr[1]); |
374 | 385 | ||
375 | return regs->result; | 386 | set_thread_flag(TIF_RESTOREALL); |
387 | return 0; | ||
376 | 388 | ||
377 | badframe: | 389 | badframe: |
378 | #if DEBUG_SIG | 390 | #if DEBUG_SIG |
@@ -454,9 +466,6 @@ static int setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info, | |||
454 | if (err) | 466 | if (err) |
455 | goto badframe; | 467 | goto badframe; |
456 | 468 | ||
457 | if (test_thread_flag(TIF_SINGLESTEP)) | ||
458 | ptrace_notify(SIGTRAP); | ||
459 | |||
460 | return 1; | 469 | return 1; |
461 | 470 | ||
462 | badframe: | 471 | badframe: |
@@ -502,6 +511,8 @@ static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) | |||
502 | * we only get here if there is a handler, we dont restart. | 511 | * we only get here if there is a handler, we dont restart. |
503 | */ | 512 | */ |
504 | regs->result = -EINTR; | 513 | regs->result = -EINTR; |
514 | regs->gpr[3] = EINTR; | ||
515 | regs->ccr |= 0x10000000; | ||
505 | break; | 516 | break; |
506 | case -ERESTARTSYS: | 517 | case -ERESTARTSYS: |
507 | /* ERESTARTSYS means to restart the syscall if there is no | 518 | /* ERESTARTSYS means to restart the syscall if there is no |
@@ -509,6 +520,8 @@ static inline void syscall_restart(struct pt_regs *regs, struct k_sigaction *ka) | |||
509 | */ | 520 | */ |
510 | if (!(ka->sa.sa_flags & SA_RESTART)) { | 521 | if (!(ka->sa.sa_flags & SA_RESTART)) { |
511 | regs->result = -EINTR; | 522 | regs->result = -EINTR; |
523 | regs->gpr[3] = EINTR; | ||
524 | regs->ccr |= 0x10000000; | ||
512 | break; | 525 | break; |
513 | } | 526 | } |
514 | /* fallthrough */ | 527 | /* fallthrough */ |
diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S index 65eaea91b499..4bb3650420b4 100644 --- a/arch/powerpc/kernel/systbl.S +++ b/arch/powerpc/kernel/systbl.S | |||
@@ -113,7 +113,7 @@ SYSCALL(sgetmask) | |||
113 | COMPAT_SYS(ssetmask) | 113 | COMPAT_SYS(ssetmask) |
114 | SYSCALL(setreuid) | 114 | SYSCALL(setreuid) |
115 | SYSCALL(setregid) | 115 | SYSCALL(setregid) |
116 | SYSX(sys_ni_syscall,ppc32_sigsuspend,ppc_sigsuspend) | 116 | SYS32ONLY(sigsuspend) |
117 | COMPAT_SYS(sigpending) | 117 | COMPAT_SYS(sigpending) |
118 | COMPAT_SYS(sethostname) | 118 | COMPAT_SYS(sethostname) |
119 | COMPAT_SYS(setrlimit) | 119 | COMPAT_SYS(setrlimit) |
@@ -160,7 +160,7 @@ SYSCALL(swapoff) | |||
160 | COMPAT_SYS(sysinfo) | 160 | COMPAT_SYS(sysinfo) |
161 | COMPAT_SYS(ipc) | 161 | COMPAT_SYS(ipc) |
162 | SYSCALL(fsync) | 162 | SYSCALL(fsync) |
163 | SYSX(sys_ni_syscall,ppc32_sigreturn,sys_sigreturn) | 163 | SYS32ONLY(sigreturn) |
164 | PPC_SYS(clone) | 164 | PPC_SYS(clone) |
165 | COMPAT_SYS(setdomainname) | 165 | COMPAT_SYS(setdomainname) |
166 | PPC_SYS(newuname) | 166 | PPC_SYS(newuname) |
@@ -213,13 +213,13 @@ COMPAT_SYS(nfsservctl) | |||
213 | SYSCALL(setresgid) | 213 | SYSCALL(setresgid) |
214 | SYSCALL(getresgid) | 214 | SYSCALL(getresgid) |
215 | COMPAT_SYS(prctl) | 215 | COMPAT_SYS(prctl) |
216 | SYSX(ppc64_rt_sigreturn,ppc32_rt_sigreturn,sys_rt_sigreturn) | 216 | COMPAT_SYS(rt_sigreturn) |
217 | COMPAT_SYS(rt_sigaction) | 217 | COMPAT_SYS(rt_sigaction) |
218 | COMPAT_SYS(rt_sigprocmask) | 218 | COMPAT_SYS(rt_sigprocmask) |
219 | COMPAT_SYS(rt_sigpending) | 219 | COMPAT_SYS(rt_sigpending) |
220 | COMPAT_SYS(rt_sigtimedwait) | 220 | COMPAT_SYS(rt_sigtimedwait) |
221 | COMPAT_SYS(rt_sigqueueinfo) | 221 | COMPAT_SYS(rt_sigqueueinfo) |
222 | SYSX(ppc64_rt_sigsuspend,ppc32_rt_sigsuspend,ppc_rt_sigsuspend) | 222 | COMPAT_SYS(rt_sigsuspend) |
223 | COMPAT_SYS(pread64) | 223 | COMPAT_SYS(pread64) |
224 | COMPAT_SYS(pwrite64) | 224 | COMPAT_SYS(pwrite64) |
225 | SYSCALL(chown) | 225 | SYSCALL(chown) |
@@ -290,7 +290,7 @@ COMPAT_SYS(clock_settime) | |||
290 | COMPAT_SYS(clock_gettime) | 290 | COMPAT_SYS(clock_gettime) |
291 | COMPAT_SYS(clock_getres) | 291 | COMPAT_SYS(clock_getres) |
292 | COMPAT_SYS(clock_nanosleep) | 292 | COMPAT_SYS(clock_nanosleep) |
293 | SYSX(ppc64_swapcontext,ppc32_swapcontext,ppc_swapcontext) | 293 | COMPAT_SYS(swapcontext) |
294 | COMPAT_SYS(tgkill) | 294 | COMPAT_SYS(tgkill) |
295 | COMPAT_SYS(utimes) | 295 | COMPAT_SYS(utimes) |
296 | COMPAT_SYS(statfs64) | 296 | COMPAT_SYS(statfs64) |
diff --git a/include/asm-powerpc/ptrace.h b/include/asm-powerpc/ptrace.h index 1f7ecdb0b6ce..9c550b314823 100644 --- a/include/asm-powerpc/ptrace.h +++ b/include/asm-powerpc/ptrace.h | |||
@@ -87,7 +87,7 @@ extern unsigned long profile_pc(struct pt_regs *regs); | |||
87 | 87 | ||
88 | #define force_successful_syscall_return() \ | 88 | #define force_successful_syscall_return() \ |
89 | do { \ | 89 | do { \ |
90 | current_thread_info()->syscall_noerror = 1; \ | 90 | set_thread_flag(TIF_NOERROR); \ |
91 | } while(0) | 91 | } while(0) |
92 | 92 | ||
93 | /* | 93 | /* |
diff --git a/include/asm-powerpc/thread_info.h b/include/asm-powerpc/thread_info.h index e525f49bd179..ac1e80e6033e 100644 --- a/include/asm-powerpc/thread_info.h +++ b/include/asm-powerpc/thread_info.h | |||
@@ -37,8 +37,7 @@ struct thread_info { | |||
37 | int preempt_count; /* 0 => preemptable, | 37 | int preempt_count; /* 0 => preemptable, |
38 | <0 => BUG */ | 38 | <0 => BUG */ |
39 | struct restart_block restart_block; | 39 | struct restart_block restart_block; |
40 | /* set by force_successful_syscall_return */ | 40 | void *nvgprs_frame; |
41 | unsigned char syscall_noerror; | ||
42 | /* low level flags - has atomic operations done on it */ | 41 | /* low level flags - has atomic operations done on it */ |
43 | unsigned long flags ____cacheline_aligned_in_smp; | 42 | unsigned long flags ____cacheline_aligned_in_smp; |
44 | }; | 43 | }; |
@@ -123,6 +122,9 @@ static inline struct thread_info *current_thread_info(void) | |||
123 | #define TIF_SINGLESTEP 9 /* singlestepping active */ | 122 | #define TIF_SINGLESTEP 9 /* singlestepping active */ |
124 | #define TIF_MEMDIE 10 | 123 | #define TIF_MEMDIE 10 |
125 | #define TIF_SECCOMP 11 /* secure computing */ | 124 | #define TIF_SECCOMP 11 /* secure computing */ |
125 | #define TIF_RESTOREALL 12 /* Restore all regs (implies NOERROR) */ | ||
126 | #define TIF_SAVE_NVGPRS 13 /* Save r14-r31 in signal frame */ | ||
127 | #define TIF_NOERROR 14 /* Force successful syscall return */ | ||
126 | 128 | ||
127 | /* as above, but as bit values */ | 129 | /* as above, but as bit values */ |
128 | #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) | 130 | #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) |
@@ -136,10 +138,14 @@ static inline struct thread_info *current_thread_info(void) | |||
136 | #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) | 138 | #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) |
137 | #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP) | 139 | #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP) |
138 | #define _TIF_SECCOMP (1<<TIF_SECCOMP) | 140 | #define _TIF_SECCOMP (1<<TIF_SECCOMP) |
141 | #define _TIF_RESTOREALL (1<<TIF_RESTOREALL) | ||
142 | #define _TIF_SAVE_NVGPRS (1<<TIF_SAVE_NVGPRS) | ||
143 | #define _TIF_NOERROR (1<<TIF_NOERROR) | ||
139 | #define _TIF_SYSCALL_T_OR_A (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP) | 144 | #define _TIF_SYSCALL_T_OR_A (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP) |
140 | 145 | ||
141 | #define _TIF_USER_WORK_MASK (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \ | 146 | #define _TIF_USER_WORK_MASK (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \ |
142 | _TIF_NEED_RESCHED) | 147 | _TIF_NEED_RESCHED | _TIF_RESTOREALL) |
148 | #define _TIF_PERSYSCALL_MASK (_TIF_RESTOREALL|_TIF_NOERROR|_TIF_SAVE_NVGPRS) | ||
143 | 149 | ||
144 | #endif /* __KERNEL__ */ | 150 | #endif /* __KERNEL__ */ |
145 | 151 | ||