1117756Sdeischen/*
2117756Sdeischen * Copyright (c) 2003 Daniel Eischen <deischen@freebsd.org>.
3117756Sdeischen * All rights reserved.
4117756Sdeischen *
5117756Sdeischen * Redistribution and use in source and binary forms, with or without
6117756Sdeischen * modification, are permitted provided that the following conditions
7117756Sdeischen * are met:
8117756Sdeischen * 1. Redistributions of source code must retain the above copyright
9117756Sdeischen *    notice, this list of conditions and the following disclaimer.
10117756Sdeischen * 2. Neither the name of the author nor the names of its contributors
11117756Sdeischen *    may be used to endorse or promote products derived from this software
12117756Sdeischen *    without specific prior written permission.
13117756Sdeischen *
14117756Sdeischen * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS'' AND
15117756Sdeischen * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16117756Sdeischen * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17117756Sdeischen * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18117756Sdeischen * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19117756Sdeischen * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20117756Sdeischen * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21117756Sdeischen * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22117756Sdeischen * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23117756Sdeischen * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24117756Sdeischen * SUCH DAMAGE.
25117756Sdeischen */
26117756Sdeischen
27117756Sdeischen#include <machine/asm.h>
28117756Sdeischen__FBSDID("$FreeBSD: releng/10.2/lib/libkse/arch/amd64/amd64/context.S 155990 2006-02-24 22:03:10Z deischen $");
29117756Sdeischen
30117756Sdeischen/*
31117756Sdeischen * The following notes ("cheat sheet") was provided by Peter Wemm.
32117756Sdeischen *
33117756Sdeischen *   scratch:
34117756Sdeischen *   rax     (1st return)
35117756Sdeischen *   rcx     (4th arg)
36117756Sdeischen *   rdx     (3rd arg, 2nd return)
37117756Sdeischen *   rsi     (2nd arg)
38117756Sdeischen *   rdi     (1st arg)
39117756Sdeischen *   r8      (5th arg)
40117756Sdeischen *   r9      (6th arg)
41117756Sdeischen *   r10     (temp, static chain?)
42117756Sdeischen *   r11     (temp)
43117756Sdeischen *
44117756Sdeischen *   preserved:
45117756Sdeischen *   rbx     (base pointer)
46117756Sdeischen *   rsp     (stack)
47117756Sdeischen *   rbp     (frame)
48117756Sdeischen *   r12-r15 (general)
49117756Sdeischen *
50117756Sdeischen *   calls:
51117756Sdeischen *   rdi     1
52117756Sdeischen *   rsi     2
53117756Sdeischen *   rdx     3
54117756Sdeischen *   rcx     4
55117756Sdeischen *   r8      5
56117756Sdeischen *   r9      6
57117756Sdeischen *
58117756Sdeischen *   return:
59117756Sdeischen *   rax     1
60117756Sdeischen *   rdx     2
61117756Sdeischen *
62117756Sdeischen *   This means:
63117756Sdeischen *   arg1 goes in %rdi, arg2 in %rsi, etc. return value is %rax (and
64117756Sdeischen *   secondary return, eg: pipe(2), in %rdx) %rcx,%rsi,%rdi etc are
65117756Sdeischen *   trashed by making a call to something. %rbx,%rbp,%r12-15 are the
66117756Sdeischen *   only registers preserved across a call. Note that unlike i386,
67117756Sdeischen *   %rsi and %rdi are scratch rather than preserved. FPU is
68117756Sdeischen *   different, args are in SSE registers rather than the x87 stack.
69117756Sdeischen *
70117756Sdeischen *   Aside from the register calling conventions, amd64 can be treated
71117756Sdeischen *   very much like i386.  Things like setjmp/longjmp etc were literal
72117756Sdeischen *   translations from i386 but with the register names updated, etc.
73117756Sdeischen *   The main gotcha is that FPU save/restore is in SSE format, which
74117756Sdeischen *   means a sparse 512 byte FPU context.
75117756Sdeischen */
76117756Sdeischen
77117756Sdeischen
78117756Sdeischen/*
79117756Sdeischen * Where do we define these?
80117756Sdeischen */
81120108Sdeischen#define	MC_SIZE			800	/* sizeof mcontext_t */
82121163Speter#define	MC_LEN_OFFSET		(25*8)	/* offset to mc_len from mcontext */
83121163Speter#define	MC_FPFMT_OFFSET		(26*8)	/* offset to mc_fpformat from mcontext */
84121163Speter#define	MC_FPFMT_NODEV		0x10000
85121163Speter#define	MC_OWNEDFP_OFFSET	(27*8)	/* offset to mc_ownedfp from mcontext */
86117756Sdeischen#define	MC_OWNEDFP_NONE 	0x20000
87117756Sdeischen#define	MC_OWNEDFP_FPU		0x20001
88117756Sdeischen#define	MC_OWNEDFP_PCB		0x20002
89117756Sdeischen#define	MC_FPREGS_OFFSET	(28*8)	/* offset to FP registers */
90117756Sdeischen#define	MC_FP_CW_OFFSET		(28*8)	/* offset to FP control word */
91117756Sdeischen
92117756Sdeischen#define	MC_RDI		(1 * 8)
93117756Sdeischen#define	MC_RSI		(2 * 8)
94117756Sdeischen#define	MC_RDX		(3 * 8)
95117756Sdeischen#define	MC_RCX		(4 * 8)
96117756Sdeischen#define	MC_R8		(5 * 8)
97117756Sdeischen#define	MC_R9		(6 * 8)
98117756Sdeischen#define	MC_RAX		(7 * 8)
99117756Sdeischen#define	MC_RBX		(8 * 8)
100117756Sdeischen#define	MC_RBP		(9 * 8)
101117756Sdeischen#define	MC_R10		(10 * 8)
102117756Sdeischen#define	MC_R11		(11 * 8)
103117756Sdeischen#define	MC_R12		(12 * 8)
104117756Sdeischen#define	MC_R13		(13 * 8)
105117756Sdeischen#define	MC_R14		(14 * 8)
106117756Sdeischen#define	MC_R15		(15 * 8)
107121163Speter#define	MC_FLAGS	(18 * 8)
108121163Speter#define	MC_RIP		(20 * 8)
109132928Sdavidxu#define	MC_CS		(21 * 8)
110121163Speter#define	MC_RFLAGS	(22 * 8)
111121163Speter#define	MC_RSP		(23 * 8)
112132928Sdavidxu#define	MC_SS		(24 * 8)
113117756Sdeischen
114130206Stjr#define	REDZONE		128		/* size of the red zone */
115130206Stjr
116117756Sdeischen/*
117117756Sdeischen * _amd64_ctx_save(mcontext_t *mcp)
118117756Sdeischen *
119132928Sdavidxu * No values are saved to mc_trapno, mc_addr, mc_err and mc_cs.
120117756Sdeischen * For the FPU state, only the floating point control word is stored.
121117756Sdeischen */
122118037SdavidxuENTRY(_amd64_save_context)
123117756Sdeischen	cmpq	$0, %rdi		/* check for null pointer */
124117756Sdeischen	jne	1f
125117756Sdeischen	movq	$-1, %rax
126117756Sdeischen	jmp	2f
127117756Sdeischen1:	movq	%rdi, MC_RDI(%rdi)
128117756Sdeischen	movq	%rsi, MC_RSI(%rdi)
129117756Sdeischen	movq	%rdx, MC_RDX(%rdi)
130117756Sdeischen	movq	%rcx, MC_RCX(%rdi)
131117756Sdeischen	movq	%r8, MC_R8(%rdi)
132117756Sdeischen	movq	%r9, MC_R9(%rdi)
133117756Sdeischen	movq	$1, MC_RAX(%rdi)	/* return 1 when restored */
134117756Sdeischen	movq	%rbx, MC_RBX(%rdi)
135117756Sdeischen	movq	%rbp, MC_RBP(%rdi)
136117756Sdeischen	movq	%r10, MC_R10(%rdi)
137117756Sdeischen	movq	%r11, MC_R11(%rdi)
138117756Sdeischen	movq	%r12, MC_R12(%rdi)
139117756Sdeischen	movq	%r13, MC_R13(%rdi)
140117756Sdeischen	movq	%r14, MC_R14(%rdi)
141117756Sdeischen	movq	%r15, MC_R15(%rdi)
142117756Sdeischen	movq	(%rsp), %rax		/* get return address */
143117756Sdeischen	movq	%rax, MC_RIP(%rdi)	/* save return address (%rip) */
144117756Sdeischen	pushfq				/* get flags */
145117756Sdeischen	popq	%rax
146117756Sdeischen	movq	%rax, MC_RFLAGS(%rdi)	/* save flags */
147117756Sdeischen	movq	%rsp, %rax		/* setcontext pushes the return */
148118037Sdavidxu	addq	$8, %rax		/*   address onto the stack; */
149117756Sdeischen	movq	%rax, MC_RSP(%rdi)	/*   account for this -- ???. */
150132928Sdavidxu	movw	%ss, MC_SS(%rdi)
151117756Sdeischen	fnstcw	MC_FP_CW_OFFSET(%rdi)	/* save FPU control word */
152117756Sdeischen	movq	$MC_OWNEDFP_NONE, MC_OWNEDFP_OFFSET(%rdi) /* no FP */
153132928Sdavidxu	movq	$MC_FPFMT_NODEV, MC_FPFMT_OFFSET(%rdi)
154117756Sdeischen	movq	$MC_SIZE, MC_LEN_OFFSET(%rdi)
155117756Sdeischen	xorq	%rax, %rax		/* return 0 */
156117756Sdeischen2:	ret
157117756Sdeischen
158117756Sdeischen/*
159117756Sdeischen * _amd64_ctx_restore(mcontext_t *mcp, intptr_t val, intptr_t *loc);
160117756Sdeischen */
161118037SdavidxuENTRY(_amd64_restore_context)
162117756Sdeischen	cmpq	$0, %rdi		/* check for null pointer */
163117756Sdeischen	jne	1f
164117756Sdeischen	movq	$-1, %rax
165155990Sdeischen	jmp	2f
166117756Sdeischen1:	cmpq	$MC_SIZE, MC_LEN_OFFSET(%rdi)	/* is context valid? */
167117756Sdeischen	je	2f
168117756Sdeischen	movq	$-1, %rax		/* bzzzt, invalid context */
169155990Sdeischen	ret
170117756Sdeischen2:	movq	MC_RCX(%rdi), %rcx
171117756Sdeischen	movq	MC_R8(%rdi), %r8
172117756Sdeischen	movq	MC_R9(%rdi), %r9
173117756Sdeischen	movq	MC_RBX(%rdi), %rbx
174117756Sdeischen	movq	MC_RBP(%rdi), %rbp
175117756Sdeischen	movq	MC_R10(%rdi), %r10
176117756Sdeischen	movq	MC_R11(%rdi), %r11
177117756Sdeischen	movq	MC_R12(%rdi), %r12
178117756Sdeischen	movq	MC_R13(%rdi), %r13
179117756Sdeischen	movq	MC_R14(%rdi), %r14
180117756Sdeischen	movq	MC_R15(%rdi), %r15
181117756Sdeischen	/*
182117756Sdeischen	 * if (mc_fpowned == MC_OWNEDFP_FPU || mc_fpowned == MC_OWNEDFP_PCB)
183117756Sdeischen	 *    restore XMM/SSE FP register format
184117756Sdeischen	 */
185117756Sdeischen	cmpq	$MC_OWNEDFP_NONE, MC_OWNEDFP_OFFSET(%rdi)
186117756Sdeischen	je	4f
187117756Sdeischen	cmpq	$MC_OWNEDFP_PCB, MC_OWNEDFP_OFFSET(%rdi)
188117756Sdeischen	je	3f
189117756Sdeischen	cmpq	$MC_OWNEDFP_FPU, MC_OWNEDFP_OFFSET(%rdi)
190117756Sdeischen	jne	4f
191117756Sdeischen3:	fxrstor	MC_FPREGS_OFFSET(%rdi)	/* restore XMM FP regs */
192117756Sdeischen	jmp	5f
193117756Sdeischen4:	fninit
194117756Sdeischen	fldcw	MC_FP_CW_OFFSET(%rdi)
195117756Sdeischen5:	movq	MC_RSP(%rdi), %rsp	/* switch to context stack */
196130206Stjr	subq	$REDZONE, %rsp
197117756Sdeischen	movq	MC_RIP(%rdi), %rax	/* return address on stack */
198117756Sdeischen	pushq	%rax
199118037Sdavidxu	movq	MC_RDI(%rdi), %rax	/* rdi on stack */
200117756Sdeischen	pushq	%rax
201117756Sdeischen	movq	MC_RDX(%rdi), %rax	/* rdx on stack */
202117756Sdeischen	pushq	%rax
203117756Sdeischen	movq	MC_RSI(%rdi), %rax	/* rsi on stack */
204117756Sdeischen	pushq	%rax
205117756Sdeischen	movq	MC_RFLAGS(%rdi), %rax	/* flags on stack*/
206117756Sdeischen	pushq	%rax
207117756Sdeischen	movq	MC_RAX(%rdi), %rax	/* restore rax */
208117756Sdeischen	/* At this point we're done with the context. */
209117756Sdeischen	cmpq	$0, %rdx		/* set *loc to val */
210118037Sdavidxu	je	6f
211117756Sdeischen	movq	%rsi, (%rdx)
212117756Sdeischen6:	popfq				/* restore flags */
213117756Sdeischen	popq	%rsi			/* restore rsi, rdx, and rdi */
214117756Sdeischen	popq	%rdx
215117756Sdeischen	popq	%rdi
216155990Sdeischen	ret	$REDZONE
217155990Sdeischen
218