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