Print this page




   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*



  23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  28 /*        All Rights Reserved   */
  29 
  30 /*
  31  * Copyright 2023 Oxide Computer Company
  32  */
  33 
  34 #include <sys/param.h>
  35 #include <sys/types.h>
  36 #include <sys/vmparam.h>
  37 #include <sys/systm.h>
  38 #include <sys/signal.h>
  39 #include <sys/stack.h>
  40 #include <sys/regset.h>
  41 #include <sys/privregs.h>
  42 #include <sys/frame.h>
  43 #include <sys/proc.h>
  44 #include <sys/brand.h>
  45 #include <sys/psw.h>
  46 #include <sys/ucontext.h>
  47 #include <sys/asm_linkage.h>
  48 #include <sys/errno.h>
  49 #include <sys/archsystm.h>
  50 #include <sys/schedctl.h>
  51 #include <sys/debug.h>
  52 #include <sys/sysmacros.h>

  53 
  54 /*
  55  * This is a wrapper around copyout_noerr that returns a guaranteed error code.
  56  * Because we're using copyout_noerr(), we need to bound the time we're under an
  57  * on_fault/no_fault and attempt to do so only while we're actually copying data
  58  * out. The main reason for this is because we're being called back from the
  59  * FPU, which is being held with a kpreempt_disable() and related, we can't use
  60  * a larger on_fault()/no_fault() as that would both hide legitimate errors we
  61  * make, masquerading as user issues, and it gets trickier to reason about the
  62  * correct restoration of our state.
  63  */
  64 static int
  65 savecontext_copyout(const void *kaddr, void *uaddr, size_t size)
  66 {
  67         label_t ljb;
  68         if (!on_fault(&ljb)) {
  69                 copyout_noerr(kaddr, uaddr, size);
  70                 no_fault();
  71                 return (0);
  72         } else {


 174                          * stop_on_fault() called from trap(), after being
 175                          * awakened it might see a pending signal and call
 176                          * savecontext(), however on the way back to userland
 177                          * there is no place it can be detected). Hence in
 178                          * anticipation of such occasions, set AST flag for
 179                          * the thread which will make the thread take an
 180                          * excursion through trap() where it will be handled
 181                          * appropriately.
 182                          */
 183                         aston(curthread);
 184                 }
 185         }
 186 
 187         getgregs(lwp, ucp->uc_mcontext.gregs);
 188         fpu_en = (lwp->lwp_pcb.pcb_fpu.fpu_flags & FPU_EN) != 0;
 189         if (fpu_en)
 190                 getfpregs(lwp, &ucp->uc_mcontext.fpregs);
 191         else
 192                 ucp->uc_flags &= ~UC_FPU;
 193 




 194         sigktou(mask, &ucp->uc_sigmask);




 195 
 196         /*
 197          * Determine if we need to get the reset of the xsave context out here.
 198          * If the thread doesn't actually have the FPU enabled, then we don't
 199          * actually need to do this. We also don't have to if it wasn't
 200          * requested.
 201          */
 202         if (!need_xsave || !fpu_en) {
 203                 return (0);
 204         }
 205 
 206         ucp->uc_flags |= UC_XSAVE;
 207 
 208         /*
 209          * While you might be asking why and contemplating despair, just know
 210          * that some things need to just be done in the face of signal (half the
 211          * reason this function exists). Basically when in signal context we
 212          * can't trigger watch points. This means we need to tell the FPU copy
 213          * logic to actually use the on_fault/no_fault and the non-error form of
 214          * copyout (which still checks if it's a user address at least).
 215          */
 216         if ((flags & SAVECTXT_F_ONFAULT) != 0) {
 217                 ret = fpu_signal_copyout(lwp, ucp->uc_xsave,
 218                     savecontext_copyout);
 219         } else {
 220                 ret = fpu_signal_copyout(lwp, ucp->uc_xsave, copyout);
 221         }
 222 









 223         return (ret);
 224 }
 225 
 226 /*
 227  * Restore user context.
 228  */
 229 void
 230 restorecontext(ucontext_t *ucp)
 231 {
 232         kthread_t *t = curthread;
 233         klwp_t *lwp = ttolwp(t);

 234 











 235         lwp->lwp_oldcontext = (uintptr_t)ucp->uc_link;
 236 
 237         if (ucp->uc_flags & UC_STACK) {
 238                 if (ucp->uc_stack.ss_flags == SS_ONSTACK)
 239                         lwp->lwp_sigaltstack = ucp->uc_stack;
 240                 else
 241                         lwp->lwp_sigaltstack.ss_flags &= ~SS_ONSTACK;
 242         }
 243 
 244         if (ucp->uc_flags & UC_CPU) {
 245                 /*
 246                  * If the trace flag is set, mark the lwp to take a
 247                  * single-step trap on return to user level (below).
 248                  * The x86 lcall interface and sysenter has already done this,
 249                  * and turned off the flag, but amd64 syscall interface has not.
 250                  */
 251                 if (lwptoregs(lwp)->r_ps & PS_T)
 252                         lwp->lwp_pcb.pcb_flags |= DEBUG_PENDING;
 253                 setgregs(lwp, ucp->uc_mcontext.gregs);
 254                 lwp->lwp_eosys = JUSTRETURN;


 273                 /*
 274                  * We don't need to acquire p->p_lock here;
 275                  * we are manipulating thread-private data.
 276                  */
 277                 schedctl_finish_sigblock(t);
 278                 sigutok(&ucp->uc_sigmask, &t->t_hold);
 279                 if (sigcheck(ttoproc(t), t))
 280                         t->t_sig_check = 1;
 281         }
 282 }
 283 
 284 
 285 int
 286 getsetcontext(int flag, void *arg)
 287 {
 288         ucontext_t uc;
 289         ucontext_t *ucp;
 290         klwp_t *lwp = ttolwp(curthread);
 291         void *fpu = NULL;
 292         stack_t dummy_stk;

 293         int ret;
 294 
 295         /*
 296          * In future releases, when the ucontext structure grows,
 297          * getcontext should be modified to only return the fields
 298          * specified in the uc_flags.  That way, the structure can grow
 299          * and still be binary compatible will all .o's which will only
 300          * have old fields defined in uc_flags
 301          */
 302 
 303         switch (flag) {
 304         default:
 305                 return (set_errno(EINVAL));
 306 
 307         case GETCONTEXT:
 308                 schedctl_finish_sigblock(curthread);
 309                 ret = savecontext(&uc, &curthread->t_hold, SAVECTXT_F_NONE);
 310                 if (ret != 0)
 311                         return (set_errno(ret));
 312                 if (uc.uc_flags & UC_SIGMASK)


 337                         return (set_errno(EFAULT));
 338                 }
 339                 ret = savecontext(&uc, &curthread->t_hold, SAVECTXT_F_EXTD);
 340                 if (ret != 0)
 341                         return (set_errno(ret));
 342                 if (uc.uc_flags & UC_SIGMASK)
 343                         SIGSET_NATIVE_TO_BRAND(&uc.uc_sigmask);
 344                 if (copyout(&uc, arg, sizeof (uc)))
 345                         return (set_errno(EFAULT));
 346                 return (0);
 347 
 348 
 349         case SETCONTEXT:
 350                 ucp = arg;
 351                 if (ucp == NULL)
 352                         exit(CLD_EXITED, 0);
 353                 /*
 354                  * Don't copyin filler or floating state unless we need it.
 355                  * The ucontext_t struct and fields are specified in the ABI.
 356                  */
 357                 if (copyin(ucp, &uc, offsetof(ucontext_t, uc_filler) -
 358                     sizeof (uc.uc_mcontext.fpregs))) {
 359                         return (set_errno(EFAULT));
 360                 }
 361                 if (uc.uc_flags & UC_SIGMASK)
 362                         SIGSET_BRAND_TO_NATIVE(&uc.uc_sigmask);
 363 
 364                 if ((uc.uc_flags & UC_FPU) &&
 365                     copyin(&ucp->uc_mcontext.fpregs, &uc.uc_mcontext.fpregs,
 366                     sizeof (uc.uc_mcontext.fpregs))) {
 367                         return (set_errno(EFAULT));
 368                 }
 369 









 370                 uc.uc_xsave = 0;
 371                 if ((uc.uc_flags & UC_XSAVE) != 0) {
 372                         int ret;
 373 
 374                         if (copyin(&ucp->uc_xsave, &uc.uc_xsave,
 375                             sizeof (uc.uc_xsave)) != 0) {
 376                                 return (set_errno(EFAULT));
 377                         }
 378 
 379                         ret = fpu_signal_copyin(lwp, &uc);
 380                         if (ret != 0) {
 381                                 return (set_errno(ret));
 382                         }
 383                 }
 384 
 385                 restorecontext(&uc);
 386 
 387                 if ((uc.uc_flags & UC_STACK) && (lwp->lwp_ustack != 0))
 388                         (void) copyout(&uc.uc_stack, (stack_t *)lwp->lwp_ustack,
 389                             sizeof (uc.uc_stack));


 467                  * flag set.
 468                  */
 469                 rp->r_ps &= ~PS_T;
 470 
 471                 if (!(lwp->lwp_pcb.pcb_flags & REQUEST_NOSTEP)) {
 472                         lwp->lwp_pcb.pcb_flags |= DEBUG_PENDING;
 473                         /*
 474                          * See comments in savecontext().
 475                          */
 476                         aston(curthread);
 477                 }
 478         }
 479 
 480         getgregs32(lwp, ucp->uc_mcontext.gregs);
 481         fpu_en = (lwp->lwp_pcb.pcb_fpu.fpu_flags & FPU_EN) != 0;
 482         if (fpu_en)
 483                 getfpregs32(lwp, &ucp->uc_mcontext.fpregs);
 484         else
 485                 ucp->uc_flags &= ~UC_FPU;
 486 




 487         sigktou(mask, &ucp->uc_sigmask);




 488 
 489         if (!need_xsave || !fpu_en) {
 490                 return (0);
 491         }
 492 
 493         ucp->uc_flags |= UC_XSAVE;
 494 
 495         /*
 496          * Due to not wanting to change or break programs, the filler in the
 497          * ucontext_t was always declared as a long, which is signed. Because
 498          * this is the 32-bit version, this is an int32_t. We cannot directly go
 499          * to a uintptr_t otherwise we might get sign extension, so we first
 500          * have to go through a uint32_t and then a uintptr_t. Otherwise, see
 501          * savecontext().
 502          */
 503         uaddr = (uintptr_t)(uint32_t)ucp->uc_xsave;
 504         if ((flags & SAVECTXT_F_ONFAULT) != 0) {
 505                 ret = fpu_signal_copyout(lwp, uaddr, savecontext_copyout);
 506         } else {
 507                 ret = fpu_signal_copyout(lwp, uaddr, copyout);
 508         }
 509 










 510         return (ret);
 511 }
 512 
 513 int
 514 getsetcontext32(int flag, void *arg)
 515 {
 516         ucontext32_t uc;
 517         ucontext_t ucnat;
 518         ucontext32_t *ucp;
 519         klwp_t *lwp = ttolwp(curthread);
 520         caddr32_t ustack32;
 521         stack32_t dummy_stk32;

 522         int ret;
 523 
 524         switch (flag) {
 525         default:
 526                 return (set_errno(EINVAL));
 527 
 528         case GETCONTEXT:
 529                 schedctl_finish_sigblock(curthread);
 530                 ret = savecontext32(&uc, &curthread->t_hold, SAVECTXT_F_NONE);
 531                 if (ret != 0)
 532                         return (set_errno(ret));
 533                 if (uc.uc_flags & UC_SIGMASK)
 534                         SIGSET_NATIVE_TO_BRAND(&uc.uc_sigmask);
 535                 if (copyout(&uc, arg, sizeof (uc)))
 536                         return (set_errno(EFAULT));
 537                 return (0);
 538 
 539         /*
 540          * See getsetcontext() for an explanation of what is going on here.
 541          */
 542         case GETCONTEXT_EXTD:
 543                 schedctl_finish_sigblock(curthread);
 544                 ucp = arg;
 545                 if (copyin(&ucp->uc_xsave, &uc.uc_xsave,
 546                     sizeof (uc.uc_xsave)) != 0) {
 547                         return (set_errno(EFAULT));
 548                 }
 549                 ret = savecontext32(&uc, &curthread->t_hold, SAVECTXT_F_EXTD);
 550                 if (ret != 0)
 551                         return (set_errno(ret));
 552                 if (uc.uc_flags & UC_SIGMASK)
 553                         SIGSET_NATIVE_TO_BRAND(&uc.uc_sigmask);
 554                 if (copyout(&uc, arg, sizeof (uc)))
 555                         return (set_errno(EFAULT));
 556                 return (0);
 557 
 558         case SETCONTEXT:
 559                 ucp = arg;
 560                 if (ucp == NULL)
 561                         exit(CLD_EXITED, 0);
 562                 if (copyin(ucp, &uc, offsetof(ucontext32_t, uc_filler) -
 563                     sizeof (uc.uc_mcontext.fpregs))) {
 564                         return (set_errno(EFAULT));
 565                 }
 566                 if (uc.uc_flags & UC_SIGMASK)
 567                         SIGSET_BRAND_TO_NATIVE(&uc.uc_sigmask);
 568                 if ((uc.uc_flags & UC_FPU) &&
 569                     copyin(&ucp->uc_mcontext.fpregs, &uc.uc_mcontext.fpregs,
 570                     sizeof (uc.uc_mcontext.fpregs))) {
 571                         return (set_errno(EFAULT));
 572                 }









 573 
 574                 uc.uc_xsave = 0;
 575                 if ((uc.uc_flags & UC_XSAVE) != 0 &&
 576                     copyin(&ucp->uc_xsave, &uc.uc_xsave,
 577                     sizeof (uc.uc_xsave)) != 0) {
 578                         return (set_errno(EFAULT));
 579                 }
 580 
 581                 ucontext_32ton(&uc, &ucnat);
 582 
 583                 if ((ucnat.uc_flags & UC_XSAVE) != 0) {
 584                         int ret = fpu_signal_copyin(lwp, &ucnat);
 585                         if (ret != 0) {
 586                                 return (set_errno(ret));
 587                         }
 588                 }
 589 
 590                 restorecontext(&ucnat);
 591 
 592                 if ((uc.uc_flags & UC_STACK) && (lwp->lwp_ustack != 0))


   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2015 Joyent, Inc.
  24  */
  25 /*
  26  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  27  * Use is subject to license terms.
  28  */
  29 
  30 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  31 /*        All Rights Reserved   */
  32 
  33 /*
  34  * Copyright 2023 Oxide Computer Company
  35  */
  36 
  37 #include <sys/param.h>
  38 #include <sys/types.h>
  39 #include <sys/vmparam.h>
  40 #include <sys/systm.h>
  41 #include <sys/signal.h>
  42 #include <sys/stack.h>
  43 #include <sys/regset.h>
  44 #include <sys/privregs.h>
  45 #include <sys/frame.h>
  46 #include <sys/proc.h>
  47 #include <sys/brand.h>
  48 #include <sys/psw.h>
  49 #include <sys/ucontext.h>
  50 #include <sys/asm_linkage.h>
  51 #include <sys/errno.h>
  52 #include <sys/archsystm.h>
  53 #include <sys/schedctl.h>
  54 #include <sys/debug.h>
  55 #include <sys/sysmacros.h>
  56 #include <sys/sdt.h>
  57 
  58 /*
  59  * This is a wrapper around copyout_noerr that returns a guaranteed error code.
  60  * Because we're using copyout_noerr(), we need to bound the time we're under an
  61  * on_fault/no_fault and attempt to do so only while we're actually copying data
  62  * out. The main reason for this is because we're being called back from the
  63  * FPU, which is being held with a kpreempt_disable() and related, we can't use
  64  * a larger on_fault()/no_fault() as that would both hide legitimate errors we
  65  * make, masquerading as user issues, and it gets trickier to reason about the
  66  * correct restoration of our state.
  67  */
  68 static int
  69 savecontext_copyout(const void *kaddr, void *uaddr, size_t size)
  70 {
  71         label_t ljb;
  72         if (!on_fault(&ljb)) {
  73                 copyout_noerr(kaddr, uaddr, size);
  74                 no_fault();
  75                 return (0);
  76         } else {


 178                          * stop_on_fault() called from trap(), after being
 179                          * awakened it might see a pending signal and call
 180                          * savecontext(), however on the way back to userland
 181                          * there is no place it can be detected). Hence in
 182                          * anticipation of such occasions, set AST flag for
 183                          * the thread which will make the thread take an
 184                          * excursion through trap() where it will be handled
 185                          * appropriately.
 186                          */
 187                         aston(curthread);
 188                 }
 189         }
 190 
 191         getgregs(lwp, ucp->uc_mcontext.gregs);
 192         fpu_en = (lwp->lwp_pcb.pcb_fpu.fpu_flags & FPU_EN) != 0;
 193         if (fpu_en)
 194                 getfpregs(lwp, &ucp->uc_mcontext.fpregs);
 195         else
 196                 ucp->uc_flags &= ~UC_FPU;
 197 
 198         if (mask != NULL) {
 199                 /*
 200                  * Save signal mask.
 201                  */
 202                 sigktou(mask, &ucp->uc_sigmask);
 203         } else {
 204                 ucp->uc_flags &= ~UC_SIGMASK;
 205                 bzero(&ucp->uc_sigmask, sizeof (ucp->uc_sigmask));
 206         }
 207 
 208         /*
 209          * Determine if we need to get the reset of the xsave context out here.
 210          * If the thread doesn't actually have the FPU enabled, then we don't
 211          * actually need to do this. We also don't have to if it wasn't
 212          * requested.
 213          */
 214         if (!need_xsave || !fpu_en) {
 215                 return (0);
 216         }
 217 
 218         ucp->uc_flags |= UC_XSAVE;
 219 
 220         /*
 221          * While you might be asking why and contemplating despair, just know
 222          * that some things need to just be done in the face of signal (half the
 223          * reason this function exists). Basically when in signal context we
 224          * can't trigger watch points. This means we need to tell the FPU copy
 225          * logic to actually use the on_fault/no_fault and the non-error form of
 226          * copyout (which still checks if it's a user address at least).
 227          */
 228         if ((flags & SAVECTXT_F_ONFAULT) != 0) {
 229                 ret = fpu_signal_copyout(lwp, ucp->uc_xsave,
 230                     savecontext_copyout);
 231         } else {
 232                 ret = fpu_signal_copyout(lwp, ucp->uc_xsave, copyout);
 233         }
 234 
 235         if (PROC_IS_BRANDED(p) && BROP(p)->b_savecontext != NULL) {
 236                 /*
 237                  * Allow the brand the chance to modify the context we
 238                  * saved:
 239                  */
 240                 /* XXX KEBE SAYS FIX ME! */
 241                 BROP(p)->b_savecontext(ucp);
 242         }
 243 
 244         return (ret);
 245 }
 246 
 247 /*
 248  * Restore user context.
 249  */
 250 void
 251 restorecontext(ucontext_t *ucp)
 252 {
 253         kthread_t *t = curthread;
 254         klwp_t *lwp = ttolwp(t);
 255         proc_t *p = lwptoproc(lwp);
 256 
 257         if (PROC_IS_BRANDED(p) && BROP(p)->b_restorecontext != NULL) {
 258                 /*
 259                  * Allow the brand the chance to modify the context before
 260                  * we restore it:
 261                  */
 262                 BROP(p)->b_restorecontext(ucp);
 263         }
 264 
 265         DTRACE_PROBE3(oldcontext__set, klwp_t *, lwp,
 266             uintptr_t, lwp->lwp_oldcontext,
 267             uintptr_t, (uintptr_t)ucp->uc_link);
 268         lwp->lwp_oldcontext = (uintptr_t)ucp->uc_link;
 269 
 270         if (ucp->uc_flags & UC_STACK) {
 271                 if (ucp->uc_stack.ss_flags == SS_ONSTACK)
 272                         lwp->lwp_sigaltstack = ucp->uc_stack;
 273                 else
 274                         lwp->lwp_sigaltstack.ss_flags &= ~SS_ONSTACK;
 275         }
 276 
 277         if (ucp->uc_flags & UC_CPU) {
 278                 /*
 279                  * If the trace flag is set, mark the lwp to take a
 280                  * single-step trap on return to user level (below).
 281                  * The x86 lcall interface and sysenter has already done this,
 282                  * and turned off the flag, but amd64 syscall interface has not.
 283                  */
 284                 if (lwptoregs(lwp)->r_ps & PS_T)
 285                         lwp->lwp_pcb.pcb_flags |= DEBUG_PENDING;
 286                 setgregs(lwp, ucp->uc_mcontext.gregs);
 287                 lwp->lwp_eosys = JUSTRETURN;


 306                 /*
 307                  * We don't need to acquire p->p_lock here;
 308                  * we are manipulating thread-private data.
 309                  */
 310                 schedctl_finish_sigblock(t);
 311                 sigutok(&ucp->uc_sigmask, &t->t_hold);
 312                 if (sigcheck(ttoproc(t), t))
 313                         t->t_sig_check = 1;
 314         }
 315 }
 316 
 317 
 318 int
 319 getsetcontext(int flag, void *arg)
 320 {
 321         ucontext_t uc;
 322         ucontext_t *ucp;
 323         klwp_t *lwp = ttolwp(curthread);
 324         void *fpu = NULL;
 325         stack_t dummy_stk;
 326         proc_t *p = lwptoproc(lwp);
 327         int ret;
 328 
 329         /*
 330          * In future releases, when the ucontext structure grows,
 331          * getcontext should be modified to only return the fields
 332          * specified in the uc_flags.  That way, the structure can grow
 333          * and still be binary compatible will all .o's which will only
 334          * have old fields defined in uc_flags
 335          */
 336 
 337         switch (flag) {
 338         default:
 339                 return (set_errno(EINVAL));
 340 
 341         case GETCONTEXT:
 342                 schedctl_finish_sigblock(curthread);
 343                 ret = savecontext(&uc, &curthread->t_hold, SAVECTXT_F_NONE);
 344                 if (ret != 0)
 345                         return (set_errno(ret));
 346                 if (uc.uc_flags & UC_SIGMASK)


 371                         return (set_errno(EFAULT));
 372                 }
 373                 ret = savecontext(&uc, &curthread->t_hold, SAVECTXT_F_EXTD);
 374                 if (ret != 0)
 375                         return (set_errno(ret));
 376                 if (uc.uc_flags & UC_SIGMASK)
 377                         SIGSET_NATIVE_TO_BRAND(&uc.uc_sigmask);
 378                 if (copyout(&uc, arg, sizeof (uc)))
 379                         return (set_errno(EFAULT));
 380                 return (0);
 381 
 382 
 383         case SETCONTEXT:
 384                 ucp = arg;
 385                 if (ucp == NULL)
 386                         exit(CLD_EXITED, 0);
 387                 /*
 388                  * Don't copyin filler or floating state unless we need it.
 389                  * The ucontext_t struct and fields are specified in the ABI.
 390                  */
 391                 if (copyin(ucp, &uc, offsetof(ucontext_t, uc_brand_data) -
 392                     sizeof (uc.uc_mcontext.fpregs))) {
 393                         return (set_errno(EFAULT));
 394                 }
 395                 if (uc.uc_flags & UC_SIGMASK)
 396                         SIGSET_BRAND_TO_NATIVE(&uc.uc_sigmask);
 397 
 398                 if ((uc.uc_flags & UC_FPU) &&
 399                     copyin(&ucp->uc_mcontext.fpregs, &uc.uc_mcontext.fpregs,
 400                     sizeof (uc.uc_mcontext.fpregs))) {
 401                         return (set_errno(EFAULT));
 402                 }
 403 
 404                 /*
 405                  * If this is a branded process, copy in the brand-private
 406                  * data:
 407                  */
 408                 if (PROC_IS_BRANDED(p) && copyin(&ucp->uc_brand_data,
 409                     &uc.uc_brand_data, sizeof (uc.uc_brand_data)) != 0) {
 410                         return (set_errno(EFAULT));
 411                 }
 412 
 413                 uc.uc_xsave = 0;
 414                 if ((uc.uc_flags & UC_XSAVE) != 0) {
 415                         int ret;
 416 
 417                         if (copyin(&ucp->uc_xsave, &uc.uc_xsave,
 418                             sizeof (uc.uc_xsave)) != 0) {
 419                                 return (set_errno(EFAULT));
 420                         }
 421 
 422                         ret = fpu_signal_copyin(lwp, &uc);
 423                         if (ret != 0) {
 424                                 return (set_errno(ret));
 425                         }
 426                 }
 427 
 428                 restorecontext(&uc);
 429 
 430                 if ((uc.uc_flags & UC_STACK) && (lwp->lwp_ustack != 0))
 431                         (void) copyout(&uc.uc_stack, (stack_t *)lwp->lwp_ustack,
 432                             sizeof (uc.uc_stack));


 510                  * flag set.
 511                  */
 512                 rp->r_ps &= ~PS_T;
 513 
 514                 if (!(lwp->lwp_pcb.pcb_flags & REQUEST_NOSTEP)) {
 515                         lwp->lwp_pcb.pcb_flags |= DEBUG_PENDING;
 516                         /*
 517                          * See comments in savecontext().
 518                          */
 519                         aston(curthread);
 520                 }
 521         }
 522 
 523         getgregs32(lwp, ucp->uc_mcontext.gregs);
 524         fpu_en = (lwp->lwp_pcb.pcb_fpu.fpu_flags & FPU_EN) != 0;
 525         if (fpu_en)
 526                 getfpregs32(lwp, &ucp->uc_mcontext.fpregs);
 527         else
 528                 ucp->uc_flags &= ~UC_FPU;
 529 
 530         if (mask != NULL) {
 531                 /*
 532                  * Save signal mask.
 533                  */
 534                 sigktou(mask, &ucp->uc_sigmask);
 535         } else {
 536                 ucp->uc_flags &= ~UC_SIGMASK;
 537                 bzero(&ucp->uc_sigmask, sizeof (ucp->uc_sigmask));
 538         }
 539 
 540         if (!need_xsave || !fpu_en) {
 541                 return (0);
 542         }
 543 
 544         ucp->uc_flags |= UC_XSAVE;
 545 
 546         /*
 547          * Due to not wanting to change or break programs, the filler in the
 548          * ucontext_t was always declared as a long, which is signed. Because
 549          * this is the 32-bit version, this is an int32_t. We cannot directly go
 550          * to a uintptr_t otherwise we might get sign extension, so we first
 551          * have to go through a uint32_t and then a uintptr_t. Otherwise, see
 552          * savecontext().
 553          */
 554         uaddr = (uintptr_t)(uint32_t)ucp->uc_xsave;
 555         if ((flags & SAVECTXT_F_ONFAULT) != 0) {
 556                 ret = fpu_signal_copyout(lwp, uaddr, savecontext_copyout);
 557         } else {
 558                 ret = fpu_signal_copyout(lwp, uaddr, copyout);
 559         }
 560 
 561 
 562         if (PROC_IS_BRANDED(p) && BROP(p)->b_savecontext32 != NULL) {
 563                 /*
 564                  * Allow the brand the chance to modify the context we
 565                  * saved:
 566                  */
 567                 /* XXX KEBE SAYS FIX ME */
 568                 BROP(p)->b_savecontext32(ucp);
 569         }
 570 
 571         return (ret);
 572 }
 573 
 574 int
 575 getsetcontext32(int flag, void *arg)
 576 {
 577         ucontext32_t uc;
 578         ucontext_t ucnat;
 579         ucontext32_t *ucp;
 580         klwp_t *lwp = ttolwp(curthread);
 581         caddr32_t ustack32;
 582         stack32_t dummy_stk32;
 583         proc_t *p = lwptoproc(lwp);
 584         int ret;
 585 
 586         switch (flag) {
 587         default:
 588                 return (set_errno(EINVAL));
 589 
 590         case GETCONTEXT:
 591                 schedctl_finish_sigblock(curthread);
 592                 ret = savecontext32(&uc, &curthread->t_hold, SAVECTXT_F_NONE);
 593                 if (ret != 0)
 594                         return (set_errno(ret));
 595                 if (uc.uc_flags & UC_SIGMASK)
 596                         SIGSET_NATIVE_TO_BRAND(&uc.uc_sigmask);
 597                 if (copyout(&uc, arg, sizeof (uc)))
 598                         return (set_errno(EFAULT));
 599                 return (0);
 600 
 601         /*
 602          * See getsetcontext() for an explanation of what is going on here.
 603          */
 604         case GETCONTEXT_EXTD:
 605                 schedctl_finish_sigblock(curthread);
 606                 ucp = arg;
 607                 if (copyin(&ucp->uc_xsave, &uc.uc_xsave,
 608                     sizeof (uc.uc_xsave)) != 0) {
 609                         return (set_errno(EFAULT));
 610                 }
 611                 ret = savecontext32(&uc, &curthread->t_hold, SAVECTXT_F_EXTD);
 612                 if (ret != 0)
 613                         return (set_errno(ret));
 614                 if (uc.uc_flags & UC_SIGMASK)
 615                         SIGSET_NATIVE_TO_BRAND(&uc.uc_sigmask);
 616                 if (copyout(&uc, arg, sizeof (uc)))
 617                         return (set_errno(EFAULT));
 618                 return (0);
 619 
 620         case SETCONTEXT:
 621                 ucp = arg;
 622                 if (ucp == NULL)
 623                         exit(CLD_EXITED, 0);
 624                 if (copyin(ucp, &uc, offsetof(ucontext32_t, uc_brand_data) -
 625                     sizeof (uc.uc_mcontext.fpregs))) {
 626                         return (set_errno(EFAULT));
 627                 }
 628                 if (uc.uc_flags & UC_SIGMASK)
 629                         SIGSET_BRAND_TO_NATIVE(&uc.uc_sigmask);
 630                 if ((uc.uc_flags & UC_FPU) &&
 631                     copyin(&ucp->uc_mcontext.fpregs, &uc.uc_mcontext.fpregs,
 632                     sizeof (uc.uc_mcontext.fpregs))) {
 633                         return (set_errno(EFAULT));
 634                 }
 635 
 636                 /*
 637                  * If this is a branded process, copy in the brand-private
 638                  * data:
 639                  */
 640                 if (PROC_IS_BRANDED(p) && copyin(&ucp->uc_brand_data,
 641                     &uc.uc_brand_data, sizeof (uc.uc_brand_data)) != 0) {
 642                         return (set_errno(EFAULT));
 643                 }
 644 
 645                 uc.uc_xsave = 0;
 646                 if ((uc.uc_flags & UC_XSAVE) != 0 &&
 647                     copyin(&ucp->uc_xsave, &uc.uc_xsave,
 648                     sizeof (uc.uc_xsave)) != 0) {
 649                         return (set_errno(EFAULT));
 650                 }
 651 
 652                 ucontext_32ton(&uc, &ucnat);
 653 
 654                 if ((ucnat.uc_flags & UC_XSAVE) != 0) {
 655                         int ret = fpu_signal_copyin(lwp, &ucnat);
 656                         if (ret != 0) {
 657                                 return (set_errno(ret));
 658                         }
 659                 }
 660 
 661                 restorecontext(&ucnat);
 662 
 663                 if ((uc.uc_flags & UC_STACK) && (lwp->lwp_ustack != 0))