]> git.saurik.com Git - apple/xnu.git/blob - bsd/dev/i386/unix_signal.c
xnu-344.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 * 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 sig_t catcher;
84 int sigstyle;
85 int sig;
86 int code;
87 struct sigcontext * scp;
88 } frame, *fp;
89 struct sigcontext context, *scp;
90 struct sigacts *ps = p->p_sigacts;
91 int oonstack;
92 thread_t thread = current_thread();
93 thread_act_t th_act = current_act();
94 struct uthread * ut;
95 struct i386_saved_state * saved_state = get_user_regs(th_act);
96 sig_t trampact;
97
98 ut = get_bsdthread_info(th_act);
99 oonstack = ps->ps_sigstk.ss_flags & SA_ONSTACK;
100 if ((ps->ps_flags & SAS_ALTSTACK) && !oonstack &&
101 (ps->ps_sigonstack & sigmask(sig))) {
102 scp = ((struct sigcontext *)ps->ps_sigstk.ss_sp) - 1;
103 ps->ps_sigstk.ss_flags |= SA_ONSTACK;
104 } else
105 scp = ((struct sigcontext *)saved_state->uesp) - 1;
106 fp = ((struct sigframe *)scp) - 1;
107
108 /*
109 * Build the argument list for the signal handler.
110 */
111
112 trampact = ps->ps_trampact[sig];
113 /* Handler should call sigreturn to get out of it */
114 frame.retaddr = 0xffffffff;
115 frame.catcher = catcher;
116 frame.sigstyle = 1;
117 frame.sig = sig;
118
119 if (sig == SIGILL || sig == SIGFPE) {
120 frame.code = code;
121 } else
122 frame.code = 0;
123 frame.scp = scp;
124 if (copyout((caddr_t)&frame, (caddr_t)fp, sizeof (frame)))
125 goto bad;
126
127 #if PC_SUPPORT
128 {
129 PCcontext_t context = threadPCContext(thread);
130
131 if (context && context->running) {
132 oonstack |= 02;
133 context->running = FALSE;
134 }
135 }
136 #endif
137 /*
138 * Build the signal context to be used by sigreturn.
139 */
140 context.sc_onstack = oonstack;
141 context.sc_mask = mask;
142 context.sc_eax = saved_state->eax;
143 context.sc_ebx = saved_state->ebx;
144 context.sc_ecx = saved_state->ecx;
145 context.sc_edx = saved_state->edx;
146 context.sc_edi = saved_state->edi;
147 context.sc_esi = saved_state->esi;
148 context.sc_ebp = saved_state->ebp;
149 context.sc_esp = saved_state->uesp;
150 context.sc_ss = saved_state->ss;
151 context.sc_eflags = saved_state->efl;
152 context.sc_eip = saved_state->eip;
153 context.sc_cs = saved_state->cs;
154 if (saved_state->efl & EFL_VM) {
155 context.sc_ds = saved_state->v86_segs.v86_ds;
156 context.sc_es = saved_state->v86_segs.v86_es;
157 context.sc_fs = saved_state->v86_segs.v86_fs;
158 context.sc_gs = saved_state->v86_segs.v86_gs;
159
160 saved_state->efl &= ~EFL_VM;
161 } else {
162 context.sc_ds = saved_state->ds;
163 context.sc_es = saved_state->es;
164 context.sc_fs = saved_state->fs;
165 context.sc_gs = saved_state->gs;
166 }
167 if (copyout((caddr_t)&context, (caddr_t)scp, sizeof (context)))
168 goto bad;
169
170 saved_state->eip = (unsigned int)trampact;
171 saved_state->cs = UCODE_SEL;
172
173 saved_state->uesp = (unsigned int)fp;
174 saved_state->ss = UDATA_SEL;
175
176 saved_state->ds = UDATA_SEL;
177 saved_state->es = UDATA_SEL;
178 saved_state->fs = NULL_SEG;
179 saved_state->gs = NULL_SEG;
180 return;
181
182 bad:
183 SIGACTION(p, SIGILL) = SIG_DFL;
184 sig = sigmask(SIGILL);
185 p->p_sigignore &= ~sig;
186 p->p_sigcatch &= ~sig;
187 ut->uu_sigmask &= ~sig;
188 /* sendsig is called with signal lock held */
189 psignal_lock(p, SIGILL, 0);
190 return;
191 }
192
193 /*
194 * System call to cleanup state after a signal
195 * has been taken. Reset signal mask and
196 * stack state from context left by sendsig (above).
197 * Return to previous pc and psl as specified by
198 * context left by sendsig. Check carefully to
199 * make sure that the user has not modified the
200 * psl to gain improper priviledges or to cause
201 * a machine fault.
202 */
203 struct sigreturn_args {
204 struct sigcontext *sigcntxp;
205 };
206 /* ARGSUSED */
207 int
208 sigreturn(p, uap, retval)
209 struct proc *p;
210 struct sigreturn_args *uap;
211 int *retval;
212 {
213 struct sigcontext context;
214 thread_t thread = current_thread();
215 thread_act_t th_act = current_act();
216 int error;
217 struct i386_saved_state* saved_state = get_user_regs(th_act);
218 struct uthread * ut;
219
220
221
222 if (saved_state == NULL)
223 return EINVAL;
224
225 if (error = copyin((caddr_t)uap->sigcntxp, (caddr_t)&context,
226 sizeof (context)))
227 return(error);
228 ut = (struct uthread *)get_bsdthread_info(th_act);
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 ut->uu_sigmask = context.sc_mask &~ sigcantmask;
235 if(ut->uu_siglist & ~ut->uu_sigmask)
236 signal_setast(current_act());
237 saved_state->eax = context.sc_eax;
238 saved_state->ebx = context.sc_ebx;
239 saved_state->ecx = context.sc_ecx;
240 saved_state->edx = context.sc_edx;
241 saved_state->edi = context.sc_edi;
242 saved_state->esi = context.sc_esi;
243 saved_state->ebp = context.sc_ebp;
244 saved_state->uesp = context.sc_esp;
245 saved_state->ss = context.sc_ss;
246 saved_state->efl = context.sc_eflags;
247 saved_state->efl &= ~EFL_USERCLR;
248 saved_state->efl |= EFL_USERSET;
249 saved_state->eip = context.sc_eip;
250 saved_state->cs = context.sc_cs;
251
252 if (context.sc_eflags & EFL_VM) {
253 saved_state->ds = NULL_SEG;
254 saved_state->es = NULL_SEG;
255 saved_state->fs = NULL_SEG;
256 saved_state->gs = NULL_SEG;
257 saved_state->v86_segs.v86_ds = context.sc_ds;
258 saved_state->v86_segs.v86_es = context.sc_es;
259 saved_state->v86_segs.v86_fs = context.sc_fs;
260 saved_state->v86_segs.v86_gs = context.sc_gs;
261
262 saved_state->efl |= EFL_VM;
263 }
264 else {
265 saved_state->ds = context.sc_ds;
266 saved_state->es = context.sc_es;
267 saved_state->fs = context.sc_fs;
268 saved_state->gs = context.sc_gs;
269 }
270
271 #if PC_SUPPORT
272 if (context.sc_onstack & 02) {
273 PCcontext_t context = threadPCContext(thread);
274
275 if (context)
276 context->running = TRUE;
277 }
278 #endif
279
280 return (EJUSTRETURN);
281 }
282
283 /*
284 * machine_exception() performs MD translation
285 * of a mach exception to a unix signal and code.
286 */
287
288 boolean_t
289 machine_exception(
290 int exception,
291 int code,
292 int subcode,
293 int *unix_signal,
294 int *unix_code
295 )
296 {
297
298 switch(exception) {
299
300 case EXC_BAD_INSTRUCTION:
301 *unix_signal = SIGILL;
302 *unix_code = code;
303 break;
304
305 case EXC_ARITHMETIC:
306 *unix_signal = SIGFPE;
307 *unix_code = code;
308 break;
309
310 default:
311 return(FALSE);
312 }
313
314 return(TRUE);
315 }