aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/signal_32.c
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/signal_32.c
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/signal_32.c')
-rw-r--r--arch/powerpc/kernel/signal_32.c59
1 files changed, 23 insertions, 36 deletions
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);