Commit 401d1f029bebb7153ca704997772113dc36d9527

Authored by David Woodhouse
Committed by Paul Mackerras
1 parent 1cd8e50620

[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>

Showing 8 changed files with 269 additions and 222 deletions Side-by-side Diff

arch/powerpc/kernel/asm-offsets.c
... ... @@ -92,9 +92,9 @@
92 92  
93 93 DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
94 94 DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
95   - DEFINE(TI_SC_NOERR, offsetof(struct thread_info, syscall_noerror));
96   -#ifdef CONFIG_PPC32
  95 + DEFINE(TI_SIGFRAME, offsetof(struct thread_info, nvgprs_frame));
97 96 DEFINE(TI_TASK, offsetof(struct thread_info, task));
  97 +#ifdef CONFIG_PPC32
98 98 DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain));
99 99 DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
100 100 #endif /* CONFIG_PPC32 */
arch/powerpc/kernel/entry_32.S
... ... @@ -200,8 +200,6 @@
200 200 bl do_show_syscall
201 201 #endif /* SHOW_SYSCALLS */
202 202 rlwinm r10,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */
203   - li r11,0
204   - stb r11,TI_SC_NOERR(r10)
205 203 lwz r11,TI_FLAGS(r10)
206 204 andi. r11,r11,_TIF_SYSCALL_T_OR_A
207 205 bne- syscall_dotrace
208 206  
209 207  
210 208  
211 209  
... ... @@ -222,25 +220,21 @@
222 220 bl do_show_syscall_exit
223 221 #endif
224 222 mr r6,r3
225   - li r11,-_LAST_ERRNO
226   - cmplw 0,r3,r11
227 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 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 226 SYNC
240 227 MTMSRD(r10)
241 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 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 238 syscall_exit_cont:
245 239 #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
246 240 /* If the process has its own DBCR0 value, load it up. The single
247 241  
248 242  
249 243  
250 244  
251 245  
252 246  
253 247  
254 248  
255 249  
256 250  
257 251  
... ... @@ -292,46 +286,113 @@
292 286 b syscall_dotrace_cont
293 287  
294 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 301 stw r3,GPR3(r1) /* Update return value */
297   - andi. r0,r9,_TIF_SYSCALL_T_OR_A
298   - beq 5f
299   - ori r10,r10,MSR_EE
300   - SYNC
301   - MTMSRD(r10) /* re-enable interrupts */
  302 +2: andi. r0,r9,(_TIF_PERSYSCALL_MASK)
  303 + beq 4f
  304 +
  305 + /* Clear per-syscall TIF flags if any are set, but _leave_
  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 325 lwz r4,_TRAP(r1)
303 326 andi. r4,r4,1
304   - beq 4f
  327 + beq 5f
305 328 SAVE_NVGPRS(r1)
306 329 li r4,0xc00
307 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 344 addi r3,r1,STACK_FRAME_OVERHEAD
310 345 bl do_syscall_trace_leave
311 346 REST_NVGPRS(r1)
312   -2:
313   - lwz r3,GPR3(r1)
  347 +
  348 +6: lwz r3,GPR3(r1)
314 349 LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */
315 350 SYNC
316 351 MTMSRD(r10) /* disable interrupts again */
317 352 rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */
318 353 lwz r9,TI_FLAGS(r12)
319   -5:
  354 +7:
320 355 andi. r0,r9,_TIF_NEED_RESCHED
321   - bne 1f
  356 + bne 8f
322 357 lwz r5,_MSR(r1)
323 358 andi. r5,r5,MSR_PR
324   - beq syscall_exit_cont
  359 + beq ret_from_except
325 360 andi. r0,r9,_TIF_SIGPENDING
326   - beq syscall_exit_cont
  361 + beq ret_from_except
327 362 b do_user_signal
328   -1:
  363 +8:
329 364 ori r10,r10,MSR_EE
330 365 SYNC
331 366 MTMSRD(r10) /* re-enable interrupts */
332 367 bl schedule
333   - b 2b
  368 + b 6b
334 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
  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 396 #ifdef SHOW_SYSCALLS
336 397 do_show_syscall:
337 398 #ifdef SHOW_SYSCALLS_TASK
338 399  
... ... @@ -401,28 +462,10 @@
401 462 #endif /* SHOW_SYSCALLS */
402 463  
403 464 /*
404   - * The sigsuspend and rt_sigsuspend system calls can call do_signal
405   - * and thus put the process into the stopped state where we might
406   - * want to examine its user state with ptrace. Therefore we need
407   - * to save all the nonvolatile registers (r13 - r31) before calling
408   - * the C code.
  465 + * The fork/clone functions need to copy the full register set into
  466 + * the child process. Therefore we need to save all the nonvolatile
  467 + * registers (r13 - r31) before calling 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 469 .globl ppc_fork
427 470 ppc_fork:
428 471 SAVE_NVGPRS(r1)
... ... @@ -447,14 +490,6 @@
447 490 stw r0,_TRAP(r1) /* register set saved */
448 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 494 * Top-level page fault handling.
460 495 * This is in assembler because if do_page_fault tells us that
... ... @@ -626,16 +661,6 @@
626 661 .long ret_from_except
627 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 664 .globl ret_from_except_full
640 665 ret_from_except_full:
641 666 REST_NVGPRS(r1)
... ... @@ -658,7 +683,7 @@
658 683 /* Check current_thread_info()->flags */
659 684 rlwinm r9,r1,0,0,(31-THREAD_SHIFT)
660 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 687 bne do_work
663 688  
664 689 restore_user:
arch/powerpc/kernel/entry_64.S
... ... @@ -113,9 +113,7 @@
113 113 addi r9,r1,STACK_FRAME_OVERHEAD
114 114 #endif
115 115 clrrdi r11,r1,THREAD_SHIFT
116   - li r12,0
117 116 ld r10,TI_FLAGS(r11)
118   - stb r12,TI_SC_NOERR(r11)
119 117 andi. r11,r10,_TIF_SYSCALL_T_OR_A
120 118 bne- syscall_dotrace
121 119 syscall_dotrace_cont:
122 120  
123 121  
124 122  
125 123  
126 124  
... ... @@ -144,25 +142,13 @@
144 142 bctrl /* Call handler */
145 143  
146 144 syscall_exit:
  145 + std r3,RESULT(r1)
147 146 #ifdef SHOW_SYSCALLS
148   - std r3,GPR3(r1)
149 147 bl .do_show_syscall_exit
150   - ld r3,GPR3(r1)
  148 + ld r3,RESULT(r1)
151 149 #endif
152   - std r3,RESULT(r1)
153   - ld r5,_CCR(r1)
154   - li r10,-_LAST_ERRNO
155   - cmpld r3,r10
156 150 clrrdi r12,r1,THREAD_SHIFT
157   - bge- syscall_error
158   -syscall_error_cont:
159 151  
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   -
166 152 /* disable interrupts so current_thread_info()->flags can't change,
167 153 and so that we don't get interrupted after loading SRR0/1. */
168 154 ld r8,_MSR(r1)
169 155  
... ... @@ -173,8 +159,13 @@
173 159 rotldi r10,r10,16
174 160 mtmsrd r10,1
175 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 164 bne- syscall_exit_work
  165 + cmpld r3,r11
  166 + ld r5,_CCR(r1)
  167 + bge- syscall_error
  168 +syscall_error_cont:
178 169 ld r7,_NIP(r1)
179 170 stdcx. r0,0,r1 /* to clear the reservation */
180 171 andi. r6,r8,MSR_PR
181 172  
182 173  
... ... @@ -193,21 +184,12 @@
193 184 rfid
194 185 b . /* prevent speculative execution */
195 186  
196   -syscall_enosys:
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
  187 +syscall_error:
207 188 oris r5,r5,0x1000 /* Set SO bit in CR */
  189 + neg r3,r3
208 190 std r5,_CCR(r1)
209 191 b syscall_error_cont
210   -
  192 +
211 193 /* Traced system call support */
212 194 syscall_dotrace:
213 195 bl .save_nvgprs
214 196  
215 197  
216 198  
... ... @@ -225,21 +207,69 @@
225 207 ld r10,TI_FLAGS(r10)
226 208 b syscall_dotrace_cont
227 209  
228   -syscall_exit_trace:
229   - std r3,GPR3(r1)
230   - bl .save_nvgprs
  210 +syscall_enosys:
  211 + li r3,-ENOSYS
  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 262 addi r3,r1,STACK_FRAME_OVERHEAD
232 263 bl .do_syscall_trace_leave
233 264 REST_NVGPRS(r1)
234   - ld r3,GPR3(r1)
235   - ld r5,_CCR(r1)
236 265 clrrdi r12,r1,THREAD_SHIFT
237   - b syscall_exit_trace_cont
238 266  
239   -/* Stuff to do on exit from a system call. */
240   -syscall_exit_work:
241   - std r3,GPR3(r1)
242   - std r5,_CCR(r1)
  267 + /* Disable interrupts again and handle other work if any */
  268 +5: mfmsr r10
  269 + rldicl r10,r10,48,1
  270 + rotldi r10,r10,16
  271 + mtmsrd r10,1
  272 +
243 273 b .ret_from_except_lite
244 274  
245 275 /* Save non-volatile GPRs, if not already saved. */
... ... @@ -252,6 +282,52 @@
252 282 std r0,_TRAP(r1)
253 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 332 * The sigsuspend and rt_sigsuspend system calls can call do_signal
257 333 * and thus put the process into the stopped state where we might
258 334  
... ... @@ -260,36 +336,7 @@
260 336 * the C code. Similarly, fork, vfork and clone need the full
261 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 339  
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   -
293 340 _GLOBAL(ppc_fork)
294 341 bl .save_nvgprs
295 342 bl .sys_fork
... ... @@ -304,37 +351,6 @@
304 351 bl .save_nvgprs
305 352 bl .sys_clone
306 353 b syscall_exit
307   -
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 354  
339 355 _GLOBAL(ret_from_fork)
340 356 bl .schedule_tail
arch/powerpc/kernel/signal_32.c
... ... @@ -76,7 +76,6 @@
76 76 * registers from *regs. This is what we need
77 77 * to do when a signal has been delivered.
78 78 */
79   -#define sigreturn_exit(regs) return 0
80 79  
81 80 #define GP_REGS_SIZE min(sizeof(elf_gregset_t32), sizeof(struct pt_regs32))
82 81 #undef __SIGNAL_FRAMESIZE
83 82  
... ... @@ -156,9 +155,17 @@
156 155 elf_greg_t64 *gregs = (elf_greg_t64 *)regs;
157 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 166 if (__put_user((unsigned int)gregs[i], &frame->mc_gregs[i]))
161 167 return -EFAULT;
  168 + }
162 169 return 0;
163 170 }
164 171  
... ... @@ -179,8 +186,6 @@
179 186  
180 187 #else /* CONFIG_PPC64 */
181 188  
182   -extern void sigreturn_exit(struct pt_regs *);
183   -
184 189 #define GP_REGS_SIZE min(sizeof(elf_gregset_t), sizeof(struct pt_regs))
185 190  
186 191 static inline int put_sigset_t(sigset_t __user *uset, sigset_t *set)
... ... @@ -256,8 +261,10 @@
256 261 while (1) {
257 262 current->state = TASK_INTERRUPTIBLE;
258 263 schedule();
259   - if (do_signal(&saveset, regs))
260   - sigreturn_exit(regs);
  264 + if (do_signal(&saveset, regs)) {
  265 + set_thread_flag(TIF_RESTOREALL);
  266 + return 0;
  267 + }
261 268 }
262 269 }
263 270  
... ... @@ -292,8 +299,10 @@
292 299 while (1) {
293 300 current->state = TASK_INTERRUPTIBLE;
294 301 schedule();
295   - if (do_signal(&saveset, regs))
296   - sigreturn_exit(regs);
  302 + if (do_signal(&saveset, regs)) {
  303 + set_thread_flag(TIF_RESTOREALL);
  304 + return 0;
  305 + }
297 306 }
298 307 }
299 308  
... ... @@ -391,9 +400,6 @@
391 400 static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame,
392 401 int sigret)
393 402 {
394   -#ifdef CONFIG_PPC32
395   - CHECK_FULL_REGS(regs);
396   -#endif
397 403 /* Make sure floating point registers are stored in regs */
398 404 flush_fp_to_thread(current);
399 405  
... ... @@ -828,12 +834,6 @@
828 834 regs->gpr[6] = (unsigned long) rt_sf;
829 835 regs->nip = (unsigned long) ka->sa.sa_handler;
830 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 837 return 1;
838 838  
839 839 badframe:
... ... @@ -911,8 +911,8 @@
911 911 */
912 912 if (do_setcontext(new_ctx, regs, 0))
913 913 do_exit(SIGSEGV);
914   - sigreturn_exit(regs);
915   - /* doesn't actually return back to here */
  914 +
  915 + set_thread_flag(TIF_RESTOREALL);
916 916 return 0;
917 917 }
918 918  
919 919  
920 920  
... ... @@ -945,12 +945,11 @@
945 945 * nobody does any...
946 946 */
947 947 compat_sys_sigaltstack((u32)(u64)&rt_sf->uc.uc_stack, 0, 0, 0, 0, 0, regs);
948   - return (int)regs->result;
949 948 #else
950 949 do_sigaltstack(&rt_sf->uc.uc_stack, NULL, regs->gpr[1]);
951   - sigreturn_exit(regs); /* doesn't return here */
952   - return 0;
953 950 #endif
  951 + set_thread_flag(TIF_RESTOREALL);
  952 + return 0;
954 953  
955 954 bad:
956 955 force_sig(SIGSEGV, current);
... ... @@ -1041,9 +1040,7 @@
1041 1040 */
1042 1041 do_sigaltstack(&ctx->uc_stack, NULL, regs->gpr[1]);
1043 1042  
1044   - sigreturn_exit(regs);
1045   - /* doesn't actually return back to here */
1046   -
  1043 + set_thread_flag(TIF_RESTOREALL);
1047 1044 out:
1048 1045 return 0;
1049 1046 }
1050 1047  
... ... @@ -1107,13 +1104,7 @@
1107 1104 regs->gpr[4] = (unsigned long) sc;
1108 1105 regs->nip = (unsigned long) ka->sa.sa_handler;
1109 1106 regs->trap = 0;
1110   -#ifdef CONFIG_PPC64
1111   - regs->result = 0;
1112 1107  
1113   - if (test_thread_flag(TIF_SINGLESTEP))
1114   - ptrace_notify(SIGTRAP);
1115   -#endif
1116   -
1117 1108 return 1;
1118 1109  
1119 1110 badframe:
1120 1111  
... ... @@ -1160,12 +1151,8 @@
1160 1151 || restore_user_regs(regs, sr, 1))
1161 1152 goto badframe;
1162 1153  
1163   -#ifdef CONFIG_PPC64
1164   - return (int)regs->result;
1165   -#else
1166   - sigreturn_exit(regs); /* doesn't return */
  1154 + set_thread_flag(TIF_RESTOREALL);
1167 1155 return 0;
1168   -#endif
1169 1156  
1170 1157 badframe:
1171 1158 force_sig(SIGSEGV, current);
arch/powerpc/kernel/signal_64.c
... ... @@ -96,8 +96,10 @@
96 96 while (1) {
97 97 current->state = TASK_INTERRUPTIBLE;
98 98 schedule();
99   - if (do_signal(&saveset, regs))
  99 + if (do_signal(&saveset, regs)) {
  100 + set_thread_flag(TIF_RESTOREALL);
100 101 return 0;
  102 + }
101 103 }
102 104 }
103 105  
... ... @@ -152,6 +154,14 @@
152 154 err |= __put_user(0, &sc->v_regs);
153 155 #endif /* CONFIG_ALTIVEC */
154 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(&regs->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 165 err |= __copy_to_user(&sc->gp_regs, regs, GP_REGS_SIZE);
156 166 err |= __copy_to_user(&sc->fp_regs, &current->thread.fpr, FP_REGS_SIZE);
157 167 err |= __put_user(signr, &sc->signal);
... ... @@ -340,6 +350,7 @@
340 350 do_exit(SIGSEGV);
341 351  
342 352 /* This returns like rt_sigreturn */
  353 + set_thread_flag(TIF_RESTOREALL);
343 354 return 0;
344 355 }
345 356  
... ... @@ -372,7 +383,8 @@
372 383 */
373 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 389 badframe:
378 390 #if DEBUG_SIG
... ... @@ -454,9 +466,6 @@
454 466 if (err)
455 467 goto badframe;
456 468  
457   - if (test_thread_flag(TIF_SINGLESTEP))
458   - ptrace_notify(SIGTRAP);
459   -
460 469 return 1;
461 470  
462 471 badframe:
... ... @@ -502,6 +511,8 @@
502 511 * we only get here if there is a handler, we dont restart.
503 512 */
504 513 regs->result = -EINTR;
  514 + regs->gpr[3] = EINTR;
  515 + regs->ccr |= 0x10000000;
505 516 break;
506 517 case -ERESTARTSYS:
507 518 /* ERESTARTSYS means to restart the syscall if there is no
... ... @@ -509,6 +520,8 @@
509 520 */
510 521 if (!(ka->sa.sa_flags & SA_RESTART)) {
511 522 regs->result = -EINTR;
  523 + regs->gpr[3] = EINTR;
  524 + regs->ccr |= 0x10000000;
512 525 break;
513 526 }
514 527 /* fallthrough */
arch/powerpc/kernel/systbl.S
... ... @@ -113,7 +113,7 @@
113 113 COMPAT_SYS(ssetmask)
114 114 SYSCALL(setreuid)
115 115 SYSCALL(setregid)
116   -SYSX(sys_ni_syscall,ppc32_sigsuspend,ppc_sigsuspend)
  116 +SYS32ONLY(sigsuspend)
117 117 COMPAT_SYS(sigpending)
118 118 COMPAT_SYS(sethostname)
119 119 COMPAT_SYS(setrlimit)
... ... @@ -160,7 +160,7 @@
160 160 COMPAT_SYS(sysinfo)
161 161 COMPAT_SYS(ipc)
162 162 SYSCALL(fsync)
163   -SYSX(sys_ni_syscall,ppc32_sigreturn,sys_sigreturn)
  163 +SYS32ONLY(sigreturn)
164 164 PPC_SYS(clone)
165 165 COMPAT_SYS(setdomainname)
166 166 PPC_SYS(newuname)
167 167  
... ... @@ -213,13 +213,13 @@
213 213 SYSCALL(setresgid)
214 214 SYSCALL(getresgid)
215 215 COMPAT_SYS(prctl)
216   -SYSX(ppc64_rt_sigreturn,ppc32_rt_sigreturn,sys_rt_sigreturn)
  216 +COMPAT_SYS(rt_sigreturn)
217 217 COMPAT_SYS(rt_sigaction)
218 218 COMPAT_SYS(rt_sigprocmask)
219 219 COMPAT_SYS(rt_sigpending)
220 220 COMPAT_SYS(rt_sigtimedwait)
221 221 COMPAT_SYS(rt_sigqueueinfo)
222   -SYSX(ppc64_rt_sigsuspend,ppc32_rt_sigsuspend,ppc_rt_sigsuspend)
  222 +COMPAT_SYS(rt_sigsuspend)
223 223 COMPAT_SYS(pread64)
224 224 COMPAT_SYS(pwrite64)
225 225 SYSCALL(chown)
... ... @@ -290,7 +290,7 @@
290 290 COMPAT_SYS(clock_gettime)
291 291 COMPAT_SYS(clock_getres)
292 292 COMPAT_SYS(clock_nanosleep)
293   -SYSX(ppc64_swapcontext,ppc32_swapcontext,ppc_swapcontext)
  293 +COMPAT_SYS(swapcontext)
294 294 COMPAT_SYS(tgkill)
295 295 COMPAT_SYS(utimes)
296 296 COMPAT_SYS(statfs64)
include/asm-powerpc/ptrace.h
... ... @@ -87,7 +87,7 @@
87 87  
88 88 #define force_successful_syscall_return() \
89 89 do { \
90   - current_thread_info()->syscall_noerror = 1; \
  90 + set_thread_flag(TIF_NOERROR); \
91 91 } while(0)
92 92  
93 93 /*
include/asm-powerpc/thread_info.h
... ... @@ -37,8 +37,7 @@
37 37 int preempt_count; /* 0 => preemptable,
38 38 <0 => BUG */
39 39 struct restart_block restart_block;
40   - /* set by force_successful_syscall_return */
41   - unsigned char syscall_noerror;
  40 + void *nvgprs_frame;
42 41 /* low level flags - has atomic operations done on it */
43 42 unsigned long flags ____cacheline_aligned_in_smp;
44 43 };
... ... @@ -123,6 +122,9 @@
123 122 #define TIF_SINGLESTEP 9 /* singlestepping active */
124 123 #define TIF_MEMDIE 10
125 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 129 /* as above, but as bit values */
128 130 #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
129 131  
... ... @@ -136,10 +138,14 @@
136 138 #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT)
137 139 #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP)
138 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 144 #define _TIF_SYSCALL_T_OR_A (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP)
140 145  
141 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 150 #endif /* __KERNEL__ */
145 151