]> git.saurik.com Git - apple/xnu.git/blame - bsd/dev/i386/unix_signal.c
xnu-792.tar.gz
[apple/xnu.git] / bsd / dev / i386 / unix_signal.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
e5568f75
A
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.
1c79356b 11 *
e5568f75
A
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
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
e5568f75
A
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.
1c79356b
A
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>
1c79356b 34
91447636 35#include <sys/systm.h>
1c79356b 36#include <sys/param.h>
91447636 37#include <sys/proc_internal.h>
1c79356b 38#include <sys/user.h>
91447636
A
39#include <sys/sysproto.h>
40#include <sys/sysent.h>
41#include <mach/thread_act.h> /* for thread_abort_safely */
1c79356b
A
42
43#include <i386/psl.h>
91447636 44#include <i386/seg.h>
1c79356b
A
45
46#include <mach/i386/thread_status.h>
1c79356b 47
91447636 48extern struct i386_saved_state *get_user_regs(thread_t);
1c79356b 49
91447636
A
50extern 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);
1c79356b 56
91447636
A
57/* Forward: */
58extern boolean_t machine_exception(int, int, int, int *, int *);
1c79356b 59
55e303ae
A
60/* Signal handler flavors supported */
61/* These defns should match the Libc implmn */
62#define UC_TRAD 1
63
1c79356b
A
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 */
1c79356b
A
74void
75sendsig(p, catcher, sig, mask, code)
76 struct proc *p;
91447636 77 user_addr_t catcher; /* sig_t */
1c79356b
A
78 int sig, mask;
79 u_long code;
80{
9bccf70c
A
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;
1c79356b 90 struct sigacts *ps = p->p_sigacts;
9bccf70c
A
91 int oonstack;
92 thread_t thread = current_thread();
9bccf70c 93 struct uthread * ut;
91447636 94 struct i386_saved_state * saved_state = get_user_regs(thread);
9bccf70c 95 sig_t trampact;
1c79356b 96
91447636 97 ut = get_bsdthread_info(thread);
1c79356b 98 oonstack = ps->ps_sigstk.ss_flags & SA_ONSTACK;
9bccf70c 99 if ((ps->ps_flags & SAS_ALTSTACK) && !oonstack &&
1c79356b 100 (ps->ps_sigonstack & sigmask(sig))) {
9bccf70c 101 scp = ((struct sigcontext *)ps->ps_sigstk.ss_sp) - 1;
1c79356b 102 ps->ps_sigstk.ss_flags |= SA_ONSTACK;
9bccf70c
A
103 } else
104 scp = ((struct sigcontext *)saved_state->uesp) - 1;
105 fp = ((struct sigframe *)scp) - 1;
1c79356b 106
9bccf70c
A
107 /*
108 * Build the argument list for the signal handler.
109 */
1c79356b 110
91447636 111 trampact = (sig_t)ps->ps_trampact[sig];
9bccf70c
A
112 /* Handler should call sigreturn to get out of it */
113 frame.retaddr = 0xffffffff;
91447636 114 frame.catcher = CAST_DOWN(sig_t,catcher); /* XXX LP64 */
55e303ae 115 frame.sigstyle = UC_TRAD;
9bccf70c 116 frame.sig = sig;
1c79356b 117
9bccf70c
A
118 if (sig == SIGILL || sig == SIGFPE) {
119 frame.code = code;
120 } else
121 frame.code = 0;
122 frame.scp = scp;
91447636 123 if (copyout((caddr_t)&frame, (user_addr_t)fp, sizeof (frame)))
9bccf70c 124 goto bad;
1c79356b 125
9bccf70c
A
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 }
91447636 156 if (copyout((caddr_t)&context, (user_addr_t)scp, sizeof (context)))
9bccf70c
A
157 goto bad;
158
159 saved_state->eip = (unsigned int)trampact;
91447636 160 saved_state->cs = USER_CS;
9bccf70c
A
161
162 saved_state->uesp = (unsigned int)fp;
91447636 163 saved_state->ss = USER_DS;
9bccf70c 164
91447636
A
165 saved_state->ds = USER_DS;
166 saved_state->es = USER_DS;
9bccf70c 167 saved_state->fs = NULL_SEG;
55e303ae 168 saved_state->gs = USER_CTHREAD;
9bccf70c 169 return;
1c79356b
A
170
171bad:
172 SIGACTION(p, SIGILL) = SIG_DFL;
173 sig = sigmask(SIGILL);
174 p->p_sigignore &= ~sig;
175 p->p_sigcatch &= ~sig;
9bccf70c 176 ut->uu_sigmask &= ~sig;
1c79356b 177 /* sendsig is called with signal lock held */
9bccf70c 178 psignal_lock(p, SIGILL, 0);
1c79356b
A
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 */
1c79356b
A
192/* ARGSUSED */
193int
91447636
A
194sigreturn(
195 struct proc *p,
196 struct sigreturn_args *uap,
197 __unused int *retval)
1c79356b
A
198{
199 struct sigcontext context;
200 thread_t thread = current_thread();
1c79356b 201 int error;
55e303ae 202 struct i386_saved_state* saved_state = (struct i386_saved_state*)
91447636 203 get_user_regs(thread);
9bccf70c
A
204 struct uthread * ut;
205
206
1c79356b 207
91447636
A
208 if (saved_state == NULL)
209 return EINVAL;
1c79356b 210
91447636
A
211 if ((error = copyin(CAST_USER_ADDR_T(uap->sigcntxp), (void *)&context,
212 sizeof (context))))
213 return(error);
1c79356b 214
91447636
A
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;
1c79356b
A
234 else
235 p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK;
91447636 236
9bccf70c
A
237 ut->uu_sigmask = context.sc_mask &~ sigcantmask;
238 if(ut->uu_siglist & ~ut->uu_sigmask)
91447636
A
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 }
1c79356b
A
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
283boolean_t
284machine_exception(
91447636
A
285 int exception,
286 int code,
287 __unused int subcode,
288 int *unix_signal,
289 int *unix_code
1c79356b
A
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}
91447636
A
311
312#include <sys/systm.h>
313#include <sys/sysent.h>
314
315int __pthread_cset(struct sysent *);
316void __pthread_creset(struct sysent *);
317
318int
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
343void
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