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 #ifndef CONFIG_MATH_EMULATION
155 return save_i387_hard(buf);
156 #else
157 if (hard_math)
158 return save_i387_hard(buf);
159 return save_i387_soft(buf);
160 #endif
161 }
162
163
164
165
166
167 static void setup_frame(struct sigaction * sa,
168 struct pt_regs * regs, int signr,
169 unsigned long oldmask)
170 {
171 unsigned long * frame;
172
173 frame = (unsigned long *) regs->esp;
174 if (regs->ss != USER_DS && sa->sa_restorer)
175 frame = (unsigned long *) sa->sa_restorer;
176 frame -= 64;
177 if (verify_area(VERIFY_WRITE,frame,64*4))
178 do_exit(SIGSEGV);
179
180
181 #define __CODE ((unsigned long)(frame+24))
182 #define CODE(x) ((unsigned long *) ((x)+__CODE))
183 put_user(__CODE,frame);
184 if (current->exec_domain && current->exec_domain->signal_invmap)
185 put_user(current->exec_domain->signal_invmap[signr], frame+1);
186 else
187 put_user(signr, frame+1);
188 put_user(regs->gs, frame+2);
189 put_user(regs->fs, frame+3);
190 put_user(regs->es, frame+4);
191 put_user(regs->ds, frame+5);
192 put_user(regs->edi, frame+6);
193 put_user(regs->esi, frame+7);
194 put_user(regs->ebp, frame+8);
195 put_user(regs->esp, frame+9);
196 put_user(regs->ebx, frame+10);
197 put_user(regs->edx, frame+11);
198 put_user(regs->ecx, frame+12);
199 put_user(regs->eax, frame+13);
200 put_user(current->tss.trap_no, frame+14);
201 put_user(current->tss.error_code, frame+15);
202 put_user(regs->eip, frame+16);
203 put_user(regs->cs, frame+17);
204 put_user(regs->eflags, frame+18);
205 put_user(regs->esp, frame+19);
206 put_user(regs->ss, frame+20);
207 put_user(save_i387((struct _fpstate *)(frame+32)),frame+21);
208
209 put_user(oldmask, frame+22);
210 put_user(current->tss.cr2, frame+23);
211
212 put_user(0x0000b858, CODE(0));
213 put_user(0x80cd0000, CODE(4));
214 put_user(__NR_sigreturn, CODE(2));
215 #undef __CODE
216 #undef CODE
217
218
219 regs->esp = (unsigned long) frame;
220 regs->eip = (unsigned long) sa->sa_handler;
221 regs->cs = USER_CS; regs->ss = USER_DS;
222 regs->ds = USER_DS; regs->es = USER_DS;
223 regs->gs = USER_DS; regs->fs = USER_DS;
224 regs->eflags &= ~TF_MASK;
225 }
226
227
228
229
230 static void handle_signal(unsigned long signr, struct sigaction *sa,
231 unsigned long oldmask, struct pt_regs * regs)
232 {
233
234 if (regs->orig_eax >= 0) {
235
236 switch (regs->eax) {
237 case -ERESTARTNOHAND:
238 regs->eax = -EINTR;
239 break;
240
241 case -ERESTARTSYS:
242 if (!(sa->sa_flags & SA_RESTART)) {
243 regs->eax = -EINTR;
244 break;
245 }
246
247 case -ERESTARTNOINTR:
248 regs->eax = regs->orig_eax;
249 regs->eip -= 2;
250 }
251 }
252
253
254 setup_frame(sa, regs, signr, oldmask);
255
256 if (sa->sa_flags & SA_ONESHOT)
257 sa->sa_handler = NULL;
258 current->blocked |= sa->sa_mask;
259 }
260
261
262
263
264
265
266
267
268
269
270 asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs)
271 {
272 unsigned long mask = ~current->blocked;
273 unsigned long signr;
274 struct sigaction * sa;
275
276 while ((signr = current->signal & mask)) {
277
278
279
280
281
282 struct task_struct *t=current;
283 __asm__("bsf %3,%1\n\t"
284 "btrl %1,%0"
285 :"=m" (t->signal),"=r" (signr)
286 :"0" (t->signal), "1" (signr));
287 sa = current->sig->action + signr;
288 signr++;
289 if ((current->flags & PF_PTRACED) && signr != SIGKILL) {
290 current->exit_code = signr;
291 current->state = TASK_STOPPED;
292 notify_parent(current);
293 schedule();
294 if (!(signr = current->exit_code))
295 continue;
296 current->exit_code = 0;
297 if (signr == SIGSTOP)
298 continue;
299 if (_S(signr) & current->blocked) {
300 current->signal |= _S(signr);
301 continue;
302 }
303 sa = current->sig->action + signr - 1;
304 }
305 if (sa->sa_handler == SIG_IGN) {
306 if (signr != SIGCHLD)
307 continue;
308
309 while (sys_waitpid(-1,NULL,WNOHANG) > 0)
310 ;
311 continue;
312 }
313 if (sa->sa_handler == SIG_DFL) {
314 if (current->pid == 1)
315 continue;
316 switch (signr) {
317 case SIGCONT: case SIGCHLD: case SIGWINCH:
318 continue;
319
320 case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:
321 if (current->flags & PF_PTRACED)
322 continue;
323 current->state = TASK_STOPPED;
324 current->exit_code = signr;
325 if (!(current->p_pptr->sig->action[SIGCHLD-1].sa_flags &
326 SA_NOCLDSTOP))
327 notify_parent(current);
328 schedule();
329 continue;
330
331 case SIGQUIT: case SIGILL: case SIGTRAP:
332 case SIGABRT: case SIGFPE: case SIGSEGV:
333 if (current->binfmt && current->binfmt->core_dump) {
334 if (current->binfmt->core_dump(signr, regs))
335 signr |= 0x80;
336 }
337
338 default:
339 current->signal |= _S(signr & 0x7f);
340 current->flags |= PF_SIGNALED;
341 do_exit(signr);
342 }
343 }
344 handle_signal(signr, sa, oldmask, regs);
345 return 1;
346 }
347
348
349 if (regs->orig_eax >= 0) {
350
351 if (regs->eax == -ERESTARTNOHAND ||
352 regs->eax == -ERESTARTSYS ||
353 regs->eax == -ERESTARTNOINTR) {
354 regs->eax = regs->orig_eax;
355 regs->eip -= 2;
356 }
357 }
358 return 0;
359 }