]>
Commit | Line | Data |
---|---|---|
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 | } |