]> git.saurik.com Git - apple/xnu.git/blob - bsd/dev/i386/unix_signal.c
7ddf4acf3c729816feb9dd3f609f9ea34c20f0a7
[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 * 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.
11 *
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
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
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>
34 #include <kern/thread_act.h>
35
36 #include <sys/param.h>
37 #include <sys/proc.h>
38 #include <sys/user.h>
39
40 #include <i386/psl.h>
41
42 #include <mach/i386/thread_status.h>
43 #include <dev/i386/sel_inline.h>
44
45
46 /*
47 * FIXME.. should be included from mach_kernel/i386/seg.h
48 */
49
50 #define USER_CS 0x17
51 #define USER_DS 0x1f
52
53 #define UDATA_SEL USER_DS
54 #define UCODE_SEL USER_CS
55
56 #define valid_user_code_selector(x) (TRUE)
57 #define valid_user_data_selector(x) (TRUE)
58 #define valid_user_stack_selector(x) (TRUE)
59
60
61 #define NULL_SEG 0
62
63 /*
64 * Send an interrupt to process.
65 *
66 * Stack is set up to allow sigcode stored
67 * in u. to call routine, followed by chmk
68 * to sigreturn routine below. After sigreturn
69 * resets the signal mask, the stack, the frame
70 * pointer, and the argument pointer, it returns
71 * to the user specified pc, psl.
72 */
73
74 void
75 sendsig(p, catcher, sig, mask, code)
76 struct proc *p;
77 sig_t catcher;
78 int sig, mask;
79 u_long code;
80 {
81 struct sigframe {
82 int retaddr;
83 int sig;
84 int code;
85 struct sigcontext * scp;
86 } frame, *fp;
87 struct sigcontext context, *scp;
88 struct sigacts *ps = p->p_sigacts;
89 int oonstack;
90 thread_t thread = current_thread();
91 thread_act_t th_act = current_act();
92 struct i386_saved_state * saved_state = get_user_regs(th_act);
93
94 oonstack = ps->ps_sigstk.ss_flags & SA_ONSTACK;
95 if ((ps->ps_flags & SAS_ALTSTACK) && !oonstack &&
96 (ps->ps_sigonstack & sigmask(sig))) {
97 scp = ((struct sigcontext *)ps->ps_sigstk.ss_sp) - 1;
98 ps->ps_sigstk.ss_flags |= SA_ONSTACK;
99 } else
100 scp = ((struct sigcontext *)saved_state->uesp) - 1;
101 fp = ((struct sigframe *)scp) - 1;
102
103 /*
104 * Build the argument list for the signal handler.
105 */
106
107 frame.retaddr = 0xffffffff; /* Handler should call sigreturn to get out of it */
108 frame.sig = sig;
109
110 if (sig == SIGILL || sig == SIGFPE) {
111 frame.code = code;
112 } else
113 frame.code = 0;
114 frame.scp = scp;
115 if (copyout((caddr_t)&frame, (caddr_t)fp, sizeof (frame)))
116 goto bad;
117
118 #if PC_SUPPORT
119 {
120 PCcontext_t context = threadPCContext(thread);
121
122 if (context && context->running) {
123 oonstack |= 02;
124 context->running = FALSE;
125 }
126 }
127 #endif
128 /*
129 * Build the signal context to be used by sigreturn.
130 */
131 context.sc_onstack = oonstack;
132 context.sc_mask = mask;
133 context.sc_eax = saved_state->eax;
134 context.sc_ebx = saved_state->ebx;
135 context.sc_ecx = saved_state->ecx;
136 context.sc_edx = saved_state->edx;
137 context.sc_edi = saved_state->edi;
138 context.sc_esi = saved_state->esi;
139 context.sc_ebp = saved_state->ebp;
140 context.sc_esp = saved_state->uesp;
141 context.sc_ss = saved_state->ss;
142 context.sc_eflags = saved_state->efl;
143 context.sc_eip = saved_state->eip;
144 context.sc_cs = saved_state->cs;
145 if (saved_state->efl & EFL_VM) {
146 context.sc_ds = saved_state->v86_segs.v86_ds;
147 context.sc_es = saved_state->v86_segs.v86_es;
148 context.sc_fs = saved_state->v86_segs.v86_fs;
149 context.sc_gs = saved_state->v86_segs.v86_gs;
150
151 saved_state->efl &= ~EFL_VM;
152 }
153 else {
154 context.sc_ds = saved_state->ds;
155 context.sc_es = saved_state->es;
156 context.sc_fs = saved_state->fs;
157 context.sc_gs = saved_state->gs;
158 }
159 if (copyout((caddr_t)&context, (caddr_t)scp, sizeof (context)))
160 goto bad;
161
162 saved_state->eip = (unsigned int)catcher;
163 saved_state->cs = UCODE_SEL;
164
165 saved_state->uesp = (unsigned int)fp;
166 saved_state->ss = UDATA_SEL;
167
168 saved_state->ds = UDATA_SEL;
169 saved_state->es = UDATA_SEL;
170 saved_state->fs = NULL_SEG;
171 saved_state->gs = NULL_SEG;
172 return;
173
174 bad:
175 SIGACTION(p, SIGILL) = SIG_DFL;
176 sig = sigmask(SIGILL);
177 p->p_sigignore &= ~sig;
178 p->p_sigcatch &= ~sig;
179 p->p_sigmask &= ~sig;
180 /* sendsig is called with signal lock held */
181 psignal_lock(p, SIGILL, 0, 1);
182 return;
183 }
184
185 /*
186 * System call to cleanup state after a signal
187 * has been taken. Reset signal mask and
188 * stack state from context left by sendsig (above).
189 * Return to previous pc and psl as specified by
190 * context left by sendsig. Check carefully to
191 * make sure that the user has not modified the
192 * psl to gain improper priviledges or to cause
193 * a machine fault.
194 */
195 struct sigreturn_args {
196 struct sigcontext *sigcntxp;
197 };
198 /* ARGSUSED */
199 int
200 sigreturn(p, uap, retval)
201 struct proc *p;
202 struct sigreturn_args *uap;
203 int *retval;
204 {
205 struct sigcontext context;
206 thread_t thread = current_thread();
207 thread_act_t th_act = current_act();
208 int error;
209 struct i386_saved_state* saved_state = get_user_regs(th_act);
210
211 if (saved_state == NULL)
212 return EINVAL;
213
214 if (error = copyin((caddr_t)uap->sigcntxp, (caddr_t)&context,
215 sizeof (context)))
216 return(error);
217
218 #if 0 /*FIXME*/
219 if ((context.sc_eflags & EFL_VM) == 0 &&
220 (!valid_user_code_selector(context.sc_cs) ||
221 !valid_user_data_selector(context.sc_ds) ||
222 !valid_user_data_selector(context.sc_es) ||
223 !valid_user_data_selector(context.sc_fs) ||
224 !valid_user_data_selector(context.sc_gs) ||
225 !valid_user_stack_selector(context.sc_ss))
226 )
227 return(EINVAL);
228 #endif
229
230 if (context.sc_onstack & 01)
231 p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK;
232 else
233 p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK;
234 p->p_sigmask = context.sc_mask &~ sigcantmask;
235 saved_state->eax = context.sc_eax;
236 saved_state->ebx = context.sc_ebx;
237 saved_state->ecx = context.sc_ecx;
238 saved_state->edx = context.sc_edx;
239 saved_state->edi = context.sc_edi;
240 saved_state->esi = context.sc_esi;
241 saved_state->ebp = context.sc_ebp;
242 saved_state->uesp = context.sc_esp;
243 saved_state->ss = context.sc_ss;
244 saved_state->efl = context.sc_eflags;
245 saved_state->efl &= ~EFL_USERCLR;
246 saved_state->efl |= EFL_USERSET;
247 saved_state->eip = context.sc_eip;
248 saved_state->cs = context.sc_cs;
249
250 if (context.sc_eflags & EFL_VM) {
251 saved_state->ds = NULL_SEG;
252 saved_state->es = NULL_SEG;
253 saved_state->fs = NULL_SEG;
254 saved_state->gs = NULL_SEG;
255 saved_state->v86_segs.v86_ds = context.sc_ds;
256 saved_state->v86_segs.v86_es = context.sc_es;
257 saved_state->v86_segs.v86_fs = context.sc_fs;
258 saved_state->v86_segs.v86_gs = context.sc_gs;
259
260 saved_state->efl |= EFL_VM;
261 }
262 else {
263 saved_state->ds = context.sc_ds;
264 saved_state->es = context.sc_es;
265 saved_state->fs = context.sc_fs;
266 saved_state->gs = context.sc_gs;
267 }
268
269 #if PC_SUPPORT
270 if (context.sc_onstack & 02) {
271 PCcontext_t context = threadPCContext(thread);
272
273 if (context)
274 context->running = TRUE;
275 }
276 #endif
277
278 return (EJUSTRETURN);
279 }
280
281 /*
282 * machine_exception() performs MD translation
283 * of a mach exception to a unix signal and code.
284 */
285
286 boolean_t
287 machine_exception(
288 int exception,
289 int code,
290 int subcode,
291 int *unix_signal,
292 int *unix_code
293 )
294 {
295
296 switch(exception) {
297
298 case EXC_BAD_INSTRUCTION:
299 *unix_signal = SIGILL;
300 *unix_code = code;
301 break;
302
303 case EXC_ARITHMETIC:
304 *unix_signal = SIGFPE;
305 *unix_code = code;
306 break;
307
308 default:
309 return(FALSE);
310 }
311
312 return(TRUE);
313 }