aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2005-11-15 13:52:18 -0500
committerPaul Mackerras <paulus@samba.org>2006-01-08 22:49:01 -0500
commit401d1f029bebb7153ca704997772113dc36d9527 (patch)
tree01a3d649ac591d7a1fb910ce29a7223ffb629f9a /arch/powerpc/kernel
parent1cd8e506209223ed10da805d99be55e268f4023c (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>
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/asm-offsets.c4
-rw-r--r--arch/powerpc/kernel/entry_32.S167
-rw-r--r--arch/powerpc/kernel/entry_64.S214
-rw-r--r--arch/powerpc/kernel/signal_32.c59
-rw-r--r--arch/powerpc/kernel/signal_64.c23
-rw-r--r--arch/powerpc/kernel/systbl.S10
6 files changed, 259 insertions, 218 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 */
23830: 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)
244syscall_exit_cont: 238syscall_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
294syscall_exit_work: 288syscall_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
3001: 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 3022: 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
3113: 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
3204: /* 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)
3084: 331
332 /* Re-enable interrupts */
3335: ori r10,r10,MSR_EE
334 SYNC
335 MTMSRD(r10)
336
337 andi. r0,r9,_TIF_SAVE_NVGPRS
338 bne save_user_nvgprs
339
340save_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)
3122: 347
313 lwz r3,GPR3(r1) 3486: 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)
3195: 3547:
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
3281: 3638:
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
370save_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
387save_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
336do_show_syscall: 397do_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
411ppc_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
419ppc_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
427ppc_fork: 470ppc_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
451ppc_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
630sigreturn_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
640ret_from_except_full: 665ret_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
664restore_user: 689restore_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
121syscall_dotrace_cont: 119syscall_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
146syscall_exit: 144syscall_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
158syscall_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
164syscall_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
168syscall_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
196syscall_enosys: 187syscall_error:
197 li r3,-ENOSYS
198 std r3,RESULT(r1)
199 clrrdi r12,r1,THREAD_SHIFT
200 ld r5,_CCR(r1)
201
202syscall_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 */
212syscall_dotrace: 194syscall_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
228syscall_exit_trace: 210syscall_enosys:
229 std r3,GPR3(r1) 211 li r3,-ENOSYS
230 bl .save_nvgprs 212 b syscall_exit
213
214syscall_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)
2281: std r3,GPR3(r1)
2292: 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
2383: ldarx r10,0,r12
239 andc r10,r10,r11
240 stdcx. r10,0,r12
241 bne- 3b
242 subi r12,r12,TI_FLAGS
243
2444: 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 */
258save_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 */
240syscall_exit_work: 2685: 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
286save_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
306save_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
322save_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
27670: 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
32980: 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
33781: 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
182extern 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
186static inline int put_sigset_t(sigset_t __user *uset, sigset_t *set) 191static 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 {
391static int save_user_regs(struct pt_regs *regs, struct mcontext __user *frame, 400static 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
839badframe: 839badframe:
@@ -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
1170badframe: 1157badframe:
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(&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 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, &current->thread.fpr, FP_REGS_SIZE); 166 err |= __copy_to_user(&sc->fp_regs, &current->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
377badframe: 389badframe:
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
462badframe: 471badframe:
@@ -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)
113COMPAT_SYS(ssetmask) 113COMPAT_SYS(ssetmask)
114SYSCALL(setreuid) 114SYSCALL(setreuid)
115SYSCALL(setregid) 115SYSCALL(setregid)
116SYSX(sys_ni_syscall,ppc32_sigsuspend,ppc_sigsuspend) 116SYS32ONLY(sigsuspend)
117COMPAT_SYS(sigpending) 117COMPAT_SYS(sigpending)
118COMPAT_SYS(sethostname) 118COMPAT_SYS(sethostname)
119COMPAT_SYS(setrlimit) 119COMPAT_SYS(setrlimit)
@@ -160,7 +160,7 @@ SYSCALL(swapoff)
160COMPAT_SYS(sysinfo) 160COMPAT_SYS(sysinfo)
161COMPAT_SYS(ipc) 161COMPAT_SYS(ipc)
162SYSCALL(fsync) 162SYSCALL(fsync)
163SYSX(sys_ni_syscall,ppc32_sigreturn,sys_sigreturn) 163SYS32ONLY(sigreturn)
164PPC_SYS(clone) 164PPC_SYS(clone)
165COMPAT_SYS(setdomainname) 165COMPAT_SYS(setdomainname)
166PPC_SYS(newuname) 166PPC_SYS(newuname)
@@ -213,13 +213,13 @@ COMPAT_SYS(nfsservctl)
213SYSCALL(setresgid) 213SYSCALL(setresgid)
214SYSCALL(getresgid) 214SYSCALL(getresgid)
215COMPAT_SYS(prctl) 215COMPAT_SYS(prctl)
216SYSX(ppc64_rt_sigreturn,ppc32_rt_sigreturn,sys_rt_sigreturn) 216COMPAT_SYS(rt_sigreturn)
217COMPAT_SYS(rt_sigaction) 217COMPAT_SYS(rt_sigaction)
218COMPAT_SYS(rt_sigprocmask) 218COMPAT_SYS(rt_sigprocmask)
219COMPAT_SYS(rt_sigpending) 219COMPAT_SYS(rt_sigpending)
220COMPAT_SYS(rt_sigtimedwait) 220COMPAT_SYS(rt_sigtimedwait)
221COMPAT_SYS(rt_sigqueueinfo) 221COMPAT_SYS(rt_sigqueueinfo)
222SYSX(ppc64_rt_sigsuspend,ppc32_rt_sigsuspend,ppc_rt_sigsuspend) 222COMPAT_SYS(rt_sigsuspend)
223COMPAT_SYS(pread64) 223COMPAT_SYS(pread64)
224COMPAT_SYS(pwrite64) 224COMPAT_SYS(pwrite64)
225SYSCALL(chown) 225SYSCALL(chown)
@@ -290,7 +290,7 @@ COMPAT_SYS(clock_settime)
290COMPAT_SYS(clock_gettime) 290COMPAT_SYS(clock_gettime)
291COMPAT_SYS(clock_getres) 291COMPAT_SYS(clock_getres)
292COMPAT_SYS(clock_nanosleep) 292COMPAT_SYS(clock_nanosleep)
293SYSX(ppc64_swapcontext,ppc32_swapcontext,ppc_swapcontext) 293COMPAT_SYS(swapcontext)
294COMPAT_SYS(tgkill) 294COMPAT_SYS(tgkill)
295COMPAT_SYS(utimes) 295COMPAT_SYS(utimes)
296COMPAT_SYS(statfs64) 296COMPAT_SYS(statfs64)