1/*
2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * Copyright (c) 1992 NeXT, Inc.
30 *
31 * HISTORY
32 * 13 May 1992 ? at NeXT
33 *	Created.
34 */
35
36#include <mach/mach_types.h>
37#include <mach/exception.h>
38#include <kern/thread.h>
39#include <sys/systm.h>
40#include <sys/param.h>
41#include <sys/proc_internal.h>
42#include <sys/user.h>
43#include <sys/sysproto.h>
44#include <sys/sysent.h>
45#include <sys/ucontext.h>
46#include <sys/wait.h>
47#include <mach/thread_act.h>    /* for thread_abort_safely */
48#include <mach/thread_status.h>
49#include <mach/arm/thread_state.h>
50#include <mach/arm/thread_status.h>
51#include <arm/machine_routines.h>
52#include <machine/pal_routines.h>
53#include <sys/kdebug.h>
54#include <sys/sdt.h>
55
56#define C_32_STK_ALIGN          16
57#define C_32_PARAMSAVE_LEN      32
58#define C_32_LINKAGE_LEN        48
59
60#define TRUNC_DOWN32(a,c)   ((((uint32_t)a)-(c)) & ((uint32_t)(-(c))))
61
62/*
63 * The stack layout possibilities (info style); This needs to mach with signal trampoline code
64 *
65 * Traditional:			1
66 * 32bit context		30
67 */
68#define UC_TRAD			1
69#define UC_FLAVOR		30
70
71 /* The following are valid mcontext sizes */
72#define UC_FLAVOR_SIZE ((ARM_THREAD_STATE_COUNT + ARM_EXCEPTION_STATE_COUNT + ARM_VFP_STATE_COUNT) * sizeof(int))
73
74/*
75 * Send an interrupt to process.
76 *
77 * Stack is set up to allow sigcode stored
78 * in u. to call routine, followed by chmk
79 * to sigreturn routine below.  After sigreturn
80 * resets the signal mask, the stack, the frame
81 * pointer, and the argument pointer, it returns
82 * to the user specified pc, psl.
83 */
84
85void sendsig(struct proc *p, user_addr_t ua_catcher, int sig, int mask, __unused uint32_t code)
86{
87    user_addr_t ua_sp;
88    user_addr_t ua_sip;
89    user_addr_t trampact;
90    user_addr_t ua_uctxp;
91    user_addr_t ua_mctxp;
92    user_siginfo_t  sinfo32;
93
94    struct uthread *ut;
95    struct mcontext mctx32;
96    struct user_ucontext32 uctx32;
97    struct sigacts *ps = p->p_sigacts;
98
99    void *state;
100    arm_thread_state_t *tstate32;
101    mach_msg_type_number_t state_count;
102
103    int stack_size = 0;
104    int infostyle = UC_TRAD;
105    int oonstack, flavor, error;
106
107    proc_unlock(p);
108
109    thread_t thread = current_thread();
110    ut = get_bsdthread_info(thread);
111
112    /*
113     * Set up thread state info.
114     */
115    flavor = ARM_THREAD_STATE;
116    state = (void *)&mctx32.ss;
117    state_count = ARM_THREAD_STATE_COUNT;
118    if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS)
119        goto bad;
120
121    flavor = ARM_EXCEPTION_STATE;
122    state = (void *)&mctx32.es;
123    state_count = ARM_EXCEPTION_STATE_COUNT;
124    if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS)
125        goto bad;
126
127    flavor = ARM_VFP_STATE;
128    state = (void *)&mctx32.fs;
129    state_count = ARM_VFP_STATE_COUNT;
130    if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS)
131        goto bad;
132
133    tstate32 = &mctx32.ss;
134
135    /*
136     * Set the signal style.
137     */
138    if (p->p_sigacts->ps_siginfo & sigmask(sig))
139        infostyle = UC_FLAVOR;
140
141    /*
142     * Get the signal disposition.
143     */
144    trampact = ps->ps_trampact[sig];
145
146    /*
147     * Figure out where our new stack lives.
148     */
149    oonstack = ut->uu_sigstk.ss_flags & SA_ONSTACK;
150    if ((ut->uu_flag & UT_ALTSTACK) && !oonstack && (ps->ps_sigonstack & sigmask(sig))) {
151        ua_sp = ut->uu_sigstk.ss_sp;
152        ua_sp += ut->uu_sigstk.ss_size;
153        stack_size = ut->uu_sigstk.ss_size;
154        ut->uu_sigstk.ss_flags |= SA_ONSTACK;
155    } else {
156        ua_sp = tstate32->sp;
157    }
158
159    /*
160     * Set up the stack.
161     */
162    ua_sp -= UC_FLAVOR_SIZE;
163    ua_mctxp = ua_sp;
164
165    ua_sp -= sizeof(struct user_ucontext32);
166    ua_uctxp = ua_sp;
167
168    ua_sp -= sizeof(siginfo_t);
169    ua_sip = ua_sp;
170
171    /*
172     * Align the stack pointer.
173     */
174    ua_sp = TRUNC_DOWN32(ua_sp, C_32_STK_ALIGN);
175
176    /*
177     * Build the signal context to be used by sigreturn.
178     */
179    uctx32.uc_onstack = oonstack;
180    uctx32.uc_sigmask = mask;
181    uctx32.uc_stack.ss_sp = ua_sp;
182    uctx32.uc_stack.ss_size = stack_size;
183
184    if (oonstack)
185            uctx32.uc_stack.ss_flags |= SS_ONSTACK;
186
187    uctx32.uc_link = 0;
188
189    uctx32.uc_mcsize = UC_FLAVOR_SIZE;
190
191    uctx32.uc_mcontext = ua_mctxp;
192
193    /*
194     * init siginfo
195     */
196    bzero((caddr_t)&sinfo32, sizeof(user_siginfo_t));
197
198    sinfo32.si_signo = sig;
199    sinfo32.pad[0]  = tstate32->sp;
200    sinfo32.si_addr = tstate32->lr;
201
202    switch (sig) {
203        case SIGILL:
204            sinfo32.si_code = ILL_NOOP;
205            break;
206        case SIGFPE:
207            sinfo32.si_code = FPE_NOOP;
208            break;
209        case SIGBUS:
210            sinfo32.si_code = BUS_ADRALN;
211            break;
212        case SIGSEGV:
213            sinfo32.si_code = SEGV_ACCERR;
214            break;
215        default:
216            {
217                int status_and_exitcode;
218
219                /*
220                 * All other signals need to fill out a minimum set of
221                 * information for the siginfo structure passed into
222                 * the signal handler, if SA_SIGINFO was specified.
223                 *
224                 * p->si_status actually contains both the status and
225                 * the exit code; we save it off in its own variable
226                 * for later breakdown.
227                 */
228                proc_lock(p);
229                sinfo32.si_pid = p->si_pid;
230                p->si_pid = 0;
231                status_and_exitcode = p->si_status;
232                p->si_status = 0;
233                sinfo32.si_uid = p->si_uid;
234                p->si_uid = 0;
235                sinfo32.si_code = p->si_code;
236                p->si_code = 0;
237                proc_unlock(p);
238                if (sinfo32.si_code == CLD_EXITED) {
239                    if (WIFEXITED(status_and_exitcode))
240                        sinfo32.si_code = CLD_EXITED;
241                    else if (WIFSIGNALED(status_and_exitcode)) {
242                        if (WCOREDUMP(status_and_exitcode)) {
243                            sinfo32.si_code = CLD_DUMPED;
244                            status_and_exitcode = W_EXITCODE(status_and_exitcode, status_and_exitcode);
245                        } else {
246                            sinfo32.si_code = CLD_KILLED;
247                            status_and_exitcode = W_EXITCODE(status_and_exitcode, status_and_exitcode);
248                        }
249                    }
250                }
251                /*
252                 * The recorded status contains the exit code and the
253                 * signal information, but the information to be passed
254                 * in the siginfo to the handler is supposed to only
255                 * contain the status, so we have to shift it out.
256                 */
257                sinfo32.si_status = WEXITSTATUS(status_and_exitcode);
258                break;
259            }
260    }
261
262    /*
263     * Copy out context info.
264     */
265    if (copyout((caddr_t)&uctx32, ua_uctxp, sizeof(struct user_ucontext32)))
266        goto bad;
267    if (copyout((caddr_t)&sinfo32, ua_sip, sizeof(user_siginfo_t)))
268        goto bad;
269    if (copyout((caddr_t)&mctx32, ua_mctxp, sizeof(struct mcontext)))
270        goto bad;
271    if (copyout((caddr_t)&ua_uctxp, ua_sp, sizeof(user_addr_t)))
272        goto bad;
273
274    /*
275     * Set up regsiters for the trampoline.
276     */
277    tstate32->r[0] = ua_catcher;
278    tstate32->r[1] = infostyle;
279    tstate32->r[2] = sig;
280    tstate32->r[3] = ua_sip;
281    tstate32->sp = ua_sp;
282
283    if (trampact & 0x01) {
284        tstate32->lr = trampact;
285        tstate32->cpsr = 0x10; /* ARM_FIQ_MODE */
286    } else {
287        trampact &= ~0x01;
288        tstate32->lr = trampact;
289        tstate32->cpsr = 0x30; /* ARM_THUMB_MODE | ARM_USER_MODE */
290    }
291
292    /*
293     * Call the trampoline.
294     */
295    flavor = ARM_THREAD_STATE;
296    state_count = ARM_THREAD_STATE_COUNT;
297    state = (void *)tstate32;
298    if ((error = thread_setstatus(thread, flavor, (thread_state_t)state, state_count)) != KERN_SUCCESS)
299        panic("sendsig: thread_setstatus failed, ret = %08X\n", error);
300
301    proc_lock(p);
302
303    return;
304
305bad:
306    proc_lock(p);
307    SIGACTION(p, SIGILL) = SIG_DFL;
308    sig = sigmask(SIGILL);
309    p->p_sigignore &= ~sig;
310    p->p_sigcatch &= ~sig;
311    ut->uu_sigmask &= ~sig;
312
313    /*
314     * sendsig is called with signal lock held
315     */
316    proc_unlock(p);
317    psignal_locked(p, SIGILL);
318    proc_lock(p);
319
320    return;
321}
322
323/*
324 * System call to cleanup state after a signal
325 * has been taken.  Reset signal mask and
326 * stack state from context left by sendsig (above).
327 * Return to previous pc and psl as specified by
328 * context left by sendsig. Check carefully to
329 * make sure that the user has not modified the
330 * psl to gain improper priviledges or to cause
331 * a machine fault.
332 */
333
334int sigreturn(struct proc *p, struct sigreturn_args *uap, __unused int *retval)
335{
336    void *state;
337    int onstack = 0;
338    int error, flavor;
339    thread_t thread;
340    struct uthread *ut;
341    struct mcontext mctx32;
342    struct user_ucontext32 uctx32;
343    mach_msg_type_number_t state_count;
344
345    thread = current_thread();
346    ut = get_bsdthread_info(thread);
347
348    /*
349     * Retrieve the user context that contains our machine context.
350     */
351    if ((error = copyin(uap->uctx, (void *)&uctx32, sizeof(struct user_ucontext32))))
352        return (error);
353
354    /*
355     * Validate that our machine context is the right size.
356     */
357    if (uctx32.uc_mcsize != UC_FLAVOR_SIZE)
358        return (EINVAL);
359
360    /*
361     * Populate our machine context info that we need to restore.
362     */
363    if ((error = copyin(uctx32.uc_mcontext, (void *)&mctx32, UC_FLAVOR_SIZE)))
364        return (error);
365
366    /*
367     * Restore the signal mask.
368     */
369    ut->uu_sigmask = uctx32.uc_sigmask & ~sigcantmask;
370
371    /*
372     * Restore other signal info.
373     */
374    if ((uctx32.uc_onstack & 0x01))
375        ut->uu_sigstk.ss_flags |= SA_ONSTACK;
376    else
377        ut->uu_sigstk.ss_flags &= ~SA_ONSTACK;
378
379    if (ut->uu_siglist & ~ut->uu_sigmask)
380        signal_setast(thread);
381
382    /*
383     * Restore the states from our machine context.
384     * NOTE: we don't really need to check on infostyle since state restoring
385     * for UC_TRAD and UC_FLAVOR is identical on this architecture.
386     */
387    flavor = ARM_THREAD_STATE;
388    state = (void *)&mctx32.ss;
389    state_count = ARM_THREAD_STATE_COUNT;
390    if (thread_setstatus(thread, flavor, (thread_state_t)state, state_count) != KERN_SUCCESS)
391        return (EINVAL);
392
393    flavor = ARM_VFP_STATE;
394    state = (void *)&mctx32.fs;
395    state_count = ARM_VFP_STATE_COUNT;
396    if (thread_setstatus(thread, flavor, (thread_state_t)state, state_count) != KERN_SUCCESS)
397        return (EINVAL);
398
399    return (EJUSTRETURN);
400}
401
402/*
403 * machine_exception() performs MD translation
404 * of a mach exception to a unix signal and code.
405 */
406
407boolean_t machine_exception(int exception, mach_exception_code_t code, __unused mach_exception_subcode_t subcode, int *unix_signal, mach_exception_code_t * unix_code)
408{
409
410    switch (exception) {
411        case EXC_BAD_ACCESS:
412            /*
413             * Map GP fault to SIGSEGV, otherwise defer to caller
414             */
415            *unix_signal = SIGSEGV;
416            *unix_code = code;
417            return (FALSE);
418        case EXC_BAD_INSTRUCTION:
419            *unix_signal = SIGILL;
420            *unix_code = code;
421            break;
422        case EXC_ARITHMETIC:
423            *unix_signal = SIGFPE;
424            *unix_code = code;
425            break;
426        case EXC_SOFTWARE:
427            *unix_signal = SIGTRAP;
428            *unix_code = code;
429            break;
430        default:
431            return (FALSE);
432    }
433
434    return (TRUE);
435}
436