This source file includes following definitions.
- sys_sigsuspend
- restore_i387_hard
- restore_i387
- sys_sigreturn
- save_i387_hard
- save_i387
- setup_frame
- handle_signal
- do_signal
1
2
3
4
5
6
7 #include <linux/config.h>
8
9 #include <linux/sched.h>
10 #include <linux/mm.h>
11 #include <linux/kernel.h>
12 #include <linux/signal.h>
13 #include <linux/errno.h>
14 #include <linux/wait.h>
15 #include <linux/ptrace.h>
16 #include <linux/unistd.h>
17
18 #include <asm/segment.h>
19
20 #define _S(nr) (1<<((nr)-1))
21
22 #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))
23
24 asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
25 asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs);
26
27
28
29
30 asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set)
31 {
32 unsigned long mask;
33 struct pt_regs * regs = (struct pt_regs *) &restart;
34
35 mask = current->blocked;
36 current->blocked = set & _BLOCKABLE;
37 regs->eax = -EINTR;
38 while (1) {
39 current->state = TASK_INTERRUPTIBLE;
40 schedule();
41 if (do_signal(mask,regs))
42 return -EINTR;
43 }
44 }
45
46
47
48
49 #define restore_i387_soft(x) do { } while (0)
50
51 static inline void restore_i387_hard(struct _fpstate *buf)
52 {
53 #ifdef __SMP__
54 if (current->flags & PF_USEDFPU) {
55 stts();
56 }
57 #else
58 if (current == last_task_used_math) {
59 last_task_used_math = NULL;
60 stts();
61 }
62 #endif
63 current->used_math = 1;
64 current->flags &= ~PF_USEDFPU;
65 memcpy_fromfs(¤t->tss.i387.hard, buf, sizeof(*buf));
66 }
67
68 static void restore_i387(struct _fpstate *buf)
69 {
70 #ifndef CONFIG_MATH_EMULATION
71 restore_i387_hard(buf);
72 #else
73 if (hard_math) {
74 restore_i387_hard(buf);
75 return;
76 }
77 restore_i387_soft(buf);
78 #endif
79 }
80
81
82
83
84
85 asmlinkage int sys_sigreturn(unsigned long __unused)
86 {
87 #define COPY(x) regs->x = context.x
88 #define COPY_SEG(x) \
89 if ((context.x & 0xfffc) && (context.x & 3) != 3) goto badframe; COPY(x);
90 #define COPY_SEG_STRICT(x) \
91 if (!(context.x & 0xfffc) || (context.x & 3) != 3) goto badframe; COPY(x);
92 struct sigcontext_struct context;
93 struct pt_regs * regs;
94
95 regs = (struct pt_regs *) &__unused;
96 if (verify_area(VERIFY_READ, (void *) regs->esp, sizeof(context)))
97 goto badframe;
98 memcpy_fromfs(&context,(void *) regs->esp, sizeof(context));
99 current->blocked = context.oldmask & _BLOCKABLE;
100 COPY_SEG(ds);
101 COPY_SEG(es);
102 COPY_SEG(fs);
103 COPY_SEG(gs);
104 COPY_SEG_STRICT(ss);
105 COPY_SEG_STRICT(cs);
106 COPY(eip);
107 COPY(ecx); COPY(edx);
108 COPY(ebx);
109 COPY(esp); COPY(ebp);
110 COPY(edi); COPY(esi);
111 regs->eflags &= ~0x40DD5;
112 regs->eflags |= context.eflags & 0x40DD5;
113 regs->orig_eax = -1;
114 if (context.fpstate) {
115 struct _fpstate * buf = context.fpstate;
116 if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
117 goto badframe;
118 restore_i387(buf);
119 }
120 return context.eax;
121 badframe:
122 do_exit(SIGSEGV);
123 }
124
125
126
127
128 #define save_i387_soft(x) NULL
129
130 static inline struct _fpstate * save_i387_hard(struct _fpstate * buf)
131 {
132 #ifdef __SMP__
133 if (current->flags & PF_USEDFPU) {
134 __asm__ __volatile__("fnsave %0":"=m" (current->tss.i387.hard));
135 stts();
136 current->flags &= ~PF_USEDFPU;
137 }
138 #else
139 if (current == last_task_used_math) {
140 __asm__ __volatile__("fnsave %0":"=m" (current->tss.i387.hard));
141 last_task_used_math = NULL;
142 __asm__ __volatile__("fwait");
143 stts();
144 }
145 #endif
146 current->tss.i387.hard.status = current->tss.i387.hard.swd;
147 memcpy_tofs(buf, ¤t->tss.i387.hard, sizeof(*buf));
148 current->used_math = 0;
149 return buf;
150 }
151
152 static struct _fpstate * save_i387(struct _fpstate * buf)
153 {
154 if (!current->used_math)
155 return NULL;
156
157 #ifndef CONFIG_MATH_EMULATION
158 return save_i387_hard(buf);
159 #else
160 if (hard_math)
161 return save_i387_hard(buf);
162 return save_i387_soft(buf);
163 #endif
164 }
165
166
167
168
169
170 static void setup_frame(struct sigaction * sa,
171 struct pt_regs * regs, int signr,
172 unsigned long oldmask)
173 {
174 unsigned long * frame;
175
176 frame = (unsigned long *) regs->esp;
177 if (regs->ss != USER_DS && sa->sa_restorer)
178 frame = (unsigned long *) sa->sa_restorer;
179 frame -= 64;
180 if (verify_area(VERIFY_WRITE,frame,64*4))
181 do_exit(SIGSEGV);
182
183
184 #define __CODE ((unsigned long)(frame+24))
185 #define CODE(x) ((unsigned long *) ((x)+__CODE))
186 put_user(__CODE,frame);
187 if (current->exec_domain && current->exec_domain->signal_invmap)
188 put_user(current->exec_domain->signal_invmap[signr], frame+1);
189 else
190 put_user(signr, frame+1);
191 put_user(regs->gs, frame+2);
192 put_user(regs->fs, frame+3);
193 put_user(regs->es, frame+4);
194 put_user(regs->ds, frame+5);
195 put_user(regs->edi, frame+6);
196 put_user(regs->esi, frame+7);
197 put_user(regs->ebp, frame+8);
198 put_user(regs->esp, frame+9);
199 put_user(regs->ebx, frame+10);
200 put_user(regs->edx, frame+11);
201 put_user(regs->ecx, frame+12);
202 put_user(regs->eax, frame+13);
203 put_user(current->tss.trap_no, frame+14);
204 put_user(current->tss.error_code, frame+15);
205 put_user(regs->eip, frame+16);
206 put_user(regs->cs, frame+17);
207 put_user(regs->eflags, frame+18);
208 put_user(regs->esp, frame+19);
209 put_user(regs->ss, frame+20);
210 put_user(save_i387((struct _fpstate *)(frame+32)),frame+21);
211
212 put_user(oldmask, frame+22);
213 put_user(current->tss.cr2, frame+23);
214
215 put_user(0x0000b858, CODE(0));
216 put_user(0x80cd0000, CODE(4));
217 put_user(__NR_sigreturn, CODE(2));
218 #undef __CODE
219 #undef CODE
220
221
222 regs->esp = (unsigned long) frame;
223 regs->eip = (unsigned long) sa->sa_handler;
224 regs->cs = USER_CS; regs->ss = USER_DS;
225 regs->ds = USER_DS; regs->es = USER_DS;
226 regs->gs = USER_DS; regs->fs = USER_DS;
227 regs->eflags &= ~TF_MASK;
228 }
229
230
231
232
233 static void handle_signal(unsigned long signr, struct sigaction *sa,
234 unsigned long oldmask, struct pt_regs * regs)
235 {
236
237 if (regs->orig_eax >= 0) {
238
239 switch (regs->eax) {
240 case -ERESTARTNOHAND:
241 regs->eax = -EINTR;
242 break;
243
244 case -ERESTARTSYS:
245 if (!(sa->sa_flags & SA_RESTART)) {
246 regs->eax = -EINTR;
247 break;
248 }
249
250 case -ERESTARTNOINTR:
251 regs->eax = regs->orig_eax;
252 regs->eip -= 2;
253 }
254 }
255
256
257 setup_frame(sa, regs, signr, oldmask);
258
259 if (sa->sa_flags & SA_ONESHOT)
260 sa->sa_handler = NULL;
261 current->blocked |= sa->sa_mask;
262 }
263
264
265
266
267
268
269
270
271
272
273 asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
274 {
275 unsigned long mask = ~current->blocked;
276 unsigned long signr;
277 struct sigaction * sa;
278
279 while ((signr = current->signal & mask)) {
280
281
282
283
284
285 struct task_struct *t=current;
286 __asm__("bsf %3,%1\n\t"
287 "btrl %1,%0"
288 :"=m" (t->signal),"=r" (signr)
289 :"0" (t->signal), "1" (signr));
290 sa = current->sig->action + signr;
291 signr++;
292 if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
293 current->exit_code = signr;
294 current->state = TASK_STOPPED;
295 notify_parent(current);
296 schedule();
297 if (!(signr = current->exit_code))
298 continue;
299 current->exit_code = 0;
300 if (signr == SIGSTOP)
301 continue;
302 if (_S(signr) & current->blocked) {
303 current->signal |= _S(signr);
304 continue;
305 }
306 sa = current->sig->action + signr - 1;
307 }
308 if (sa->sa_handler == SIG_IGN) {
309 if (signr != SIGCHLD)
310 continue;
311
312 while (sys_waitpid(-1,NULL,WNOHANG) > 0)
313 ;
314 continue;
315 }
316 if (sa->sa_handler == SIG_DFL) {
317 if (current->pid == 1)
318 continue;
319 switch (signr) {
320 case SIGCONT: case SIGCHLD: case SIGWINCH:
321 continue;
322
323 case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
324 if (current->flags & PF_PTRACED)
325 continue;
326 current->state = TASK_STOPPED;
327 current->exit_code = signr;
328 if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
329 SA_NOCLDSTOP))
330 notify_parent(current);
331 schedule();
332 continue;
333
334 case SIGQUIT: case SIGILL: case SIGTRAP:
335 case SIGABRT: case SIGFPE: case SIGSEGV:
336 if (current->binfmt && current->binfmt->core_dump) {
337 if (current->binfmt->core_dump(signr, regs))
338 signr |= 0x80;
339 }
340
341 default:
342 current->signal |= _S(signr & 0x7f);
343 current->flags |= PF_SIGNALED;
344 do_exit(signr);
345 }
346 }
347 handle_signal(signr, sa, oldmask, regs);
348 return 1;
349 }
350
351
352 if (regs->orig_eax >= 0) {
353
354 if (regs->eax == -ERESTARTNOHAND ||
355 regs->eax == -ERESTARTSYS ||
356 regs->eax == -ERESTARTNOINTR) {
357 regs->eax = regs->orig_eax;
358 regs->eip -= 2;
359 }
360 }
361 return 0;
362 }