Print this page
15254 %ymm registers not restored after signal handler
15367 x86 getfpregs() summons corrupting %xmm ghosts
15333 want x86 /proc xregs support (libc_db, libproc, mdb, etc.)
15336 want libc functions for extended ucontext_t
15334 want ps_lwphandle-specific reg routines
15328 FPU_CW_INIT mistreats reserved bit
15335 i86pc fpu_subr.c isn't really platform-specific
15332 setcontext(2) isn't actually noreturn
15331 need <sys/stdalign.h>
Change-Id: I7060aa86042dfb989f77fc3323c065ea2eafa9ad
Conflicts:
    usr/src/uts/common/fs/proc/prcontrol.c
    usr/src/uts/intel/os/archdep.c
    usr/src/uts/intel/sys/ucontext.h
    usr/src/uts/intel/syscall/getcontext.c
        
*** 29,38 ****
--- 29,42 ----
  
  /*      Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
  /*      Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T   */
  /*      All Rights Reserved   */
  
+ /*
+  * Copyright 2023 Oxide Computer Company
+  */
+ 
  #include <sys/types.h>
  #include <sys/param.h>
  #include <sys/sysmacros.h>
  #include <sys/signal.h>
  #include <sys/systm.h>
*** 110,122 ****
   *
   * old %rsp:
   *              <128 bytes of untouched stack space>
   *              <a siginfo_t [optional]>
   *              <a ucontext_t>
!  *              <siginfo_t *>
!  *              <signal number>
!  * new %rsp:    <return address (deliberately invalid)>
   *
   * The signal number and siginfo_t pointer are only pushed onto the stack in
   * order to allow stack backtraces.  The actual signal handling code expects the
   * arguments in registers.
   */
--- 114,127 ----
   *
   * old %rsp:
   *              <128 bytes of untouched stack space>
   *              <a siginfo_t [optional]>
   *              <a ucontext_t>
!  *              <a ucontext_t's xsave state>
!  *              <siginfo_t *>                             ---+
!  *              <signal number>                              | sigframe
!  * new %rsp:    <return address (deliberately invalid)>   ---+
   *
   * The signal number and siginfo_t pointer are only pushed onto the stack in
   * order to allow stack backtraces.  The actual signal handling code expects the
   * arguments in registers.
   */
*** 128,139 ****
  };
  
  int
  sendsig(int sig, k_siginfo_t *sip, void (*hdlr)())
  {
!         volatile int minstacksz;
!         int newstack;
          label_t ljb;
          volatile caddr_t sp;
          caddr_t fp;
          volatile struct regs *rp;
          volatile greg_t upc;
--- 133,146 ----
  };
  
  int
  sendsig(int sig, k_siginfo_t *sip, void (*hdlr)())
  {
!         volatile size_t minstacksz;
!         boolean_t newstack;
!         size_t xsave_size;
!         int ret;
          label_t ljb;
          volatile caddr_t sp;
          caddr_t fp;
          volatile struct regs *rp;
          volatile greg_t upc;
*** 169,186 ****
           * above means that sp (and thus sigframe) will be 8-byte aligned,
           * but not 16-byte aligned. ucontext_t, however, contains %xmm regs
           * which must be 16-byte aligned. Because of this, for correct
           * alignment, sigframe must be a multiple of 8-bytes in length, but
           * not 16-bytes. This will place ucontext_t at a nice 16-byte boundary.
           */
  
!         /* LINTED: logical expression always true: op "||" */
!         ASSERT((sizeof (struct sigframe) % 16) == 8);
  
          minstacksz = sizeof (struct sigframe) + SA(sizeof (*uc));
          if (sip != NULL)
                  minstacksz += SA(sizeof (siginfo_t));
          ASSERT((minstacksz & (STACK_ENTRY_ALIGN - 1ul)) == 0);
  
          /*
           * Figure out whether we will be handling this signal on
           * an alternate stack specified by the user.  Then allocate
--- 176,205 ----
           * above means that sp (and thus sigframe) will be 8-byte aligned,
           * but not 16-byte aligned. ucontext_t, however, contains %xmm regs
           * which must be 16-byte aligned. Because of this, for correct
           * alignment, sigframe must be a multiple of 8-bytes in length, but
           * not 16-bytes. This will place ucontext_t at a nice 16-byte boundary.
+          *
+          * When we move onto the xsave state, right now, we don't guarantee any
+          * alignment of the resulting data, but we will ensure that the
+          * resulting sp does have proper alignment. This will ensure that the
+          * guarantee on the ucontex_t is not violated.
           */
  
!         CTASSERT((sizeof (struct sigframe) % 16) == 8);
  
          minstacksz = sizeof (struct sigframe) + SA(sizeof (*uc));
          if (sip != NULL)
                  minstacksz += SA(sizeof (siginfo_t));
+ 
+         if (fpu_xsave_enabled()) {
+                 xsave_size = SA(fpu_signal_size(lwp));
+                 minstacksz += xsave_size;
+         } else {
+                 xsave_size = 0;
+         }
+ 
          ASSERT((minstacksz & (STACK_ENTRY_ALIGN - 1ul)) == 0);
  
          /*
           * Figure out whether we will be handling this signal on
           * an alternate stack specified by the user.  Then allocate
*** 293,312 ****
                              sizeof (curthread->t_rprof->rp_state));
                  }
          } else
                  sip_addr = NULL;
  
          /*
!          * save the current context on the user stack directly after the
!          * sigframe. Since sigframe is 8-byte-but-not-16-byte aligned,
!          * and since sizeof (struct sigframe) is 24, this guarantees
!          * 16-byte alignment for ucontext_t and its %xmm registers.
           */
-         uc = (ucontext_t *)(sp + sizeof (struct sigframe));
          tuc = kmem_alloc(sizeof (*tuc), KM_SLEEP);
!         no_fault();
!         savecontext(tuc, &lwp->lwp_sigoldmask);
          if (on_fault(&ljb))
                  goto badstack;
          copyout_noerr(tuc, uc, sizeof (*tuc));
          kmem_free(tuc, sizeof (*tuc));
          tuc = NULL;
--- 312,341 ----
                              sizeof (curthread->t_rprof->rp_state));
                  }
          } else
                  sip_addr = NULL;
  
+         no_fault();
+ 
          /*
!          * Save the current context on the user stack directly after the
!          * sigframe. Since sigframe is 8-byte-but-not-16-byte aligned, and since
!          * sizeof (struct sigframe) is 24, this guarantees 16-byte alignment for
!          * ucontext_t and its %xmm registers. The xsave state part of the
!          * ucontext_t may be inbetween these two. However, we have ensured that
!          * the size of the stack space is 16-byte aligned as the actual size may
!          * vary.
           */
          tuc = kmem_alloc(sizeof (*tuc), KM_SLEEP);
!         if (xsave_size != 0) {
!                 tuc->uc_xsave = (unsigned long)(sp + sizeof (struct sigframe));
!         }
!         uc = (ucontext_t *)(sp + sizeof (struct sigframe) + xsave_size);
!         ret = savecontext(tuc, &lwp->lwp_sigoldmask, SAVECTXT_F_EXTD |
!             SAVECTXT_F_ONFAULT);
!         if (ret != 0)
!                 goto postfault;
          if (on_fault(&ljb))
                  goto badstack;
          copyout_noerr(tuc, uc, sizeof (*tuc));
          kmem_free(tuc, sizeof (*tuc));
          tuc = NULL;
*** 376,385 ****
--- 405,415 ----
           */
          return (1);
  
  badstack:
          no_fault();
+ postfault:
          if (watched)
                  watch_enable_addr((caddr_t)sp, minstacksz, S_WRITE);
          if (tuc)
                  kmem_free(tuc, sizeof (*tuc));
  #ifdef DEBUG
*** 397,406 ****
--- 427,437 ----
   * An i386 SVR4/ABI signal frame looks like this on the stack:
   *
   * old %esp:
   *              <a siginfo32_t [optional]>
   *              <a ucontext32_t>
+  *              <a ucontext32_t's xsave state>
   *              <pointer to that ucontext32_t>
   *              <pointer to that siginfo32_t>
   *              <signo>
   * new %esp:    <return address (deliberately invalid)>
   */
*** 412,423 ****
  };
  
  int
  sendsig32(int sig, k_siginfo_t *sip, void (*hdlr)())
  {
!         volatile int minstacksz;
!         int newstack;
          label_t ljb;
          volatile caddr_t sp;
          caddr_t fp;
          volatile struct regs *rp;
          volatile greg_t upc;
--- 443,456 ----
  };
  
  int
  sendsig32(int sig, k_siginfo_t *sip, void (*hdlr)())
  {
!         volatile size_t minstacksz;
!         boolean_t newstack;
!         size_t xsave_size;
!         int ret;
          label_t ljb;
          volatile caddr_t sp;
          caddr_t fp;
          volatile struct regs *rp;
          volatile greg_t upc;
*** 432,441 ****
--- 465,481 ----
          upc = rp->r_pc;
  
          minstacksz = SA32(sizeof (struct sigframe32)) + SA32(sizeof (*uc));
          if (sip != NULL)
                  minstacksz += SA32(sizeof (siginfo32_t));
+ 
+         if (fpu_xsave_enabled()) {
+                 xsave_size = SA32(fpu_signal_size(lwp));
+                 minstacksz += xsave_size;
+         } else {
+                 xsave_size = 0;
+         }
          ASSERT((minstacksz & (STACK_ALIGN32 - 1)) == 0);
  
          /*
           * Figure out whether we will be handling this signal on
           * an alternate stack specified by the user.  Then allocate
*** 538,554 ****
                              sip_addr->si_mstate,
                              sizeof (curthread->t_rprof->rp_state));
                  }
          } else
                  sip_addr = NULL;
  
          /* save the current context on the user stack */
          fp -= SA32(sizeof (*tuc));
          uc = (ucontext32_t *)fp;
!         tuc = kmem_alloc(sizeof (*tuc), KM_SLEEP);
!         no_fault();
!         savecontext32(tuc, &lwp->lwp_sigoldmask);
          if (on_fault(&ljb))
                  goto badstack;
          copyout_noerr(tuc, uc, sizeof (*tuc));
          kmem_free(tuc, sizeof (*tuc));
          tuc = NULL;
--- 578,601 ----
                              sip_addr->si_mstate,
                              sizeof (curthread->t_rprof->rp_state));
                  }
          } else
                  sip_addr = NULL;
+         no_fault();
  
          /* save the current context on the user stack */
+         tuc = kmem_alloc(sizeof (*tuc), KM_SLEEP);
          fp -= SA32(sizeof (*tuc));
          uc = (ucontext32_t *)fp;
!         if (xsave_size != 0) {
!                 fp -= xsave_size;
!                 tuc->uc_xsave = (int32_t)(uintptr_t)fp;
!         }
!         ret = savecontext32(tuc, &lwp->lwp_sigoldmask, SAVECTXT_F_EXTD |
!             SAVECTXT_F_ONFAULT);
!         if (ret != 0)
!                 goto postfault;
          if (on_fault(&ljb))
                  goto badstack;
          copyout_noerr(tuc, uc, sizeof (*tuc));
          kmem_free(tuc, sizeof (*tuc));
          tuc = NULL;
*** 618,627 ****
--- 665,675 ----
           */
          return (1);
  
  badstack:
          no_fault();
+ postfault:
          if (watched)
                  watch_enable_addr((caddr_t)sp, minstacksz, S_WRITE);
          if (tuc)
                  kmem_free(tuc, sizeof (*tuc));
  #ifdef DEBUG