* [RFC] Attempt to clean up sigsuspend et al @ 2005-11-11 21:37 David Woodhouse 2005-11-12 0:28 ` Paul Mackerras 0 siblings, 1 reply; 10+ messages in thread From: David Woodhouse @ 2005-11-11 21:37 UTC (permalink / raw) To: paulus; +Cc: linuxppc-dev We currently play tricks with assembly wrappers for various syscalls, in case a signal is delivered. We need to make sure the registers are all saved for the benefit of ptrace, and we need to return to userspace without clobbering r4 and r5, as the normal syscall exit path would. As usual, these tricks differ subtly between ppc32 and ppc64 too. This is an attempt to get rid of it all, motivated mostly because I want to add two _new_ functions which would need such treatment (pselect, ppoll). We define a new thread flag TIF_RESTOREALL which is set by the syscall which needs this treatment, and make the syscall return path honour it. This seems to work as far as I've tested it (i.e. the system boots) for ppc64, but I haven't even attempted to compile the 32-bit version yet. I've also removed the explicit calls to ptrace_notify() which were in #ifdef CONFIG_PPC64 -- if we're now stopping on the way back to userspace, we don't need to do that any more. I'm going to need to go through some of the sigsuspend/signal cases with a fine-tooth comb and make sure we're still getting a ptrace stop (and only _one_ ptrace stop) in all cases where that's appropriate. I also tried to clean up entry_64.S so it only checks the thread flags in the fast path _once_. This means that for ptrace we'll disable interrupts, then check the flags and enable interrupts again before calling do_syscall_trace_leave(). That makes the slow path match the PPC32 code and makes the fast path smaller. Comments? diff --git a/arch/powerpc/kernel/entry_32.S b/arch/powerpc/kernel/entry_32.S index 2e99ae4..59dc2e7 100644 --- a/arch/powerpc/kernel/entry_32.S +++ b/arch/powerpc/kernel/entry_32.S @@ -222,25 +222,25 @@ ret_from_syscall: bl do_show_syscall_exit #endif mr r6,r3 - li r11,-_LAST_ERRNO - cmplw 0,r3,r11 + lwz r11,_CCR(r1) /* Load CR */ + li r10,-_LAST_ERRNO + cmplw 0,r3,r10 rlwinm r12,r1,0,0,(31-THREAD_SHIFT) /* current_thread_info() */ blt+ 30f - lbz r11,TI_SC_NOERR(r12) - cmpwi r11,0 + lbz r10,TI_SC_NOERR(r12) + cmpwi r10,0 bne 30f neg r3,r3 - lwz r10,_CCR(r1) /* Set SO bit in CR */ - oris r10,r10,0x1000 - stw r10,_CCR(r1) + oris r11,r11,0x1000 /* Set SO bit in CR */ /* disable interrupts so current_thread_info()->flags can't change */ 30: 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) + andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL) bne- syscall_exit_work + 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 @@ -292,9 +292,13 @@ syscall_dotrace: b syscall_dotrace_cont syscall_exit_work: + andi. r0,r9,_TIF_RESTOREALL + bne- 3f + stw r6,RESULT(r1) /* Save result */ stw r3,GPR3(r1) /* Update return value */ - andi. r0,r9,_TIF_SYSCALL_T_OR_A + stw r11,_CCR(r1) +3: andi. r0,r9,_TIF_SYSCALL_T_OR_A beq 5f ori r10,r10,MSR_EE SYNC @@ -407,22 +411,6 @@ show_syscalls_task: * 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) @@ -447,14 +435,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 @@ -626,16 +606,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) @@ -658,7 +628,7 @@ user_exc_return: /* r10 contains MSR_KE /* 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: @@ -876,6 +846,8 @@ load_dbcr0: #endif /* !(CONFIG_4xx || CONFIG_BOOKE) */ do_work: /* r10 contains MSR_KERNEL here */ + andi. r0,r9,_TIF_RESTOREALL + bne- do_clear_restoreall andi. r0,r9,_TIF_NEED_RESCHED beq do_user_signal @@ -890,6 +862,8 @@ recheck: MTMSRD(r10) /* disable interrupts */ rlwinm r9,r1,0,0,(31-THREAD_SHIFT) lwz r9,TI_FLAGS(r9) + andi. r0,r9,_TIF_RESTOREALL + bne- do_clear_restoreall andi. r0,r9,_TIF_NEED_RESCHED bne- do_resched andi. r0,r9,_TIF_SIGPENDING @@ -911,6 +885,9 @@ do_user_signal: /* r10 contains MSR_KE REST_NVGPRS(r1) b recheck +do_clear_restoreall: + bl do_clear_tif_restoreall + b recheck /* * We come here when we are at the end of handling an exception * that occurred at a place where taking an exception will lose diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 2d22bf0..756663e 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -157,12 +157,6 @@ syscall_exit: bge- syscall_error syscall_error_cont: - /* check for syscall tracing or audit */ - ld r9,TI_FLAGS(r12) - andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) - bne- syscall_exit_trace -syscall_exit_trace_cont: - /* disable interrupts so current_thread_info()->flags can't change, and so that we don't get interrupted after loading SRR0/1. */ ld r8,_MSR(r1) @@ -173,8 +167,9 @@ syscall_exit_trace_cont: rotldi r10,r10,16 mtmsrd r10,1 ld r9,TI_FLAGS(r12) - andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED) + andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL) bne- syscall_exit_work + std r5,_CCR(r1) ld r7,_NIP(r1) stdcx. r0,0,r1 /* to clear the reservation */ andi. r6,r8,MSR_PR @@ -205,7 +200,6 @@ syscall_error: bne- syscall_error_cont neg r3,r3 oris r5,r5,0x1000 /* Set SO bit in CR */ - std r5,_CCR(r1) b syscall_error_cont /* Traced system call support */ @@ -225,8 +219,22 @@ syscall_dotrace: ld r10,TI_FLAGS(r10) b syscall_dotrace_cont -syscall_exit_trace: +syscall_exit_work: + /* Avoid saving r3 and ccr if TIF_RESTOREALL flag is set */ + andi. r0,r9,_TIF_RESTOREALL + bne- 1f + std r3,GPR3(r1) + std r5,_CCR(r1) + + /* If tracing, re-enable interrupts and do it */ +1: andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) + beq .ret_from_except_lite + + mfmsr r10 + ori r10,r10,MSR_EE + mtmsrd r10,1 + bl .save_nvgprs addi r3,r1,STACK_FRAME_OVERHEAD bl .do_syscall_trace_leave @@ -234,12 +242,14 @@ syscall_exit_trace: ld r3,GPR3(r1) ld r5,_CCR(r1) clrrdi r12,r1,THREAD_SHIFT - b syscall_exit_trace_cont -/* Stuff to do on exit from a system call. */ -syscall_exit_work: - std r3,GPR3(r1) - std r5,_CCR(r1) + /* Disable interrupts again and handle other work if any */ + mfmsr r10 + rldicl r10,r10,48,1 + rotldi r10,r10,16 + mtmsrd r10,1 + + ld r9,TI_FLAGS(r12) b .ret_from_except_lite /* Save non-volatile GPRs, if not already saved. */ @@ -260,35 +270,6 @@ _GLOBAL(save_nvgprs) * the C code. Similarly, fork, vfork and clone need the full * register state on the stack so that it can be copied to the child. */ -_GLOBAL(ppc32_sigsuspend) - bl .save_nvgprs - bl .compat_sys_sigsuspend - b 70f - -_GLOBAL(ppc64_rt_sigsuspend) - bl .save_nvgprs - bl .sys_rt_sigsuspend - b 70f - -_GLOBAL(ppc32_rt_sigsuspend) - bl .save_nvgprs - bl .compat_sys_rt_sigsuspend -70: cmpdi 0,r3,0 - /* If it returned an error, we need to return via syscall_exit to set - the SO bit in cr0 and potentially stop for ptrace. */ - bne syscall_exit - /* If sigsuspend() returns zero, we are going into a signal handler. We - may need to call audit_syscall_exit() to mark the exit from sigsuspend() */ -#ifdef CONFIG_AUDITSYSCALL - ld r3,PACACURRENT(r13) - ld r4,AUDITCONTEXT(r3) - cmpdi 0,r4,0 - beq .ret_from_except /* No audit_context: Leave immediately. */ - li r4, 2 /* AUDITSC_FAILURE */ - li r5,-4 /* It's always -EINTR */ - bl .audit_syscall_exit -#endif - b .ret_from_except _GLOBAL(ppc_fork) bl .save_nvgprs @@ -305,37 +286,6 @@ _GLOBAL(ppc_clone) bl .sys_clone b syscall_exit -_GLOBAL(ppc32_swapcontext) - bl .save_nvgprs - bl .compat_sys_swapcontext - b 80f - -_GLOBAL(ppc64_swapcontext) - bl .save_nvgprs - bl .sys_swapcontext - b 80f - -_GLOBAL(ppc32_sigreturn) - bl .compat_sys_sigreturn - b 80f - -_GLOBAL(ppc32_rt_sigreturn) - bl .compat_sys_rt_sigreturn - b 80f - -_GLOBAL(ppc64_rt_sigreturn) - bl .sys_rt_sigreturn - -80: cmpdi 0,r3,0 - blt syscall_exit - clrrdi r4,r1,THREAD_SHIFT - ld r4,TI_FLAGS(r4) - andi. r4,r4,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) - beq+ 81f - addi r3,r1,STACK_FRAME_OVERHEAD - bl .do_syscall_trace_leave -81: b .ret_from_except - _GLOBAL(ret_from_fork) bl .schedule_tail REST_NVGPRS(r1) @@ -602,7 +552,12 @@ user_work: bl .schedule b .ret_from_except_lite -1: bl .save_nvgprs +1: andi. r0,r4,_TIF_RESTOREALL + beq 2f + bl .do_clear_tif_restoreall + b .ret_from_except_lite + +2: bl .save_nvgprs li r3,0 addi r4,r1,STACK_FRAME_OVERHEAD bl .do_signal diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 081d931..d18aebd 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -75,7 +75,6 @@ * registers from *regs. This is what we need * to do when a signal has been delivered. */ -#define sigreturn_exit(regs) return 0 #define GP_REGS_SIZE min(sizeof(elf_gregset_t32), sizeof(struct pt_regs32)) #undef __SIGNAL_FRAMESIZE @@ -178,8 +177,6 @@ static inline int restore_general_regs(s #else /* CONFIG_PPC64 */ -extern void sigreturn_exit(struct pt_regs *); - #define GP_REGS_SIZE min(sizeof(elf_gregset_t), sizeof(struct pt_regs)) static inline int put_sigset_t(sigset_t __user *uset, sigset_t *set) @@ -255,8 +252,10 @@ long sys_sigsuspend(old_sigset_t mask, i while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(&saveset, regs)) - sigreturn_exit(regs); + if (do_signal(&saveset, regs)) { + set_thread_flag(TIF_RESTOREALL); + return 0; + } } } @@ -291,8 +290,10 @@ long sys_rt_sigsuspend( while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(&saveset, regs)) - sigreturn_exit(regs); + if (do_signal(&saveset, regs)) { + set_thread_flag(TIF_RESTOREALL); + return 0; + } } } @@ -829,12 +830,6 @@ static int handle_rt_signal(unsigned lon regs->gpr[6] = (unsigned long) rt_sf; regs->nip = (unsigned long) ka->sa.sa_handler; regs->trap = 0; -#ifdef CONFIG_PPC64 - regs->result = 0; - - if (test_thread_flag(TIF_SINGLESTEP)) - ptrace_notify(SIGTRAP); -#endif return 1; badframe: @@ -912,8 +907,8 @@ long sys_swapcontext(struct ucontext __u */ if (do_setcontext(new_ctx, regs, 0)) do_exit(SIGSEGV); - sigreturn_exit(regs); - /* doesn't actually return back to here */ + + set_thread_flag(TIF_RESTOREALL); return 0; } @@ -946,12 +941,11 @@ long sys_rt_sigreturn(int r3, int r4, in * nobody does any... */ compat_sys_sigaltstack((u32)(u64)&rt_sf->uc.uc_stack, 0, 0, 0, 0, 0, regs); - return (int)regs->result; #else do_sigaltstack(&rt_sf->uc.uc_stack, NULL, regs->gpr[1]); - sigreturn_exit(regs); /* doesn't return here */ - return 0; #endif + set_thread_flag(TIF_RESTOREALL); + return 0; bad: force_sig(SIGSEGV, current); @@ -1042,9 +1036,7 @@ int sys_debug_setcontext(struct ucontext */ do_sigaltstack(&ctx->uc_stack, NULL, regs->gpr[1]); - sigreturn_exit(regs); - /* doesn't actually return back to here */ - + set_thread_flag(TIF_RESTOREALL); out: return 0; } @@ -1109,12 +1101,6 @@ static int handle_signal(unsigned long s regs->gpr[4] = (unsigned long) sc; regs->nip = (unsigned long) ka->sa.sa_handler; regs->trap = 0; -#ifdef CONFIG_PPC64 - regs->result = 0; - - if (test_thread_flag(TIF_SINGLESTEP)) - ptrace_notify(SIGTRAP); -#endif return 1; @@ -1162,12 +1148,8 @@ long sys_sigreturn(int r3, int r4, int r || restore_user_regs(regs, sr, 1)) goto badframe; -#ifdef CONFIG_PPC64 - return (int)regs->result; -#else - sigreturn_exit(regs); /* doesn't return */ + set_thread_flag(TIF_RESTOREALL); return 0; -#endif badframe: force_sig(SIGSEGV, current); diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 58194e1..7520ad4 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 * while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(&saveset, regs)) + if (do_signal(&saveset, regs)) { + set_thread_flag(TIF_RESTOREALL); return 0; + } } } @@ -343,6 +345,7 @@ int sys_swapcontext(struct ucontext __us do_exit(SIGSEGV); /* This returns like rt_sigreturn */ + set_thread_flag(TIF_RESTOREALL); return 0; } @@ -375,7 +378,8 @@ int sys_rt_sigreturn(unsigned long r3, u */ do_sigaltstack(&uc->uc_stack, NULL, regs->gpr[1]); - return regs->result; + set_thread_flag(TIF_RESTOREALL); + return 0; badframe: #if DEBUG_SIG @@ -454,9 +458,6 @@ static int setup_rt_frame(int signr, str if (err) goto badframe; - if (test_thread_flag(TIF_SINGLESTEP)) - ptrace_notify(SIGTRAP); - return 1; badframe: diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c index f72ced1..f8ec816 100644 --- a/arch/powerpc/kernel/syscalls.c +++ b/arch/powerpc/kernel/syscalls.c @@ -356,3 +356,8 @@ void do_show_syscall_exit(unsigned long { printk(" -> %lx, current=%p cpu=%d\n", r3, current, smp_processor_id()); } + +void do_clear_tif_restoreall(void) +{ + clear_thread_flag(TIF_RESTOREALL); +} diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S index 65eaea9..4bb3650 100644 --- a/arch/powerpc/kernel/systbl.S +++ b/arch/powerpc/kernel/systbl.S @@ -113,7 +113,7 @@ SYSCALL(sgetmask) COMPAT_SYS(ssetmask) SYSCALL(setreuid) SYSCALL(setregid) -SYSX(sys_ni_syscall,ppc32_sigsuspend,ppc_sigsuspend) +SYS32ONLY(sigsuspend) COMPAT_SYS(sigpending) COMPAT_SYS(sethostname) COMPAT_SYS(setrlimit) @@ -160,7 +160,7 @@ SYSCALL(swapoff) COMPAT_SYS(sysinfo) COMPAT_SYS(ipc) SYSCALL(fsync) -SYSX(sys_ni_syscall,ppc32_sigreturn,sys_sigreturn) +SYS32ONLY(sigreturn) PPC_SYS(clone) COMPAT_SYS(setdomainname) PPC_SYS(newuname) @@ -213,13 +213,13 @@ COMPAT_SYS(nfsservctl) SYSCALL(setresgid) SYSCALL(getresgid) COMPAT_SYS(prctl) -SYSX(ppc64_rt_sigreturn,ppc32_rt_sigreturn,sys_rt_sigreturn) +COMPAT_SYS(rt_sigreturn) COMPAT_SYS(rt_sigaction) COMPAT_SYS(rt_sigprocmask) COMPAT_SYS(rt_sigpending) COMPAT_SYS(rt_sigtimedwait) COMPAT_SYS(rt_sigqueueinfo) -SYSX(ppc64_rt_sigsuspend,ppc32_rt_sigsuspend,ppc_rt_sigsuspend) +COMPAT_SYS(rt_sigsuspend) COMPAT_SYS(pread64) COMPAT_SYS(pwrite64) SYSCALL(chown) @@ -290,7 +290,7 @@ COMPAT_SYS(clock_settime) COMPAT_SYS(clock_gettime) COMPAT_SYS(clock_getres) COMPAT_SYS(clock_nanosleep) -SYSX(ppc64_swapcontext,ppc32_swapcontext,ppc_swapcontext) +COMPAT_SYS(swapcontext) COMPAT_SYS(tgkill) COMPAT_SYS(utimes) COMPAT_SYS(statfs64) diff --git a/include/asm-powerpc/thread_info.h b/include/asm-powerpc/thread_info.h index e525f49..d10ec17 100644 --- a/include/asm-powerpc/thread_info.h +++ b/include/asm-powerpc/thread_info.h @@ -123,6 +123,7 @@ static inline struct thread_info *curren #define TIF_SINGLESTEP 9 /* singlestepping active */ #define TIF_MEMDIE 10 #define TIF_SECCOMP 11 /* secure computing */ +#define TIF_RESTOREALL 12 /* signal handler invoked */ /* as above, but as bit values */ #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) @@ -136,10 +137,11 @@ static inline struct thread_info *curren #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP) #define _TIF_SECCOMP (1<<TIF_SECCOMP) +#define _TIF_RESTOREALL (1<<TIF_RESTOREALL) #define _TIF_SYSCALL_T_OR_A (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP) #define _TIF_USER_WORK_MASK (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \ - _TIF_NEED_RESCHED) + _TIF_NEED_RESCHED | _TIF_RESTOREALL) #endif /* __KERNEL__ */ -- dwmw2 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [RFC] Attempt to clean up sigsuspend et al 2005-11-11 21:37 [RFC] Attempt to clean up sigsuspend et al David Woodhouse @ 2005-11-12 0:28 ` Paul Mackerras 2005-11-12 0:48 ` David Woodhouse 0 siblings, 1 reply; 10+ messages in thread From: Paul Mackerras @ 2005-11-12 0:28 UTC (permalink / raw) To: David Woodhouse; +Cc: linuxppc-dev David Woodhouse writes: > This is an attempt to get rid of it all, motivated mostly because I want > to add two _new_ functions which would need such treatment (pselect, > ppoll). > > We define a new thread flag TIF_RESTOREALL which is set by the syscall > which needs this treatment, and make the syscall return path honour it. > This seems to work as far as I've tested it (i.e. the system boots) for > ppc64, but I haven't even attempted to compile the 32-bit version yet. Ummm, I don't see where you save the non-volatile GPRs to the exception frame _before_ do_signal (called from within *_sigsuspend) copies them to the user stack... Paul. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] Attempt to clean up sigsuspend et al 2005-11-12 0:28 ` Paul Mackerras @ 2005-11-12 0:48 ` David Woodhouse 2005-11-13 6:58 ` Paul Mackerras 0 siblings, 1 reply; 10+ messages in thread From: David Woodhouse @ 2005-11-12 0:48 UTC (permalink / raw) To: Paul Mackerras; +Cc: linuxppc-dev On Sat, 2005-11-12 at 11:28 +1100, Paul Mackerras wrote: > Ummm, I don't see where you save the non-volatile GPRs to the > exception frame _before_ do_signal (called from within *_sigsuspend) > copies them to the user stack... Hm, yeah. I suppose I could make a TIF_xxx flag make entry.S do that. It's not massively pretty, but then it wasn't pretty beforehand either. At least I'd have made the ppc32 and ppc64 code match, removed the assembly wrappers for a bunch of syscalls, and shortened the syscall exit fast path on ppc64. I'd probably still be removing more lines of code than I add, but I'm not entirely convinced by the whole plan. What do you think? Failing that, I'll just switch them both to do either what ppc32 currently does with sigreturn_exit() or what ppc64 does with returning zero to take the ret_from_except path. Probably the former, since pselect() and ppoll() will sometimes want to return zero without invoking a signal handler. And we can probably shorten the ppc64 syscall exit path anyway, either way. -- dwmw2 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] Attempt to clean up sigsuspend et al 2005-11-12 0:48 ` David Woodhouse @ 2005-11-13 6:58 ` Paul Mackerras 2005-11-13 9:41 ` David Woodhouse 2005-11-15 0:19 ` David Woodhouse 0 siblings, 2 replies; 10+ messages in thread From: Paul Mackerras @ 2005-11-13 6:58 UTC (permalink / raw) To: David Woodhouse; +Cc: linuxppc-dev David Woodhouse writes: > I suppose I could make a TIF_xxx flag make entry.S do that. It's not > massively pretty, but then it wasn't pretty beforehand either. At least > I'd have made the ppc32 and ppc64 code match, removed the assembly > wrappers for a bunch of syscalls, and shortened the syscall exit fast > path on ppc64. > > I'd probably still be removing more lines of code than I add, but I'm > not entirely convinced by the whole plan. What do you think? Or have a mark in the syscall table (e.g. set the bottom bit of the address) for the syscalls that need the full register set. That does mean an extra conditional branch in the syscall entry path for all syscalls, though. > Failing that, I'll just switch them both to do either what ppc32 > currently does with sigreturn_exit() or what ppc64 does with returning > zero to take the ret_from_except path. Probably the former, since > pselect() and ppoll() will sometimes want to return zero without > invoking a signal handler. And we can probably shorten the ppc64 > syscall exit path anyway, either way. I'll be upset if you can shorten it by a lot - I thought I had it pretty tight already. :) Paul. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] Attempt to clean up sigsuspend et al 2005-11-13 6:58 ` Paul Mackerras @ 2005-11-13 9:41 ` David Woodhouse 2005-11-13 10:09 ` Paul Mackerras 2005-11-15 0:19 ` David Woodhouse 1 sibling, 1 reply; 10+ messages in thread From: David Woodhouse @ 2005-11-13 9:41 UTC (permalink / raw) To: Paul Mackerras; +Cc: linuxppc-dev On Sun, 2005-11-13 at 17:58 +1100, Paul Mackerras wrote: > Or have a mark in the syscall table (e.g. set the bottom bit of the > address) for the syscalls that need the full register set. That does > mean an extra conditional branch in the syscall entry path for all > syscalls, though. We don't need to do it on entry; we can do it on exit. If do_signal() sees that the nvgprs weren't saved in the pt_regs it's playing with, then it can set a new TIF_SAVENVPGRS_TO_SIG_FRAME bit. I don't think we even need to store a pointer saying where to put them -- the signal frame will always be at the top of the userspace stack. As long as we handle the new bit before TIF_SIGPENDING and before another call to do_signal(), we don't need to worry about recursive signals and having to fill in more than one signal frame. -- dwmw2 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] Attempt to clean up sigsuspend et al 2005-11-13 9:41 ` David Woodhouse @ 2005-11-13 10:09 ` Paul Mackerras 2005-11-13 11:58 ` David Woodhouse 0 siblings, 1 reply; 10+ messages in thread From: Paul Mackerras @ 2005-11-13 10:09 UTC (permalink / raw) To: David Woodhouse; +Cc: linuxppc-dev David Woodhouse writes: > We don't need to do it on entry; we can do it on exit. If do_signal() > sees that the nvgprs weren't saved in the pt_regs it's playing with, > then it can set a new TIF_SAVENVPGRS_TO_SIG_FRAME bit. I don't think we > even need to store a pointer saying where to put them -- the signal > frame will always be at the top of the userspace stack. Two problems with that: (1) for *sigsuspend, if do_signal returns 0, then we need to go back and keep waiting, and (2) it doesn't handle the other syscalls that need the full register set, such as fork, clone etc. Also, for the *sigsuspend case, we need to pass the saved signal set to do_signal, not NULL (as the call from the exception exit path does). Paul. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] Attempt to clean up sigsuspend et al 2005-11-13 10:09 ` Paul Mackerras @ 2005-11-13 11:58 ` David Woodhouse 2005-11-14 4:43 ` Paul Mackerras 0 siblings, 1 reply; 10+ messages in thread From: David Woodhouse @ 2005-11-13 11:58 UTC (permalink / raw) To: Paul Mackerras; +Cc: linuxppc-dev On Sun, 2005-11-13 at 21:09 +1100, Paul Mackerras wrote: > > We don't need to do it on entry; we can do it on exit. If do_signal() > > sees that the nvgprs weren't saved in the pt_regs it's playing with, > > then it can set a new TIF_SAVENVPGRS_TO_SIG_FRAME bit. I don't think we > > even need to store a pointer saying where to put them -- the signal > > frame will always be at the top of the userspace stack. > > Two problems with that: (1) for *sigsuspend, if do_signal returns 0, > then we need to go back and keep waiting, and (2) it doesn't handle > the other syscalls that need the full register set, such as fork, > clone etc. Also, for the *sigsuspend case, we need to pass the saved > signal set to do_signal, not NULL (as the call from the exception exit > path does). It doesn't address fork/vfork/clone; certainly. I haven't really looked at that code path at all yet. It was the *suspend() functions which offended me, mostly because I need similar behaviour for pselect() and ppoll() and I didn't want to add to the mess. But I think other things you mention are OK -- we'd still call do_signal() from *sigsuspend() just as we do at the moment, with the same loop. It's just that do_signal() would notice that the nvgprs aren't saved, and would set the TIF_SAVENVPGRS_TO_SIG_FRAME bit. .. if (!regs->trap & 1) set_thread_flag(TIF_SAVENVGPRS_SIG); We end up returning to userspace via entry.S, and the code there notices the SAVENVGPRS bit and saves _just_ r14-r31 into the signal frame. It doesn't have to call do_signal() again, so doesn't have to get the right saved signal mask when doing so. (Actually in the case of swapcontext() we don't know that the nvgprs should be saved in a signal frame at the top of the userspace stack; the context will be elsewhere. We probably do need to store a pointer in the thread_info, but that's OK too) -- dwmw2 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] Attempt to clean up sigsuspend et al 2005-11-13 11:58 ` David Woodhouse @ 2005-11-14 4:43 ` Paul Mackerras 2005-11-14 20:05 ` David Woodhouse 0 siblings, 1 reply; 10+ messages in thread From: Paul Mackerras @ 2005-11-14 4:43 UTC (permalink / raw) To: David Woodhouse; +Cc: linuxppc-dev David Woodhouse writes: > But I think other things you mention are OK -- we'd still call > do_signal() from *sigsuspend() just as we do at the moment, with the > same loop. It's just that do_signal() would notice that the nvgprs > aren't saved, and would set the TIF_SAVENVPGRS_TO_SIG_FRAME bit. .. Ah ok, I see now, that sounds all right. > (Actually in the case of swapcontext() we don't know that the nvgprs > should be saved in a signal frame at the top of the userspace stack; the > context will be elsewhere. We probably do need to store a pointer in the > thread_info, but that's OK too) True. Paul. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [RFC] Attempt to clean up sigsuspend et al 2005-11-14 4:43 ` Paul Mackerras @ 2005-11-14 20:05 ` David Woodhouse 0 siblings, 0 replies; 10+ messages in thread From: David Woodhouse @ 2005-11-14 20:05 UTC (permalink / raw) To: Paul Mackerras; +Cc: linuxppc-dev On Mon, 2005-11-14 at 15:43 +1100, Paul Mackerras wrote: > Ah ok, I see now, that sounds all right. I've also changed force_successful_syscall_return() to use a TIF flag, so we don't have to clear ti->syscall_noerror in the syscall entry path and that can shrink too. The syscall exit path now checks ti->flags only once in the fast path, instead of checking it twice as it did before. All the interesting stuff is done in the slow path. We lose the assembly wrappers for the signal-related functions, and clean up the syscall table to call them directly. It looks a bit like this... I still need to test it a little harder than "Yes, it boots", and I need to sync up the 32-bit version. Then we can have syscall entry/exit paths that actually look similar to each other. What do you think? diff --git a/arch/powerpc/kernel/asm-offsets.c b/arch/powerpc/kernel/asm-offsets.c index b757572..e3e6081 100644 --- a/arch/powerpc/kernel/asm-offsets.c +++ b/arch/powerpc/kernel/asm-offsets.c @@ -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 */ diff --git a/arch/powerpc/kernel/entry_64.S b/arch/powerpc/kernel/entry_64.S index 2d22bf0..564452b 100644 --- a/arch/powerpc/kernel/entry_64.S +++ b/arch/powerpc/kernel/entry_64.S @@ -113,9 +113,7 @@ system_call_common: addi r9,r1,STACK_FRAME_OVERHEAD #endif clrrdi r11,r1,THREAD_SHIFT - li r12,0 ld r10,TI_FLAGS(r11) - stb r12,TI_SC_NOERR(r11) andi. r11,r10,_TIF_SYSCALL_T_OR_A bne- syscall_dotrace syscall_dotrace_cont: @@ -145,23 +143,11 @@ system_call: /* label this so stack tr syscall_exit: #ifdef SHOW_SYSCALLS - std r3,GPR3(r1) + std r3,RESULT(r1) bl .do_show_syscall_exit - ld r3,GPR3(r1) + ld r3,RESULT(r1) #endif - std r3,RESULT(r1) - ld r5,_CCR(r1) - li r10,-_LAST_ERRNO - cmpld r3,r10 clrrdi r12,r1,THREAD_SHIFT - bge- syscall_error -syscall_error_cont: - - /* check for syscall tracing or audit */ - ld r9,TI_FLAGS(r12) - andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) - bne- syscall_exit_trace -syscall_exit_trace_cont: /* disable interrupts so current_thread_info()->flags can't change, and so that we don't get interrupted after loading SRR0/1. */ @@ -173,8 +159,14 @@ syscall_exit_trace_cont: rotldi r10,r10,16 mtmsrd r10,1 ld r9,TI_FLAGS(r12) - andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SIGPENDING|_TIF_NEED_RESCHED) + li r11,-_LAST_ERRNO + andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SIGPENDING|_TIF_NEED_RESCHED|_TIF_RESTOREALL|_TIF_SAVE_NVGPRS|_TIF_NOERROR) bne- syscall_exit_work + std r3,RESULT(r1) + cmpld r3,r11 + ld r5,_CCR(r1) + bge- syscall_error +syscall_error_cont: ld r7,_NIP(r1) stdcx. r0,0,r1 /* to clear the reservation */ andi. r6,r8,MSR_PR @@ -193,21 +185,13 @@ syscall_exit_trace_cont: rfid b . /* prevent speculative execution */ -syscall_enosys: - li r3,-ENOSYS - std r3,RESULT(r1) - clrrdi r12,r1,THREAD_SHIFT - ld r5,_CCR(r1) - -syscall_error: - lbz r11,TI_SC_NOERR(r12) - cmpwi 0,r11,0 - bne- syscall_error_cont +syscall_error: neg r3,r3 oris r5,r5,0x1000 /* Set SO bit in CR */ + std r3,RESULT(r1) std r5,_CCR(r1) b syscall_error_cont - + /* Traced system call support */ syscall_dotrace: bl .save_nvgprs @@ -225,21 +209,72 @@ syscall_dotrace: ld r10,TI_FLAGS(r10) b syscall_dotrace_cont -syscall_exit_trace: +syscall_enosys: + li r3,-ENOSYS + b syscall_exit + +syscall_exit_work: + /* If TIF_RESTOREALL is set, don't scribble on either r3 or ccr. + If TIF_NOERROR is set, just save r3 as it is. */ + + andi. r0,r9,_TIF_RESTOREALL + bne- 2f + cmpld r3,r11 /* r10 is -LAST_ERRNO */ + blt- 1f + andi. r0,r9,_TIF_NOERROR + bne- 1f + ld r5,_CCR(r1) + neg r3,r3 + oris r5,r5,0x1000 /* Set SO bit in CR */ + std r5,_CCR(r1) +1: + std r3,RESULT(r1) std r3,GPR3(r1) - bl .save_nvgprs + +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: ldarx r10,0,r12 + andc r10,r10,r11 + stdcx. r10,0,r12 + bne- 3b + subi r12,r12,TI_FLAGS + +4: bl save_nvgprs + /* Anything else left to do? */ + andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP|_TIF_SAVE_NVGPRS) + beq .ret_from_except_lite + + /* Re-enable interrupts */ + mfmsr r10 + ori r10,r10,MSR_EE + mtmsrd r10,1 + + andi. r0,r9,_TIF_SAVE_NVGPRS + bne save_user_nvgprs + + /* If tracing, re-enable interrupts and do it */ +save_user_nvgprs_cont: + andi. r0,r9,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) + beq 5f + addi r3,r1,STACK_FRAME_OVERHEAD bl .do_syscall_trace_leave REST_NVGPRS(r1) - ld r3,GPR3(r1) - ld r5,_CCR(r1) clrrdi r12,r1,THREAD_SHIFT - b syscall_exit_trace_cont -/* Stuff to do on exit from a system call. */ -syscall_exit_work: - std r3,GPR3(r1) - std r5,_CCR(r1) + /* Disable interrupts again and handle other work if any */ +5: mfmsr r10 + rldicl r10,r10,48,1 + rotldi r10,r10,16 + mtmsrd r10,1 + b .ret_from_except_lite /* Save non-volatile GPRs, if not already saved. */ @@ -252,6 +288,109 @@ _GLOBAL(save_nvgprs) std r0,_TRAP(r1) blr + +save_user_nvgprs: + /* Re-enable interrupts before copying to user */ + mfmsr r10 + ori r10,r10,MSR_EE + mtmsrd r10,1 + + ld r10,TI_SIGFRAME(r9) + andi. r0,r9,_TIF_32BIT + beq- save_user_nvgprs_64 + + /* 32-bit save to userspace */ +101: stw r14,56(r10) +102: stw r15,60(r10) +103: stw r16,64(r10) +104: stw r17,68(r10) +105: stw r18,72(r10) +106: stw r19,76(r10) +107: stw r20,80(r10) +108: stw r21,84(r10) +109: stw r22,88(r10) +110: stw r23,92(r10) +111: stw r24,96(r10) +112: stw r25,100(r10) +113: stw r26,104(r10) +114: stw r27,108(r10) +115: stw r28,112(r10) +116: stw r29,116(r10) +117: stw r30,120(r10) +118: stw r31,124(r10) + b save_user_nvgprs_cont + +save_user_nvgprs_64: + /* 64-bit save to userspace */ +119: std r14,112(r10) +120: std r15,120(r10) +121: std r16,128(r10) +122: std r17,136(r10) +123: std r18,144(r10) +124: std r19,152(r10) +125: std r20,160(r10) +126: std r21,168(r10) +127: std r22,176(r10) +128: std r23,184(r10) +129: std r24,192(r10) +130: std r25,200(r10) +131: std r26,208(r10) +132: std r27,216(r10) +133: std r28,224(r10) +134: std r28,232(r10) +135: std r28,240(r10) +136: std r28,248(r10) + b save_user_nvgprs_cont + + .section __ex_table,"a" + .align 3 + .llong 101b,save_user_nvgprs_fault + .llong 102b,save_user_nvgprs_fault + .llong 103b,save_user_nvgprs_fault + .llong 104b,save_user_nvgprs_fault + .llong 105b,save_user_nvgprs_fault + .llong 106b,save_user_nvgprs_fault + .llong 107b,save_user_nvgprs_fault + .llong 108b,save_user_nvgprs_fault + .llong 109b,save_user_nvgprs_fault + .llong 110b,save_user_nvgprs_fault + .llong 111b,save_user_nvgprs_fault + .llong 112b,save_user_nvgprs_fault + .llong 113b,save_user_nvgprs_fault + .llong 114b,save_user_nvgprs_fault + .llong 115b,save_user_nvgprs_fault + .llong 116b,save_user_nvgprs_fault + .llong 117b,save_user_nvgprs_fault + .llong 118b,save_user_nvgprs_fault + .llong 119b,save_user_nvgprs_fault + .llong 120b,save_user_nvgprs_fault + .llong 121b,save_user_nvgprs_fault + .llong 122b,save_user_nvgprs_fault + .llong 123b,save_user_nvgprs_fault + .llong 124b,save_user_nvgprs_fault + .llong 125b,save_user_nvgprs_fault + .llong 126b,save_user_nvgprs_fault + .llong 127b,save_user_nvgprs_fault + .llong 128b,save_user_nvgprs_fault + .llong 129b,save_user_nvgprs_fault + .llong 130b,save_user_nvgprs_fault + .llong 131b,save_user_nvgprs_fault + .llong 132b,save_user_nvgprs_fault + .llong 133b,save_user_nvgprs_fault + .llong 134b,save_user_nvgprs_fault + .llong 135b,save_user_nvgprs_fault + .llong 136b,save_user_nvgprs_fault + .previous + +save_user_nvgprs_fault: + li r3,9 // SIGSEGV + ld r4,TI_TASK(r9) + bl .force_sigsegv + + clrrdi r12,r1,THREAD_SHIFT + ld r9,TI_FLAGS(r12) + b save_user_nvgprs_cont + /* * The sigsuspend and rt_sigsuspend system calls can call do_signal * and thus put the process into the stopped state where we might @@ -260,35 +399,6 @@ _GLOBAL(save_nvgprs) * the C code. Similarly, fork, vfork and clone need the full * register state on the stack so that it can be copied to the child. */ -_GLOBAL(ppc32_sigsuspend) - bl .save_nvgprs - bl .compat_sys_sigsuspend - b 70f - -_GLOBAL(ppc64_rt_sigsuspend) - bl .save_nvgprs - bl .sys_rt_sigsuspend - b 70f - -_GLOBAL(ppc32_rt_sigsuspend) - bl .save_nvgprs - bl .compat_sys_rt_sigsuspend -70: cmpdi 0,r3,0 - /* If it returned an error, we need to return via syscall_exit to set - the SO bit in cr0 and potentially stop for ptrace. */ - bne syscall_exit - /* If sigsuspend() returns zero, we are going into a signal handler. We - may need to call audit_syscall_exit() to mark the exit from sigsuspend() */ -#ifdef CONFIG_AUDITSYSCALL - ld r3,PACACURRENT(r13) - ld r4,AUDITCONTEXT(r3) - cmpdi 0,r4,0 - beq .ret_from_except /* No audit_context: Leave immediately. */ - li r4, 2 /* AUDITSC_FAILURE */ - li r5,-4 /* It's always -EINTR */ - bl .audit_syscall_exit -#endif - b .ret_from_except _GLOBAL(ppc_fork) bl .save_nvgprs @@ -305,37 +415,6 @@ _GLOBAL(ppc_clone) bl .sys_clone b syscall_exit -_GLOBAL(ppc32_swapcontext) - bl .save_nvgprs - bl .compat_sys_swapcontext - b 80f - -_GLOBAL(ppc64_swapcontext) - bl .save_nvgprs - bl .sys_swapcontext - b 80f - -_GLOBAL(ppc32_sigreturn) - bl .compat_sys_sigreturn - b 80f - -_GLOBAL(ppc32_rt_sigreturn) - bl .compat_sys_rt_sigreturn - b 80f - -_GLOBAL(ppc64_rt_sigreturn) - bl .sys_rt_sigreturn - -80: cmpdi 0,r3,0 - blt syscall_exit - clrrdi r4,r1,THREAD_SHIFT - ld r4,TI_FLAGS(r4) - andi. r4,r4,(_TIF_SYSCALL_T_OR_A|_TIF_SINGLESTEP) - beq+ 81f - addi r3,r1,STACK_FRAME_OVERHEAD - bl .do_syscall_trace_leave -81: b .ret_from_except - _GLOBAL(ret_from_fork) bl .schedule_tail REST_NVGPRS(r1) diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 081d931..88b86ac 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -75,7 +75,6 @@ * registers from *regs. This is what we need * to do when a signal has been delivered. */ -#define sigreturn_exit(regs) return 0 #define GP_REGS_SIZE min(sizeof(elf_gregset_t32), sizeof(struct pt_regs32)) #undef __SIGNAL_FRAMESIZE @@ -155,9 +154,18 @@ static inline int save_general_regs(stru elf_greg_t64 *gregs = (elf_greg_t64 *)regs; int i; - for (i = 0; i <= PT_RESULT; i ++) + if (!FULL_REGS(regs)) { + printk("Save NVGPRS at %lx\n", (unsigned long)frame->mc_gregs); + set_thread_flag(TIF_SAVE_NVGPRS); + current_thread_info()->nvgprs_frame = frame->mc_gregs; + } + + for (i = 0; i <= PT_RESULT; i ++) { + if (i == 14 && !FULL_REGS(regs)) + i = 32; if (__put_user((unsigned int)gregs[i], &frame->mc_gregs[i])) return -EFAULT; + } return 0; } @@ -178,8 +186,6 @@ static inline int restore_general_regs(s #else /* CONFIG_PPC64 */ -extern void sigreturn_exit(struct pt_regs *); - #define GP_REGS_SIZE min(sizeof(elf_gregset_t), sizeof(struct pt_regs)) static inline int put_sigset_t(sigset_t __user *uset, sigset_t *set) @@ -255,8 +261,10 @@ long sys_sigsuspend(old_sigset_t mask, i while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(&saveset, regs)) - sigreturn_exit(regs); + if (do_signal(&saveset, regs)) { + set_thread_flag(TIF_RESTOREALL); + return 0; + } } } @@ -291,8 +299,10 @@ long sys_rt_sigsuspend( while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(&saveset, regs)) - sigreturn_exit(regs); + if (do_signal(&saveset, regs)) { + set_thread_flag(TIF_RESTOREALL); + return 0; + } } } @@ -829,12 +839,6 @@ static int handle_rt_signal(unsigned lon regs->gpr[6] = (unsigned long) rt_sf; regs->nip = (unsigned long) ka->sa.sa_handler; regs->trap = 0; -#ifdef CONFIG_PPC64 - regs->result = 0; - - if (test_thread_flag(TIF_SINGLESTEP)) - ptrace_notify(SIGTRAP); -#endif return 1; badframe: @@ -912,8 +916,8 @@ long sys_swapcontext(struct ucontext __u */ if (do_setcontext(new_ctx, regs, 0)) do_exit(SIGSEGV); - sigreturn_exit(regs); - /* doesn't actually return back to here */ + + set_thread_flag(TIF_RESTOREALL); return 0; } @@ -946,12 +950,11 @@ long sys_rt_sigreturn(int r3, int r4, in * nobody does any... */ compat_sys_sigaltstack((u32)(u64)&rt_sf->uc.uc_stack, 0, 0, 0, 0, 0, regs); - return (int)regs->result; #else do_sigaltstack(&rt_sf->uc.uc_stack, NULL, regs->gpr[1]); - sigreturn_exit(regs); /* doesn't return here */ - return 0; #endif + set_thread_flag(TIF_RESTOREALL); + return 0; bad: force_sig(SIGSEGV, current); @@ -1042,9 +1045,7 @@ int sys_debug_setcontext(struct ucontext */ do_sigaltstack(&ctx->uc_stack, NULL, regs->gpr[1]); - sigreturn_exit(regs); - /* doesn't actually return back to here */ - + set_thread_flag(TIF_RESTOREALL); out: return 0; } @@ -1109,12 +1110,6 @@ static int handle_signal(unsigned long s regs->gpr[4] = (unsigned long) sc; regs->nip = (unsigned long) ka->sa.sa_handler; regs->trap = 0; -#ifdef CONFIG_PPC64 - regs->result = 0; - - if (test_thread_flag(TIF_SINGLESTEP)) - ptrace_notify(SIGTRAP); -#endif return 1; @@ -1162,12 +1157,8 @@ long sys_sigreturn(int r3, int r4, int r || restore_user_regs(regs, sr, 1)) goto badframe; -#ifdef CONFIG_PPC64 - return (int)regs->result; -#else - sigreturn_exit(regs); /* doesn't return */ + set_thread_flag(TIF_RESTOREALL); return 0; -#endif badframe: force_sig(SIGSEGV, current); diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 58194e1..e071e95 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 * while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(&saveset, regs)) + if (do_signal(&saveset, regs)) { + set_thread_flag(TIF_RESTOREALL); return 0; + } } } @@ -155,6 +157,14 @@ static long setup_sigcontext(struct sigc err |= __put_user(0, &sc->v_regs); #endif /* CONFIG_ALTIVEC */ err |= __put_user(&sc->gp_regs, &sc->regs); + if (!FULL_REGS(regs)) { + /* Zero out the unsaved GPRs to avoid information + leak, and set TIF_SAVE_NVGPRS to ensure that the + registers do actually get saved later. */ + memset(®s->gpr[14], 0, 18 * sizeof(unsigned long)); + set_thread_flag(TIF_SAVE_NVGPRS); + current_thread_info()->nvgprs_frame = &sc->gp_regs; + } err |= __copy_to_user(&sc->gp_regs, regs, GP_REGS_SIZE); err |= __copy_to_user(&sc->fp_regs, ¤t->thread.fpr, FP_REGS_SIZE); err |= __put_user(signr, &sc->signal); @@ -343,6 +353,7 @@ int sys_swapcontext(struct ucontext __us do_exit(SIGSEGV); /* This returns like rt_sigreturn */ + set_thread_flag(TIF_RESTOREALL); return 0; } @@ -375,7 +386,8 @@ int sys_rt_sigreturn(unsigned long r3, u */ do_sigaltstack(&uc->uc_stack, NULL, regs->gpr[1]); - return regs->result; + set_thread_flag(TIF_RESTOREALL); + return 0; badframe: #if DEBUG_SIG @@ -454,9 +466,6 @@ static int setup_rt_frame(int signr, str if (err) goto badframe; - if (test_thread_flag(TIF_SINGLESTEP)) - ptrace_notify(SIGTRAP); - return 1; badframe: diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S index 65eaea9..4bb3650 100644 --- a/arch/powerpc/kernel/systbl.S +++ b/arch/powerpc/kernel/systbl.S @@ -113,7 +113,7 @@ SYSCALL(sgetmask) COMPAT_SYS(ssetmask) SYSCALL(setreuid) SYSCALL(setregid) -SYSX(sys_ni_syscall,ppc32_sigsuspend,ppc_sigsuspend) +SYS32ONLY(sigsuspend) COMPAT_SYS(sigpending) COMPAT_SYS(sethostname) COMPAT_SYS(setrlimit) @@ -160,7 +160,7 @@ SYSCALL(swapoff) COMPAT_SYS(sysinfo) COMPAT_SYS(ipc) SYSCALL(fsync) -SYSX(sys_ni_syscall,ppc32_sigreturn,sys_sigreturn) +SYS32ONLY(sigreturn) PPC_SYS(clone) COMPAT_SYS(setdomainname) PPC_SYS(newuname) @@ -213,13 +213,13 @@ COMPAT_SYS(nfsservctl) SYSCALL(setresgid) SYSCALL(getresgid) COMPAT_SYS(prctl) -SYSX(ppc64_rt_sigreturn,ppc32_rt_sigreturn,sys_rt_sigreturn) +COMPAT_SYS(rt_sigreturn) COMPAT_SYS(rt_sigaction) COMPAT_SYS(rt_sigprocmask) COMPAT_SYS(rt_sigpending) COMPAT_SYS(rt_sigtimedwait) COMPAT_SYS(rt_sigqueueinfo) -SYSX(ppc64_rt_sigsuspend,ppc32_rt_sigsuspend,ppc_rt_sigsuspend) +COMPAT_SYS(rt_sigsuspend) COMPAT_SYS(pread64) COMPAT_SYS(pwrite64) SYSCALL(chown) @@ -290,7 +290,7 @@ COMPAT_SYS(clock_settime) COMPAT_SYS(clock_gettime) COMPAT_SYS(clock_getres) COMPAT_SYS(clock_nanosleep) -SYSX(ppc64_swapcontext,ppc32_swapcontext,ppc_swapcontext) +COMPAT_SYS(swapcontext) COMPAT_SYS(tgkill) COMPAT_SYS(utimes) COMPAT_SYS(statfs64) diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 32f2158..2010d35 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -205,8 +205,8 @@ void _exception(int signr, struct pt_reg if (handler == SIG_DFL) { /* init has generated a synchronous exception and it doesn't have a handler for the signal */ - printk(KERN_CRIT "init has generated signal %d " - "but has no handler for it\n", signr); + die("init has generated signal %d " + "but has no handler for it\n", regs, signr); do_exit(signr); } } diff --git a/include/asm-powerpc/ptrace.h b/include/asm-powerpc/ptrace.h index 1f7ecdb..9c550b3 100644 --- a/include/asm-powerpc/ptrace.h +++ b/include/asm-powerpc/ptrace.h @@ -87,7 +87,7 @@ extern unsigned long profile_pc(struct p #define force_successful_syscall_return() \ do { \ - current_thread_info()->syscall_noerror = 1; \ + set_thread_flag(TIF_NOERROR); \ } while(0) /* diff --git a/include/asm-powerpc/thread_info.h b/include/asm-powerpc/thread_info.h index e525f49..ac1e80e 100644 --- a/include/asm-powerpc/thread_info.h +++ b/include/asm-powerpc/thread_info.h @@ -37,8 +37,7 @@ struct thread_info { int preempt_count; /* 0 => preemptable, <0 => BUG */ struct restart_block restart_block; - /* set by force_successful_syscall_return */ - unsigned char syscall_noerror; + void *nvgprs_frame; /* low level flags - has atomic operations done on it */ unsigned long flags ____cacheline_aligned_in_smp; }; @@ -123,6 +122,9 @@ static inline struct thread_info *curren #define TIF_SINGLESTEP 9 /* singlestepping active */ #define TIF_MEMDIE 10 #define TIF_SECCOMP 11 /* secure computing */ +#define TIF_RESTOREALL 12 /* Restore all regs (implies NOERROR) */ +#define TIF_SAVE_NVGPRS 13 /* Save r14-r31 in signal frame */ +#define TIF_NOERROR 14 /* Force successful syscall return */ /* as above, but as bit values */ #define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE) @@ -136,10 +138,14 @@ static inline struct thread_info *curren #define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT) #define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP) #define _TIF_SECCOMP (1<<TIF_SECCOMP) +#define _TIF_RESTOREALL (1<<TIF_RESTOREALL) +#define _TIF_SAVE_NVGPRS (1<<TIF_SAVE_NVGPRS) +#define _TIF_NOERROR (1<<TIF_NOERROR) #define _TIF_SYSCALL_T_OR_A (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SECCOMP) #define _TIF_USER_WORK_MASK (_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \ - _TIF_NEED_RESCHED) + _TIF_NEED_RESCHED | _TIF_RESTOREALL) +#define _TIF_PERSYSCALL_MASK (_TIF_RESTOREALL|_TIF_NOERROR|_TIF_SAVE_NVGPRS) #endif /* __KERNEL__ */ -- dwmw2 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [RFC] Attempt to clean up sigsuspend et al 2005-11-13 6:58 ` Paul Mackerras 2005-11-13 9:41 ` David Woodhouse @ 2005-11-15 0:19 ` David Woodhouse 1 sibling, 0 replies; 10+ messages in thread From: David Woodhouse @ 2005-11-15 0:19 UTC (permalink / raw) To: Paul Mackerras; +Cc: linuxppc-dev [-- Attachment #1: Type: text/plain, Size: 772 bytes --] On Sun, 2005-11-13 at 17:58 +1100, Paul Mackerras wrote: > I'll be upset if you can shorten it by a lot - I thought I had it > pretty tight already. :) The patch appears to speed up a null syscall benchmark by about 3%. With the old kernel I get an average of 5863600 cycles for 100000 getpid() calls; with the new kernel it's 5695256 cycles. I still haven't done much testing for correctness, but it needs at least this (d'oh)... --- arch/powerpc/kernel/entry_64.S~ 2005-11-14 23:41:22.000000000 +0000 +++ arch/powerpc/kernel/entry_64.S 2005-11-14 23:45:35.000000000 +0000 @@ -295,7 +295,7 @@ save_user_nvgprs: ori r10,r10,MSR_EE mtmsrd r10,1 - ld r10,TI_SIGFRAME(r9) + ld r10,TI_SIGFRAME(r12) andi. r0,r9,_TIF_32BIT beq- save_user_nvgprs_64 -- dwmw2 [-- Attachment #2: newkernel.txt --] [-- Type: text/plain, Size: 2040 bytes --] Used 5687730 cycles Used 5721828 cycles Used 5686992 cycles Used 5658466 cycles Used 5630346 cycles Used 5640494 cycles Used 5709830 cycles Used 5654279 cycles Used 5659045 cycles Used 5747328 cycles Used 5635214 cycles Used 5694711 cycles Used 5646751 cycles Used 5738407 cycles Used 5898139 cycles Used 5787047 cycles Used 5670900 cycles Used 5707616 cycles Used 5694654 cycles Used 5722101 cycles Used 5666626 cycles Used 5702401 cycles Used 5723496 cycles Used 5708662 cycles Used 5675878 cycles Used 5772019 cycles Used 5653936 cycles Used 5675029 cycles Used 5657729 cycles Used 5694485 cycles Used 5781104 cycles Used 5687276 cycles Used 5668391 cycles Used 5661477 cycles Used 5729791 cycles Used 5667902 cycles Used 5669606 cycles Used 5655594 cycles Used 5703992 cycles Used 5685671 cycles Used 5659003 cycles Used 5710373 cycles Used 5754017 cycles Used 5677565 cycles Used 5699307 cycles Used 5734777 cycles Used 5647465 cycles Used 5630120 cycles Used 5688174 cycles Used 5697787 cycles Used 5735130 cycles Used 5795555 cycles Used 5657136 cycles Used 5705851 cycles Used 5708684 cycles Used 5680934 cycles Used 5666883 cycles Used 5650389 cycles Used 5702600 cycles Used 5692186 cycles Used 5667843 cycles Used 5612066 cycles Used 5675461 cycles Used 5663601 cycles Used 5667161 cycles Used 5736776 cycles Used 5727070 cycles Used 5720203 cycles Used 5824526 cycles Used 5694799 cycles Used 5600060 cycles Used 5767003 cycles Used 5691184 cycles Used 5705613 cycles Used 5670786 cycles Used 5728827 cycles Used 5685249 cycles Used 5742188 cycles Used 5699514 cycles Used 5670884 cycles Used 5758295 cycles Used 5712180 cycles Used 5697514 cycles Used 5757201 cycles Used 5694345 cycles Used 5669453 cycles Used 5674303 cycles Used 5647565 cycles Used 5663152 cycles Used 5683005 cycles Used 5666470 cycles Used 5714193 cycles Used 5689820 cycles Used 5679402 cycles Used 5672894 cycles Used 5682461 cycles Used 5701143 cycles Used 5683074 cycles Used 5760015 cycles Used 5663922 cycles Used 5677554 cycles Used 5690482 cycles [-- Attachment #3: oldkernel.txt --] [-- Type: text/plain, Size: 1780 bytes --] Used 5882164 cycles Used 5850099 cycles Used 5930877 cycles Used 5841572 cycles Used 5809251 cycles Used 5845593 cycles Used 5832703 cycles Used 5819283 cycles Used 5885083 cycles Used 5888057 cycles Used 5857240 cycles Used 5838354 cycles Used 5829058 cycles Used 5826108 cycles Used 5892050 cycles Used 5907373 cycles Used 5837317 cycles Used 5885804 cycles Used 5944564 cycles Used 5837752 cycles Used 5832153 cycles Used 5883830 cycles Used 5883603 cycles Used 5804154 cycles Used 5852603 cycles Used 5826546 cycles Used 5843635 cycles Used 5797480 cycles Used 5846276 cycles Used 5891924 cycles Used 5849252 cycles Used 5857151 cycles Used 5881152 cycles Used 5924924 cycles Used 5872509 cycles Used 5805744 cycles Used 5831126 cycles Used 5844736 cycles Used 5827185 cycles Used 5848652 cycles Used 5863982 cycles Used 5873140 cycles Used 5937342 cycles Used 6000375 cycles Used 5840141 cycles Used 5906836 cycles Used 5974467 cycles Used 5811534 cycles Used 5866358 cycles Used 5850431 cycles Used 5822444 cycles Used 5817241 cycles Used 5836811 cycles Used 5912106 cycles Used 5859462 cycles Used 5861770 cycles Used 5897209 cycles Used 5779781 cycles Used 5844075 cycles Used 5801599 cycles Used 5852515 cycles Used 6151891 cycles Used 5809307 cycles Used 5817957 cycles Used 5842894 cycles Used 5878106 cycles Used 5867384 cycles Used 5905804 cycles Used 5856291 cycles Used 5916764 cycles Used 5851960 cycles Used 5846597 cycles Used 5833760 cycles Used 5806083 cycles Used 5838144 cycles Used 6102020 cycles Used 5883813 cycles Used 5853801 cycles Used 5883441 cycles Used 5827994 cycles Used 5918981 cycles Used 5788855 cycles Used 5824117 cycles Used 5890999 cycles Used 5828463 cycles Used 5870945 cycles Used 5876589 cycles Used 5789181 cycles Used 5843746 cycles [-- Attachment #4: syscalltest.S --] [-- Type: text/plain, Size: 413 bytes --] .globl main main: subi 1,1,12 stw 14,0(1) stw 15,4(1) stw 16,8(1) li 14, 10000 mftb 15 1: li 0, 24 sc li 0, 24 sc li 0, 24 sc li 0, 24 sc li 0, 24 sc li 0, 24 sc li 0, 24 sc li 0, 24 sc li 0, 24 sc li 0, 24 sc addic. 14,14,-1 bne 1b mftb 16 sub 4,16,15 lwz 14,0(1) lwz 15,4(1) lwz 16,8(1) addi 1,1,12 lis 3,msg@ha la 3,msg@l(3) b printf msg: .string "Used %d cycles\n" ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2005-11-15 0:19 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2005-11-11 21:37 [RFC] Attempt to clean up sigsuspend et al David Woodhouse 2005-11-12 0:28 ` Paul Mackerras 2005-11-12 0:48 ` David Woodhouse 2005-11-13 6:58 ` Paul Mackerras 2005-11-13 9:41 ` David Woodhouse 2005-11-13 10:09 ` Paul Mackerras 2005-11-13 11:58 ` David Woodhouse 2005-11-14 4:43 ` Paul Mackerras 2005-11-14 20:05 ` David Woodhouse 2005-11-15 0:19 ` David Woodhouse
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox