2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
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
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
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
23 * @APPLE_LICENSE_HEADER_END@
26 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
29 #include <mach/mach_types.h>
30 #include <mach/exception_types.h>
32 #include <sys/param.h>
35 #include <sys/ucontext.h>
37 #include <ppc/signal.h>
38 #include <sys/signalvar.h>
39 #include <sys/kdebug.h>
41 #include <kern/thread.h>
42 #include <kern/thread_act.h>
43 #include <mach/ppc/thread_status.h>
45 #include <ppc/proc_reg.h>
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))
54 * Arrange for this process to run a signal handler
58 sendsig(p
, catcher
, sig
, mask
, code
)
64 struct mcontext mctx
, *p_mctx
;
65 struct ucontext uctx
, *p_uctx
;
66 siginfo_t sinfo
, *p_sinfo
;
67 struct sigacts
*ps
= p
->p_sigacts
;
71 unsigned long state_count
;
74 unsigned long paramp
,linkp
;
81 th_act
= current_act();
82 ut
= get_bsdthread_info(th_act
);
84 state_count
= PPC_EXCEPTION_STATE_COUNT
;
85 if (act_machine_get_state(th_act
, PPC_EXCEPTION_STATE
, &mctx
.es
, &state_count
) != KERN_SUCCESS
) {
88 state_count
= PPC_THREAD_STATE_COUNT
;
89 if (act_machine_get_state(th_act
, PPC_THREAD_STATE
, &mctx
.ss
, &state_count
) != KERN_SUCCESS
) {
92 state_count
= PPC_FLOAT_STATE_COUNT
;
93 if (act_machine_get_state(th_act
, PPC_FLOAT_STATE
, &mctx
.fs
, &state_count
) != KERN_SUCCESS
) {
98 if (find_user_vec(th_act
)) {
100 state_count
= PPC_VECTOR_STATE_COUNT
;
101 if (act_machine_get_state(th_act
, PPC_VECTOR_STATE
, &mctx
.vs
, &state_count
) != KERN_SUCCESS
) {
107 trampact
= ps
->ps_trampact
[sig
];
108 oonstack
= ps
->ps_sigstk
.ss_flags
& SA_ONSTACK
;
109 if (p
->p_sigacts
->ps_siginfo
& sigmask(sig
))
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
;
117 stack_size
= ps
->ps_sigstk
.ss_size
;
118 ps
->ps_sigstk
.ss_flags
|= SA_ONSTACK
;
123 /* preserve RED ZONE area */
124 sp
= TRUNC_DOWN(sp
, C_REDZONE_LEN
, C_STK_ALIGN
);
126 /* context goes first on stack */
127 sp
-= sizeof(*p_uctx
);
128 p_uctx
= (struct ucontext
*) sp
;
130 /* this is where siginfo goes on stack */
131 sp
-= sizeof(*p_sinfo
);
132 p_sinfo
= (siginfo_t
*) sp
;
134 /* next are the saved registers */
135 sp
-= sizeof(*p_mctx
);
136 p_mctx
= (struct mcontext
*)sp
;
138 /* C calling conventions, create param save and linkage
142 sp
= TRUNC_DOWN(sp
, C_PARAMSAVE_LEN
, C_STK_ALIGN
);
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
;
152 uctx
.uc_stack
.ss_flags
|= SS_ONSTACK
;
155 uctx
.uc_mcsize
= (size_t)((PPC_EXCEPTION_STATE_COUNT
+ PPC_THREAD_STATE_COUNT
+ PPC_FLOAT_STATE_COUNT
) * sizeof(int));
157 uctx
.uc_mcsize
+= (size_t)(PPC_VECTOR_STATE_COUNT
* sizeof(int));
158 uctx
.uc_mcontext
= p_mctx
;
161 bzero((caddr_t
)&sinfo
, sizeof(siginfo_t
));
162 sinfo
.si_signo
= sig
;
165 sinfo
.si_pid
= p
->si_pid
;
167 sinfo
.si_status
= p
->si_status
;
169 sinfo
.si_uid
= p
->si_uid
;
171 sinfo
.si_code
= p
->si_code
;
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
;
180 sinfo
.si_code
= CLD_KILLED
;
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
;
193 sinfo
.si_code
= ILL_NOOP
;
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
;
213 sinfo
.si_code
= FPE_NOOP
;
217 sinfo
.si_addr
= (void *)mctx
.ss
.srr0
;
218 /* on ppc we generate only if EXC_PPC_UNALIGNED */
219 sinfo
.si_code
= BUS_ADRALN
;
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
;
230 sinfo
.si_code
= SEGV_MAPERR
;
236 /* copy info out to user space */
237 if (copyout((caddr_t
)&uctx
, (caddr_t
)p_uctx
, sizeof(struct ucontext
)))
239 if (copyout((caddr_t
)&sinfo
, (caddr_t
)p_sinfo
, sizeof(siginfo_t
)))
241 if (copyout((caddr_t
)&mctx
, (caddr_t
)p_mctx
, uctx
.uc_mcsize
))
244 /* Place our arguments in arg registers: rtm dependent */
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
;
252 mctx
.ss
.srr0
= (unsigned long)trampact
;
253 mctx
.ss
.srr1
= get_msr_exportmask(); /* MSR_EXPORT_MASK_SET */
255 state_count
= PPC_THREAD_STATE_COUNT
;
256 if (act_machine_set_state(th_act
, PPC_THREAD_STATE
, &mctx
.ss
, &state_count
) != KERN_SUCCESS
) {
263 SIGACTION(p
, SIGILL
) = SIG_DFL
;
264 sig
= sigmask(SIGILL
);
265 p
->p_sigignore
&= ~sig
;
266 p
->p_sigcatch
&= ~sig
;
267 ut
->uu_sigmask
&= ~sig
;
268 /* sendsig is called with signal lock held */
269 psignal_lock(p
, SIGILL
, 0);
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
283 struct sigreturn_args
{
284 struct ucontext
*uctx
;
289 sigreturn(p
, uap
, retval
)
291 struct sigreturn_args
*uap
;
294 struct ucontext uctx
, *p_uctx
;
295 struct mcontext mctx
, *p_mctx
;
298 struct ppc_float_state fs
;
299 struct ppc_exception_state es
;
300 struct sigacts
*ps
= p
->p_sigacts
;
302 register sig_t action
;
303 unsigned long state_count
;
304 unsigned int nbits
, rbits
;
308 th_act
= current_act();
310 ut
= (struct uthread
*)get_bsdthread_info(th_act
);
311 if (error
= copyin(uap
->uctx
, &uctx
, sizeof(struct ucontext
))) {
314 if (error
= copyin(uctx
.uc_mcontext
, &mctx
, sizeof(struct mcontext
))) {
318 if (uctx
.uc_onstack
& 01)
319 p
->p_sigacts
->ps_sigstk
.ss_flags
|= SA_ONSTACK
;
321 p
->p_sigacts
->ps_sigstk
.ss_flags
&= ~SA_ONSTACK
;
322 ut
->uu_sigmask
= uctx
.uc_sigmask
& ~sigcantmask
;
325 if (ut
->uu_siglist
& ~ut
->uu_sigmask
)
326 signal_setast(current_act());
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
);
336 state_count
= (size_t)((PPC_EXCEPTION_STATE_COUNT
+ PPC_THREAD_STATE_COUNT
+ PPC_FLOAT_STATE_COUNT
) * sizeof(int));
338 if (uctx
.uc_mcsize
> state_count
)
341 state_count
= PPC_THREAD_STATE_COUNT
;
342 if (act_machine_set_state(th_act
, PPC_THREAD_STATE
, &mctx
.ss
, &state_count
) != KERN_SUCCESS
) {
346 state_count
= PPC_FLOAT_STATE_COUNT
;
347 if (act_machine_set_state(th_act
, PPC_FLOAT_STATE
, &mctx
.fs
, &state_count
) != KERN_SUCCESS
) {
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);
360 state_count
= PPC_VECTOR_STATE_COUNT
;
361 if (act_machine_set_state(th_act
, PPC_VECTOR_STATE
, &mctx
.vs
, &state_count
) != KERN_SUCCESS
) {
366 return (EJUSTRETURN
);
370 * machine_exception() performs MD translation
371 * of a mach exception to a unix signal and code.
385 case EXC_BAD_INSTRUCTION
:
386 *unix_signal
= SIGILL
;
391 *unix_signal
= SIGFPE
;
396 if (code
== EXC_PPC_TRAP
) {
397 *unix_signal
= SIGTRAP
;