Skip to content

Commit

Permalink
[PATCH] syscall entry/exit revamp
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
David Woodhouse authored and Paul Mackerras committed Jan 9, 2006
1 parent 1cd8e50 commit 401d1f0
Show file tree
Hide file tree
Showing 8 changed files with 269 additions and 222 deletions.
4 changes: 2 additions & 2 deletions arch/powerpc/kernel/asm-offsets.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,9 @@ int main(void)

DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
DEFINE(TI_SC_NOERR, offsetof(struct thread_info, syscall_noerror));
#ifdef CONFIG_PPC32
DEFINE(TI_SIGFRAME, offsetof(struct thread_info, nvgprs_frame));
DEFINE(TI_TASK, offsetof(struct thread_info, task));
#ifdef CONFIG_PPC32
DEFINE(TI_EXECDOMAIN, offsetof(struct thread_info, exec_domain));
DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
#endif /* CONFIG_PPC32 */
Expand Down
167 changes: 96 additions & 71 deletions arch/powerpc/kernel/entry_32.S
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,6 @@ _GLOBAL(DoSyscall)
bl do_show_syscall
#endif /* SHOW_SYSCALLS */
rlwinm r10,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */
li r11,0
stb r11,TI_SC_NOERR(r10)
lwz r11,TI_FLAGS(r10)
andi. r11,r11,_TIF_SYSCALL_T_OR_A
bne- syscall_dotrace
Expand All @@ -222,25 +220,21 @@ ret_from_syscall:
bl do_show_syscall_exit
#endif
mr r6,r3
li r11,-_LAST_ERRNO
cmplw 0,r3,r11
rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */
blt+ 30f
lbz r11,TI_SC_NOERR(r12)
cmpwi r11,0
bne 30f
neg r3,r3
lwz r10,_CCR(r1) /* Set SO bit in CR */
oris r10,r10,0x1000
stw r10,_CCR(r1)

/* disable interrupts so current_thread_info()->flags can't change */
30: LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */
LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */
SYNC
MTMSRD(r10)
lwz r9,TI_FLAGS(r12)
andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED)
li r8,-_LAST_ERRNO
andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL)
bne- syscall_exit_work
cmplw 0,r3,r8
blt+ syscall_exit_cont
lwz r11,_CCR(r1) /* Load CR */
neg r3,r3
oris r11,r11,0x1000 /* Set SO bit in CR */
stw r11,_CCR(r1)
syscall_exit_cont:
#if defined(CONFIG_4xx) || defined(CONFIG_BOOKE)
/* If the process has its own DBCR0 value, load it up. The single
Expand Down Expand Up @@ -292,46 +286,113 @@ syscall_dotrace:
b syscall_dotrace_cont

syscall_exit_work:
stw r6,RESULT(r1) /* Save result */
andi. r0,r9,_TIF_RESTOREALL
bne- 2f
cmplw 0,r3,r8
blt+ 1f
andi. r0,r9,_TIF_NOERROR
bne- 1f
lwz r11,_CCR(r1) /* Load CR */
neg r3,r3
oris r11,r11,0x1000 /* Set SO bit in CR */
stw r11,_CCR(r1)

1: stw r6,RESULT(r1) /* Save result */
stw r3,GPR3(r1) /* Update return value */
andi. r0,r9,_TIF_SYSCALL_T_OR_A
beq 5f
ori r10,r10,MSR_EE
SYNC
MTMSRD(r10) /* re-enable interrupts */
2: andi. r0,r9,(_TIF_PERSYSCALL_MASK)
beq 4f

/* Clear per-syscall TIF flags if any are set, but _leave_
_TIF_SAVE_NVGPRS set in r9 since we haven't dealt with that
yet. */

li r11,_TIF_PERSYSCALL_MASK
addi r12,r12,TI_FLAGS
3: lwarx r8,0,r12
andc r8,r8,r11
#ifdef CONFIG_IBM405_ERR77
dcbt 0,r12
#endif
stwcx. r8,0,r12
bne- 3b
subi r12,r12,TI_FLAGS

4: /* Anything which requires enabling interrupts? */
andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SAVE_NVGPRS)
beq 7f

/* Save NVGPRS if they're not saved already */
lwz r4,_TRAP(r1)
andi. r4,r4,1
beq 4f
beq 5f
SAVE_NVGPRS(r1)
li r4,0xc00
stw r4,_TRAP(r1)
4:

/* Re-enable interrupts */
5: ori r10,r10,MSR_EE
SYNC
MTMSRD(r10)

andi. r0,r9,_TIF_SAVE_NVGPRS
bne save_user_nvgprs

save_user_nvgprs_cont:
andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP)
beq 7f

addi r3,r1,STACK_FRAME_OVERHEAD
bl do_syscall_trace_leave
REST_NVGPRS(r1)
2:
lwz r3,GPR3(r1)

6: lwz r3,GPR3(r1)
LOAD_MSR_KERNEL(r10,MSR_KERNEL) /* doesn't include MSR_EE */
SYNC
MTMSRD(r10) /* disable interrupts again */
rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */
lwz r9,TI_FLAGS(r12)
5:
7:
andi. r0,r9,_TIF_NEED_RESCHED
bne 1f
bne 8f
lwz r5,_MSR(r1)
andi. r5,r5,MSR_PR
beq syscall_exit_cont
beq ret_from_except
andi. r0,r9,_TIF_SIGPENDING
beq syscall_exit_cont
beq ret_from_except
b do_user_signal
1:
8:
ori r10,r10,MSR_EE
SYNC
MTMSRD(r10) /* re-enable interrupts */
bl schedule
b 2b
b 6b

save_user_nvgprs:
ld r8,TI_SIGFRAME(r12)

.macro savewords start, end
1: stw \start,4*(\start)(r8)
.section __ex_table,"a"
.align 2
.long 1b,save_user_nvgprs_fault
.previous
.if \end - \start
savewords "(\start+1)",\end
.endif
.endm
savewords 14,31
b save_user_nvgprs_cont


save_user_nvgprs_fault:
li r3,11 /* SIGSEGV */
ld r4,TI_TASK(r12)
bl force_sigsegv

rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */
ld r9,TI_FLAGS(r12)
b save_user_nvgprs_cont

#ifdef SHOW_SYSCALLS
do_show_syscall:
#ifdef SHOW_SYSCALLS_TASK
Expand Down Expand Up @@ -401,28 +462,10 @@ show_syscalls_task:
#endif /* SHOW_SYSCALLS */

/*
* The sigsuspend and rt_sigsuspend system calls can call do_signal
* and thus put the process into the stopped state where we might
* want to examine its user state with ptrace. Therefore we need
* to save all the nonvolatile registers (r13 - r31) before calling
* the C code.
* The fork/clone functions need to copy the full register set into
* the child process. Therefore we need to save all the nonvolatile
* registers (r13 - r31) before calling the C code.
*/
.globl ppc_sigsuspend
ppc_sigsuspend:
SAVE_NVGPRS(r1)
lwz r0,_TRAP(r1)
rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */
stw r0,_TRAP(r1) /* register set saved */
b sys_sigsuspend

.globl ppc_rt_sigsuspend
ppc_rt_sigsuspend:
SAVE_NVGPRS(r1)
lwz r0,_TRAP(r1)
rlwinm r0,r0,0,0,30
stw r0,_TRAP(r1)
b sys_rt_sigsuspend

.globl ppc_fork
ppc_fork:
SAVE_NVGPRS(r1)
Expand All @@ -447,14 +490,6 @@ ppc_clone:
stw r0,_TRAP(r1) /* register set saved */
b sys_clone

.globl ppc_swapcontext
ppc_swapcontext:
SAVE_NVGPRS(r1)
lwz r0,_TRAP(r1)
rlwinm r0,r0,0,0,30 /* clear LSB to indicate full */
stw r0,_TRAP(r1) /* register set saved */
b sys_swapcontext

/*
* Top-level page fault handling.
* This is in assembler because if do_page_fault tells us that
Expand Down Expand Up @@ -626,16 +661,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_601)
.long ret_from_except
#endif

.globl sigreturn_exit
sigreturn_exit:
subi r1,r3,STACK_FRAME_OVERHEAD
rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */
lwz r9,TI_FLAGS(r12)
andi. r0,r9,_TIF_SYSCALL_T_OR_A
beq+ ret_from_except_full
bl do_syscall_trace_leave
/* fall through */

.globl ret_from_except_full
ret_from_except_full:
REST_NVGPRS(r1)
Expand All @@ -658,7 +683,7 @@ user_exc_return: /* r10 contains MSR_KERNEL here */
/* Check current_thread_info()->flags */
rlwinm r9,r1,0,0,(31-THREAD_SHIFT)
lwz r9,TI_FLAGS(r9)
andi. r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED)
andi. r0,r9,(_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL)
bne do_work

restore_user:
Expand Down
Loading

0 comments on commit 401d1f0

Please sign in to comment.