1 /*
   2  * CDDL HEADER START
   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 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * Copyright 2023 Oxide Computer Company
  29  */
  30 
  31         .file   "getcontext.s"
  32 
  33 #include <sys/asm_linkage.h>
  34 
  35         ANSI_PRAGMA_WEAK(getcontext,function)
  36         ANSI_PRAGMA_WEAK(swapcontext,function)
  37 
  38 #include "SYS.h"
  39 #include <assym.h>
  40 
  41 /*
  42  * getcontext() and swapcontext() are written in assembler since it has to
  43  * capture the correct machine state of the caller, including
  44  * the registers: %edi, %esi and %ebx.
  45  *
  46  * As swapcontext() is actually equivalent to getcontext() + setcontext(),
  47  * swapcontext() shares the most code with getcontext().
  48  */
  49 
  50 
  51 #define GETCONTEXT_IMPL(func)                                           \
  52         movl    4(%esp), %eax;          /* %eax <-- first arg: ucp */        \
  53         pushl   %eax;                   /* push ucp for system call */  \
  54         call    func;                   /* call getcontext: syscall */  \
  55         addl    $4, %esp;               /* pop arg */                   \
  56         andl    %eax, %eax;             /* if (err_ret_from_syscall) */ \
  57         je      1f;                                                     \
  58         ret;                            /*      then return */          \
  59 1:                                                                      \
  60         movl    4(%esp), %eax;          /* recompute first arg */       \
  61         /*                                                              \
  62          * fix up %esp and %eip                                         \
  63          */                                                             \
  64         leal    UC_MCONTEXT_GREGS (%eax), %edx;                         \
  65                                 /* %edx <-- &ucp->uc_mcontext.gregs */        \
  66         movl    0(%esp), %eax;  /* read return PC from stack */         \
  67         movl    %eax, EIP_OFF (%edx);                                   \
  68                                 /* store ret PC in EIP of env var */    \
  69         leal    4(%esp), %eax;  /* get caller's sp at time of call */   \
  70         movl    %eax, UESP_OFF (%edx);                                  \
  71                                 /* store the sp into UESP of env var */ \
  72         xorl    %eax, %eax;     /* return 0 */                          \
  73         movl    %eax, EAX_OFF (%edx);                                   \
  74                                 /* getcontext returns 0 after a setcontext */
  75 
  76 /*
  77  * int getcontext(ucontext_t *ucp)
  78  */
  79         ENTRY(getcontext)
  80         GETCONTEXT_IMPL(__getcontext)
  81         ret
  82         SET_SIZE(getcontext)
  83 
  84 
  85 /*
  86  * int swapcontext(ucontext_t *oucp, const ucontext_t *ucp)
  87  */
  88         ENTRY(swapcontext)
  89         GETCONTEXT_IMPL(__getcontext)
  90         /* call setcontext */
  91         movl    8(%esp), %eax           /* %eax <-- second arg: ucp */
  92         pushl   %eax                    /* push ucp for setcontext */
  93         call    setcontext
  94         addl    $4, %esp                /* pop arg: just in case */
  95         ret
  96         SET_SIZE(swapcontext)
  97 
  98 /*
  99  * int getcontext_extd(ucontext_t *ucp, uint32_t flags)
 100  */
 101         ENTRY(getcontext_extd)
 102         movl    8(%esp), %eax
 103         cmpl    $0, %eax                /* if (flags != 0) */
 104         jne     2f
 105         GETCONTEXT_IMPL(__getcontext_extd)
 106         ret
 107 2:
 108         movl    $EINVAL, %eax           /* errno = EINVAL; */
 109         jmp     __cerror                /* return (-1) */
 110         SET_SIZE(getcontext_extd)
 111 
 112 
 113 /*
 114  * int swapcontext_extd(ucontext_t *oucp, const ucontext_t *ucp)
 115  */
 116         ENTRY(swapcontext_extd)
 117         movl    8(%esp), %eax
 118         cmpl    $0, %eax                /* if (flags != 0) */
 119         jne     2f
 120         GETCONTEXT_IMPL(__getcontext_extd)
 121         /* call setcontext */
 122         movl    12(%esp), %eax          /* %eax <-- second arg: ucp */
 123         pushl   %eax                    /* push ucp for setcontext */
 124         call    setcontext
 125         addl    $4, %esp                /* pop arg: just in case */
 126         ret
 127 2:
 128         movl    $EINVAL, %eax           /* errno = EINVAL; */
 129         jmp     __cerror                /* return (-1) */
 130         SET_SIZE(swapcontext_extd)