]> git.saurik.com Git - apple/xnu.git/blob - bsd/dev/i386/unix_signal.c
xnu-792.6.61.tar.gz
[apple/xnu.git] / bsd / dev / i386 / unix_signal.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * Copyright (c) 1992 NeXT, Inc.
24 *
25 * HISTORY
26 * 13 May 1992 ? at NeXT
27 * Created.
28 */
29
30 #include <mach/mach_types.h>
31 #include <mach/exception.h>
32
33 #include <kern/thread.h>
34
35 #include <sys/systm.h>
36 #include <sys/param.h>
37 #include <sys/proc_internal.h>
38 #include <sys/user.h>
39 #include <sys/sysproto.h>
40 #include <sys/sysent.h>
41 #include <mach/thread_act.h> /* for thread_abort_safely */
42
43 #include <i386/psl.h>
44 #include <i386/seg.h>
45
46 #include <mach/i386/thread_status.h>
47
48 extern struct i386_saved_state *get_user_regs(thread_t);
49
50 extern boolean_t valid_user_segment_selectors(uint16_t cs,
51 uint16_t ss,
52 uint16_t ds,
53 uint16_t es,
54 uint16_t fs,
55 uint16_t gs);
56
57 /* Forward: */
58 extern boolean_t machine_exception(int, int, int, int *, int *);
59
60 /* Signal handler flavors supported */
61 /* These defns should match the Libc implmn */
62 #define UC_TRAD 1
63
64 /*
65 * Send an interrupt to process.
66 *
67 * Stack is set up to allow sigcode stored
68 * in u. to call routine, followed by chmk
69 * to sigreturn routine below. After sigreturn
70 * resets the signal mask, the stack, the frame
71 * pointer, and the argument pointer, it returns
72 * to the user specified pc, psl.
73 */
74 void
75 sendsig(p, catcher, sig, mask, code)
76 struct proc *p;
77 user_addr_t catcher; /* sig_t */
78 int sig, mask;
79 u_long code;
80 {
81 struct sigframe {
82 int retaddr;
83 sig_t catcher;
84 int sigstyle;
85 int sig;
86 int code;
87 struct sigcontext * scp;
88 } frame, *fp;
89 struct sigcontext context, *scp;
90 struct sigacts *ps = p->p_sigacts;
91 int oonstack;
92 thread_t thread = current_thread();
93 struct uthread * ut;
94 struct i386_saved_state * saved_state = get_user_regs(thread);
95 sig_t trampact;
96
97 ut = get_bsdthread_info(thread);
98 oonstack = ps->ps_sigstk.ss_flags & SA_ONSTACK;
99 if ((ps->ps_flags & SAS_ALTSTACK) && !oonstack &&
100 (ps->ps_sigonstack & sigmask(sig))) {
101 scp = ((struct sigcontext *)ps->ps_sigstk.ss_sp) - 1;
102 ps->ps_sigstk.ss_flags |= SA_ONSTACK;
103 } else
104 scp = ((struct sigcontext *)saved_state->uesp) - 1;
105 fp = ((struct sigframe *)scp) - 1;
106
107 /*
108 * Build the argument list for the signal handler.
109 */
110
111 trampact = (sig_t)ps->ps_trampact[sig];
112 /* Handler should call sigreturn to get out of it */
113 frame.retaddr = 0xffffffff;
114 frame.catcher = CAST_DOWN(sig_t,catcher); /* XXX LP64 */
115 frame.sigstyle = UC_TRAD;
116 frame.sig = sig;
117
118 if (sig == SIGILL || sig == SIGFPE) {
119 frame.code = code;
120 } else
121 frame.code = 0;
122 frame.scp = scp;
123 if (copyout((caddr_t)&frame, (user_addr_t)fp, sizeof (frame)))
124 goto bad;
125
126 /*
127 * Build the signal context to be used by sigreturn.
128 */
129 context.sc_onstack = oonstack;
130 context.sc_mask = mask;
131 context.sc_eax = saved_state->eax;
132 context.sc_ebx = saved_state->ebx;
133 context.sc_ecx = saved_state->ecx;
134 context.sc_edx = saved_state->edx;
135 context.sc_edi = saved_state->edi;
136 context.sc_esi = saved_state->esi;
137 context.sc_ebp = saved_state->ebp;
138 context.sc_esp = saved_state->uesp;
139 context.sc_ss = saved_state->ss;
140 context.sc_eflags = saved_state->efl;
141 context.sc_eip = saved_state->eip;
142 context.sc_cs = saved_state->cs;
143 if (saved_state->efl & EFL_VM) {
144 context.sc_ds = saved_state->v86_segs.v86_ds;
145 context.sc_es = saved_state->v86_segs.v86_es;
146 context.sc_fs = saved_state->v86_segs.v86_fs;
147 context.sc_gs = saved_state->v86_segs.v86_gs;
148
149 saved_state->efl &= ~EFL_VM;
150 } else {
151 context.sc_ds = saved_state->ds;
152 context.sc_es = saved_state->es;
153 context.sc_fs = saved_state->fs;
154 context.sc_gs = saved_state->gs;
155 }
156 if (copyout((caddr_t)&context, (user_addr_t)scp, sizeof (context)))
157 goto bad;
158
159 saved_state->eip = (unsigned int)trampact;
160 saved_state->cs = USER_CS;
161
162 saved_state->uesp = (unsigned int)fp;
163 saved_state->ss = USER_DS;
164
165 saved_state->ds = USER_DS;
166 saved_state->es = USER_DS;
167 saved_state->fs = NULL_SEG;
168 saved_state->gs = USER_CTHREAD;
169 return;
170
171 bad:
172 SIGACTION(p, SIGILL) = SIG_DFL;
173 sig = sigmask(SIGILL);
174 p->p_sigignore &= ~sig;
175 p->p_sigcatch &= ~sig;
176 ut->uu_sigmask &= ~sig;
177 /* sendsig is called with signal lock held */
178 psignal_lock(p, SIGILL, 0);
179 return;
180 }
181
182 /*
183 * System call to cleanup state after a signal
184 * has been taken. Reset signal mask and
185 * stack state from context left by sendsig (above).
186 * Return to previous pc and psl as specified by
187 * context left by sendsig. Check carefully to
188 * make sure that the user has not modified the
189 * psl to gain improper priviledges or to cause
190 * a machine fault.
191 */
192 /* ARGSUSED */
193 int
194 sigreturn(
195 struct proc *p,
196 struct sigreturn_args *uap,
197 __unused int *retval)
198 {
199 struct sigcontext context;
200 thread_t thread = current_thread();
201 int error;
202 struct i386_saved_state* saved_state = (struct i386_saved_state*)
203 get_user_regs(thread);
204 struct uthread * ut;
205
206
207
208 if (saved_state == NULL)
209 return EINVAL;
210
211 if ((error = copyin(CAST_USER_ADDR_T(uap->sigcntxp), (void *)&context,
212 sizeof (context))))
213 return(error);
214
215 /*
216 * Validate segment selectors.
217 * Bad values would result in kernel exception at context switch
218 * back to user mode. If other state is invalid an exception will
219 * occur in user context.
220 */
221 if (!valid_user_segment_selectors(context.sc_cs,
222 context.sc_ss,
223 context.sc_ds,
224 context.sc_es,
225 context.sc_fs,
226 context.sc_gs)) {
227 return EINVAL;
228 }
229
230 ut = (struct uthread *)get_bsdthread_info(thread);
231
232 if (context.sc_onstack & 01)
233 p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK;
234 else
235 p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK;
236
237 ut->uu_sigmask = context.sc_mask &~ sigcantmask;
238 if(ut->uu_siglist & ~ut->uu_sigmask)
239 signal_setast(thread);
240
241 saved_state->eax = context.sc_eax;
242 saved_state->ebx = context.sc_ebx;
243 saved_state->ecx = context.sc_ecx;
244 saved_state->edx = context.sc_edx;
245 saved_state->edi = context.sc_edi;
246 saved_state->esi = context.sc_esi;
247 saved_state->ebp = context.sc_ebp;
248 saved_state->uesp = context.sc_esp;
249 saved_state->ss = context.sc_ss;
250 saved_state->efl = context.sc_eflags;
251 saved_state->efl &= ~EFL_USERCLR;
252 saved_state->efl |= EFL_USERSET;
253 saved_state->eip = context.sc_eip;
254 saved_state->cs = context.sc_cs;
255
256 if (context.sc_eflags & EFL_VM) {
257 saved_state->ds = NULL_SEG;
258 saved_state->es = NULL_SEG;
259 saved_state->fs = NULL_SEG;
260 saved_state->gs = NULL_SEG;
261 saved_state->v86_segs.v86_ds = context.sc_ds;
262 saved_state->v86_segs.v86_es = context.sc_es;
263 saved_state->v86_segs.v86_fs = context.sc_fs;
264 saved_state->v86_segs.v86_gs = context.sc_gs;
265
266 saved_state->efl |= EFL_VM;
267 }
268 else {
269 saved_state->ds = context.sc_ds;
270 saved_state->es = context.sc_es;
271 saved_state->fs = context.sc_fs;
272 saved_state->gs = context.sc_gs;
273 }
274
275 return (EJUSTRETURN);
276 }
277
278 /*
279 * machine_exception() performs MD translation
280 * of a mach exception to a unix signal and code.
281 */
282
283 boolean_t
284 machine_exception(
285 int exception,
286 int code,
287 __unused int subcode,
288 int *unix_signal,
289 int *unix_code
290 )
291 {
292
293 switch(exception) {
294
295 case EXC_BAD_INSTRUCTION:
296 *unix_signal = SIGILL;
297 *unix_code = code;
298 break;
299
300 case EXC_ARITHMETIC:
301 *unix_signal = SIGFPE;
302 *unix_code = code;
303 break;
304
305 default:
306 return(FALSE);
307 }
308
309 return(TRUE);
310 }
311
312 #include <sys/systm.h>
313 #include <sys/sysent.h>
314
315 int __pthread_cset(struct sysent *);
316 void __pthread_creset(struct sysent *);
317
318 int
319 __pthread_cset(struct sysent *callp)
320 {
321 unsigned int cancel_enable;
322 thread_t thread;
323 struct uthread * uthread;
324
325 thread = current_thread();
326 uthread = get_bsdthread_info(thread);
327
328 cancel_enable = callp->sy_cancel;
329 if (cancel_enable == _SYSCALL_CANCEL_NONE) {
330 uthread->uu_flag |= UT_NOTCANCELPT;
331 } else {
332 if((uthread->uu_flag & (UT_CANCELDISABLE | UT_CANCEL | UT_CANCELED)) == UT_CANCEL) {
333 if (cancel_enable == _SYSCALL_CANCEL_PRE)
334 return(EINTR);
335 else
336 thread_abort_safely(thread);
337 }
338 }
339 return(0);
340 }
341
342
343 void
344 __pthread_creset(struct sysent *callp)
345 {
346
347 unsigned int cancel_enable;
348 thread_t thread;
349 struct uthread * uthread;
350
351 thread = current_thread();
352 uthread = get_bsdthread_info(thread);
353
354 cancel_enable = callp->sy_cancel;
355 if (!cancel_enable)
356 uthread->uu_flag &= ~UT_NOTCANCELPT;
357
358 }
359