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