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