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