]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/dev/i386/unix_signal.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / dev / i386 / unix_signal.c
index eb96e879edaba0d778bd1f805c533b7a71a52a6c..1a531a286cdad48963683a5a78ab38018225b7b4 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- * 
+ *
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * This file contains Original Code and/or Modifications of Original Code
  * as defined in and that are subject to the Apple Public Source License
  * Version 2.0 (the 'License'). You may not use this file except in
  * unlawful or unlicensed copies of an Apple operating system, or to
  * circumvent, violate, or enable the circumvention or violation of, any
  * terms of an Apple operating system software license agreement.
  * unlawful or unlicensed copies of an Apple operating system, or to
  * circumvent, violate, or enable the circumvention or violation of, any
  * terms of an Apple operating system software license agreement.
- * 
+ *
  * Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this file.
  * Please obtain a copy of the License at
  * http://www.opensource.apple.com/apsl/ and read it before using this file.
- * 
+ *
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * The Original Code and all software distributed under the License are
  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
  * Please see the License for the specific language governing rights and
  * limitations under the License.
- * 
+ *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
-/* 
+/*
  * Copyright (c) 1992 NeXT, Inc.
  *
  * HISTORY
  * Copyright (c) 1992 NeXT, Inc.
  *
  * HISTORY
@@ -37,6 +37,7 @@
 #include <mach/exception.h>
 
 #include <kern/thread.h>
 #include <mach/exception.h>
 
 #include <kern/thread.h>
+#include <kern/ast.h>
 
 #include <sys/systm.h>
 #include <sys/param.h>
 
 #include <sys/systm.h>
 #include <sys/param.h>
 #include <sys/sysent.h>
 #include <sys/ucontext.h>
 #include <sys/wait.h>
 #include <sys/sysent.h>
 #include <sys/ucontext.h>
 #include <sys/wait.h>
-#include <mach/thread_act.h>   /* for thread_abort_safely */
-#include <mach/thread_status.h>        
+
+#include <sys/ux_exception.h>
+
+#include <mach/thread_act.h>    /* for thread_abort_safely */
+#include <mach/thread_status.h>
 
 #include <i386/eflags.h>
 #include <i386/psl.h>
 #include <i386/machine_routines.h>
 #include <i386/seg.h>
 
 #include <i386/eflags.h>
 #include <i386/psl.h>
 #include <i386/machine_routines.h>
 #include <i386/seg.h>
+#include <i386/fpu.h>
 
 
-#include <sys/kdebug.h>
+#include <machine/pal_routines.h>
 
 
+#include <sys/kdebug.h>
 #include <sys/sdt.h>
 
 
 #include <sys/sdt.h>
 
 
-
 /* Forward: */
 /* Forward: */
-extern boolean_t machine_exception(int, mach_exception_code_t, 
-               mach_exception_subcode_t, int *, mach_exception_subcode_t *);
-extern kern_return_t thread_getstatus(register thread_t act, int flavor,
-                       thread_state_t tstate, mach_msg_type_number_t *count);
+extern kern_return_t thread_getstatus(thread_t act, int flavor,
+    thread_state_t tstate, mach_msg_type_number_t *count);
 extern kern_return_t thread_setstatus(thread_t thread, int flavor,
 extern kern_return_t thread_setstatus(thread_t thread, int flavor,
-                       thread_state_t tstate, mach_msg_type_number_t count);
+    thread_state_t tstate, mach_msg_type_number_t count);
 
 /* Signal handler flavors supported */
 /* These defns should match the Libc implmn */
 
 /* Signal handler flavors supported */
 /* These defns should match the Libc implmn */
-#define UC_TRAD                        1
-#define UC_FLAVOR              30
-#define        UC_SET_ALT_STACK        0x40000000
-#define        UC_RESET_ALT_STACK      0x80000000
+#define UC_TRAD                 1
+#define UC_FLAVOR               30
+#define UC_SET_ALT_STACK        0x40000000
+#define UC_RESET_ALT_STACK      0x80000000
 
 
-#define        C_32_STK_ALIGN          16
-#define        C_64_STK_ALIGN          16
-#define        C_64_REDZONE_LEN        128
-#define TRUNC_DOWN32(a,c)      ((((uint32_t)a)-(c)) & ((uint32_t)(-(c))))
-#define TRUNC_DOWN64(a,c)      ((((uint64_t)a)-(c)) & ((uint64_t)(-(c))))
+#define C_32_STK_ALIGN          16
+#define C_64_STK_ALIGN          16
+#define C_64_REDZONE_LEN        128
+#define TRUNC_DOWN32(a, c)       ((((uint32_t)a)-(c)) & ((uint32_t)(-(c))))
+#define TRUNC_DOWN64(a, c)       ((((uint64_t)a)-(c)) & ((uint64_t)(-(c))))
 
 /*
  * Send an interrupt to process.
 
 /*
  * Send an interrupt to process.
@@ -87,85 +90,118 @@ extern kern_return_t thread_setstatus(thread_t thread, int flavor,
  * Stack is set up to allow sigcode stored
  * in u. to call routine, followed by chmk
  * to sigreturn routine below.  After sigreturn
  * Stack is set up to allow sigcode stored
  * in u. to call routine, followed by chmk
  * to sigreturn routine below.  After sigreturn
- * resets the signal mask, the stack, the frame 
+ * resets the signal mask, the stack, the frame
  * pointer, and the argument pointer, it returns
  * to the user specified pc, psl.
  */
 struct sigframe32 {
  * pointer, and the argument pointer, it returns
  * to the user specified pc, psl.
  */
 struct sigframe32 {
-       int             retaddr;
-       user32_addr_t   catcher; /* sig_t */
-       int             sigstyle;
-       int             sig;
-       user32_addr_t   sinfo;  /* siginfo32_t* */
-       user32_addr_t   uctx;   /* struct ucontext32 */
+       int             retaddr;
+       user32_addr_t   catcher; /* sig_t */
+       int             sigstyle;
+       int             sig;
+       user32_addr_t   sinfo;  /* siginfo32_t* */
+       user32_addr_t   uctx;   /* struct ucontext32 */
+       user32_addr_t   token;
+};
+
+/*
+ * Declare table of structure flavors and sizes for 64-bit and 32-bit processes
+ * for the cases of extended states (plain FP, or AVX):
+ */
+typedef struct {
+       int flavor; natural_t state_count; size_t  mcontext_size;
+} xstate_info_t;
+static const xstate_info_t thread_state64[] = {
+       [FP]          = { x86_FLOAT_STATE64, x86_FLOAT_STATE64_COUNT, sizeof(struct mcontext64) },
+       [FP_FULL]     = { x86_FLOAT_STATE64, x86_FLOAT_STATE64_COUNT, sizeof(struct mcontext64_full) },
+       [AVX]         = { x86_AVX_STATE64, x86_AVX_STATE64_COUNT, sizeof(struct mcontext_avx64) },
+       [AVX_FULL]    = { x86_AVX_STATE64, x86_AVX_STATE64_COUNT, sizeof(struct mcontext_avx64_full) },
+       [AVX512]      = { x86_AVX512_STATE64, x86_AVX512_STATE64_COUNT, sizeof(struct mcontext_avx512_64) },
+       [AVX512_FULL] = { x86_AVX512_STATE64, x86_AVX512_STATE64_COUNT, sizeof(struct mcontext_avx512_64_full) }
+};
+static const xstate_info_t thread_state32[] = {
+       [FP]     = { x86_FLOAT_STATE32, x86_FLOAT_STATE32_COUNT, sizeof(struct mcontext32) },
+       [AVX]    = { x86_AVX_STATE32, x86_AVX_STATE32_COUNT, sizeof(struct mcontext_avx32) },
+       [AVX512] = { x86_AVX512_STATE32, x86_AVX512_STATE32_COUNT, sizeof(struct mcontext_avx512_32) }
 };
 
 /*
  * NOTE: Source and target may *NOT* overlap!
 };
 
 /*
  * NOTE: Source and target may *NOT* overlap!
+ * XXX: Unify with bsd/kern/kern_exit.c
  */
 static void
  */
 static void
-siginfo_user_to_user32(user_siginfo_t *in, user32_siginfo_t *out)
+siginfo_user_to_user32_x86(user_siginfo_t *in, user32_siginfo_t *out)
 {
 {
-       out->si_signo   = in->si_signo;
-       out->si_errno   = in->si_errno;
-       out->si_code    = in->si_code;
-       out->si_pid     = in->si_pid;
-       out->si_uid     = in->si_uid;
-       out->si_status  = in->si_status;
-       out->si_addr    = CAST_DOWN_EXPLICIT(user32_addr_t,in->si_addr);
+       out->si_signo   = in->si_signo;
+       out->si_errno   = in->si_errno;
+       out->si_code    = in->si_code;
+       out->si_pid     = in->si_pid;
+       out->si_uid     = in->si_uid;
+       out->si_status  = in->si_status;
+       out->si_addr    = CAST_DOWN_EXPLICIT(user32_addr_t, in->si_addr);
        /* following cast works for sival_int because of padding */
        /* following cast works for sival_int because of padding */
-       out->si_value.sival_ptr = CAST_DOWN_EXPLICIT(user32_addr_t,in->si_value.sival_ptr);
-       out->si_band    = in->si_band;                  /* range reduction */
-       out->__pad[0]   = in->pad[0];                   /* mcontext.ss.r1 */
+       out->si_value.sival_ptr = CAST_DOWN_EXPLICIT(user32_addr_t, in->si_value.sival_ptr);
+       out->si_band    = in->si_band;                  /* range reduction */
+       out->__pad[0]   = in->pad[0];                   /* mcontext.ss.r1 */
 }
 
 static void
 }
 
 static void
-siginfo_user_to_user64(user_siginfo_t *in, user64_siginfo_t *out)
+siginfo_user_to_user64_x86(user_siginfo_t *in, user64_siginfo_t *out)
 {
 {
-       out->si_signo   = in->si_signo;
-       out->si_errno   = in->si_errno;
-       out->si_code    = in->si_code;
-       out->si_pid     = in->si_pid;
-       out->si_uid     = in->si_uid;
-       out->si_status  = in->si_status;
-       out->si_addr    = in->si_addr;
-       out->si_value.sival_ptr = in->si_value.sival_ptr;
-       out->si_band    = in->si_band;                  /* range reduction */
-       out->__pad[0]   = in->pad[0];                   /* mcontext.ss.r1 */
+       out->si_signo   = in->si_signo;
+       out->si_errno   = in->si_errno;
+       out->si_code    = in->si_code;
+       out->si_pid     = in->si_pid;
+       out->si_uid     = in->si_uid;
+       out->si_status  = in->si_status;
+       out->si_addr    = in->si_addr;
+       out->si_value.sival_ptr = in->si_value.sival_ptr;
+       out->si_band    = in->si_band;                  /* range reduction */
+       out->__pad[0]   = in->pad[0];                   /* mcontext.ss.r1 */
 }
 
 void
 }
 
 void
-sendsig(struct proc *p, user_addr_t ua_catcher, int sig, int mask, __unused uint32_t code)
+sendsig(struct proc *p, user_addr_t ua_catcher, int sig, int mask, __unused uint32_t code, sigset_t siginfo)
 {
 {
-        union {
-           struct mcontext32   mctx32;
-           struct mcontext64   mctx64;
-       } mctx;
-       user_addr_t     ua_sp;
-       user_addr_t     ua_fp;
-       user_addr_t     ua_cr2;
-       user_addr_t     ua_sip;
-       user_addr_t     ua_uctxp;
-       user_addr_t     ua_mctxp;
-       user_siginfo_t  sinfo64;
+       union {
+               struct mcontext_avx32           mctx_avx32;
+               struct mcontext_avx64           mctx_avx64;
+               struct mcontext_avx64_full      mctx_avx64_full;
+               struct mcontext_avx512_32       mctx_avx512_32;
+               struct mcontext_avx512_64       mctx_avx512_64;
+               struct mcontext_avx512_64_full  mctx_avx512_64_full;
+       } mctx_store, *mctxp = &mctx_store;
+
+       user_addr_t     ua_sp;
+       user_addr_t     ua_fp;
+       user_addr_t     ua_cr2;
+       user_addr_t     ua_sip;
+       user_addr_t     ua_uctxp;
+       user_addr_t     ua_mctxp;
+       user_siginfo_t  sinfo64;
 
        struct sigacts *ps = p->p_sigacts;
 
        struct sigacts *ps = p->p_sigacts;
-       int oonstack, flavor; 
+       int oonstack, flavor;
        user_addr_t trampact;
        int sigonstack;
        user_addr_t trampact;
        int sigonstack;
-       void * state;
+       void * state, *fpstate;
        mach_msg_type_number_t state_count;
 
        thread_t thread;
        struct uthread * ut;
        int stack_size = 0;
        int infostyle = UC_TRAD;
        mach_msg_type_number_t state_count;
 
        thread_t thread;
        struct uthread * ut;
        int stack_size = 0;
        int infostyle = UC_TRAD;
-    
+       xstate_t        sig_xstate;
+       user_addr_t     token_uctx;
+       kern_return_t   kr;
+       boolean_t       reset_ss = TRUE;
+
        thread = current_thread();
        ut = get_bsdthread_info(thread);
 
        thread = current_thread();
        ut = get_bsdthread_info(thread);
 
-       if (p->p_sigacts->ps_siginfo & sigmask(sig))
+       if (siginfo & sigmask(sig)) {
                infostyle = UC_FLAVOR;
                infostyle = UC_FLAVOR;
+       }
 
        oonstack = ut->uu_sigstk.ss_flags & SA_ONSTACK;
        trampact = ps->ps_trampact[sig];
 
        oonstack = ut->uu_sigstk.ss_flags & SA_ONSTACK;
        trampact = ps->ps_trampact[sig];
@@ -178,31 +214,69 @@ sendsig(struct proc *p, user_addr_t ua_catcher, int sig, int mask, __unused uint
 
        bzero((caddr_t)&sinfo64, sizeof(sinfo64));
        sinfo64.si_signo = sig;
 
        bzero((caddr_t)&sinfo64, sizeof(sinfo64));
        sinfo64.si_signo = sig;
-               
+
+       bzero(mctxp, sizeof(*mctxp));
+
+       sig_xstate = current_xstate();
 
        if (proc_is64bit(p)) {
 
        if (proc_is64bit(p)) {
-               x86_thread_state64_t    *tstate64;
-               struct user_ucontext64  uctx64;
+               x86_thread_state64_t    *tstate64;
+               struct user_ucontext64  uctx64;
+               user64_addr_t token;
+               int task_has_ldt = thread_task_has_ldt(thread);
+
+               if (task_has_ldt) {
+                       flavor = x86_THREAD_FULL_STATE64;
+                       state_count = x86_THREAD_FULL_STATE64_COUNT;
+                       fpstate = (void *)&mctxp->mctx_avx64_full.fs;
+                       sig_xstate |= STATE64_FULL;
+               } else {
+                       flavor = x86_THREAD_STATE64;
+                       state_count = x86_THREAD_STATE64_COUNT;
+                       fpstate = (void *)&mctxp->mctx_avx64.fs;
+               }
+               state = (void *)&mctxp->mctx_avx64.ss;
 
 
-               flavor = x86_THREAD_STATE64;
-               state_count = x86_THREAD_STATE64_COUNT;
-               state = (void *)&mctx.mctx64.ss;
-               if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS)
-                       goto bad;
+               /*
+                * The state copying is performed with pointers to fields in the state
+                * struct.  This works specifically because the mcontext is layed-out with the
+                * variable-sized FP-state as the last member.  However, with the requirement
+                * to support passing "full" 64-bit state to the signal handler, that layout has now
+                * changed (since the "full" state has a larger "ss" member than the non-"full"
+                * structure.  Because of this, and to retain the array-lookup method of determining
+                * structure sizes, we OR-in STATE64_FULL to sig_xstate to ensure the proper mcontext
+                * size is passed.
+                */
 
 
-               flavor = x86_FLOAT_STATE64;
-               state_count = x86_FLOAT_STATE64_COUNT;
-               state = (void *)&mctx.mctx64.fs;
-               if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS)
-                       goto bad;
+               if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS) {
+                       goto bad;
+               }
+
+               if ((sig_xstate & STATE64_FULL) && mctxp->mctx_avx64.ss.cs != USER64_CS) {
+                       if ((ut->uu_flag & UT_ALTSTACK) && !oonstack &&
+                           (sigonstack)) {
+                               reset_ss = TRUE;
+                       } else {
+                               reset_ss = FALSE;
+                       }
+               } else {
+                       reset_ss = FALSE;
+               }
+
+               flavor      = thread_state64[sig_xstate].flavor;
+               state_count = thread_state64[sig_xstate].state_count;
+               if (thread_getstatus(thread, flavor, (thread_state_t)fpstate, &state_count) != KERN_SUCCESS) {
+                       goto bad;
+               }
 
                flavor = x86_EXCEPTION_STATE64;
                state_count = x86_EXCEPTION_STATE64_COUNT;
 
                flavor = x86_EXCEPTION_STATE64;
                state_count = x86_EXCEPTION_STATE64_COUNT;
-               state = (void *)&mctx.mctx64.es;
-               if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS)
-                       goto bad;
+               state = (void *)&mctxp->mctx_avx64.es;
+               if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS) {
+                       goto bad;
+               }
 
 
-               tstate64 = &mctx.mctx64.ss;
+               tstate64 = &mctxp->mctx_avx64.ss;
 
                /* figure out where our new stack lives */
                if ((ut->uu_flag & UT_ALTSTACK) && !oonstack &&
 
                /* figure out where our new stack lives */
                if ((ut->uu_flag & UT_ALTSTACK) && !oonstack &&
@@ -212,20 +286,23 @@ sendsig(struct proc *p, user_addr_t ua_catcher, int sig, int mask, __unused uint
                        ua_sp += stack_size;
                        ut->uu_sigstk.ss_flags |= SA_ONSTACK;
                } else {
                        ua_sp += stack_size;
                        ut->uu_sigstk.ss_flags |= SA_ONSTACK;
                } else {
-                       ua_sp = tstate64->rsp;
+                       if ((sig_xstate & STATE64_FULL) && tstate64->cs != USER64_CS) {
+                               reset_ss = FALSE;
+                       }
+                       ua_sp = tstate64->rsp;
                }
                }
-               ua_cr2 = mctx.mctx64.es.faultvaddr;
+               ua_cr2 = mctxp->mctx_avx64.es.faultvaddr;
 
                /* The x86_64 ABI defines a 128-byte red zone. */
                ua_sp -= C_64_REDZONE_LEN;
 
 
                /* The x86_64 ABI defines a 128-byte red zone. */
                ua_sp -= C_64_REDZONE_LEN;
 
-               ua_sp -= sizeof (struct user_ucontext64);
-               ua_uctxp = ua_sp;                        // someone tramples the first word!
+               ua_sp -= sizeof(struct user_ucontext64);
+               ua_uctxp = ua_sp;                        // someone tramples the first word!
 
 
-               ua_sp -= sizeof (user64_siginfo_t);
+               ua_sp -= sizeof(user64_siginfo_t);
                ua_sip = ua_sp;
 
                ua_sip = ua_sp;
 
-               ua_sp -= sizeof (struct mcontext64);
+               ua_sp -= thread_state64[sig_xstate].mcontext_size;
                ua_mctxp = ua_sp;
 
                /*
                ua_mctxp = ua_sp;
 
                /*
@@ -240,6 +317,14 @@ sendsig(struct proc *p, user_addr_t ua_catcher, int sig, int mask, __unused uint
                 */
                ua_fp -= sizeof(user_addr_t);
 
                 */
                ua_fp -= sizeof(user_addr_t);
 
+               /*
+                * Generate the validation token for sigreturn
+                */
+               token_uctx = ua_uctxp;
+               kr = machine_thread_siguctx_pointer_convert_to_user(thread, &token_uctx);
+               assert(kr == KERN_SUCCESS);
+               token = (user64_addr_t)token_uctx ^ (user64_addr_t)ps->ps_sigreturn_token;
+
                /*
                 * Build the signal context to be used by sigreturn.
                 */
                /*
                 * Build the signal context to be used by sigreturn.
                 */
@@ -250,18 +335,21 @@ sendsig(struct proc *p, user_addr_t ua_catcher, int sig, int mask, __unused uint
                uctx64.uc_stack.ss_sp = ua_fp;
                uctx64.uc_stack.ss_size = stack_size;
 
                uctx64.uc_stack.ss_sp = ua_fp;
                uctx64.uc_stack.ss_size = stack_size;
 
-               if (oonstack)
-                       uctx64.uc_stack.ss_flags |= SS_ONSTACK; 
+               if (oonstack) {
+                       uctx64.uc_stack.ss_flags |= SS_ONSTACK;
+               }
                uctx64.uc_link = 0;
 
                uctx64.uc_link = 0;
 
-               uctx64.uc_mcsize = sizeof(struct mcontext64);
+               uctx64.uc_mcsize = thread_state64[sig_xstate].mcontext_size;
                uctx64.uc_mcontext64 = ua_mctxp;
                uctx64.uc_mcontext64 = ua_mctxp;
-               
-               if (copyout((caddr_t)&uctx64, ua_uctxp, sizeof (uctx64))) 
-                       goto bad;
 
 
-               if (copyout((caddr_t)&mctx.mctx64, ua_mctxp, sizeof (struct mcontext64))) 
-                       goto bad;
+               if (copyout((caddr_t)&uctx64, ua_uctxp, sizeof(uctx64))) {
+                       goto bad;
+               }
+
+               if (copyout((caddr_t)&mctx_store, ua_mctxp, thread_state64[sig_xstate].mcontext_size)) {
+                       goto bad;
+               }
 
                sinfo64.pad[0]  = tstate64->rsp;
                sinfo64.si_addr = tstate64->rip;
 
                sinfo64.pad[0]  = tstate64->rsp;
                sinfo64.si_addr = tstate64->rip;
@@ -269,14 +357,34 @@ sendsig(struct proc *p, user_addr_t ua_catcher, int sig, int mask, __unused uint
                tstate64->rip = trampact;
                tstate64->rsp = ua_fp;
                tstate64->rflags = get_eflags_exportmask();
                tstate64->rip = trampact;
                tstate64->rsp = ua_fp;
                tstate64->rflags = get_eflags_exportmask();
+
                /*
                /*
-                * JOE - might not need to set these
+                * SETH - need to set these for processes with LDTs
                 */
                tstate64->cs = USER64_CS;
                tstate64->fs = NULL_SEG;
                 */
                tstate64->cs = USER64_CS;
                tstate64->fs = NULL_SEG;
-               tstate64->gs = USER_CTHREAD;
+               /*
+                * Set gs to 0 here to prevent restoration of %gs on return-to-user.  If we
+                * did NOT do that here and %gs was non-zero, we'd blow away gsbase when
+                * we restore %gs in the kernel exit trampoline.
+                */
+               tstate64->gs = 0;
+
+               if (sig_xstate & STATE64_FULL) {
+                       /* Reset DS, ES, and possibly SS */
+                       if (reset_ss) {
+                               /*
+                                * Restore %ss if (a) an altstack was used for signal delivery
+                                * or (b) %cs at the time of the signal was the default
+                                * (USER64_CS)
+                                */
+                               mctxp->mctx_avx64_full.ss.ss = USER64_DS;
+                       }
+                       mctxp->mctx_avx64_full.ss.ds = USER64_DS;
+                       mctxp->mctx_avx64_full.ss.es = 0;
+               }
 
 
-               /* 
+               /*
                 * Build the argument list for the signal handler.
                 * Handler should call sigreturn to get out of it
                 */
                 * Build the argument list for the signal handler.
                 * Handler should call sigreturn to get out of it
                 */
@@ -285,31 +393,35 @@ sendsig(struct proc *p, user_addr_t ua_catcher, int sig, int mask, __unused uint
                tstate64->rdx = sig;
                tstate64->rcx = ua_sip;
                tstate64->r8  = ua_uctxp;
                tstate64->rdx = sig;
                tstate64->rcx = ua_sip;
                tstate64->r8  = ua_uctxp;
-
+               tstate64->r9  = token;
        } else {
        } else {
-               x86_thread_state32_t    *tstate32;
-               struct user_ucontext32  uctx32;
-               struct sigframe32       frame32;
+               x86_thread_state32_t    *tstate32;
+               struct user_ucontext32  uctx32;
+               struct sigframe32       frame32;
+               user32_addr_t token;
 
 
-               flavor = x86_THREAD_STATE32;
+               flavor = x86_THREAD_STATE32;
                state_count = x86_THREAD_STATE32_COUNT;
                state_count = x86_THREAD_STATE32_COUNT;
-               state = (void *)&mctx.mctx32.ss;
-               if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS)
-                       goto bad;
+               state = (void *)&mctxp->mctx_avx32.ss;
+               if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS) {
+                       goto bad;
+               }
 
 
-               flavor = x86_FLOAT_STATE32;
-               state_count = x86_FLOAT_STATE32_COUNT;
-               state = (void *)&mctx.mctx32.fs;
-               if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS)
-                       goto bad;
+               flavor = thread_state32[sig_xstate].flavor;
+               state_count = thread_state32[sig_xstate].state_count;
+               state = (void *)&mctxp->mctx_avx32.fs;
+               if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS) {
+                       goto bad;
+               }
 
                flavor = x86_EXCEPTION_STATE32;
                state_count = x86_EXCEPTION_STATE32_COUNT;
 
                flavor = x86_EXCEPTION_STATE32;
                state_count = x86_EXCEPTION_STATE32_COUNT;
-               state = (void *)&mctx.mctx32.es;
-               if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS)
-                       goto bad;
+               state = (void *)&mctxp->mctx_avx32.es;
+               if (thread_getstatus(thread, flavor, (thread_state_t)state, &state_count) != KERN_SUCCESS) {
+                       goto bad;
+               }
 
 
-               tstate32 = &mctx.mctx32.ss;
+               tstate32 = &mctxp->mctx_avx32.ss;
 
                /* figure out where our new stack lives */
                if ((ut->uu_flag & UT_ALTSTACK) && !oonstack &&
 
                /* figure out where our new stack lives */
                if ((ut->uu_flag & UT_ALTSTACK) && !oonstack &&
@@ -319,20 +431,20 @@ sendsig(struct proc *p, user_addr_t ua_catcher, int sig, int mask, __unused uint
                        ua_sp += stack_size;
                        ut->uu_sigstk.ss_flags |= SA_ONSTACK;
                } else {
                        ua_sp += stack_size;
                        ut->uu_sigstk.ss_flags |= SA_ONSTACK;
                } else {
-                       ua_sp = tstate32->esp;
+                       ua_sp = tstate32->esp;
                }
                }
-               ua_cr2 = mctx.mctx32.es.faultvaddr;
+               ua_cr2 = mctxp->mctx_avx32.es.faultvaddr;
 
 
-               ua_sp -= sizeof (struct user_ucontext32);
-               ua_uctxp = ua_sp;                        // someone tramples the first word!
+               ua_sp -= sizeof(struct user_ucontext32);
+               ua_uctxp = ua_sp;                        // someone tramples the first word!
 
 
-               ua_sp -= sizeof (user32_siginfo_t);
+               ua_sp -= sizeof(user32_siginfo_t);
                ua_sip = ua_sp;
 
                ua_sip = ua_sp;
 
-               ua_sp -= sizeof (struct mcontext32);
+               ua_sp -= thread_state32[sig_xstate].mcontext_size;
                ua_mctxp = ua_sp;
 
                ua_mctxp = ua_sp;
 
-               ua_sp -= sizeof (struct sigframe32);
+               ua_sp -= sizeof(struct sigframe32);
                ua_fp = ua_sp;
 
                /*
                ua_fp = ua_sp;
 
                /*
@@ -347,19 +459,30 @@ sendsig(struct proc *p, user_addr_t ua_catcher, int sig, int mask, __unused uint
                 */
                ua_fp -= sizeof(frame32.retaddr);
 
                 */
                ua_fp -= sizeof(frame32.retaddr);
 
-               /* 
+               /*
+                * Generate the validation token for sigreturn
+                */
+               token_uctx = ua_uctxp;
+               kr = machine_thread_siguctx_pointer_convert_to_user(thread, &token_uctx);
+               assert(kr == KERN_SUCCESS);
+               token = CAST_DOWN_EXPLICIT(user32_addr_t, token_uctx) ^
+                   CAST_DOWN_EXPLICIT(user32_addr_t, ps->ps_sigreturn_token);
+
+               /*
                 * Build the argument list for the signal handler.
                 * Handler should call sigreturn to get out of it
                 */
                 * Build the argument list for the signal handler.
                 * Handler should call sigreturn to get out of it
                 */
-               frame32.retaddr = -1;   
+               frame32.retaddr = -1;
                frame32.sigstyle = infostyle;
                frame32.sig = sig;
                frame32.catcher = CAST_DOWN_EXPLICIT(user32_addr_t, ua_catcher);
                frame32.sinfo = CAST_DOWN_EXPLICIT(user32_addr_t, ua_sip);
                frame32.uctx = CAST_DOWN_EXPLICIT(user32_addr_t, ua_uctxp);
                frame32.sigstyle = infostyle;
                frame32.sig = sig;
                frame32.catcher = CAST_DOWN_EXPLICIT(user32_addr_t, ua_catcher);
                frame32.sinfo = CAST_DOWN_EXPLICIT(user32_addr_t, ua_sip);
                frame32.uctx = CAST_DOWN_EXPLICIT(user32_addr_t, ua_uctxp);
+               frame32.token = token;
 
 
-               if (copyout((caddr_t)&frame32, ua_fp, sizeof (frame32))) 
-                       goto bad;
+               if (copyout((caddr_t)&frame32, ua_fp, sizeof(frame32))) {
+                       goto bad;
+               }
 
                /*
                 * Build the signal context to be used by sigreturn.
 
                /*
                 * Build the signal context to be used by sigreturn.
@@ -371,151 +494,153 @@ sendsig(struct proc *p, user_addr_t ua_catcher, int sig, int mask, __unused uint
                uctx32.uc_stack.ss_sp = CAST_DOWN_EXPLICIT(user32_addr_t, ua_fp);
                uctx32.uc_stack.ss_size = stack_size;
 
                uctx32.uc_stack.ss_sp = CAST_DOWN_EXPLICIT(user32_addr_t, ua_fp);
                uctx32.uc_stack.ss_size = stack_size;
 
-               if (oonstack)
-                       uctx32.uc_stack.ss_flags |= SS_ONSTACK; 
+               if (oonstack) {
+                       uctx32.uc_stack.ss_flags |= SS_ONSTACK;
+               }
                uctx32.uc_link = 0;
 
                uctx32.uc_link = 0;
 
-               uctx32.uc_mcsize = sizeof(struct mcontext32);
+               uctx32.uc_mcsize = thread_state64[sig_xstate].mcontext_size;
 
                uctx32.uc_mcontext = CAST_DOWN_EXPLICIT(user32_addr_t, ua_mctxp);
 
                uctx32.uc_mcontext = CAST_DOWN_EXPLICIT(user32_addr_t, ua_mctxp);
-               
-               if (copyout((caddr_t)&uctx32, ua_uctxp, sizeof (uctx32))) 
-                       goto bad;
 
 
-               if (copyout((caddr_t)&mctx.mctx32, ua_mctxp, sizeof (struct mcontext32))) 
-                       goto bad;
+               if (copyout((caddr_t)&uctx32, ua_uctxp, sizeof(uctx32))) {
+                       goto bad;
+               }
+
+               if (copyout((caddr_t)&mctx_store, ua_mctxp, thread_state32[sig_xstate].mcontext_size)) {
+                       goto bad;
+               }
 
                sinfo64.pad[0]  = tstate32->esp;
                sinfo64.si_addr = tstate32->eip;
        }
 
        switch (sig) {
 
                sinfo64.pad[0]  = tstate32->esp;
                sinfo64.si_addr = tstate32->eip;
        }
 
        switch (sig) {
-               case SIGILL:
-                       switch (ut->uu_code) {
-                               case EXC_I386_INVOP:
-                                       sinfo64.si_code = ILL_ILLOPC;
-                                       break;
-                               default:
-                                       sinfo64.si_code = ILL_NOOP;
-                       }
+       case SIGILL:
+               switch (ut->uu_code) {
+               case EXC_I386_INVOP:
+                       sinfo64.si_code = ILL_ILLOPC;
                        break;
                        break;
-               case SIGFPE:
+               default:
+                       sinfo64.si_code = ILL_NOOP;
+               }
+               break;
+       case SIGFPE:
 #define FP_IE 0 /* Invalid operation */
 #define FP_DE 1 /* Denormalized operand */
 #define FP_ZE 2 /* Zero divide */
 #define FP_OE 3 /* overflow */
 #define FP_UE 4 /* underflow */
 #define FP_PE 5 /* precision */
 #define FP_IE 0 /* Invalid operation */
 #define FP_DE 1 /* Denormalized operand */
 #define FP_ZE 2 /* Zero divide */
 #define FP_OE 3 /* overflow */
 #define FP_UE 4 /* underflow */
 #define FP_PE 5 /* precision */
-                       if (ut->uu_code == EXC_I386_DIV) {
-                               sinfo64.si_code = FPE_INTDIV;
-                       }
-                       else if (ut->uu_code == EXC_I386_INTO) {
-                               sinfo64.si_code = FPE_INTOVF;
-                       }
-                       else if (ut->uu_subcode & (1 << FP_ZE)) {
-                               sinfo64.si_code = FPE_FLTDIV;
-                       } else if (ut->uu_subcode & (1 << FP_OE)) {
-                               sinfo64.si_code = FPE_FLTOVF;
-                       } else if (ut->uu_subcode & (1 << FP_UE)) {
-                               sinfo64.si_code = FPE_FLTUND;
-                       } else if (ut->uu_subcode & (1 << FP_PE)) {
-                               sinfo64.si_code = FPE_FLTRES;
-                       } else if (ut->uu_subcode & (1 << FP_IE)) {
-                               sinfo64.si_code = FPE_FLTINV;
-                       } else {
-                               sinfo64.si_code = FPE_NOOP;
-                       }
+               if (ut->uu_code == EXC_I386_DIV) {
+                       sinfo64.si_code = FPE_INTDIV;
+               } else if (ut->uu_code == EXC_I386_INTO) {
+                       sinfo64.si_code = FPE_INTOVF;
+               } else if (ut->uu_subcode & (1 << FP_ZE)) {
+                       sinfo64.si_code = FPE_FLTDIV;
+               } else if (ut->uu_subcode & (1 << FP_OE)) {
+                       sinfo64.si_code = FPE_FLTOVF;
+               } else if (ut->uu_subcode & (1 << FP_UE)) {
+                       sinfo64.si_code = FPE_FLTUND;
+               } else if (ut->uu_subcode & (1 << FP_PE)) {
+                       sinfo64.si_code = FPE_FLTRES;
+               } else if (ut->uu_subcode & (1 << FP_IE)) {
+                       sinfo64.si_code = FPE_FLTINV;
+               } else {
+                       sinfo64.si_code = FPE_NOOP;
+               }
+               break;
+       case SIGBUS:
+               sinfo64.si_code = BUS_ADRERR;
+               sinfo64.si_addr = ua_cr2;
+               break;
+       case SIGTRAP:
+               sinfo64.si_code = TRAP_BRKPT;
+               break;
+       case SIGSEGV:
+               sinfo64.si_addr = ua_cr2;
+
+               switch (ut->uu_code) {
+               case EXC_I386_GPFLT:
+                       /* CR2 is meaningless after GP fault */
+                       /* XXX namespace clash! */
+                       sinfo64.si_addr = 0ULL;
+                       sinfo64.si_code = 0;
                        break;
                        break;
-               case SIGBUS:
-                       sinfo64.si_code = BUS_ADRERR;
-                       sinfo64.si_addr = ua_cr2;
+               case KERN_PROTECTION_FAILURE:
+                       sinfo64.si_code = SEGV_ACCERR;
                        break;
                        break;
-               case SIGTRAP:
-                       sinfo64.si_code = TRAP_BRKPT;
+               case KERN_INVALID_ADDRESS:
+                       sinfo64.si_code = SEGV_MAPERR;
                        break;
                        break;
-               case SIGSEGV:
-                       sinfo64.si_addr = ua_cr2;
-
-                       switch (ut->uu_code) {
-                               case EXC_I386_GPFLT:
-                                       /* CR2 is meaningless after GP fault */
-                                       /* XXX namespace clash! */
-                                       sinfo64.si_addr = 0ULL;
-                                       sinfo64.si_code = 0;
-                                       break;
-                               case KERN_PROTECTION_FAILURE:
-                                       sinfo64.si_code = SEGV_ACCERR;
-                                       break;
-                               case KERN_INVALID_ADDRESS:
-                                       sinfo64.si_code = SEGV_MAPERR;
-                                       break;
-                               default:
-                                       sinfo64.si_code = FPE_NOOP;
-                       }
-                               break;
                default:
                default:
-               {
-                       int status_and_exitcode;
+                       sinfo64.si_code = FPE_NOOP;
+               }
+               break;
+       default:
+       {
+               int status_and_exitcode;
 
 
-                       /*
-                        * All other signals need to fill out a minimum set of
-                        * information for the siginfo structure passed into
-                        * the signal handler, if SA_SIGINFO was specified.
-                        *
-                        * p->si_status actually contains both the status and
-                        * the exit code; we save it off in its own variable
-                        * for later breakdown.
-                        */
-                       proc_lock(p);
-                       sinfo64.si_pid = p->si_pid;
-                       p->si_pid =0;
-                       status_and_exitcode = p->si_status;
-                       p->si_status = 0;
-                       sinfo64.si_uid = p->si_uid;
-                       p->si_uid =0;
-                       sinfo64.si_code = p->si_code;
-                       p->si_code = 0;
-                       proc_unlock(p);
-                       if (sinfo64.si_code == CLD_EXITED) {
-                               if (WIFEXITED(status_and_exitcode)) 
-                                       sinfo64.si_code = CLD_EXITED;
-                               else if (WIFSIGNALED(status_and_exitcode)) {
-                                       if (WCOREDUMP(status_and_exitcode)) {
-                                               sinfo64.si_code = CLD_DUMPED;
-                                               status_and_exitcode = W_EXITCODE(status_and_exitcode,status_and_exitcode);
-                                       } else {
-                                               sinfo64.si_code = CLD_KILLED;
-                                               status_and_exitcode = W_EXITCODE(status_and_exitcode,status_and_exitcode);
-                                       }
+               /*
+                * All other signals need to fill out a minimum set of
+                * information for the siginfo structure passed into
+                * the signal handler, if SA_SIGINFO was specified.
+                *
+                * p->si_status actually contains both the status and
+                * the exit code; we save it off in its own variable
+                * for later breakdown.
+                */
+               proc_lock(p);
+               sinfo64.si_pid = p->si_pid;
+               p->si_pid = 0;
+               status_and_exitcode = p->si_status;
+               p->si_status = 0;
+               sinfo64.si_uid = p->si_uid;
+               p->si_uid = 0;
+               sinfo64.si_code = p->si_code;
+               p->si_code = 0;
+               proc_unlock(p);
+               if (sinfo64.si_code == CLD_EXITED) {
+                       if (WIFEXITED(status_and_exitcode)) {
+                               sinfo64.si_code = CLD_EXITED;
+                       } else if (WIFSIGNALED(status_and_exitcode)) {
+                               if (WCOREDUMP(status_and_exitcode)) {
+                                       sinfo64.si_code = CLD_DUMPED;
+                                       status_and_exitcode = W_EXITCODE(status_and_exitcode, status_and_exitcode);
+                               } else {
+                                       sinfo64.si_code = CLD_KILLED;
+                                       status_and_exitcode = W_EXITCODE(status_and_exitcode, status_and_exitcode);
                                }
                        }
                                }
                        }
-                       /*
-                        * The recorded status contains the exit code and the
-                        * signal information, but the information to be passed
-                        * in the siginfo to the handler is supposed to only
-                        * contain the status, so we have to shift it out.
-                        */
-                       sinfo64.si_status = WEXITSTATUS(status_and_exitcode);
-                       break;
                }
                }
+               /*
+                * The recorded status contains the exit code and the
+                * signal information, but the information to be passed
+                * in the siginfo to the handler is supposed to only
+                * contain the status, so we have to shift it out.
+                */
+               sinfo64.si_status = (WEXITSTATUS(status_and_exitcode) & 0x00FFFFFF) | (((uint32_t)(p->p_xhighbits) << 24) & 0xFF000000);
+               p->p_xhighbits = 0;
+               break;
+       }
        }
        if (proc_is64bit(p)) {
                user64_siginfo_t sinfo64_user64;
        }
        if (proc_is64bit(p)) {
                user64_siginfo_t sinfo64_user64;
-               
+
                bzero((caddr_t)&sinfo64_user64, sizeof(sinfo64_user64));
                bzero((caddr_t)&sinfo64_user64, sizeof(sinfo64_user64));
-                         
-               siginfo_user_to_user64(&sinfo64,&sinfo64_user64);
+
+               siginfo_user_to_user64_x86(&sinfo64, &sinfo64_user64);
 
 #if CONFIG_DTRACE
 
 #if CONFIG_DTRACE
-        bzero((caddr_t)&(ut->t_dtrace_siginfo), sizeof(ut->t_dtrace_siginfo));
+               bzero((caddr_t)&(ut->t_dtrace_siginfo), sizeof(ut->t_dtrace_siginfo));
 
 
-        ut->t_dtrace_siginfo.si_signo = sinfo64.si_signo;
-        ut->t_dtrace_siginfo.si_code = sinfo64.si_code;
-        ut->t_dtrace_siginfo.si_pid = sinfo64.si_pid;
-        ut->t_dtrace_siginfo.si_uid = sinfo64.si_uid;
-        ut->t_dtrace_siginfo.si_status = sinfo64.si_status;
+               ut->t_dtrace_siginfo.si_signo = sinfo64.si_signo;
+               ut->t_dtrace_siginfo.si_code = sinfo64.si_code;
+               ut->t_dtrace_siginfo.si_pid = sinfo64.si_pid;
+               ut->t_dtrace_siginfo.si_uid = sinfo64.si_uid;
+               ut->t_dtrace_siginfo.si_status = sinfo64.si_status;
                /* XXX truncates faulting address to void * on K32  */
                /* XXX truncates faulting address to void * on K32  */
-        ut->t_dtrace_siginfo.si_addr = CAST_DOWN(void *, sinfo64.si_addr);
+               ut->t_dtrace_siginfo.si_addr = CAST_DOWN(void *, sinfo64.si_addr);
 
                /* Fire DTrace proc:::fault probe when signal is generated by hardware. */
                switch (sig) {
 
                /* Fire DTrace proc:::fault probe when signal is generated by hardware. */
                switch (sig) {
@@ -528,32 +653,38 @@ sendsig(struct proc *p, user_addr_t ua_catcher, int sig, int mask, __unused uint
 
                /* XXX truncates catcher address to uintptr_t */
                DTRACE_PROC3(signal__handle, int, sig, siginfo_t *, &(ut->t_dtrace_siginfo),
 
                /* XXX truncates catcher address to uintptr_t */
                DTRACE_PROC3(signal__handle, int, sig, siginfo_t *, &(ut->t_dtrace_siginfo),
-                       void (*)(void), CAST_DOWN(sig_t, ua_catcher));
+                   void (*)(void), CAST_DOWN(sig_t, ua_catcher));
 #endif /* CONFIG_DTRACE */
 
 #endif /* CONFIG_DTRACE */
 
-               if (copyout((caddr_t)&sinfo64_user64, ua_sip, sizeof (sinfo64_user64))) 
+               if (copyout((caddr_t)&sinfo64_user64, ua_sip, sizeof(sinfo64_user64))) {
                        goto bad;
                        goto bad;
+               }
 
 
-               flavor = x86_THREAD_STATE64;
-               state_count = x86_THREAD_STATE64_COUNT;
-               state = (void *)&mctx.mctx64.ss;
+               if (sig_xstate & STATE64_FULL) {
+                       flavor = x86_THREAD_FULL_STATE64;
+                       state_count = x86_THREAD_FULL_STATE64_COUNT;
+               } else {
+                       flavor = x86_THREAD_STATE64;
+                       state_count = x86_THREAD_STATE64_COUNT;
+               }
+               state = (void *)&mctxp->mctx_avx64.ss;
        } else {
        } else {
-               x86_thread_state32_t    *tstate32;
+               x86_thread_state32_t    *tstate32;
                user32_siginfo_t sinfo32;
 
                bzero((caddr_t)&sinfo32, sizeof(sinfo32));
 
                user32_siginfo_t sinfo32;
 
                bzero((caddr_t)&sinfo32, sizeof(sinfo32));
 
-               siginfo_user_to_user32(&sinfo64,&sinfo32);
+               siginfo_user_to_user32_x86(&sinfo64, &sinfo32);
 
 #if CONFIG_DTRACE
 
 #if CONFIG_DTRACE
-        bzero((caddr_t)&(ut->t_dtrace_siginfo), sizeof(ut->t_dtrace_siginfo));
+               bzero((caddr_t)&(ut->t_dtrace_siginfo), sizeof(ut->t_dtrace_siginfo));
 
 
-        ut->t_dtrace_siginfo.si_signo = sinfo32.si_signo;
-        ut->t_dtrace_siginfo.si_code = sinfo32.si_code;
-        ut->t_dtrace_siginfo.si_pid = sinfo32.si_pid;
-        ut->t_dtrace_siginfo.si_uid = sinfo32.si_uid;
-        ut->t_dtrace_siginfo.si_status = sinfo32.si_status;
-        ut->t_dtrace_siginfo.si_addr = CAST_DOWN(void *, sinfo32.si_addr);
+               ut->t_dtrace_siginfo.si_signo = sinfo32.si_signo;
+               ut->t_dtrace_siginfo.si_code = sinfo32.si_code;
+               ut->t_dtrace_siginfo.si_pid = sinfo32.si_pid;
+               ut->t_dtrace_siginfo.si_uid = sinfo32.si_uid;
+               ut->t_dtrace_siginfo.si_status = sinfo32.si_status;
+               ut->t_dtrace_siginfo.si_addr = CAST_DOWN(void *, sinfo32.si_addr);
 
                /* Fire DTrace proc:::fault probe when signal is generated by hardware. */
                switch (sig) {
 
                /* Fire DTrace proc:::fault probe when signal is generated by hardware. */
                switch (sig) {
@@ -565,13 +696,14 @@ sendsig(struct proc *p, user_addr_t ua_catcher, int sig, int mask, __unused uint
                }
 
                DTRACE_PROC3(signal__handle, int, sig, siginfo_t *, &(ut->t_dtrace_siginfo),
                }
 
                DTRACE_PROC3(signal__handle, int, sig, siginfo_t *, &(ut->t_dtrace_siginfo),
-                       void (*)(void), CAST_DOWN(sig_t, ua_catcher));
+                   void (*)(void), CAST_DOWN(sig_t, ua_catcher));
 #endif /* CONFIG_DTRACE */
 
 #endif /* CONFIG_DTRACE */
 
-               if (copyout((caddr_t)&sinfo32, ua_sip, sizeof (sinfo32))) 
+               if (copyout((caddr_t)&sinfo32, ua_sip, sizeof(sinfo32))) {
                        goto bad;
                        goto bad;
-       
-               tstate32 = &mctx.mctx32.ss;
+               }
+
+               tstate32 = &mctxp->mctx_avx32.ss;
 
                tstate32->eip = CAST_DOWN_EXPLICIT(user32_addr_t, trampact);
                tstate32->esp = CAST_DOWN_EXPLICIT(user32_addr_t, ua_fp);
 
                tstate32->eip = CAST_DOWN_EXPLICIT(user32_addr_t, trampact);
                tstate32->esp = CAST_DOWN_EXPLICIT(user32_addr_t, ua_fp);
@@ -589,16 +721,20 @@ sendsig(struct proc *p, user_addr_t ua_catcher, int sig, int mask, __unused uint
                state_count = x86_THREAD_STATE32_COUNT;
                state = (void *)tstate32;
        }
                state_count = x86_THREAD_STATE32_COUNT;
                state = (void *)tstate32;
        }
-       if (thread_setstatus(thread, flavor, (thread_state_t)state, state_count) != KERN_SUCCESS)
-               goto bad;
+       if (thread_setstatus(thread, flavor, (thread_state_t)state, state_count) != KERN_SUCCESS) {
+               goto bad;
+       }
        ml_fp_setvalid(FALSE);
 
        ml_fp_setvalid(FALSE);
 
+       /* Tell the PAL layer about the signal */
+       pal_set_signal_delivery( thread );
 
        proc_lock(p);
 
        return;
 
 bad:
 
        proc_lock(p);
 
        return;
 
 bad:
+
        proc_lock(p);
        SIGACTION(p, SIGILL) = SIG_DFL;
        sig = sigmask(SIGILL);
        proc_lock(p);
        SIGACTION(p, SIGILL) = SIG_DFL;
        sig = sigmask(SIGILL);
@@ -626,135 +762,201 @@ bad:
 int
 sigreturn(struct proc *p, struct sigreturn_args *uap, __unused int *retval)
 {
 int
 sigreturn(struct proc *p, struct sigreturn_args *uap, __unused int *retval)
 {
-        union {
-           struct mcontext32   mctx32;
-           struct mcontext64   mctx64;
-       } mctx;
+       union {
+               struct mcontext_avx32           mctx_avx32;
+               struct mcontext_avx64           mctx_avx64;
+               struct mcontext_avx64_full      mctx_avx64_full;
+               struct mcontext_avx512_32       mctx_avx512_32;
+               struct mcontext_avx512_64       mctx_avx512_64;
+               struct mcontext_avx512_64_full  mctx_avx512_64_full;
+       } mctx_store, *mctxp = &mctx_store;
+
        thread_t thread = current_thread();
        struct uthread * ut;
        thread_t thread = current_thread();
        struct uthread * ut;
-       int     error;
-       int     onstack = 0;
+       struct sigacts *ps = p->p_sigacts;
+       int     error;
+       int     onstack = 0;
 
        mach_msg_type_number_t ts_count;
        unsigned int           ts_flavor;
 
        mach_msg_type_number_t ts_count;
        unsigned int           ts_flavor;
-       void                *  ts;
+       void                *  ts;
        mach_msg_type_number_t fs_count;
        unsigned int           fs_flavor;
        mach_msg_type_number_t fs_count;
        unsigned int           fs_flavor;
-       void                *  fs;
+       void                *  fs;
+       int                    rval = EJUSTRETURN;
+       xstate_t               sig_xstate;
+       uint32_t            sigreturn_validation;
+       user_addr_t         token_uctx;
+       kern_return_t       kr;
 
        ut = (struct uthread *)get_bsdthread_info(thread);
 
 
        ut = (struct uthread *)get_bsdthread_info(thread);
 
+       /* see osfmk/kern/restartable.c */
+       act_set_ast_reset_pcs(thread);
        /*
         * If we are being asked to change the altstack flag on the thread, we
         * just set/reset it and return (the uap->uctx is not used).
         */
        if ((unsigned int)uap->infostyle == UC_SET_ALT_STACK) {
                ut->uu_sigstk.ss_flags |= SA_ONSTACK;
        /*
         * If we are being asked to change the altstack flag on the thread, we
         * just set/reset it and return (the uap->uctx is not used).
         */
        if ((unsigned int)uap->infostyle == UC_SET_ALT_STACK) {
                ut->uu_sigstk.ss_flags |= SA_ONSTACK;
-               return (0);
+               return 0;
        } else if ((unsigned int)uap->infostyle == UC_RESET_ALT_STACK) {
                ut->uu_sigstk.ss_flags &= ~SA_ONSTACK;
        } else if ((unsigned int)uap->infostyle == UC_RESET_ALT_STACK) {
                ut->uu_sigstk.ss_flags &= ~SA_ONSTACK;
-               return (0);
+               return 0;
        }
 
        }
 
-       if (proc_is64bit(p)) {
-               struct user_ucontext64  uctx64;
+       bzero(mctxp, sizeof(*mctxp));
 
 
-               if ((error = copyin(uap->uctx, (void *)&uctx64, sizeof (uctx64))))
-                       return(error);
+       sig_xstate = current_xstate();
 
 
-               if ((error = copyin(uctx64.uc_mcontext64, (void *)&mctx.mctx64, sizeof (struct mcontext64))))
-                       return(error);
+       sigreturn_validation = atomic_load_explicit(
+               &ps->ps_sigreturn_validation, memory_order_relaxed);
+       token_uctx = uap->uctx;
+       kr = machine_thread_siguctx_pointer_convert_to_user(thread, &token_uctx);
+       assert(kr == KERN_SUCCESS);
+
+       if (proc_is64bit(p)) {
+               struct user_ucontext64  uctx64;
+               user64_addr_t token;
+               int task_has_ldt = thread_task_has_ldt(thread);
+
+               if ((error = copyin(uap->uctx, (void *)&uctx64, sizeof(uctx64)))) {
+                       return error;
+               }
 
                onstack = uctx64.uc_onstack & 01;
                ut->uu_sigmask = uctx64.uc_sigmask & ~sigcantmask;
 
 
                onstack = uctx64.uc_onstack & 01;
                ut->uu_sigmask = uctx64.uc_sigmask & ~sigcantmask;
 
-               ts_flavor = x86_THREAD_STATE64;
-               ts_count  = x86_THREAD_STATE64_COUNT;
-               ts = (void *)&mctx.mctx64.ss;
+               if (task_has_ldt) {
+                       ts_flavor = x86_THREAD_FULL_STATE64;
+                       ts_count  = x86_THREAD_FULL_STATE64_COUNT;
+                       fs = (void *)&mctxp->mctx_avx64_full.fs;
+                       sig_xstate |= STATE64_FULL;
+               } else {
+                       ts_flavor = x86_THREAD_STATE64;
+                       ts_count  = x86_THREAD_STATE64_COUNT;
+                       fs = (void *)&mctxp->mctx_avx64.fs;
+               }
+
+               if ((error = copyin(uctx64.uc_mcontext64, (void *)mctxp, thread_state64[sig_xstate].mcontext_size))) {
+                       return error;
+               }
 
 
-               fs_flavor = x86_FLOAT_STATE64;
-               fs_count  = x86_FLOAT_STATE64_COUNT;
-               fs = (void *)&mctx.mctx64.fs;
+               ts = (void *)&mctxp->mctx_avx64.ss;
 
 
-      } else {
-               struct user_ucontext32  uctx32;
+               fs_flavor = thread_state64[sig_xstate].flavor;
+               fs_count  = thread_state64[sig_xstate].state_count;
 
 
-               if ((error = copyin(uap->uctx, (void *)&uctx32, sizeof (uctx32)))) 
-                       return(error);
+               token = (user64_addr_t)token_uctx ^ (user64_addr_t)ps->ps_sigreturn_token;
+               if ((user64_addr_t)uap->token != token) {
+#if DEVELOPMENT || DEBUG
+                       printf("process %s[%d] sigreturn token mismatch: received 0x%llx expected 0x%llx\n",
+                           p->p_comm, p->p_pid, (user64_addr_t)uap->token, token);
+#endif /* DEVELOPMENT || DEBUG */
+                       if (sigreturn_validation != PS_SIGRETURN_VALIDATION_DISABLED) {
+                               rval = EINVAL;
+                       }
+               }
+       } else {
+               struct user_ucontext32  uctx32;
+               user32_addr_t token;
 
 
-               if ((error = copyin(CAST_USER_ADDR_T(uctx32.uc_mcontext), (void *)&mctx.mctx32, sizeof (struct mcontext32)))) 
-                       return(error);
+               if ((error = copyin(uap->uctx, (void *)&uctx32, sizeof(uctx32)))) {
+                       return error;
+               }
+
+               if ((error = copyin(CAST_USER_ADDR_T(uctx32.uc_mcontext), (void *)mctxp, thread_state32[sig_xstate].mcontext_size))) {
+                       return error;
+               }
 
                onstack = uctx32.uc_onstack & 01;
                ut->uu_sigmask = uctx32.uc_sigmask & ~sigcantmask;
 
 
                onstack = uctx32.uc_onstack & 01;
                ut->uu_sigmask = uctx32.uc_sigmask & ~sigcantmask;
 
-               ts_flavor = x86_THREAD_STATE32;
+               ts_flavor = x86_THREAD_STATE32;
                ts_count  = x86_THREAD_STATE32_COUNT;
                ts_count  = x86_THREAD_STATE32_COUNT;
-               ts = (void *)&mctx.mctx32.ss;
-
-               fs_flavor = x86_FLOAT_STATE32;
-               fs_count  = x86_FLOAT_STATE32_COUNT;
-               fs = (void *)&mctx.mctx32.fs;
+               ts = (void *)&mctxp->mctx_avx32.ss;
+
+               fs_flavor = thread_state32[sig_xstate].flavor;
+               fs_count  = thread_state32[sig_xstate].state_count;
+               fs = (void *)&mctxp->mctx_avx32.fs;
+
+               token = CAST_DOWN_EXPLICIT(user32_addr_t, uap->uctx) ^
+                   CAST_DOWN_EXPLICIT(user32_addr_t, ps->ps_sigreturn_token);
+               if ((user32_addr_t)uap->token != token) {
+#if DEVELOPMENT || DEBUG
+                       printf("process %s[%d] sigreturn token mismatch: received 0x%x expected 0x%x\n",
+                           p->p_comm, p->p_pid, (user32_addr_t)uap->token, token);
+#endif /* DEVELOPMENT || DEBUG */
+                       if (sigreturn_validation != PS_SIGRETURN_VALIDATION_DISABLED) {
+                               rval = EINVAL;
+                       }
+               }
        }
 
        }
 
-       if (onstack)
+       if (onstack) {
                ut->uu_sigstk.ss_flags |= SA_ONSTACK;
                ut->uu_sigstk.ss_flags |= SA_ONSTACK;
-       else
+       } else {
                ut->uu_sigstk.ss_flags &= ~SA_ONSTACK;
                ut->uu_sigstk.ss_flags &= ~SA_ONSTACK;
+       }
 
 
-       if (ut->uu_siglist & ~ut->uu_sigmask)
+       if (ut->uu_siglist & ~ut->uu_sigmask) {
                signal_setast(thread);
                signal_setast(thread);
+       }
+
+       if (rval == EINVAL) {
+               goto error_ret;
+       }
 
        /*
         * thread_set_state() does all the needed checks for the passed in
         * content
         */
 
        /*
         * thread_set_state() does all the needed checks for the passed in
         * content
         */
-       if (thread_setstatus(thread, ts_flavor, ts, ts_count) != KERN_SUCCESS)
-               return(EINVAL);
+       if (thread_setstatus(thread, ts_flavor, ts, ts_count) != KERN_SUCCESS) {
+               rval = EINVAL;
+#if DEVELOPMENT || DEBUG
+               printf("process %s[%d] sigreturn thread_setstatus error %d\n",
+                   p->p_comm, p->p_pid, rval);
+#endif /* DEVELOPMENT || DEBUG */
+               goto error_ret;
+       }
 
        ml_fp_setvalid(TRUE);
 
 
        ml_fp_setvalid(TRUE);
 
-       if (thread_setstatus(thread, fs_flavor, fs, fs_count)  != KERN_SUCCESS)
-               return(EINVAL);
-
-       return (EJUSTRETURN);
+       if (thread_setstatus(thread, fs_flavor, fs, fs_count) != KERN_SUCCESS) {
+               rval = EINVAL;
+#if DEVELOPMENT || DEBUG
+               printf("process %s[%d] sigreturn thread_setstatus error %d\n",
+                   p->p_comm, p->p_pid, rval);
+#endif /* DEVELOPMENT || DEBUG */
+               goto error_ret;
+       }
+error_ret:
+       return rval;
 }
 
 
 /*
 }
 
 
 /*
- * machine_exception() performs MD translation
- * of a mach exception to a unix signal and code.
+ * machine_exception() performs machine-dependent translation
+ * of a mach exception to a unix signal.
  */
  */
-
-boolean_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)
+int
+machine_exception(int                           exception,
+    mach_exception_code_t         code,
+    __unused mach_exception_subcode_t      subcode)
 {
 {
-
-       switch(exception) {
-
+       switch (exception) {
        case EXC_BAD_ACCESS:
                /* Map GP fault to SIGSEGV, otherwise defer to caller */
                if (code == EXC_I386_GPFLT) {
        case EXC_BAD_ACCESS:
                /* Map GP fault to SIGSEGV, otherwise defer to caller */
                if (code == EXC_I386_GPFLT) {
-                       *unix_signal = SIGSEGV;
-                       *unix_code = code;
-                       break;
+                       return SIGSEGV;
                }
                }
-               return(FALSE);
+               break;
 
        case EXC_BAD_INSTRUCTION:
 
        case EXC_BAD_INSTRUCTION:
-               *unix_signal = SIGILL;
-               *unix_code = code;
-               break;
+               return SIGILL;
 
        case EXC_ARITHMETIC:
 
        case EXC_ARITHMETIC:
-               *unix_signal = SIGFPE;
-               *unix_code = code;
-               break;
+               return SIGFPE;
 
        case EXC_SOFTWARE:
                if (code == EXC_I386_BOUND) {
 
        case EXC_SOFTWARE:
                if (code == EXC_I386_BOUND) {
@@ -762,15 +964,10 @@ machine_exception(
                         * Map #BR, the Bound Range Exceeded exception, to
                         * SIGTRAP.
                         */
                         * Map #BR, the Bound Range Exceeded exception, to
                         * SIGTRAP.
                         */
-                       *unix_signal = SIGTRAP;
-                       *unix_code = code;
-                       break;
+                       return SIGTRAP;
                }
                }
-
-       default:
-               return(FALSE);
+               break;
        }
        }
-   
-       return(TRUE);
-}
 
 
+       return 0;
+}