Print this page
manifest
        
*** 25,35 ****
  /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
  /*        All Rights Reserved   */
  /*
   * Copyright (c) 2018, Joyent, Inc.
   * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
!  * Copyright 2022 Oxide Computer Company
   */
  
  #include <sys/param.h>
  #include <sys/types.h>
  #include <sys/vmparam.h>
--- 25,35 ----
  /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
  /*        All Rights Reserved   */
  /*
   * Copyright (c) 2018, Joyent, Inc.
   * Copyright 2012 Nexenta Systems, Inc.  All rights reserved.
!  * Copyright 2023 Oxide Computer Company
   */
  
  #include <sys/param.h>
  #include <sys/types.h>
  #include <sys/vmparam.h>
*** 237,364 ****
   * Set floating-point registers from a native fpregset_t.
   */
  void
  setfpregs(klwp_t *lwp, fpregset_t *fp)
  {
!         struct fpu_ctx *fpu = &lwp->lwp_pcb.pcb_fpu;
! 
!         if (fpu->fpu_flags & FPU_EN) {
!                 if (!(fpu->fpu_flags & FPU_VALID)) {
!                         /*
!                          * FPU context is still active, release the
!                          * ownership.
!                          */
!                         fp_free(fpu);
!                 }
!         }
!         /*
!          * Else: if we are trying to change the FPU state of a thread which
!          * hasn't yet initialized floating point, store the state in
!          * the pcb and indicate that the state is valid.  When the
!          * thread enables floating point, it will use this state instead
!          * of the default state.
!          */
! 
!         switch (fp_save_mech) {
!         case FP_FXSAVE:
!                 fpregset_to_fxsave(fp, fpu->fpu_regs.kfpu_u.kfpu_fx);
!                 fpu->fpu_regs.kfpu_xstatus =
!                     fp->fp_reg_set.fpchip_state.xstatus;
!                 break;
! 
!         case FP_XSAVE:
!                 fpregset_to_fxsave(fp,
!                     &fpu->fpu_regs.kfpu_u.kfpu_xs->xs_fxsave);
!                 fpu->fpu_regs.kfpu_xstatus =
!                     fp->fp_reg_set.fpchip_state.xstatus;
!                 fpu->fpu_regs.kfpu_u.kfpu_xs->xs_header.xsh_xstate_bv |=
!                     (XFEATURE_LEGACY_FP | XFEATURE_SSE);
!                 break;
!         default:
!                 panic("Invalid fp_save_mech");
!                 /*NOTREACHED*/
!         }
! 
!         fpu->fpu_regs.kfpu_status = fp->fp_reg_set.fpchip_state.status;
!         fpu->fpu_flags |= FPU_VALID;
!         PCB_SET_UPDATE_FPU(&lwp->lwp_pcb);
  }
  
  /*
   * Get floating-point registers into a native fpregset_t.
   */
  void
  getfpregs(klwp_t *lwp, fpregset_t *fp)
  {
!         struct fpu_ctx *fpu = &lwp->lwp_pcb.pcb_fpu;
! 
!         kpreempt_disable();
!         if (fpu->fpu_flags & FPU_EN) {
!                 /*
!                  * If we have FPU hw and the thread's pcb doesn't have
!                  * a valid FPU state then get the state from the hw.
!                  */
!                 if (fpu_exists && ttolwp(curthread) == lwp &&
!                     !(fpu->fpu_flags & FPU_VALID))
!                         fp_save(fpu); /* get the current FPU state */
!         }
! 
!         /*
!          * There are 3 possible cases we have to be aware of here:
!          *
!          * 1. FPU is enabled.  FPU state is stored in the current LWP.
!          *
!          * 2. FPU is not enabled, and there have been no intervening /proc
!          *    modifications.  Return initial FPU state.
!          *
!          * 3. FPU is not enabled, but a /proc consumer has modified FPU state.
!          *    FPU state is stored in the current LWP.
!          */
!         if ((fpu->fpu_flags & FPU_EN) || (fpu->fpu_flags & FPU_VALID)) {
!                 /*
!                  * Cases 1 and 3.
!                  */
!                 switch (fp_save_mech) {
!                 case FP_FXSAVE:
!                         fxsave_to_fpregset(fpu->fpu_regs.kfpu_u.kfpu_fx, fp);
!                         fp->fp_reg_set.fpchip_state.xstatus =
!                             fpu->fpu_regs.kfpu_xstatus;
!                         break;
!                 case FP_XSAVE:
!                         fxsave_to_fpregset(
!                             &fpu->fpu_regs.kfpu_u.kfpu_xs->xs_fxsave, fp);
!                         fp->fp_reg_set.fpchip_state.xstatus =
!                             fpu->fpu_regs.kfpu_xstatus;
!                         break;
!                 default:
!                         panic("Invalid fp_save_mech");
!                         /*NOTREACHED*/
!                 }
!                 fp->fp_reg_set.fpchip_state.status = fpu->fpu_regs.kfpu_status;
!         } else {
!                 /*
!                  * Case 2.
!                  */
!                 switch (fp_save_mech) {
!                 case FP_FXSAVE:
!                 case FP_XSAVE:
!                         /*
!                          * For now, we don't have any AVX specific field in ABI.
!                          * If we add any in the future, we need to initial them
!                          * as well.
!                          */
!                         fxsave_to_fpregset(&sse_initial, fp);
!                         fp->fp_reg_set.fpchip_state.xstatus =
!                             fpu->fpu_regs.kfpu_xstatus;
!                         break;
!                 default:
!                         panic("Invalid fp_save_mech");
!                         /*NOTREACHED*/
!                 }
!                 fp->fp_reg_set.fpchip_state.status = fpu->fpu_regs.kfpu_status;
!         }
!         kpreempt_enable();
  }
  
  #if defined(_SYSCALL32_IMPL)
  
  /*
--- 237,257 ----
   * Set floating-point registers from a native fpregset_t.
   */
  void
  setfpregs(klwp_t *lwp, fpregset_t *fp)
  {
!         fpu_set_fpregset(lwp, fp);
  }
  
  /*
   * Get floating-point registers into a native fpregset_t.
   */
  void
  getfpregs(klwp_t *lwp, fpregset_t *fp)
  {
!         bzero(fp, sizeof (*fp));
!         fpu_get_fpregset(lwp, fp);
  }
  
  #if defined(_SYSCALL32_IMPL)
  
  /*
*** 526,545 ****
           * Copy the brand-private data:
           */
          dst->uc_brand_data[0] = (void *)(uintptr_t)src->uc_brand_data[0];
          dst->uc_brand_data[1] = (void *)(uintptr_t)src->uc_brand_data[1];
          dst->uc_brand_data[2] = (void *)(uintptr_t)src->uc_brand_data[2];
  }
  
  #endif  /* _SYSCALL32_IMPL */
  
  /*
   * Return the user-level PC.
   * If in a system call, return the address of the syscall trap.
   */
  greg_t
! getuserpc()
  {
          greg_t upc = lwptoregs(ttolwp(curthread))->r_pc;
          uint32_t insn;
  
          if (curthread->t_sysnum == 0)
--- 419,444 ----
           * Copy the brand-private data:
           */
          dst->uc_brand_data[0] = (void *)(uintptr_t)src->uc_brand_data[0];
          dst->uc_brand_data[1] = (void *)(uintptr_t)src->uc_brand_data[1];
          dst->uc_brand_data[2] = (void *)(uintptr_t)src->uc_brand_data[2];
+ 
+         if (src->uc_flags & UC_XSAVE) {
+                 dst->uc_xsave = (long)(uint32_t)src->uc_xsave;
+         } else {
+                 dst->uc_xsave = 0;
+         }
  }
  
  #endif  /* _SYSCALL32_IMPL */
  
  /*
   * Return the user-level PC.
   * If in a system call, return the address of the syscall trap.
   */
  greg_t
! getuserpc(void)
  {
          greg_t upc = lwptoregs(ttolwp(curthread))->r_pc;
          uint32_t insn;
  
          if (curthread->t_sysnum == 0)