]> git.saurik.com Git - apple/xnu.git/blob - bsd/dev/i386/unix_signal.c
xnu-344.49.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 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * Copyright (c) 1992 NeXT, Inc.
27 *
28 * HISTORY
29 * 13 May 1992 ? at NeXT
30 * Created.
31 */
32
33 #include <mach/mach_types.h>
34 #include <mach/exception.h>
35
36 #include <kern/thread.h>
37 #include <kern/thread_act.h>
38
39 #include <sys/param.h>
40 #include <sys/proc.h>
41 #include <sys/user.h>
42
43 #include <i386/psl.h>
44
45 #include <mach/i386/thread_status.h>
46 #include <dev/i386/sel_inline.h>
47
48
49 /*
50 * FIXME.. should be included from mach_kernel/i386/seg.h
51 */
52
53 #define USER_CS 0x17
54 #define USER_DS 0x1f
55
56 #define UDATA_SEL USER_DS
57 #define UCODE_SEL USER_CS
58
59 #define valid_user_code_selector(x) (TRUE)
60 #define valid_user_data_selector(x) (TRUE)
61 #define valid_user_stack_selector(x) (TRUE)
62
63
64 #define NULL_SEG 0
65
66 /*
67 * Send an interrupt to process.
68 *
69 * Stack is set up to allow sigcode stored
70 * in u. to call routine, followed by chmk
71 * to sigreturn routine below. After sigreturn
72 * resets the signal mask, the stack, the frame
73 * pointer, and the argument pointer, it returns
74 * to the user specified pc, psl.
75 */
76
77 void
78 sendsig(p, catcher, sig, mask, code)
79 struct proc *p;
80 sig_t catcher;
81 int sig, mask;
82 u_long code;
83 {
84 struct sigframe {
85 int retaddr;
86 sig_t catcher;
87 int sigstyle;
88 int sig;
89 int code;
90 struct sigcontext * scp;
91 } frame, *fp;
92 struct sigcontext context, *scp;
93 struct sigacts *ps = p->p_sigacts;
94 int oonstack;
95 thread_t thread = current_thread();
96 thread_act_t th_act = current_act();
97 struct uthread * ut;
98 struct i386_saved_state * saved_state = get_user_regs(th_act);
99 sig_t trampact;
100
101 ut = get_bsdthread_info(th_act);
102 oonstack = ps->ps_sigstk.ss_flags & SA_ONSTACK;
103 if ((ps->ps_flags & SAS_ALTSTACK) && !oonstack &&
104 (ps->ps_sigonstack & sigmask(sig))) {
105 scp = ((struct sigcontext *)ps->ps_sigstk.ss_sp) - 1;
106 ps->ps_sigstk.ss_flags |= SA_ONSTACK;
107 } else
108 scp = ((struct sigcontext *)saved_state->uesp) - 1;
109 fp = ((struct sigframe *)scp) - 1;
110
111 /*
112 * Build the argument list for the signal handler.
113 */
114
115 trampact = ps->ps_trampact[sig];
116 /* Handler should call sigreturn to get out of it */
117 frame.retaddr = 0xffffffff;
118 frame.catcher = catcher;
119 frame.sigstyle = 1;
120 frame.sig = sig;
121
122 if (sig == SIGILL || sig == SIGFPE) {
123 frame.code = code;
124 } else
125 frame.code = 0;
126 frame.scp = scp;
127 if (copyout((caddr_t)&frame, (caddr_t)fp, sizeof (frame)))
128 goto bad;
129
130 #if PC_SUPPORT
131 {
132 PCcontext_t context = threadPCContext(thread);
133
134 if (context && context->running) {
135 oonstack |= 02;
136 context->running = FALSE;
137 }
138 }
139 #endif
140 /*
141 * Build the signal context to be used by sigreturn.
142 */
143 context.sc_onstack = oonstack;
144 context.sc_mask = mask;
145 context.sc_eax = saved_state->eax;
146 context.sc_ebx = saved_state->ebx;
147 context.sc_ecx = saved_state->ecx;
148 context.sc_edx = saved_state->edx;
149 context.sc_edi = saved_state->edi;
150 context.sc_esi = saved_state->esi;
151 context.sc_ebp = saved_state->ebp;
152 context.sc_esp = saved_state->uesp;
153 context.sc_ss = saved_state->ss;
154 context.sc_eflags = saved_state->efl;
155 context.sc_eip = saved_state->eip;
156 context.sc_cs = saved_state->cs;
157 if (saved_state->efl & EFL_VM) {
158 context.sc_ds = saved_state->v86_segs.v86_ds;
159 context.sc_es = saved_state->v86_segs.v86_es;
160 context.sc_fs = saved_state->v86_segs.v86_fs;
161 context.sc_gs = saved_state->v86_segs.v86_gs;
162
163 saved_state->efl &= ~EFL_VM;
164 } else {
165 context.sc_ds = saved_state->ds;
166 context.sc_es = saved_state->es;
167 context.sc_fs = saved_state->fs;
168 context.sc_gs = saved_state->gs;
169 }
170 if (copyout((caddr_t)&context, (caddr_t)scp, sizeof (context)))
171 goto bad;
172
173 saved_state->eip = (unsigned int)trampact;
174 saved_state->cs = UCODE_SEL;
175
176 saved_state->uesp = (unsigned int)fp;
177 saved_state->ss = UDATA_SEL;
178
179 saved_state->ds = UDATA_SEL;
180 saved_state->es = UDATA_SEL;
181 saved_state->fs = NULL_SEG;
182 saved_state->gs = NULL_SEG;
183 return;
184
185 bad:
186 SIGACTION(p, SIGILL) = SIG_DFL;
187 sig = sigmask(SIGILL);
188 p->p_sigignore &= ~sig;
189 p->p_sigcatch &= ~sig;
190 ut->uu_sigmask &= ~sig;
191 /* sendsig is called with signal lock held */
192 psignal_lock(p, SIGILL, 0);
193 return;
194 }
195
196 /*
197 * System call to cleanup state after a signal
198 * has been taken. Reset signal mask and
199 * stack state from context left by sendsig (above).
200 * Return to previous pc and psl as specified by
201 * context left by sendsig. Check carefully to
202 * make sure that the user has not modified the
203 * psl to gain improper priviledges or to cause
204 * a machine fault.
205 */
206 struct sigreturn_args {
207 struct sigcontext *sigcntxp;
208 };
209 /* ARGSUSED */
210 int
211 sigreturn(p, uap, retval)
212 struct proc *p;
213 struct sigreturn_args *uap;
214 int *retval;
215 {
216 struct sigcontext context;
217 thread_t thread = current_thread();
218 thread_act_t th_act = current_act();
219 int error;
220 struct i386_saved_state* saved_state = get_user_regs(th_act);
221 struct uthread * ut;
222
223
224
225 if (saved_state == NULL)
226 return EINVAL;
227
228 if (error = copyin((caddr_t)uap->sigcntxp, (caddr_t)&context,
229 sizeof (context)))
230 return(error);
231 ut = (struct uthread *)get_bsdthread_info(th_act);
232
233 if (context.sc_onstack & 01)
234 p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK;
235 else
236 p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK;
237 ut->uu_sigmask = context.sc_mask &~ sigcantmask;
238 if(ut->uu_siglist & ~ut->uu_sigmask)
239 signal_setast(current_act());
240 saved_state->eax = context.sc_eax;
241 saved_state->ebx = context.sc_ebx;
242 saved_state->ecx = context.sc_ecx;
243 saved_state->edx = context.sc_edx;
244 saved_state->edi = context.sc_edi;
245 saved_state->esi = context.sc_esi;
246 saved_state->ebp = context.sc_ebp;
247 saved_state->uesp = context.sc_esp;
248 saved_state->ss = context.sc_ss;
249 saved_state->efl = context.sc_eflags;
250 saved_state->efl &= ~EFL_USERCLR;
251 saved_state->efl |= EFL_USERSET;
252 saved_state->eip = context.sc_eip;
253 saved_state->cs = context.sc_cs;
254
255 if (context.sc_eflags & EFL_VM) {
256 saved_state->ds = NULL_SEG;
257 saved_state->es = NULL_SEG;
258 saved_state->fs = NULL_SEG;
259 saved_state->gs = NULL_SEG;
260 saved_state->v86_segs.v86_ds = context.sc_ds;
261 saved_state->v86_segs.v86_es = context.sc_es;
262 saved_state->v86_segs.v86_fs = context.sc_fs;
263 saved_state->v86_segs.v86_gs = context.sc_gs;
264
265 saved_state->efl |= EFL_VM;
266 }
267 else {
268 saved_state->ds = context.sc_ds;
269 saved_state->es = context.sc_es;
270 saved_state->fs = context.sc_fs;
271 saved_state->gs = context.sc_gs;
272 }
273
274 #if PC_SUPPORT
275 if (context.sc_onstack & 02) {
276 PCcontext_t context = threadPCContext(thread);
277
278 if (context)
279 context->running = TRUE;
280 }
281 #endif
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 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 }