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