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         .file   "getcontext.s"
  28 
  29 #include <sys/asm_linkage.h>
  30 
  31         ANSI_PRAGMA_WEAK(getcontext,function)
  32         ANSI_PRAGMA_WEAK(swapcontext,function)
  33 
  34 #include "SYS.h"
  35 #include <assym.h>
  36 
  37 /*
  38  * getcontext() and swapcontext() are written in assembler since it has to
  39  * capture the correct machine state of the caller, including
  40  * the registers: %edi, %esi and %ebx.
  41  *
  42  * As swapcontext() is actually equivalent to getcontext() + setcontext(),
  43  * swapcontext() shares the most code with getcontext().
  44  */
  45 
  46 
  47 #define GETCONTEXT_IMPL                                                 \
  48         movl    4(%esp), %eax;          /* %eax <-- first arg: ucp */        \
  49         pushl   %eax;                   /* push ucp for system call */  \
  50         call    __getcontext;           /* call getcontext: syscall */  \
  51         addl    $4, %esp;               /* pop arg */                   \
  52         andl    %eax, %eax;             /* if (err_ret_from_syscall) */ \
  53         je      1f;                                                     \
  54         ret;                            /*      then return */          \
  55 1:                                                                      \
  56         movl    4(%esp), %eax;          /* recompute first arg */       \
  57         /*                                                              \
  58          * fix up %esp and %eip                                         \
  59          */                                                             \
  60         leal    UC_MCONTEXT_GREGS (%eax), %edx;                         \
  61                                 /* %edx <-- &ucp->uc_mcontext.gregs */        \
  62         movl    0(%esp), %eax;  /* read return PC from stack */         \
  63         movl    %eax, EIP_OFF (%edx);                                   \
  64                                 /* store ret PC in EIP of env var */    \
  65         leal    4(%esp), %eax;  /* get caller's sp at time of call */   \
  66         movl    %eax, UESP_OFF (%edx);                                  \
  67                                 /* store the sp into UESP of env var */ \
  68         xorl    %eax, %eax;     /* return 0 */                          \
  69         movl    %eax, EAX_OFF (%edx);                                   \
  70                                 /* getcontext returns 0 after a setcontext */
  71 
  72 /*
  73  * getcontext(ucontext_t *ucp)
  74  */
  75         ENTRY(getcontext)
  76         GETCONTEXT_IMPL
  77         ret
  78         SET_SIZE(getcontext)
  79 
  80 
  81 /*
  82  * swapcontext(ucontext_t *oucp, const ucontext_t *ucp)
  83  */
  84         ENTRY(swapcontext)
  85         GETCONTEXT_IMPL
  86         / call setcontext
  87         movl    8(%esp), %eax           /* %eax <-- second arg: ucp */
  88         pushl   %eax                    /* push ucp for setcontext */
  89         call    setcontext
  90         addl    $4, %esp                /* pop arg: just in case */
  91         ret
  92         SET_SIZE(swapcontext)