diff options
Diffstat (limited to 'arch/xtensa/kernel/signal.c')
-rw-r--r-- | arch/xtensa/kernel/signal.c | 65 |
1 files changed, 42 insertions, 23 deletions
diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c index 42d9fd8a4225..299be42d116b 100644 --- a/arch/xtensa/kernel/signal.c +++ b/arch/xtensa/kernel/signal.c | |||
@@ -35,13 +35,17 @@ asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset); | |||
35 | 35 | ||
36 | extern struct task_struct *coproc_owners[]; | 36 | extern struct task_struct *coproc_owners[]; |
37 | 37 | ||
38 | extern void release_all_cp (struct task_struct *); | ||
39 | |||
40 | struct rt_sigframe | 38 | struct rt_sigframe |
41 | { | 39 | { |
42 | struct siginfo info; | 40 | struct siginfo info; |
43 | struct ucontext uc; | 41 | struct ucontext uc; |
44 | cp_state_t cpstate; | 42 | struct { |
43 | xtregs_opt_t opt; | ||
44 | xtregs_user_t user; | ||
45 | #if XTENSA_HAVE_COPROCESSORS | ||
46 | xtregs_coprocessor_t cp; | ||
47 | #endif | ||
48 | } xtregs; | ||
45 | unsigned char retcode[6]; | 49 | unsigned char retcode[6]; |
46 | unsigned int window[4]; | 50 | unsigned int window[4]; |
47 | }; | 51 | }; |
@@ -132,9 +136,10 @@ errout: | |||
132 | */ | 136 | */ |
133 | 137 | ||
134 | static int | 138 | static int |
135 | setup_sigcontext(struct sigcontext __user *sc, cp_state_t *cpstate, | 139 | setup_sigcontext(struct rt_sigframe __user *frame, struct pt_regs *regs) |
136 | struct pt_regs *regs) | ||
137 | { | 140 | { |
141 | struct sigcontext __user *sc = &frame->uc.uc_mcontext; | ||
142 | struct thread_info *ti = current_thread_info(); | ||
138 | int err = 0; | 143 | int err = 0; |
139 | 144 | ||
140 | #define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) | 145 | #define COPY(x) err |= __put_user(regs->x, &sc->sc_##x) |
@@ -148,21 +153,32 @@ setup_sigcontext(struct sigcontext __user *sc, cp_state_t *cpstate, | |||
148 | 153 | ||
149 | err |= flush_window_regs_user(regs); | 154 | err |= flush_window_regs_user(regs); |
150 | err |= __copy_to_user (sc->sc_a, regs->areg, 16 * 4); | 155 | err |= __copy_to_user (sc->sc_a, regs->areg, 16 * 4); |
156 | err |= __put_user(0, &sc->sc_xtregs); | ||
151 | 157 | ||
152 | // err |= __copy_to_user (sc->sc_a, regs->areg, XCHAL_NUM_AREGS * 4) | 158 | if (err) |
159 | return err; | ||
153 | 160 | ||
154 | #if XCHAL_HAVE_CP | 161 | #if XTENSA_HAVE_COPROCESSORS |
155 | # error Coprocessors unsupported | 162 | coprocessor_flush_all(ti); |
156 | err |= save_cpextra(cpstate); | 163 | coprocessor_release_all(ti); |
157 | err |= __put_user(err ? NULL : cpstate, &sc->sc_cpstate); | 164 | err |= __copy_to_user(&frame->xtregs.cp, &ti->xtregs_cp, |
165 | sizeof (frame->xtregs.cp)); | ||
158 | #endif | 166 | #endif |
167 | err |= __copy_to_user(&frame->xtregs.opt, ®s->xtregs_opt, | ||
168 | sizeof (xtregs_opt_t)); | ||
169 | err |= __copy_to_user(&frame->xtregs.user, &ti->xtregs_user, | ||
170 | sizeof (xtregs_user_t)); | ||
171 | |||
172 | err |= __put_user(err ? NULL : &frame->xtregs, &sc->sc_xtregs); | ||
159 | 173 | ||
160 | return err; | 174 | return err; |
161 | } | 175 | } |
162 | 176 | ||
163 | static int | 177 | static int |
164 | restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | 178 | restore_sigcontext(struct pt_regs *regs, struct rt_sigframe __user *frame) |
165 | { | 179 | { |
180 | struct sigcontext __user *sc = &frame->uc.uc_mcontext; | ||
181 | struct thread_info *ti = current_thread_info(); | ||
166 | unsigned int err = 0; | 182 | unsigned int err = 0; |
167 | unsigned long ps; | 183 | unsigned long ps; |
168 | 184 | ||
@@ -180,6 +196,8 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | |||
180 | regs->windowbase = 0; | 196 | regs->windowbase = 0; |
181 | regs->windowstart = 1; | 197 | regs->windowstart = 1; |
182 | 198 | ||
199 | regs->syscall = -1; /* disable syscall checks */ | ||
200 | |||
183 | /* For PS, restore only PS.CALLINC. | 201 | /* For PS, restore only PS.CALLINC. |
184 | * Assume that all other bits are either the same as for the signal | 202 | * Assume that all other bits are either the same as for the signal |
185 | * handler, or the user mode value doesn't matter (e.g. PS.OWB). | 203 | * handler, or the user mode value doesn't matter (e.g. PS.OWB). |
@@ -195,8 +213,9 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | |||
195 | 213 | ||
196 | err |= __copy_from_user(regs->areg, sc->sc_a, 16 * 4); | 214 | err |= __copy_from_user(regs->areg, sc->sc_a, 16 * 4); |
197 | 215 | ||
198 | #if XCHAL_HAVE_CP | 216 | if (err) |
199 | # error Coprocessors unsupported | 217 | return err; |
218 | |||
200 | /* The signal handler may have used coprocessors in which | 219 | /* The signal handler may have used coprocessors in which |
201 | * case they are still enabled. We disable them to force a | 220 | * case they are still enabled. We disable them to force a |
202 | * reloading of the original task's CP state by the lazy | 221 | * reloading of the original task's CP state by the lazy |
@@ -204,20 +223,20 @@ restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) | |||
204 | * Also, we essentially discard any coprocessor state that the | 223 | * Also, we essentially discard any coprocessor state that the |
205 | * signal handler created. */ | 224 | * signal handler created. */ |
206 | 225 | ||
207 | if (!err) { | 226 | #if XTENSA_HAVE_COPROCESSORS |
208 | struct task_struct *tsk = current; | 227 | coprocessor_release_all(ti); |
209 | release_all_cp(tsk); | 228 | err |= __copy_from_user(&ti->xtregs_cp, &frame->xtregs.cp, |
210 | err |= __copy_from_user(tsk->thread.cpextra, sc->sc_cpstate, | 229 | sizeof (frame->xtregs.cp)); |
211 | XTENSA_CP_EXTRA_SIZE); | ||
212 | } | ||
213 | #endif | 230 | #endif |
231 | err |= __copy_from_user(&ti->xtregs_user, &frame->xtregs.user, | ||
232 | sizeof (xtregs_user_t)); | ||
233 | err |= __copy_from_user(®s->xtregs_opt, &frame->xtregs.opt, | ||
234 | sizeof (xtregs_opt_t)); | ||
214 | 235 | ||
215 | regs->syscall = -1; /* disable syscall checks */ | ||
216 | return err; | 236 | return err; |
217 | } | 237 | } |
218 | 238 | ||
219 | 239 | ||
220 | |||
221 | /* | 240 | /* |
222 | * Do a signal return; undo the signal stack. | 241 | * Do a signal return; undo the signal stack. |
223 | */ | 242 | */ |
@@ -246,7 +265,7 @@ asmlinkage long xtensa_rt_sigreturn(long a0, long a1, long a2, long a3, | |||
246 | recalc_sigpending(); | 265 | recalc_sigpending(); |
247 | spin_unlock_irq(¤t->sighand->siglock); | 266 | spin_unlock_irq(¤t->sighand->siglock); |
248 | 267 | ||
249 | if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) | 268 | if (restore_sigcontext(regs, frame)) |
250 | goto badframe; | 269 | goto badframe; |
251 | 270 | ||
252 | ret = regs->areg[2]; | 271 | ret = regs->areg[2]; |
@@ -359,7 +378,7 @@ static void setup_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
359 | err |= __put_user(sas_ss_flags(regs->areg[1]), | 378 | err |= __put_user(sas_ss_flags(regs->areg[1]), |
360 | &frame->uc.uc_stack.ss_flags); | 379 | &frame->uc.uc_stack.ss_flags); |
361 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); | 380 | err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); |
362 | err |= setup_sigcontext(&frame->uc.uc_mcontext, &frame->cpstate, regs); | 381 | err |= setup_sigcontext(frame, regs); |
363 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); | 382 | err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); |
364 | 383 | ||
365 | /* Create sys_rt_sigreturn syscall in stack frame */ | 384 | /* Create sys_rt_sigreturn syscall in stack frame */ |