1/*-
2 * Copyright (c) 2001 Daniel Eischen <deischen@freebsd.org>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Neither the name of the author nor the names of its contributors
11 *    may be used to endorse or promote products derived from this software
12 *    without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <machine/asm.h>
28__FBSDID("$FreeBSD$");
29
30/*
31 * Where do we define these?
32 */
33#define	MC_LEN_OFFSET		80	/* offset to mc_len from mcontext */
34#define	MC_LEN			640	/* mc_len <machine/ucontext.h> */
35#define	MC_FPFMT_OFFSET		84
36#define MC_FPFMT_NODEV		0x10000
37#define MC_FPFMT_387		0x10001
38#define	MC_FPFMT_XMM		0x10002
39#define	MC_OWNEDFP_OFFSET	88
40#define	MC_OWNEDFP_NONE		0x20000
41#define	MC_OWNEDFP_FPU		0x20001
42#define	MC_OWNEDFP_PCB		0x20002
43#define	MC_FPREGS_OFFSET	96	/* offset to FP regs from mcontext */
44#define	MC_FP_CW_OFFSET		96	/* offset to FP control word */
45
46/*
47 * int thr_setcontext(mcontext_t *mcp, intptr_t val, intptr_t *loc)
48 *
49 * Restores the context in mcp.
50 *
51 * Returns 0 if there are no errors; -1 otherwise
52 */
53	.weak CNAME(_thr_setcontext)
54	.set CNAME(_thr_setcontext),CNAME(__thr_setcontext)
55ENTRY(__thr_setcontext)
56	movl	4(%esp), %edx		/* get address of mcontext */
57	cmpl	$0, %edx		/* check for null pointer */
58	jne	1f
59	movl	$-1, %eax
60	jmp	8f
611:	cmpl	$MC_LEN, MC_LEN_OFFSET(%edx)	/* is context valid? */
62	je	2f
63	movl	$-1, %eax		/* bzzzt, invalid context */
64	jmp	8f
652:	/*movl	4(%edx), %gs*/		/* we don't touch %gs */
66	movw	8(%edx), %fs
67	movw	12(%edx), %es
68	movw	16(%edx), %ds
69	movw	76(%edx), %ss
70	movl	20(%edx), %edi
71	movl	24(%edx), %esi
72	movl	28(%edx), %ebp
73	movl	%esp, %ecx		/* save current stack in ecx */
74	movl	72(%edx), %esp		/* switch to context defined stack */
75	pushl	60(%edx)		/* push return address on stack */
76	pushl	44(%edx)		/* push ecx on stack */
77	pushl	48(%edx)		/* push eax on stack */
78	/*
79	 * if (mc_fpowned == MC_OWNEDFP_FPU || mc_fpowned == MC_OWNEDFP_PCB) {
80	 *    if (mc_fpformat == MC_FPFMT_387)
81	 *        restore 387 FP register format
82	 *    else if (mc_fpformat == MC_FPFMT_XMM)
83	 *        restore XMM/SSE FP register format
84	 * }
85	 */
86	cmpl	$MC_OWNEDFP_FPU, MC_OWNEDFP_OFFSET(%edx)
87	je	3f
88	cmpl	$MC_OWNEDFP_PCB, MC_OWNEDFP_OFFSET(%edx)
89	jne	5f
903:	cmpl	$MC_FPFMT_387, MC_FPFMT_OFFSET(%edx)
91	jne	4f
92	frstor	MC_FPREGS_OFFSET(%edx)	/* restore 387 FP regs */
93	jmp	6f
944:	cmpl	$MC_FPFMT_XMM, MC_FPFMT_OFFSET(%edx)
95	jne	5f
96	fxrstor	MC_FPREGS_OFFSET(%edx)	/* restore XMM FP regs */
97	jmp	6f
985:	fninit
99	fldcw	MC_FP_CW_OFFSET(%edx)
1006:	pushl	68(%edx)		/* push flags register on stack*/
101	movl	36(%edx), %ebx		/* restore ebx and edx */
102	movl	40(%edx), %edx
103	movl	12(%ecx), %eax		/* get 3rd arg (loc) */
104	cmpl	$0, %eax		/* do nothing if loc == null */
105	je	7f
106	movl	8(%ecx), %ecx		/* get 2nd arg (val) */
107	movl	%ecx, (%eax)		/* set loc = val */
1087:	popfl				/* restore flags after test */
109	popl	%eax			/* restore eax and ecx last */
110	popl	%ecx
1118:	ret
112
113/*
114 * int thr_getcontext(mcontext_t *mcp);
115 *
116 * Returns -1 if there is an error, 0 no errors; 1 upon return
117 * from a setcontext().
118 */
119	.weak CNAME(_thr_getcontext)
120	.set CNAME(_thr_getcontext),CNAME(__thr_getcontext)
121ENTRY(__thr_getcontext)
122	pushl	%edx			/* save edx */
123	movl	8(%esp), %edx		/* get address of mcontext */
124	cmpl	$0, %edx		/* check for null pointer */
125	jne	1f
126	popl	%edx			/* restore edx and stack */
127	movl	$-1, %eax
128	jmp	2f
1291:	/*movw	%gs, 4(%edx)*/		/* we don't touch %gs */
130	movw	%fs, 8(%edx)
131	movw	%es, 12(%edx)
132	movw	%ds, 16(%edx)
133	movw	%ss, 76(%edx)
134	movl	%edi, 20(%edx)
135	movl	%esi, 24(%edx)
136	movl	%ebp, 28(%edx)
137	movl	%ebx, 36(%edx)
138	movl	$1, 48(%edx)		/* store successful return in eax */
139	popl	%eax			/* get saved value of edx */
140	movl	%eax, 40(%edx)		/* save edx */
141	movl	%ecx, 44(%edx)
142	movl	(%esp), %eax		/* get return address */
143	movl	%eax, 60(%edx)		/* save return address */
144	fnstcw	MC_FP_CW_OFFSET(%edx)
145	movl	$MC_LEN, MC_LEN_OFFSET(%edx)
146	movl	$MC_FPFMT_NODEV, MC_FPFMT_OFFSET(%edx)	/* no FP */
147	movl	$MC_OWNEDFP_NONE, MC_OWNEDFP_OFFSET(%edx) /* no FP */
148	pushfl
149	popl	%eax			/* get eflags */
150	movl	%eax, 68(%edx)		/* store eflags */
151	movl	%esp, %eax		/* setcontext pushes the return  */
152	addl	$4, %eax		/*   address onto the top of the */
153	movl	%eax, 72(%edx)		/*   stack; account for this     */
154	movl	40(%edx), %edx		/* restore edx -- is this needed? */
155	xorl	%eax, %eax		/* return 0 */
1562:	ret
157