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() is written in assembler since it has to capture the correct
  39  * machine state of the calle.
  40  *
  41  * As swapcontext() is actually equivalent to getcontext() + setcontext(),
  42  * swapcontext() shares the most code with getcontext().
  43  */
  44 
  45 #define GETCONTEXT_IMPL(offset)                                         \
  46         pushq   %rdi;           /* preserve the ucontext_t pointer */   \
  47         call    __getcontext;                                           \
  48                                 /* call getcontext: syscall */          \
  49         popq    %rdx;                                                   \
  50         andl    %eax, %eax;     /* if (error_return_from_syscall) */    \
  51         je      1f;                                                     \
  52         addq    $offset, %rsp;                                          \
  53         ret;                    /*      then just return */             \
  54 1:                                                                      \
  55         /*                                                              \
  56          * fix up %rsp and %rip                                         \
  57          */                                                             \
  58         addq    $UC_MCONTEXT_GREGS, %rdx;                               \
  59                                 /* &ucp->uc_mcontext.gregs */            \
  60         movq    offset+0(%rsp), %rax;                                   \
  61                                 /* read return PC from stack */         \
  62         movq    %rax, RIP_OFF (%rdx);                                   \
  63                                 /* store ret PC in EIP of env var */    \
  64         leaq    offset+8(%rsp), %rax;                                   \
  65                                 /* get caller's sp at time of call */   \
  66         movq    %rax, RSP_OFF (%rdx);                                   \
  67                                 /* store the sp into UESP of env var */ \
  68         xorq    %rax, %rax;     /* return 0 */                          \
  69         movq    %rax, RAX_OFF (%rdx);                                   \
  70                                 /* getcontext returns 0 after setcontext */
  71 
  72 /*      
  73  * getcontext(ucontext_t *ucp)
  74  */
  75 
  76         ENTRY(getcontext)
  77         GETCONTEXT_IMPL(0)
  78         ret
  79         SET_SIZE(getcontext)
  80 
  81 /*
  82  * swapcontext(ucontext_t *oucp, const ucontext_t *ucp)
  83  */
  84 
  85         ENTRY(swapcontext)
  86         pushq   %rsi                    /* preserve the 2nd argument */
  87         
  88         GETCONTEXT_IMPL(8)
  89 
  90         /* call setcontext */
  91         popq    %rdi
  92         call    setcontext
  93         ret
  94         SET_SIZE(swapcontext)