2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
26 #include <mach/mach_types.h>
27 #include <mach/exception_types.h>
29 #include <sys/param.h>
32 #include <sys/ucontext.h>
34 #include <ppc/signal.h>
35 #include <sys/signalvar.h>
36 #include <sys/kdebug.h>
38 #include <kern/thread.h>
39 #include <kern/thread_act.h>
40 #include <mach/ppc/thread_status.h>
42 #include <ppc/proc_reg.h>
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))
51 * Arrange for this process to run a signal handler
55 sendsig(p
, catcher
, sig
, mask
, code
)
61 struct mcontext mctx
, *p_mctx
;
62 struct ucontext uctx
, *p_uctx
;
63 siginfo_t sinfo
, *p_sinfo
;
64 struct sigacts
*ps
= p
->p_sigacts
;
68 unsigned long state_count
;
71 unsigned long paramp
,linkp
;
78 th_act
= current_act();
79 ut
= get_bsdthread_info(th_act
);
81 state_count
= PPC_EXCEPTION_STATE_COUNT
;
82 if (act_machine_get_state(th_act
, PPC_EXCEPTION_STATE
, &mctx
.es
, &state_count
) != KERN_SUCCESS
) {
85 state_count
= PPC_THREAD_STATE_COUNT
;
86 if (act_machine_get_state(th_act
, PPC_THREAD_STATE
, &mctx
.ss
, &state_count
) != KERN_SUCCESS
) {
89 state_count
= PPC_FLOAT_STATE_COUNT
;
90 if (act_machine_get_state(th_act
, PPC_FLOAT_STATE
, &mctx
.fs
, &state_count
) != KERN_SUCCESS
) {
95 if (find_user_vec(th_act
)) {
97 state_count
= PPC_VECTOR_STATE_COUNT
;
98 if (act_machine_get_state(th_act
, PPC_VECTOR_STATE
, &mctx
.vs
, &state_count
) != KERN_SUCCESS
) {
104 trampact
= ps
->ps_trampact
[sig
];
105 oonstack
= ps
->ps_sigstk
.ss_flags
& SA_ONSTACK
;
106 if (p
->p_sigacts
->ps_siginfo
& sigmask(sig
))
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
;
114 stack_size
= ps
->ps_sigstk
.ss_size
;
115 ps
->ps_sigstk
.ss_flags
|= SA_ONSTACK
;
120 /* preserve RED ZONE area */
121 sp
= TRUNC_DOWN(sp
, C_REDZONE_LEN
, C_STK_ALIGN
);
123 /* context goes first on stack */
124 sp
-= sizeof(*p_uctx
);
125 p_uctx
= (struct ucontext
*) sp
;
127 /* this is where siginfo goes on stack */
128 sp
-= sizeof(*p_sinfo
);
129 p_sinfo
= (siginfo_t
*) sp
;
131 /* next are the saved registers */
132 sp
-= sizeof(*p_mctx
);
133 p_mctx
= (struct mcontext
*)sp
;
135 /* C calling conventions, create param save and linkage
139 sp
= TRUNC_DOWN(sp
, C_PARAMSAVE_LEN
, C_STK_ALIGN
);
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
;
149 uctx
.uc_stack
.ss_flags
|= SS_ONSTACK
;
152 uctx
.uc_mcsize
= (size_t)((PPC_EXCEPTION_STATE_COUNT
+ PPC_THREAD_STATE_COUNT
+ PPC_FLOAT_STATE_COUNT
) * sizeof(int));
154 uctx
.uc_mcsize
+= (size_t)(PPC_VECTOR_STATE_COUNT
* sizeof(int));
155 uctx
.uc_mcontext
= p_mctx
;
158 bzero((caddr_t
)&sinfo
, sizeof(siginfo_t
));
159 sinfo
.si_signo
= sig
;
162 sinfo
.si_pid
= p
->si_pid
;
164 sinfo
.si_status
= p
->si_status
;
166 sinfo
.si_uid
= p
->si_uid
;
168 sinfo
.si_code
= p
->si_code
;
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
;
177 sinfo
.si_code
= CLD_KILLED
;
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
;
190 sinfo
.si_code
= ILL_NOOP
;
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
;
210 sinfo
.si_code
= FPE_NOOP
;
214 sinfo
.si_addr
= (void *)mctx
.ss
.srr0
;
215 /* on ppc we generate only if EXC_PPC_UNALIGNED */
216 sinfo
.si_code
= BUS_ADRALN
;
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
;
227 sinfo
.si_code
= SEGV_MAPERR
;
233 /* copy info out to user space */
234 if (copyout((caddr_t
)&uctx
, (caddr_t
)p_uctx
, sizeof(struct ucontext
)))
236 if (copyout((caddr_t
)&sinfo
, (caddr_t
)p_sinfo
, sizeof(siginfo_t
)))
238 if (copyout((caddr_t
)&mctx
, (caddr_t
)p_mctx
, uctx
.uc_mcsize
))
241 /* Place our arguments in arg registers: rtm dependent */
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
;
249 mctx
.ss
.srr0
= (unsigned long)trampact
;
250 mctx
.ss
.srr1
= get_msr_exportmask(); /* MSR_EXPORT_MASK_SET */
252 state_count
= PPC_THREAD_STATE_COUNT
;
253 if (act_machine_set_state(th_act
, PPC_THREAD_STATE
, &mctx
.ss
, &state_count
) != KERN_SUCCESS
) {
260 SIGACTION(p
, SIGILL
) = SIG_DFL
;
261 sig
= sigmask(SIGILL
);
262 p
->p_sigignore
&= ~sig
;
263 p
->p_sigcatch
&= ~sig
;
264 ut
->uu_sigmask
&= ~sig
;
265 /* sendsig is called with signal lock held */
266 psignal_lock(p
, SIGILL
, 0);
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
280 struct sigreturn_args
{
281 struct ucontext
*uctx
;
286 sigreturn(p
, uap
, retval
)
288 struct sigreturn_args
*uap
;
291 struct ucontext uctx
, *p_uctx
;
292 struct mcontext mctx
, *p_mctx
;
295 struct ppc_float_state fs
;
296 struct ppc_exception_state es
;
297 struct sigacts
*ps
= p
->p_sigacts
;
299 register sig_t action
;
300 unsigned long state_count
;
301 unsigned int nbits
, rbits
;
305 th_act
= current_act();
307 ut
= (struct uthread
*)get_bsdthread_info(th_act
);
308 if (error
= copyin(uap
->uctx
, &uctx
, sizeof(struct ucontext
))) {
311 if (error
= copyin(uctx
.uc_mcontext
, &mctx
, sizeof(struct mcontext
))) {
315 if (uctx
.uc_onstack
& 01)
316 p
->p_sigacts
->ps_sigstk
.ss_flags
|= SA_ONSTACK
;
318 p
->p_sigacts
->ps_sigstk
.ss_flags
&= ~SA_ONSTACK
;
319 ut
->uu_sigmask
= uctx
.uc_sigmask
& ~sigcantmask
;
322 if (ut
->uu_siglist
& ~ut
->uu_sigmask
)
323 signal_setast(current_act());
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
);
333 state_count
= (size_t)((PPC_EXCEPTION_STATE_COUNT
+ PPC_THREAD_STATE_COUNT
+ PPC_FLOAT_STATE_COUNT
) * sizeof(int));
335 if (uctx
.uc_mcsize
> state_count
)
338 state_count
= PPC_THREAD_STATE_COUNT
;
339 if (act_machine_set_state(th_act
, PPC_THREAD_STATE
, &mctx
.ss
, &state_count
) != KERN_SUCCESS
) {
343 state_count
= PPC_FLOAT_STATE_COUNT
;
344 if (act_machine_set_state(th_act
, PPC_FLOAT_STATE
, &mctx
.fs
, &state_count
) != KERN_SUCCESS
) {
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);
357 state_count
= PPC_VECTOR_STATE_COUNT
;
358 if (act_machine_set_state(th_act
, PPC_VECTOR_STATE
, &mctx
.vs
, &state_count
) != KERN_SUCCESS
) {
363 return (EJUSTRETURN
);
367 * machine_exception() performs MD translation
368 * of a mach exception to a unix signal and code.
382 case EXC_BAD_INSTRUCTION
:
383 *unix_signal
= SIGILL
;
388 *unix_signal
= SIGFPE
;
393 if (code
== EXC_PPC_TRAP
) {
394 *unix_signal
= SIGTRAP
;