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