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 */		\
541:									\
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)
95