]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
43866e37 | 6 | * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. |
1c79356b | 7 | * |
43866e37 A |
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 | |
1c79356b A |
17 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
18 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
43866e37 A |
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. | |
1c79356b A |
22 | * |
23 | * @APPLE_LICENSE_HEADER_END@ | |
24 | */ | |
25 | /* | |
26 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. | |
27 | */ | |
28 | ||
29 | #include <mach/mach_types.h> | |
30 | #include <mach/exception_types.h> | |
31 | ||
32 | #include <sys/param.h> | |
33 | #include <sys/proc.h> | |
34 | #include <sys/user.h> | |
9bccf70c | 35 | #include <sys/ucontext.h> |
1c79356b A |
36 | |
37 | #include <ppc/signal.h> | |
38 | #include <sys/signalvar.h> | |
9bccf70c A |
39 | #include <sys/kdebug.h> |
40 | #include <sys/wait.h> | |
1c79356b A |
41 | #include <kern/thread.h> |
42 | #include <kern/thread_act.h> | |
43 | #include <mach/ppc/thread_status.h> | |
de355530 | 44 | #define __ELF__ 0 |
9bccf70c | 45 | #include <ppc/proc_reg.h> |
1c79356b A |
46 | |
47 | #define C_REDZONE_LEN 224 | |
48 | #define C_STK_ALIGN 16 | |
49 | #define C_PARAMSAVE_LEN 64 | |
50 | #define C_LINKAGE_LEN 48 | |
51 | #define TRUNC_DOWN(a,b,c) (((((unsigned)a)-(b))/(c)) * (c)) | |
52 | ||
53 | /* | |
54 | * Arrange for this process to run a signal handler | |
55 | */ | |
56 | ||
1c79356b A |
57 | void |
58 | sendsig(p, catcher, sig, mask, code) | |
59 | struct proc *p; | |
60 | sig_t catcher; | |
61 | int sig, mask; | |
62 | u_long code; | |
63 | { | |
9bccf70c A |
64 | struct mcontext mctx, *p_mctx; |
65 | struct ucontext uctx, *p_uctx; | |
66 | siginfo_t sinfo, *p_sinfo; | |
1c79356b A |
67 | struct sigacts *ps = p->p_sigacts; |
68 | int framesize; | |
69 | int oonstack; | |
70 | unsigned long sp; | |
1c79356b | 71 | unsigned long state_count; |
1c79356b | 72 | thread_act_t th_act; |
9bccf70c | 73 | struct uthread *ut; |
1c79356b | 74 | unsigned long paramp,linkp; |
de355530 | 75 | int infostyle = 1; |
9bccf70c A |
76 | sig_t trampact; |
77 | int vec_used = 0; | |
78 | int stack_size = 0; | |
79 | int stack_flags = 0; | |
1c79356b | 80 | |
1c79356b | 81 | th_act = current_act(); |
9bccf70c | 82 | ut = get_bsdthread_info(th_act); |
1c79356b | 83 | |
de355530 A |
84 | state_count = PPC_EXCEPTION_STATE_COUNT; |
85 | if (act_machine_get_state(th_act, PPC_EXCEPTION_STATE, &mctx.es, &state_count) != KERN_SUCCESS) { | |
86 | goto bad; | |
87 | } | |
1c79356b | 88 | state_count = PPC_THREAD_STATE_COUNT; |
de355530 | 89 | if (act_machine_get_state(th_act, PPC_THREAD_STATE, &mctx.ss, &state_count) != KERN_SUCCESS) { |
1c79356b | 90 | goto bad; |
de355530 A |
91 | } |
92 | state_count = PPC_FLOAT_STATE_COUNT; | |
93 | if (act_machine_get_state(th_act, PPC_FLOAT_STATE, &mctx.fs, &state_count) != KERN_SUCCESS) { | |
94 | goto bad; | |
95 | } | |
1c79356b | 96 | |
9bccf70c A |
97 | vec_save(th_act); |
98 | if (find_user_vec(th_act)) { | |
99 | vec_used = 1; | |
de355530 A |
100 | state_count = PPC_VECTOR_STATE_COUNT; |
101 | if (act_machine_get_state(th_act, PPC_VECTOR_STATE, &mctx.vs, &state_count) != KERN_SUCCESS) { | |
102 | goto bad; | |
103 | } | |
104 | ||
105 | } | |
9bccf70c A |
106 | |
107 | trampact = ps->ps_trampact[sig]; | |
1c79356b | 108 | oonstack = ps->ps_sigstk.ss_flags & SA_ONSTACK; |
de355530 A |
109 | if (p->p_sigacts->ps_siginfo & sigmask(sig)) |
110 | infostyle = 2; | |
1c79356b A |
111 | |
112 | /* figure out where our new stack lives */ | |
113 | if ((ps->ps_flags & SAS_ALTSTACK) && !oonstack && | |
114 | (ps->ps_sigonstack & sigmask(sig))) { | |
115 | sp = (unsigned long)(ps->ps_sigstk.ss_sp); | |
116 | sp += ps->ps_sigstk.ss_size; | |
9bccf70c | 117 | stack_size = ps->ps_sigstk.ss_size; |
1c79356b A |
118 | ps->ps_sigstk.ss_flags |= SA_ONSTACK; |
119 | } | |
de355530 A |
120 | else |
121 | sp = mctx.ss.r1; | |
1c79356b | 122 | |
9bccf70c | 123 | /* preserve RED ZONE area */ |
1c79356b A |
124 | sp = TRUNC_DOWN(sp, C_REDZONE_LEN, C_STK_ALIGN); |
125 | ||
de355530 | 126 | /* context goes first on stack */ |
9bccf70c A |
127 | sp -= sizeof(*p_uctx); |
128 | p_uctx = (struct ucontext *) sp; | |
129 | ||
130 | /* this is where siginfo goes on stack */ | |
131 | sp -= sizeof(*p_sinfo); | |
132 | p_sinfo = (siginfo_t *) sp; | |
1c79356b | 133 | |
de355530 A |
134 | /* next are the saved registers */ |
135 | sp -= sizeof(*p_mctx); | |
136 | p_mctx = (struct mcontext *)sp; | |
137 | ||
9bccf70c | 138 | /* C calling conventions, create param save and linkage |
de355530 A |
139 | * areas |
140 | */ | |
1c79356b A |
141 | |
142 | sp = TRUNC_DOWN(sp, C_PARAMSAVE_LEN, C_STK_ALIGN); | |
143 | paramp = sp; | |
144 | sp -= C_LINKAGE_LEN; | |
145 | linkp = sp; | |
146 | ||
9bccf70c A |
147 | uctx.uc_onstack = oonstack; |
148 | uctx.uc_sigmask = mask; | |
149 | uctx.uc_stack.ss_sp = (char *)sp; | |
150 | uctx.uc_stack.ss_size = stack_size; | |
151 | if (oonstack) | |
152 | uctx.uc_stack.ss_flags |= SS_ONSTACK; | |
153 | ||
154 | uctx.uc_link = 0; | |
de355530 | 155 | uctx.uc_mcsize = (size_t)((PPC_EXCEPTION_STATE_COUNT + PPC_THREAD_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int)); |
9bccf70c A |
156 | if (vec_used) |
157 | uctx.uc_mcsize += (size_t)(PPC_VECTOR_STATE_COUNT * sizeof(int)); | |
de355530 | 158 | uctx.uc_mcontext = p_mctx; |
9bccf70c A |
159 | |
160 | /* setup siginfo */ | |
161 | bzero((caddr_t)&sinfo, sizeof(siginfo_t)); | |
162 | sinfo.si_signo = sig; | |
163 | switch (sig) { | |
164 | case SIGCHLD: | |
165 | sinfo.si_pid = p->si_pid; | |
166 | p->si_pid =0; | |
167 | sinfo.si_status = p->si_status; | |
168 | p->si_status = 0; | |
169 | sinfo.si_uid = p->si_uid; | |
170 | p->si_uid =0; | |
171 | sinfo.si_code = p->si_code; | |
172 | p->si_code = 0; | |
173 | if (sinfo.si_code == CLD_EXITED) { | |
174 | if (WIFEXITED(sinfo.si_status)) | |
175 | sinfo.si_code = CLD_EXITED; | |
176 | else if (WIFSIGNALED(sinfo.si_status)) { | |
177 | if (WCOREDUMP(sinfo.si_status)) | |
178 | sinfo.si_code = CLD_DUMPED; | |
179 | else | |
180 | sinfo.si_code = CLD_KILLED; | |
181 | } | |
182 | } | |
183 | break; | |
184 | case SIGILL: | |
185 | sinfo.si_addr = (void *)mctx.ss.srr0; | |
186 | if (mctx.ss.srr1 & (1 << (31 - SRR1_PRG_ILL_INS_BIT))) | |
187 | sinfo.si_code = ILL_ILLOPC; | |
188 | else if (mctx.ss.srr1 & (1 << (31 - SRR1_PRG_PRV_INS_BIT))) | |
189 | sinfo.si_code = ILL_PRVOPC; | |
190 | else if (mctx.ss.srr1 & (1 << (31 - SRR1_PRG_TRAP_BIT))) | |
191 | sinfo.si_code = ILL_ILLTRP; | |
192 | else | |
193 | sinfo.si_code = ILL_NOOP; | |
194 | break; | |
195 | case SIGFPE: | |
196 | #define FPSCR_VX 2 | |
197 | #define FPSCR_OX 3 | |
198 | #define FPSCR_UX 4 | |
199 | #define FPSCR_ZX 5 | |
200 | #define FPSCR_XX 6 | |
201 | sinfo.si_addr = (void *)mctx.ss.srr0; | |
202 | if (mctx.fs.fpscr & (1 << (31 - FPSCR_VX))) | |
203 | sinfo.si_code = FPE_FLTINV; | |
204 | else if (mctx.fs.fpscr & (1 << (31 - FPSCR_OX))) | |
205 | sinfo.si_code = FPE_FLTOVF; | |
206 | else if (mctx.fs.fpscr & (1 << (31 - FPSCR_UX))) | |
207 | sinfo.si_code = FPE_FLTUND; | |
208 | else if (mctx.fs.fpscr & (1 << (31 - FPSCR_ZX))) | |
209 | sinfo.si_code = FPE_FLTDIV; | |
210 | else if (mctx.fs.fpscr & (1 << (31 - FPSCR_XX))) | |
211 | sinfo.si_code = FPE_FLTRES; | |
212 | else | |
213 | sinfo.si_code = FPE_NOOP; | |
214 | break; | |
215 | ||
216 | case SIGBUS: | |
217 | sinfo.si_addr = (void *)mctx.ss.srr0; | |
218 | /* on ppc we generate only if EXC_PPC_UNALIGNED */ | |
219 | sinfo.si_code = BUS_ADRALN; | |
220 | break; | |
221 | ||
222 | case SIGSEGV: | |
223 | sinfo.si_addr = (void *)mctx.ss.srr0; | |
224 | /* First check in srr1 and then in dsisr */ | |
225 | if (mctx.ss.srr1 & (1 << (31 - DSISR_PROT_BIT))) | |
226 | sinfo.si_code = SEGV_ACCERR; | |
227 | else if (mctx.es.dsisr & (1 << (31 - DSISR_PROT_BIT))) | |
228 | sinfo.si_code = SEGV_ACCERR; | |
229 | else | |
230 | sinfo.si_code = SEGV_MAPERR; | |
231 | break; | |
232 | default: | |
233 | break; | |
234 | } | |
1c79356b A |
235 | |
236 | /* copy info out to user space */ | |
9bccf70c | 237 | if (copyout((caddr_t)&uctx, (caddr_t)p_uctx, sizeof(struct ucontext))) |
1c79356b | 238 | goto bad; |
9bccf70c | 239 | if (copyout((caddr_t)&sinfo, (caddr_t)p_sinfo, sizeof(siginfo_t))) |
1c79356b | 240 | goto bad; |
de355530 | 241 | if (copyout((caddr_t)&mctx, (caddr_t)p_mctx, uctx.uc_mcsize)) |
1c79356b A |
242 | goto bad; |
243 | ||
244 | /* Place our arguments in arg registers: rtm dependent */ | |
245 | ||
9bccf70c A |
246 | mctx.ss.r3 = (unsigned long)catcher; |
247 | mctx.ss.r4 = (unsigned long)infostyle; | |
248 | mctx.ss.r5 = (unsigned long)sig; | |
249 | mctx.ss.r6 = (unsigned long)p_sinfo; | |
250 | mctx.ss.r7 = (unsigned long)p_uctx; | |
1c79356b | 251 | |
9bccf70c A |
252 | mctx.ss.srr0 = (unsigned long)trampact; |
253 | mctx.ss.srr1 = get_msr_exportmask(); /* MSR_EXPORT_MASK_SET */ | |
254 | mctx.ss.r1 = sp; | |
1c79356b | 255 | state_count = PPC_THREAD_STATE_COUNT; |
de355530 | 256 | if (act_machine_set_state(th_act, PPC_THREAD_STATE, &mctx.ss, &state_count) != KERN_SUCCESS) { |
1c79356b A |
257 | goto bad; |
258 | } | |
de355530 | 259 | |
1c79356b A |
260 | return; |
261 | ||
262 | bad: | |
263 | SIGACTION(p, SIGILL) = SIG_DFL; | |
264 | sig = sigmask(SIGILL); | |
265 | p->p_sigignore &= ~sig; | |
266 | p->p_sigcatch &= ~sig; | |
9bccf70c | 267 | ut->uu_sigmask &= ~sig; |
1c79356b | 268 | /* sendsig is called with signal lock held */ |
9bccf70c | 269 | psignal_lock(p, SIGILL, 0); |
1c79356b A |
270 | return; |
271 | } | |
272 | ||
273 | /* | |
274 | * System call to cleanup state after a signal | |
275 | * has been taken. Reset signal mask and | |
276 | * stack state from context left by sendsig (above). | |
277 | * Return to previous pc and psl as specified by | |
278 | * context left by sendsig. Check carefully to | |
279 | * make sure that the user has not modified the | |
280 | * psl to gain improper priviledges or to cause | |
281 | * a machine fault. | |
282 | */ | |
283 | struct sigreturn_args { | |
9bccf70c | 284 | struct ucontext *uctx; |
1c79356b A |
285 | }; |
286 | ||
287 | /* ARGSUSED */ | |
288 | int | |
289 | sigreturn(p, uap, retval) | |
290 | struct proc *p; | |
291 | struct sigreturn_args *uap; | |
292 | int *retval; | |
293 | { | |
de355530 A |
294 | struct ucontext uctx, *p_uctx; |
295 | struct mcontext mctx, *p_mctx; | |
1c79356b | 296 | int error; |
1c79356b | 297 | thread_act_t th_act; |
de355530 A |
298 | struct ppc_float_state fs; |
299 | struct ppc_exception_state es; | |
9bccf70c A |
300 | struct sigacts *ps = p->p_sigacts; |
301 | sigset_t mask; | |
302 | register sig_t action; | |
1c79356b | 303 | unsigned long state_count; |
de355530 | 304 | unsigned int nbits, rbits; |
9bccf70c A |
305 | struct uthread * ut; |
306 | int vec_used = 0; | |
1c79356b | 307 | |
1c79356b A |
308 | th_act = current_act(); |
309 | ||
9bccf70c A |
310 | ut = (struct uthread *)get_bsdthread_info(th_act); |
311 | if (error = copyin(uap->uctx, &uctx, sizeof(struct ucontext))) { | |
1c79356b A |
312 | return(error); |
313 | } | |
de355530 | 314 | if (error = copyin(uctx.uc_mcontext, &mctx, sizeof(struct mcontext))) { |
9bccf70c A |
315 | return(error); |
316 | } | |
317 | ||
318 | if (uctx.uc_onstack & 01) | |
319 | p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK; | |
320 | else | |
321 | p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK; | |
d7e50217 | 322 | ut->uu_sigmask = uctx.uc_sigmask & ~sigcantmask; |
de355530 A |
323 | |
324 | ||
9bccf70c A |
325 | if (ut->uu_siglist & ~ut->uu_sigmask) |
326 | signal_setast(current_act()); | |
327 | ||
de355530 A |
328 | nbits = get_msr_nbits(); |
329 | rbits = get_msr_rbits(); | |
330 | /* adjust the critical fields */ | |
331 | /* make sure naughty bits are off */ | |
332 | mctx.ss.srr1 &= ~(nbits); | |
333 | /* make sure necessary bits are on */ | |
334 | mctx.ss.srr1 |= (rbits); | |
1c79356b | 335 | |
de355530 | 336 | state_count = (size_t)((PPC_EXCEPTION_STATE_COUNT + PPC_THREAD_STATE_COUNT + PPC_FLOAT_STATE_COUNT) * sizeof(int)); |
1c79356b | 337 | |
de355530 A |
338 | if (uctx.uc_mcsize > state_count) |
339 | vec_used = 1; | |
340 | ||
341 | state_count = PPC_THREAD_STATE_COUNT; | |
342 | if (act_machine_set_state(th_act, PPC_THREAD_STATE, &mctx.ss, &state_count) != KERN_SUCCESS) { | |
1c79356b A |
343 | return(EINVAL); |
344 | } | |
345 | ||
346 | state_count = PPC_FLOAT_STATE_COUNT; | |
de355530 | 347 | if (act_machine_set_state(th_act, PPC_FLOAT_STATE, &mctx.fs, &state_count) != KERN_SUCCESS) { |
1c79356b A |
348 | return(EINVAL); |
349 | } | |
9bccf70c A |
350 | |
351 | mask = sigmask(SIGFPE); | |
352 | if (((ut->uu_sigmask & mask) == 0) && (p->p_sigcatch & mask) && ((p->p_sigignore & mask) == 0)) { | |
353 | action = ps->ps_sigact[SIGFPE]; | |
354 | if((action != SIG_DFL) && (action != SIG_IGN)) { | |
355 | thread_enable_fpe(th_act, 1); | |
356 | } | |
357 | } | |
358 | ||
359 | if (vec_used) { | |
360 | state_count = PPC_VECTOR_STATE_COUNT; | |
de355530 | 361 | if (act_machine_set_state(th_act, PPC_VECTOR_STATE, &mctx.vs, &state_count) != KERN_SUCCESS) { |
9bccf70c A |
362 | return(EINVAL); |
363 | } | |
364 | } | |
de355530 | 365 | |
1c79356b A |
366 | return (EJUSTRETURN); |
367 | } | |
368 | ||
369 | /* | |
370 | * machine_exception() performs MD translation | |
371 | * of a mach exception to a unix signal and code. | |
372 | */ | |
373 | ||
374 | boolean_t | |
375 | machine_exception( | |
376 | int exception, | |
377 | int code, | |
378 | int subcode, | |
379 | int *unix_signal, | |
380 | int *unix_code | |
381 | ) | |
382 | { | |
383 | switch(exception) { | |
384 | ||
385 | case EXC_BAD_INSTRUCTION: | |
386 | *unix_signal = SIGILL; | |
387 | *unix_code = code; | |
388 | break; | |
389 | ||
390 | case EXC_ARITHMETIC: | |
391 | *unix_signal = SIGFPE; | |
392 | *unix_code = code; | |
393 | break; | |
394 | ||
395 | case EXC_SOFTWARE: | |
396 | if (code == EXC_PPC_TRAP) { | |
397 | *unix_signal = SIGTRAP; | |
398 | *unix_code = code; | |
399 | break; | |
400 | } else | |
401 | return(FALSE); | |
402 | ||
403 | default: | |
404 | return(FALSE); | |
405 | } | |
406 | ||
407 | return(TRUE); | |
408 | } | |
409 |