diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2006-01-19 05:42:49 -0500 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-01-19 05:42:49 -0500 |
commit | 2d7d5f05111a9d913131a2764d8b20157f8f758d (patch) | |
tree | 792deb7a3b9f72894d16affff1569a15b35e428b /arch/sparc | |
parent | f7111ceb5266750db2a1d193b98fb6a3d9b5a56a (diff) |
[SPARC]: Add support for *at(), ppoll, and pselect syscalls.
This also includes by necessity _TIF_RESTORE_SIGMASK support,
which actually resulted in a lot of cleanups.
The sparc signal handling code is quite a mess and I should
clean it up some day.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc')
-rw-r--r-- | arch/sparc/kernel/entry.S | 56 | ||||
-rw-r--r-- | arch/sparc/kernel/rtrap.S | 9 | ||||
-rw-r--r-- | arch/sparc/kernel/signal.c | 117 | ||||
-rw-r--r-- | arch/sparc/kernel/sparc_ksyms.c | 2 | ||||
-rw-r--r-- | arch/sparc/kernel/systbls.S | 10 |
5 files changed, 44 insertions, 150 deletions
diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index 03ecb4e4614e..c51d08d218ef 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S | |||
@@ -1277,62 +1277,6 @@ sys_sigstack: | |||
1277 | mov %l5, %o7 | 1277 | mov %l5, %o7 |
1278 | 1278 | ||
1279 | .align 4 | 1279 | .align 4 |
1280 | .globl sys_sigpause | ||
1281 | sys_sigpause: | ||
1282 | /* Note: %o0 already has correct value... */ | ||
1283 | call do_sigpause | ||
1284 | add %sp, STACKFRAME_SZ, %o1 | ||
1285 | |||
1286 | ld [%curptr + TI_FLAGS], %l5 | ||
1287 | andcc %l5, _TIF_SYSCALL_TRACE, %g0 | ||
1288 | be 1f | ||
1289 | nop | ||
1290 | |||
1291 | call syscall_trace | ||
1292 | nop | ||
1293 | |||
1294 | 1: | ||
1295 | /* We are returning to a signal handler. */ | ||
1296 | RESTORE_ALL | ||
1297 | |||
1298 | .align 4 | ||
1299 | .globl sys_sigsuspend | ||
1300 | sys_sigsuspend: | ||
1301 | call do_sigsuspend | ||
1302 | add %sp, STACKFRAME_SZ, %o0 | ||
1303 | |||
1304 | ld [%curptr + TI_FLAGS], %l5 | ||
1305 | andcc %l5, _TIF_SYSCALL_TRACE, %g0 | ||
1306 | be 1f | ||
1307 | nop | ||
1308 | |||
1309 | call syscall_trace | ||
1310 | nop | ||
1311 | |||
1312 | 1: | ||
1313 | /* We are returning to a signal handler. */ | ||
1314 | RESTORE_ALL | ||
1315 | |||
1316 | .align 4 | ||
1317 | .globl sys_rt_sigsuspend | ||
1318 | sys_rt_sigsuspend: | ||
1319 | /* Note: %o0, %o1 already have correct value... */ | ||
1320 | call do_rt_sigsuspend | ||
1321 | add %sp, STACKFRAME_SZ, %o2 | ||
1322 | |||
1323 | ld [%curptr + TI_FLAGS], %l5 | ||
1324 | andcc %l5, _TIF_SYSCALL_TRACE, %g0 | ||
1325 | be 1f | ||
1326 | nop | ||
1327 | |||
1328 | call syscall_trace | ||
1329 | nop | ||
1330 | |||
1331 | 1: | ||
1332 | /* We are returning to a signal handler. */ | ||
1333 | RESTORE_ALL | ||
1334 | |||
1335 | .align 4 | ||
1336 | .globl sys_sigreturn | 1280 | .globl sys_sigreturn |
1337 | sys_sigreturn: | 1281 | sys_sigreturn: |
1338 | call do_sigreturn | 1282 | call do_sigreturn |
diff --git a/arch/sparc/kernel/rtrap.S b/arch/sparc/kernel/rtrap.S index f7460d897e79..77ca6fd81253 100644 --- a/arch/sparc/kernel/rtrap.S +++ b/arch/sparc/kernel/rtrap.S | |||
@@ -68,15 +68,14 @@ ret_trap_lockless_ipi: | |||
68 | 68 | ||
69 | ld [%curptr + TI_FLAGS], %g2 | 69 | ld [%curptr + TI_FLAGS], %g2 |
70 | signal_p: | 70 | signal_p: |
71 | andcc %g2, (_TIF_NOTIFY_RESUME|_TIF_SIGPENDING), %g0 | 71 | andcc %g2, (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK), %g0 |
72 | bz,a ret_trap_continue | 72 | bz,a ret_trap_continue |
73 | ld [%sp + STACKFRAME_SZ + PT_PSR], %t_psr | 73 | ld [%sp + STACKFRAME_SZ + PT_PSR], %t_psr |
74 | 74 | ||
75 | clr %o0 | 75 | mov %l5, %o1 |
76 | mov %l5, %o2 | 76 | mov %l6, %o2 |
77 | mov %l6, %o3 | ||
78 | call do_signal | 77 | call do_signal |
79 | add %sp, STACKFRAME_SZ, %o1 ! pt_regs ptr | 78 | add %sp, STACKFRAME_SZ, %o0 ! pt_regs ptr |
80 | 79 | ||
81 | /* Fall through. */ | 80 | /* Fall through. */ |
82 | ld [%sp + STACKFRAME_SZ + PT_PSR], %t_psr | 81 | ld [%sp + STACKFRAME_SZ + PT_PSR], %t_psr |
diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c index 5f34d7dc2b89..0748d8147bbf 100644 --- a/arch/sparc/kernel/signal.c +++ b/arch/sparc/kernel/signal.c | |||
@@ -35,9 +35,6 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr, | |||
35 | void *fpqueue, unsigned long *fpqdepth); | 35 | void *fpqueue, unsigned long *fpqdepth); |
36 | extern void fpload(unsigned long *fpregs, unsigned long *fsr); | 36 | extern void fpload(unsigned long *fpregs, unsigned long *fsr); |
37 | 37 | ||
38 | asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, | ||
39 | unsigned long orig_o0, int restart_syscall); | ||
40 | |||
41 | /* Signal frames: the original one (compatible with SunOS): | 38 | /* Signal frames: the original one (compatible with SunOS): |
42 | * | 39 | * |
43 | * Set up a signal frame... Make the stack look the way SunOS | 40 | * Set up a signal frame... Make the stack look the way SunOS |
@@ -95,98 +92,30 @@ struct rt_signal_frame { | |||
95 | #define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame) + 7) & (~7))) | 92 | #define NF_ALIGNEDSZ (((sizeof(struct new_signal_frame) + 7) & (~7))) |
96 | #define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame) + 7) & (~7))) | 93 | #define RT_ALIGNEDSZ (((sizeof(struct rt_signal_frame) + 7) & (~7))) |
97 | 94 | ||
98 | /* | 95 | static int _sigpause_common(old_sigset_t set) |
99 | * atomically swap in the new signal mask, and wait for a signal. | ||
100 | * This is really tricky on the Sparc, watch out... | ||
101 | */ | ||
102 | asmlinkage void _sigpause_common(old_sigset_t set, struct pt_regs *regs) | ||
103 | { | 96 | { |
104 | sigset_t saveset; | ||
105 | |||
106 | set &= _BLOCKABLE; | 97 | set &= _BLOCKABLE; |
107 | spin_lock_irq(¤t->sighand->siglock); | 98 | spin_lock_irq(¤t->sighand->siglock); |
108 | saveset = current->blocked; | 99 | current->saved_sigmask = current->blocked; |
109 | siginitset(¤t->blocked, set); | 100 | siginitset(¤t->blocked, set); |
110 | recalc_sigpending(); | 101 | recalc_sigpending(); |
111 | spin_unlock_irq(¤t->sighand->siglock); | 102 | spin_unlock_irq(¤t->sighand->siglock); |
112 | 103 | ||
113 | regs->pc = regs->npc; | 104 | current->state = TASK_INTERRUPTIBLE; |
114 | regs->npc += 4; | 105 | schedule(); |
115 | 106 | set_thread_flag(TIF_RESTORE_SIGMASK); | |
116 | /* Condition codes and return value where set here for sigpause, | ||
117 | * and so got used by setup_frame, which again causes sigreturn() | ||
118 | * to return -EINTR. | ||
119 | */ | ||
120 | while (1) { | ||
121 | current->state = TASK_INTERRUPTIBLE; | ||
122 | schedule(); | ||
123 | /* | ||
124 | * Return -EINTR and set condition code here, | ||
125 | * so the interrupted system call actually returns | ||
126 | * these. | ||
127 | */ | ||
128 | regs->psr |= PSR_C; | ||
129 | regs->u_regs[UREG_I0] = EINTR; | ||
130 | if (do_signal(&saveset, regs, 0, 0)) | ||
131 | return; | ||
132 | } | ||
133 | } | ||
134 | 107 | ||
135 | asmlinkage void do_sigpause(unsigned int set, struct pt_regs *regs) | 108 | return -ERESTARTNOHAND; |
136 | { | ||
137 | _sigpause_common(set, regs); | ||
138 | } | 109 | } |
139 | 110 | ||
140 | asmlinkage void do_sigsuspend (struct pt_regs *regs) | 111 | asmlinkage int sys_sigpause(unsigned int set) |
141 | { | 112 | { |
142 | _sigpause_common(regs->u_regs[UREG_I0], regs); | 113 | return _sigpause_common(set); |
143 | } | 114 | } |
144 | 115 | ||
145 | asmlinkage void do_rt_sigsuspend(sigset_t __user *uset, size_t sigsetsize, | 116 | asmlinkage int sys_sigsuspend(old_sigset_t set) |
146 | struct pt_regs *regs) | ||
147 | { | 117 | { |
148 | sigset_t oldset, set; | 118 | return _sigpause_common(set); |
149 | |||
150 | /* XXX: Don't preclude handling different sized sigset_t's. */ | ||
151 | if (sigsetsize != sizeof(sigset_t)) { | ||
152 | regs->psr |= PSR_C; | ||
153 | regs->u_regs[UREG_I0] = EINVAL; | ||
154 | return; | ||
155 | } | ||
156 | |||
157 | if (copy_from_user(&set, uset, sizeof(set))) { | ||
158 | regs->psr |= PSR_C; | ||
159 | regs->u_regs[UREG_I0] = EFAULT; | ||
160 | return; | ||
161 | } | ||
162 | |||
163 | sigdelsetmask(&set, ~_BLOCKABLE); | ||
164 | spin_lock_irq(¤t->sighand->siglock); | ||
165 | oldset = current->blocked; | ||
166 | current->blocked = set; | ||
167 | recalc_sigpending(); | ||
168 | spin_unlock_irq(¤t->sighand->siglock); | ||
169 | |||
170 | regs->pc = regs->npc; | ||
171 | regs->npc += 4; | ||
172 | |||
173 | /* Condition codes and return value where set here for sigpause, | ||
174 | * and so got used by setup_frame, which again causes sigreturn() | ||
175 | * to return -EINTR. | ||
176 | */ | ||
177 | while (1) { | ||
178 | current->state = TASK_INTERRUPTIBLE; | ||
179 | schedule(); | ||
180 | /* | ||
181 | * Return -EINTR and set condition code here, | ||
182 | * so the interrupted system call actually returns | ||
183 | * these. | ||
184 | */ | ||
185 | regs->psr |= PSR_C; | ||
186 | regs->u_regs[UREG_I0] = EINTR; | ||
187 | if (do_signal(&oldset, regs, 0, 0)) | ||
188 | return; | ||
189 | } | ||
190 | } | 119 | } |
191 | 120 | ||
192 | static inline int | 121 | static inline int |
@@ -1067,13 +996,13 @@ static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, | |||
1067 | * want to handle. Thus you cannot kill init even with a SIGKILL even by | 996 | * want to handle. Thus you cannot kill init even with a SIGKILL even by |
1068 | * mistake. | 997 | * mistake. |
1069 | */ | 998 | */ |
1070 | asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, | 999 | asmlinkage void do_signal(struct pt_regs * regs, unsigned long orig_i0, int restart_syscall) |
1071 | unsigned long orig_i0, int restart_syscall) | ||
1072 | { | 1000 | { |
1073 | siginfo_t info; | 1001 | siginfo_t info; |
1074 | struct sparc_deliver_cookie cookie; | 1002 | struct sparc_deliver_cookie cookie; |
1075 | struct k_sigaction ka; | 1003 | struct k_sigaction ka; |
1076 | int signr; | 1004 | int signr; |
1005 | sigset_t *oldset; | ||
1077 | 1006 | ||
1078 | /* | 1007 | /* |
1079 | * XXX Disable svr4 signal handling until solaris emulation works. | 1008 | * XXX Disable svr4 signal handling until solaris emulation works. |
@@ -1089,7 +1018,9 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, | |||
1089 | cookie.restart_syscall = restart_syscall; | 1018 | cookie.restart_syscall = restart_syscall; |
1090 | cookie.orig_i0 = orig_i0; | 1019 | cookie.orig_i0 = orig_i0; |
1091 | 1020 | ||
1092 | if (!oldset) | 1021 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) |
1022 | oldset = ¤t->saved_sigmask; | ||
1023 | else | ||
1093 | oldset = ¤t->blocked; | 1024 | oldset = ¤t->blocked; |
1094 | 1025 | ||
1095 | signr = get_signal_to_deliver(&info, &ka, regs, &cookie); | 1026 | signr = get_signal_to_deliver(&info, &ka, regs, &cookie); |
@@ -1098,7 +1029,14 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, | |||
1098 | syscall_restart(cookie.orig_i0, regs, &ka.sa); | 1029 | syscall_restart(cookie.orig_i0, regs, &ka.sa); |
1099 | handle_signal(signr, &ka, &info, oldset, | 1030 | handle_signal(signr, &ka, &info, oldset, |
1100 | regs, svr4_signal); | 1031 | regs, svr4_signal); |
1101 | return 1; | 1032 | /* a signal was successfully delivered; the saved |
1033 | * sigmask will have been stored in the signal frame, | ||
1034 | * and will be restored by sigreturn, so we can simply | ||
1035 | * clear the TIF_RESTORE_SIGMASK flag. | ||
1036 | */ | ||
1037 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | ||
1038 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
1039 | return; | ||
1102 | } | 1040 | } |
1103 | if (cookie.restart_syscall && | 1041 | if (cookie.restart_syscall && |
1104 | (regs->u_regs[UREG_I0] == ERESTARTNOHAND || | 1042 | (regs->u_regs[UREG_I0] == ERESTARTNOHAND || |
@@ -1115,7 +1053,14 @@ asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, | |||
1115 | regs->pc -= 4; | 1053 | regs->pc -= 4; |
1116 | regs->npc -= 4; | 1054 | regs->npc -= 4; |
1117 | } | 1055 | } |
1118 | return 0; | 1056 | |
1057 | /* if there's no signal to deliver, we just put the saved sigmask | ||
1058 | * back | ||
1059 | */ | ||
1060 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) { | ||
1061 | clear_thread_flag(TIF_RESTORE_SIGMASK); | ||
1062 | sigprocmask(SIG_SETMASK, ¤t->saved_sigmask, NULL); | ||
1063 | } | ||
1119 | } | 1064 | } |
1120 | 1065 | ||
1121 | asmlinkage int | 1066 | asmlinkage int |
diff --git a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c index 0b0d492c953b..19b25399d7e4 100644 --- a/arch/sparc/kernel/sparc_ksyms.c +++ b/arch/sparc/kernel/sparc_ksyms.c | |||
@@ -66,7 +66,6 @@ struct poll { | |||
66 | 66 | ||
67 | extern int svr4_getcontext (svr4_ucontext_t *, struct pt_regs *); | 67 | extern int svr4_getcontext (svr4_ucontext_t *, struct pt_regs *); |
68 | extern int svr4_setcontext (svr4_ucontext_t *, struct pt_regs *); | 68 | extern int svr4_setcontext (svr4_ucontext_t *, struct pt_regs *); |
69 | void _sigpause_common (unsigned int set, struct pt_regs *); | ||
70 | extern void (*__copy_1page)(void *, const void *); | 69 | extern void (*__copy_1page)(void *, const void *); |
71 | extern void __memmove(void *, const void *, __kernel_size_t); | 70 | extern void __memmove(void *, const void *, __kernel_size_t); |
72 | extern void (*bzero_1page)(void *); | 71 | extern void (*bzero_1page)(void *); |
@@ -227,7 +226,6 @@ EXPORT_SYMBOL(kunmap_atomic); | |||
227 | /* Solaris/SunOS binary compatibility */ | 226 | /* Solaris/SunOS binary compatibility */ |
228 | EXPORT_SYMBOL(svr4_setcontext); | 227 | EXPORT_SYMBOL(svr4_setcontext); |
229 | EXPORT_SYMBOL(svr4_getcontext); | 228 | EXPORT_SYMBOL(svr4_getcontext); |
230 | EXPORT_SYMBOL(_sigpause_common); | ||
231 | 229 | ||
232 | EXPORT_SYMBOL(dump_thread); | 230 | EXPORT_SYMBOL(dump_thread); |
233 | 231 | ||
diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S index e457a40838fc..6877ae4cd1d9 100644 --- a/arch/sparc/kernel/systbls.S +++ b/arch/sparc/kernel/systbls.S | |||
@@ -75,7 +75,10 @@ sys_call_table: | |||
75 | /*265*/ .long sys_timer_delete, sys_timer_create, sys_nis_syscall, sys_io_setup, sys_io_destroy | 75 | /*265*/ .long sys_timer_delete, sys_timer_create, sys_nis_syscall, sys_io_setup, sys_io_destroy |
76 | /*270*/ .long sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink | 76 | /*270*/ .long sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink |
77 | /*275*/ .long sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_waitid | 77 | /*275*/ .long sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_waitid |
78 | /*280*/ .long sys_ni_syscall, sys_add_key, sys_request_key, sys_keyctl | 78 | /*280*/ .long sys_ni_syscall, sys_add_key, sys_request_key, sys_keyctl, sys_openat |
79 | /*285*/ .long sys_mkdirat, sys_mknodat, sys_fchownat, sys_futimesat, sys_newfstatat | ||
80 | /*290*/ .long sys_unlinkat, sys_renameat, sys_linkat, sys_symlinkat, sys_readlinkat | ||
81 | /*295*/ .long sys_fchmodat, sys_faccessat, sys_pselect6, sys_ppoll | ||
79 | 82 | ||
80 | #ifdef CONFIG_SUNOS_EMUL | 83 | #ifdef CONFIG_SUNOS_EMUL |
81 | /* Now the SunOS syscall table. */ | 84 | /* Now the SunOS syscall table. */ |
@@ -181,6 +184,11 @@ sunos_sys_table: | |||
181 | .long sunos_nosys, sunos_nosys, sunos_nosys | 184 | .long sunos_nosys, sunos_nosys, sunos_nosys |
182 | .long sunos_nosys | 185 | .long sunos_nosys |
183 | /*280*/ .long sunos_nosys, sunos_nosys, sunos_nosys | 186 | /*280*/ .long sunos_nosys, sunos_nosys, sunos_nosys |
187 | .long sunos_nosys, sunos_nosys, sunos_nosys | ||
188 | .long sunos_nosys, sunos_nosys, sunos_nosys | ||
184 | .long sunos_nosys | 189 | .long sunos_nosys |
190 | /*290*/ .long sunos_nosys, sunos_nosys, sunos_nosys | ||
191 | .long sunos_nosys, sunos_nosys, sunos_nosys | ||
192 | .long sunos_nosys, sunos_nosys, sunos_nosys | ||
185 | 193 | ||
186 | #endif | 194 | #endif |