]> git.saurik.com Git - apple/xnu.git/blob - bsd/dev/ppc/unix_signal.c
8947566419e248b35fed648a21b811c2eb0aedc7
[apple/xnu.git] / bsd / dev / ppc / unix_signal.c
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) 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>
32
33 #include <ppc/signal.h>
34 #include <sys/signalvar.h>
35 #include <kern/thread.h>
36 #include <kern/thread_act.h>
37 #include <mach/ppc/thread_status.h>
38
39 #define C_REDZONE_LEN 224
40 #define C_STK_ALIGN 16
41 #define C_PARAMSAVE_LEN 64
42 #define C_LINKAGE_LEN 48
43 #define TRUNC_DOWN(a,b,c) (((((unsigned)a)-(b))/(c)) * (c))
44
45 /*
46 * Arrange for this process to run a signal handler
47 */
48
49
50 struct sigregs {
51 struct ppc_saved_state ss;
52 struct ppc_float_state fs;
53 };
54
55 void
56 sendsig(p, catcher, sig, mask, code)
57 struct proc *p;
58 sig_t catcher;
59 int sig, mask;
60 u_long code;
61 {
62 struct sigregs *p_regs;
63 struct sigcontext context, *p_context;
64 struct sigacts *ps = p->p_sigacts;
65 int framesize;
66 int oonstack;
67 unsigned long sp;
68 struct ppc_saved_state statep;
69 struct ppc_float_state fs;
70 unsigned long state_count;
71 struct thread *thread;
72 thread_act_t th_act;
73 unsigned long paramp,linkp;
74
75 thread = current_thread();
76 th_act = current_act();
77
78 state_count = PPC_THREAD_STATE_COUNT;
79 if (act_machine_get_state(th_act, PPC_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) {
80 goto bad;
81 }
82 state_count = PPC_FLOAT_STATE_COUNT;
83 if (act_machine_get_state(th_act, PPC_FLOAT_STATE, &fs, &state_count) != KERN_SUCCESS) {
84 goto bad;
85 }
86
87 oonstack = ps->ps_sigstk.ss_flags & SA_ONSTACK;
88
89 /* figure out where our new stack lives */
90 if ((ps->ps_flags & SAS_ALTSTACK) && !oonstack &&
91 (ps->ps_sigonstack & sigmask(sig))) {
92 sp = (unsigned long)(ps->ps_sigstk.ss_sp);
93 sp += ps->ps_sigstk.ss_size;
94 ps->ps_sigstk.ss_flags |= SA_ONSTACK;
95 }
96 else
97 sp = statep.r1;
98
99 // preserve RED ZONE area
100 sp = TRUNC_DOWN(sp, C_REDZONE_LEN, C_STK_ALIGN);
101
102 // context goes first on stack
103 sp -= sizeof(*p_context);
104 p_context = (struct sigcontext *) sp;
105
106 // next are the saved registers
107 sp -= sizeof(*p_regs);
108 p_regs = (struct sigregs *)sp;
109
110 // C calling conventions, create param save and linkage
111 // areas
112
113 sp = TRUNC_DOWN(sp, C_PARAMSAVE_LEN, C_STK_ALIGN);
114 paramp = sp;
115 sp -= C_LINKAGE_LEN;
116 linkp = sp;
117
118 /* fill out sigcontext */
119 context.sc_onstack = oonstack;
120 context.sc_mask = mask;
121 context.sc_ir = statep.srr0;
122 context.sc_psw = statep.srr1;
123 context.sc_regs = p_regs;
124
125 /* copy info out to user space */
126 if (copyout((caddr_t)&context, (caddr_t)p_context, sizeof(context)))
127 goto bad;
128 if (copyout((caddr_t)&statep, (caddr_t)&p_regs->ss,
129 sizeof(struct ppc_saved_state)))
130 goto bad;
131 if (copyout((caddr_t)&fs, (caddr_t)&p_regs->fs,
132 sizeof(struct ppc_float_state)))
133 goto bad;
134
135 /* Place our arguments in arg registers: rtm dependent */
136
137 statep.r3 = (unsigned long)sig;
138 statep.r4 = (unsigned long)code;
139 statep.r5 = (unsigned long)p_context;
140
141 statep.srr0 = (unsigned long)catcher;
142 statep.srr1 = get_msr_exportmask(); /* MSR_EXPORT_MASK_SET */
143 statep.r1 = sp;
144 state_count = PPC_THREAD_STATE_COUNT;
145 if (act_machine_set_state(th_act, PPC_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) {
146 goto bad;
147 }
148
149 return;
150
151 bad:
152 SIGACTION(p, SIGILL) = SIG_DFL;
153 sig = sigmask(SIGILL);
154 p->p_sigignore &= ~sig;
155 p->p_sigcatch &= ~sig;
156 p->p_sigmask &= ~sig;
157 /* sendsig is called with signal lock held */
158 psignal_lock(p, SIGILL, 0, 1);
159 return;
160 }
161
162 /*
163 * System call to cleanup state after a signal
164 * has been taken. Reset signal mask and
165 * stack state from context left by sendsig (above).
166 * Return to previous pc and psl as specified by
167 * context left by sendsig. Check carefully to
168 * make sure that the user has not modified the
169 * psl to gain improper priviledges or to cause
170 * a machine fault.
171 */
172 struct sigreturn_args {
173 struct sigcontext *sigcntxp;
174 };
175
176 /* ARGSUSED */
177 int
178 sigreturn(p, uap, retval)
179 struct proc *p;
180 struct sigreturn_args *uap;
181 int *retval;
182 {
183 struct sigcontext context;
184 struct sigregs *p_regs;
185 int error;
186 struct thread *thread;
187 thread_act_t th_act;
188 struct ppc_saved_state statep;
189 struct ppc_float_state fs;
190 unsigned long state_count;
191 unsigned int nbits, rbits;
192
193 thread = current_thread();
194 th_act = current_act();
195
196 if (error = copyin(uap->sigcntxp, &context, sizeof(context))) {
197 return(error);
198 }
199 state_count = PPC_THREAD_STATE_COUNT;
200 if (act_machine_get_state(th_act, PPC_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) {
201 return(EINVAL);
202 }
203 state_count = PPC_FLOAT_STATE_COUNT;
204 if (act_machine_get_state(th_act, PPC_FLOAT_STATE, &fs, &state_count) != KERN_SUCCESS) {
205 return(EINVAL);
206 }
207 nbits = get_msr_nbits();
208 rbits = get_msr_rbits();
209 /* adjust the critical fields */
210 /* make sure naughty bits are off */
211 context.sc_psw &= ~(nbits);
212 /* make sure necessary bits are on */
213 context.sc_psw |= (rbits);
214
215 // /* we return from sigreturns as if we faulted in */
216 // entry->es_flags = (entry->es_flags & ~ES_GATEWAY) | ES_TRAP;
217
218 if (context.sc_regs) {
219 p_regs = (struct sigregs *)context.sc_regs;
220 if (error = copyin(&p_regs->ss, &statep,
221 sizeof(struct ppc_saved_state)))
222 return(error);
223
224 if (error = copyin(&p_regs->fs, &fs,
225 sizeof(struct ppc_float_state)))
226 return(error);
227
228 }
229 else {
230 statep.r1 = context.sc_sp;
231 }
232 // entry->es_general.saved.stack_pointer = context.sc_sp;
233
234 if (context.sc_onstack & 01)
235 p->p_sigacts->ps_sigstk.ss_flags |= SA_ONSTACK;
236 else
237 p->p_sigacts->ps_sigstk.ss_flags &= ~SA_ONSTACK;
238 p->p_sigmask = context.sc_mask &~ sigcantmask;
239 statep.srr0 = context.sc_ir;
240 statep.srr1 = context.sc_psw;
241
242 state_count = PPC_THREAD_STATE_COUNT;
243 if (act_machine_set_state(th_act, PPC_THREAD_STATE, &statep, &state_count) != KERN_SUCCESS) {
244 return(EINVAL);
245 }
246
247 state_count = PPC_FLOAT_STATE_COUNT;
248 if (act_machine_set_state(th_act, PPC_FLOAT_STATE, &fs, &state_count) != KERN_SUCCESS) {
249 return(EINVAL);
250 }
251 return (EJUSTRETURN);
252 }
253
254 /*
255 * machine_exception() performs MD translation
256 * of a mach exception to a unix signal and code.
257 */
258
259 boolean_t
260 machine_exception(
261 int exception,
262 int code,
263 int subcode,
264 int *unix_signal,
265 int *unix_code
266 )
267 {
268 switch(exception) {
269
270 case EXC_BAD_INSTRUCTION:
271 *unix_signal = SIGILL;
272 *unix_code = code;
273 break;
274
275 case EXC_ARITHMETIC:
276 *unix_signal = SIGFPE;
277 *unix_code = code;
278 break;
279
280 case EXC_SOFTWARE:
281 if (code == EXC_PPC_TRAP) {
282 *unix_signal = SIGTRAP;
283 *unix_code = code;
284 break;
285 } else
286 return(FALSE);
287
288 default:
289 return(FALSE);
290 }
291
292 return(TRUE);
293 }
294