Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com) | |
3 | * Licensed under the GPL | |
4 | */ | |
5 | ||
6 | #include "linux/signal.h" | |
7 | #include "linux/ptrace.h" | |
8 | #include "asm/current.h" | |
9 | #include "asm/ucontext.h" | |
10 | #include "asm/uaccess.h" | |
11 | #include "asm/unistd.h" | |
12 | #include "frame_kern.h" | |
1da177e4 LT |
13 | #include "sigcontext.h" |
14 | #include "registers.h" | |
15 | #include "mode.h" | |
16 | ||
17 | #ifdef CONFIG_MODE_SKAS | |
18 | ||
19 | #include "skas.h" | |
20 | ||
21 | static int copy_sc_from_user_skas(struct pt_regs *regs, | |
4d338e1a | 22 | struct sigcontext __user *from) |
1da177e4 LT |
23 | { |
24 | struct sigcontext sc; | |
25 | unsigned long fpregs[HOST_FP_SIZE]; | |
26 | int err; | |
27 | ||
28 | err = copy_from_user(&sc, from, sizeof(sc)); | |
29 | err |= copy_from_user(fpregs, sc.fpstate, sizeof(fpregs)); | |
30 | if(err) | |
31 | return(err); | |
32 | ||
33 | REGS_GS(regs->regs.skas.regs) = sc.gs; | |
34 | REGS_FS(regs->regs.skas.regs) = sc.fs; | |
35 | REGS_ES(regs->regs.skas.regs) = sc.es; | |
36 | REGS_DS(regs->regs.skas.regs) = sc.ds; | |
37 | REGS_EDI(regs->regs.skas.regs) = sc.edi; | |
38 | REGS_ESI(regs->regs.skas.regs) = sc.esi; | |
39 | REGS_EBP(regs->regs.skas.regs) = sc.ebp; | |
40 | REGS_SP(regs->regs.skas.regs) = sc.esp; | |
41 | REGS_EBX(regs->regs.skas.regs) = sc.ebx; | |
42 | REGS_EDX(regs->regs.skas.regs) = sc.edx; | |
43 | REGS_ECX(regs->regs.skas.regs) = sc.ecx; | |
44 | REGS_EAX(regs->regs.skas.regs) = sc.eax; | |
45 | REGS_IP(regs->regs.skas.regs) = sc.eip; | |
46 | REGS_CS(regs->regs.skas.regs) = sc.cs; | |
47 | REGS_EFLAGS(regs->regs.skas.regs) = sc.eflags; | |
48 | REGS_SS(regs->regs.skas.regs) = sc.ss; | |
1da177e4 LT |
49 | |
50 | err = restore_fp_registers(userspace_pid[0], fpregs); | |
51 | if(err < 0){ | |
52 | printk("copy_sc_from_user_skas - PTRACE_SETFPREGS failed, " | |
53 | "errno = %d\n", err); | |
54 | return(1); | |
55 | } | |
56 | ||
57 | return(0); | |
58 | } | |
59 | ||
f983c45e | 60 | int copy_sc_to_user_skas(struct sigcontext __user *to, struct _fpstate __user *to_fp, |
98c18238 | 61 | struct pt_regs *regs, unsigned long sp) |
1da177e4 LT |
62 | { |
63 | struct sigcontext sc; | |
64 | unsigned long fpregs[HOST_FP_SIZE]; | |
c578455a | 65 | struct faultinfo * fi = ¤t->thread.arch.faultinfo; |
1da177e4 LT |
66 | int err; |
67 | ||
68 | sc.gs = REGS_GS(regs->regs.skas.regs); | |
69 | sc.fs = REGS_FS(regs->regs.skas.regs); | |
70 | sc.es = REGS_ES(regs->regs.skas.regs); | |
71 | sc.ds = REGS_DS(regs->regs.skas.regs); | |
72 | sc.edi = REGS_EDI(regs->regs.skas.regs); | |
73 | sc.esi = REGS_ESI(regs->regs.skas.regs); | |
74 | sc.ebp = REGS_EBP(regs->regs.skas.regs); | |
98c18238 | 75 | sc.esp = sp; |
1da177e4 LT |
76 | sc.ebx = REGS_EBX(regs->regs.skas.regs); |
77 | sc.edx = REGS_EDX(regs->regs.skas.regs); | |
78 | sc.ecx = REGS_ECX(regs->regs.skas.regs); | |
79 | sc.eax = REGS_EAX(regs->regs.skas.regs); | |
80 | sc.eip = REGS_IP(regs->regs.skas.regs); | |
81 | sc.cs = REGS_CS(regs->regs.skas.regs); | |
82 | sc.eflags = REGS_EFLAGS(regs->regs.skas.regs); | |
83 | sc.esp_at_signal = regs->regs.skas.regs[UESP]; | |
84 | sc.ss = regs->regs.skas.regs[SS]; | |
c578455a BS |
85 | sc.cr2 = fi->cr2; |
86 | sc.err = fi->error_code; | |
87 | sc.trapno = fi->trap_no; | |
1da177e4 LT |
88 | |
89 | err = save_fp_registers(userspace_pid[0], fpregs); | |
90 | if(err < 0){ | |
91 | printk("copy_sc_to_user_skas - PTRACE_GETFPREGS failed, " | |
92 | "errno = %d\n", err); | |
93 | return(1); | |
94 | } | |
4d338e1a | 95 | to_fp = (to_fp ? to_fp : (struct _fpstate __user *) (to + 1)); |
1da177e4 LT |
96 | sc.fpstate = to_fp; |
97 | ||
98 | if(err) | |
99 | return(err); | |
100 | ||
101 | return(copy_to_user(to, &sc, sizeof(sc)) || | |
102 | copy_to_user(to_fp, fpregs, sizeof(fpregs))); | |
103 | } | |
104 | #endif | |
105 | ||
106 | #ifdef CONFIG_MODE_TT | |
107 | ||
108 | /* These copy a sigcontext to/from userspace. They copy the fpstate pointer, | |
109 | * blowing away the old, good one. So, that value is saved, and then restored | |
110 | * after the sigcontext copy. In copy_from, the variable holding the saved | |
111 | * fpstate pointer, and the sigcontext that it should be restored to are both | |
112 | * in the kernel, so we can just restore using an assignment. In copy_to, the | |
113 | * saved pointer is in the kernel, but the sigcontext is in userspace, so we | |
114 | * copy_to_user it. | |
115 | */ | |
4d338e1a | 116 | int copy_sc_from_user_tt(struct sigcontext *to, struct sigcontext __user *from, |
1da177e4 LT |
117 | int fpsize) |
118 | { | |
4d338e1a AV |
119 | struct _fpstate *to_fp; |
120 | struct _fpstate __user *from_fp; | |
1da177e4 LT |
121 | unsigned long sigs; |
122 | int err; | |
123 | ||
124 | to_fp = to->fpstate; | |
1da177e4 LT |
125 | sigs = to->oldmask; |
126 | err = copy_from_user(to, from, sizeof(*to)); | |
e54a5dfb | 127 | from_fp = to->fpstate; |
1da177e4 LT |
128 | to->oldmask = sigs; |
129 | to->fpstate = to_fp; | |
130 | if(to_fp != NULL) | |
131 | err |= copy_from_user(to_fp, from_fp, fpsize); | |
132 | return(err); | |
133 | } | |
134 | ||
f983c45e | 135 | int copy_sc_to_user_tt(struct sigcontext __user *to, struct _fpstate __user *fp, |
98c18238 | 136 | struct sigcontext *from, int fpsize, unsigned long sp) |
1da177e4 | 137 | { |
4d338e1a AV |
138 | struct _fpstate __user *to_fp; |
139 | struct _fpstate *from_fp; | |
1da177e4 LT |
140 | int err; |
141 | ||
4d338e1a | 142 | to_fp = (fp ? fp : (struct _fpstate __user *) (to + 1)); |
1da177e4 LT |
143 | from_fp = from->fpstate; |
144 | err = copy_to_user(to, from, sizeof(*to)); | |
98c18238 JD |
145 | |
146 | /* The SP in the sigcontext is the updated one for the signal | |
147 | * delivery. The sp passed in is the original, and this needs | |
148 | * to be restored, so we stick it in separately. | |
149 | */ | |
f53389d8 | 150 | err |= copy_to_user(&SC_SP(to), &sp, sizeof(sp)); |
98c18238 | 151 | |
1da177e4 LT |
152 | if(from_fp != NULL){ |
153 | err |= copy_to_user(&to->fpstate, &to_fp, sizeof(to->fpstate)); | |
154 | err |= copy_to_user(to_fp, from_fp, fpsize); | |
155 | } | |
98c18238 | 156 | return err; |
1da177e4 LT |
157 | } |
158 | #endif | |
159 | ||
160 | static int copy_sc_from_user(struct pt_regs *to, void __user *from) | |
161 | { | |
162 | int ret; | |
163 | ||
164 | ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from, | |
165 | sizeof(struct _fpstate)), | |
166 | copy_sc_from_user_skas(to, from)); | |
167 | return(ret); | |
168 | } | |
169 | ||
f983c45e | 170 | static int copy_sc_to_user(struct sigcontext __user *to, struct _fpstate __user *fp, |
98c18238 | 171 | struct pt_regs *from, unsigned long sp) |
1da177e4 LT |
172 | { |
173 | return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), | |
98c18238 JD |
174 | sizeof(*fp), sp), |
175 | copy_sc_to_user_skas(to, fp, from, sp))); | |
1da177e4 LT |
176 | } |
177 | ||
4d338e1a | 178 | static int copy_ucontext_to_user(struct ucontext __user *uc, struct _fpstate __user *fp, |
1da177e4 LT |
179 | sigset_t *set, unsigned long sp) |
180 | { | |
181 | int err = 0; | |
182 | ||
183 | err |= put_user(current->sas_ss_sp, &uc->uc_stack.ss_sp); | |
184 | err |= put_user(sas_ss_flags(sp), &uc->uc_stack.ss_flags); | |
185 | err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size); | |
98c18238 | 186 | err |= copy_sc_to_user(&uc->uc_mcontext, fp, ¤t->thread.regs, sp); |
1da177e4 LT |
187 | err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set)); |
188 | return(err); | |
189 | } | |
190 | ||
191 | struct sigframe | |
192 | { | |
4d338e1a | 193 | char __user *pretcode; |
1da177e4 LT |
194 | int sig; |
195 | struct sigcontext sc; | |
196 | struct _fpstate fpstate; | |
197 | unsigned long extramask[_NSIG_WORDS-1]; | |
198 | char retcode[8]; | |
199 | }; | |
200 | ||
201 | struct rt_sigframe | |
202 | { | |
4d338e1a | 203 | char __user *pretcode; |
1da177e4 | 204 | int sig; |
4d338e1a AV |
205 | struct siginfo __user *pinfo; |
206 | void __user *puc; | |
1da177e4 LT |
207 | struct siginfo info; |
208 | struct ucontext uc; | |
209 | struct _fpstate fpstate; | |
210 | char retcode[8]; | |
211 | }; | |
212 | ||
213 | int setup_signal_stack_sc(unsigned long stack_top, int sig, | |
214 | struct k_sigaction *ka, struct pt_regs *regs, | |
215 | sigset_t *mask) | |
216 | { | |
217 | struct sigframe __user *frame; | |
4d338e1a | 218 | void __user *restorer; |
98c18238 | 219 | unsigned long save_sp = PT_REGS_SP(regs); |
1da177e4 LT |
220 | int err = 0; |
221 | ||
222 | stack_top &= -8UL; | |
4d338e1a | 223 | frame = (struct sigframe __user *) stack_top - 1; |
1da177e4 LT |
224 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
225 | return 1; | |
226 | ||
4d338e1a | 227 | restorer = frame->retcode; |
1da177e4 LT |
228 | if(ka->sa.sa_flags & SA_RESTORER) |
229 | restorer = ka->sa.sa_restorer; | |
230 | ||
98c18238 JD |
231 | /* Update SP now because the page fault handler refuses to extend |
232 | * the stack if the faulting address is too far below the current | |
233 | * SP, which frame now certainly is. If there's an error, the original | |
234 | * value is restored on the way out. | |
235 | * When writing the sigcontext to the stack, we have to write the | |
236 | * original value, so that's passed to copy_sc_to_user, which does | |
237 | * the right thing with it. | |
238 | */ | |
239 | PT_REGS_SP(regs) = (unsigned long) frame; | |
240 | ||
1da177e4 LT |
241 | err |= __put_user(restorer, &frame->pretcode); |
242 | err |= __put_user(sig, &frame->sig); | |
98c18238 | 243 | err |= copy_sc_to_user(&frame->sc, NULL, regs, save_sp); |
1da177e4 LT |
244 | err |= __put_user(mask->sig[0], &frame->sc.oldmask); |
245 | if (_NSIG_WORDS > 1) | |
246 | err |= __copy_to_user(&frame->extramask, &mask->sig[1], | |
247 | sizeof(frame->extramask)); | |
248 | ||
249 | /* | |
250 | * This is popl %eax ; movl $,%eax ; int $0x80 | |
251 | * | |
252 | * WE DO NOT USE IT ANY MORE! It's only left here for historical | |
253 | * reasons and because gdb uses it as a signature to notice | |
254 | * signal handler stack frames. | |
255 | */ | |
256 | err |= __put_user(0xb858, (short __user *)(frame->retcode+0)); | |
257 | err |= __put_user(__NR_sigreturn, (int __user *)(frame->retcode+2)); | |
258 | err |= __put_user(0x80cd, (short __user *)(frame->retcode+6)); | |
259 | ||
260 | if(err) | |
98c18238 | 261 | goto err; |
1da177e4 LT |
262 | |
263 | PT_REGS_SP(regs) = (unsigned long) frame; | |
264 | PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler; | |
265 | PT_REGS_EAX(regs) = (unsigned long) sig; | |
266 | PT_REGS_EDX(regs) = (unsigned long) 0; | |
267 | PT_REGS_ECX(regs) = (unsigned long) 0; | |
268 | ||
269 | if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED)) | |
270 | ptrace_notify(SIGTRAP); | |
98c18238 JD |
271 | return 0; |
272 | ||
273 | err: | |
274 | PT_REGS_SP(regs) = save_sp; | |
275 | return err; | |
1da177e4 LT |
276 | } |
277 | ||
278 | int setup_signal_stack_si(unsigned long stack_top, int sig, | |
279 | struct k_sigaction *ka, struct pt_regs *regs, | |
280 | siginfo_t *info, sigset_t *mask) | |
281 | { | |
282 | struct rt_sigframe __user *frame; | |
4d338e1a | 283 | void __user *restorer; |
98c18238 | 284 | unsigned long save_sp = PT_REGS_SP(regs); |
1da177e4 LT |
285 | int err = 0; |
286 | ||
287 | stack_top &= -8UL; | |
4d338e1a | 288 | frame = (struct rt_sigframe __user *) stack_top - 1; |
1da177e4 LT |
289 | if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) |
290 | return 1; | |
291 | ||
4d338e1a | 292 | restorer = frame->retcode; |
1da177e4 LT |
293 | if(ka->sa.sa_flags & SA_RESTORER) |
294 | restorer = ka->sa.sa_restorer; | |
295 | ||
98c18238 JD |
296 | /* See comment above about why this is here */ |
297 | PT_REGS_SP(regs) = (unsigned long) frame; | |
298 | ||
1da177e4 LT |
299 | err |= __put_user(restorer, &frame->pretcode); |
300 | err |= __put_user(sig, &frame->sig); | |
301 | err |= __put_user(&frame->info, &frame->pinfo); | |
302 | err |= __put_user(&frame->uc, &frame->puc); | |
303 | err |= copy_siginfo_to_user(&frame->info, info); | |
304 | err |= copy_ucontext_to_user(&frame->uc, &frame->fpstate, mask, | |
98c18238 | 305 | save_sp); |
1da177e4 LT |
306 | |
307 | /* | |
308 | * This is movl $,%eax ; int $0x80 | |
309 | * | |
310 | * WE DO NOT USE IT ANY MORE! It's only left here for historical | |
311 | * reasons and because gdb uses it as a signature to notice | |
312 | * signal handler stack frames. | |
313 | */ | |
314 | err |= __put_user(0xb8, (char __user *)(frame->retcode+0)); | |
315 | err |= __put_user(__NR_rt_sigreturn, (int __user *)(frame->retcode+1)); | |
316 | err |= __put_user(0x80cd, (short __user *)(frame->retcode+5)); | |
317 | ||
318 | if(err) | |
98c18238 | 319 | goto err; |
1da177e4 | 320 | |
1da177e4 LT |
321 | PT_REGS_IP(regs) = (unsigned long) ka->sa.sa_handler; |
322 | PT_REGS_EAX(regs) = (unsigned long) sig; | |
323 | PT_REGS_EDX(regs) = (unsigned long) &frame->info; | |
324 | PT_REGS_ECX(regs) = (unsigned long) &frame->uc; | |
325 | ||
326 | if ((current->ptrace & PT_DTRACE) && (current->ptrace & PT_PTRACED)) | |
327 | ptrace_notify(SIGTRAP); | |
98c18238 JD |
328 | return 0; |
329 | ||
330 | err: | |
331 | PT_REGS_SP(regs) = save_sp; | |
332 | return err; | |
1da177e4 LT |
333 | } |
334 | ||
335 | long sys_sigreturn(struct pt_regs regs) | |
336 | { | |
337 | unsigned long sp = PT_REGS_SP(¤t->thread.regs); | |
4d338e1a | 338 | struct sigframe __user *frame = (struct sigframe __user *)(sp - 8); |
1da177e4 LT |
339 | sigset_t set; |
340 | struct sigcontext __user *sc = &frame->sc; | |
341 | unsigned long __user *oldmask = &sc->oldmask; | |
342 | unsigned long __user *extramask = frame->extramask; | |
343 | int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long); | |
344 | ||
350d5bd8 | 345 | if(copy_from_user(&set.sig[0], oldmask, sizeof(set.sig[0])) || |
1da177e4 LT |
346 | copy_from_user(&set.sig[1], extramask, sig_size)) |
347 | goto segfault; | |
348 | ||
349 | sigdelsetmask(&set, ~_BLOCKABLE); | |
350 | ||
351 | spin_lock_irq(¤t->sighand->siglock); | |
352 | current->blocked = set; | |
353 | recalc_sigpending(); | |
354 | spin_unlock_irq(¤t->sighand->siglock); | |
355 | ||
356 | if(copy_sc_from_user(¤t->thread.regs, sc)) | |
357 | goto segfault; | |
358 | ||
359 | /* Avoid ERESTART handling */ | |
360 | PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; | |
361 | return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); | |
362 | ||
363 | segfault: | |
364 | force_sig(SIGSEGV, current); | |
365 | return 0; | |
366 | } | |
367 | ||
368 | long sys_rt_sigreturn(struct pt_regs regs) | |
369 | { | |
4d338e1a AV |
370 | unsigned long sp = PT_REGS_SP(¤t->thread.regs); |
371 | struct rt_sigframe __user *frame = (struct rt_sigframe __user *) (sp - 4); | |
1da177e4 LT |
372 | sigset_t set; |
373 | struct ucontext __user *uc = &frame->uc; | |
374 | int sig_size = _NSIG_WORDS * sizeof(unsigned long); | |
375 | ||
376 | if(copy_from_user(&set, &uc->uc_sigmask, sig_size)) | |
377 | goto segfault; | |
378 | ||
379 | sigdelsetmask(&set, ~_BLOCKABLE); | |
380 | ||
381 | spin_lock_irq(¤t->sighand->siglock); | |
382 | current->blocked = set; | |
383 | recalc_sigpending(); | |
384 | spin_unlock_irq(¤t->sighand->siglock); | |
385 | ||
386 | if(copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext)) | |
387 | goto segfault; | |
388 | ||
389 | /* Avoid ERESTART handling */ | |
390 | PT_REGS_SYSCALL_NR(¤t->thread.regs) = -1; | |
391 | return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); | |
392 | ||
393 | segfault: | |
394 | force_sig(SIGSEGV, current); | |
395 | return 0; | |
396 | } | |
397 | ||
398 | /* | |
399 | * Overrides for Emacs so that we follow Linus's tabbing style. | |
400 | * Emacs will notice this stuff at the end of the file and automatically | |
401 | * adjust the settings for this buffer only. This must remain at the end | |
402 | * of the file. | |
403 | * --------------------------------------------------------------------------- | |
404 | * Local variables: | |
405 | * c-file-style: "linux" | |
406 | * End: | |
407 | */ |