1111519Sdavidxu/*
2111519Sdavidxu * Copyright (c) 2002 Jonathan Mini <mini@freebsd.org>.
3111519Sdavidxu * Copyright (c) 2001 Daniel Eischen <deischen@freebsd.org>.
4111519Sdavidxu * All rights reserved.
5111519Sdavidxu *
6111519Sdavidxu * Redistribution and use in source and binary forms, with or without
7111519Sdavidxu * modification, are permitted provided that the following conditions
8111519Sdavidxu * are met:
9111519Sdavidxu * 1. Redistributions of source code must retain the above copyright
10111519Sdavidxu *    notice, this list of conditions and the following disclaimer.
11111519Sdavidxu * 2. Neither the name of the author nor the names of its contributors
12111519Sdavidxu *    may be used to endorse or promote products derived from this software
13111519Sdavidxu *    without specific prior written permission.
14111519Sdavidxu *
15111519Sdavidxu * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS'' AND
16111519Sdavidxu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17111519Sdavidxu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18111519Sdavidxu * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19111519Sdavidxu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20111519Sdavidxu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21111519Sdavidxu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22111519Sdavidxu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23111519Sdavidxu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24111519Sdavidxu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25111519Sdavidxu * SUCH DAMAGE.
26111519Sdavidxu *
27111519Sdavidxu * $FreeBSD$
28111519Sdavidxu */
29111519Sdavidxu
30111519Sdavidxu#include <machine/asm.h>
31111519Sdavidxu__FBSDID("$FreeBSD$");
32111519Sdavidxu
33111519Sdavidxu/*
34111519Sdavidxu * Where do we define these?
35111519Sdavidxu */
36111519Sdavidxu#define	MC_SIZE			640	/* sizeof mcontext_t */
37111519Sdavidxu#define	UC_MC_OFFSET		16	/* offset to mcontext from ucontext */
38111519Sdavidxu#define	UC_MC_LEN_OFFSET	96	/* offset to mc_len from mcontext */
39111519Sdavidxu#define	MC_LEN_OFFSET		80	/* offset to mc_len from mcontext */
40111519Sdavidxu#define	MC_FP_REGS_OFFSET	96	/* offset to FP regs from mcontext */
41111519Sdavidxu#define	MC_FP_CW_OFFSET		96	/* offset to FP control word */
42111519Sdavidxu#define	MC_OWNEDFP_OFFSET	88	/* offset to mc_ownedfp from mcontext */
43111519Sdavidxu#define	KM_STACK_SP_OFFSET	36	/* offset to km_stack.ss_sp */
44111519Sdavidxu#define	KM_STACK_SIZE_OFFSET	40	/* offset to km_stack.ss_sp */
45111519Sdavidxu#define	KM_FUNC_OFFSET		32	/* offset to km_func */
46111519Sdavidxu
47111519Sdavidxu/*
48111519Sdavidxu * int uts_to_thread(struct kse_thr_mailbox *tdp,
49111519Sdavidxu *	struct kse_thr_mailbox **curthreadp);
50111519Sdavidxu *
51111519Sdavidxu * Does not return on success, returns -1 otherwise.
52111519Sdavidxu */
53111519SdavidxuENTRY(uts_to_thread)
54111519Sdavidxu	movl	4(%esp), %edx		/* get address of kse_thr_mailbox */
55111519Sdavidxu					/* .. ucontext_t is at offset 0 */
56111519Sdavidxu	cmpl	$0, %edx		/* check for null pointer */
57111519Sdavidxu	jne	1f
58111519Sdavidxu	movl	$-1, %eax
59111519Sdavidxu	jmp	5f
60111519Sdavidxu1:	cmpl	$MC_SIZE, UC_MC_LEN_OFFSET(%edx) /* is context valid? */
61111519Sdavidxu	je	2f
62111519Sdavidxu	movl	$-1, %eax		/* bzzzt, invalid context */
63111519Sdavidxu	jmp	5f
64111519Sdavidxu2:	movl	8(%esp), %ecx		/* get address of curthreadp */
65111519Sdavidxu	movl	%edx, %ebx		/* save the pointer for later */
66111519Sdavidxu	/*
67111519Sdavidxu	 * From here on, we don't touch the old stack.
68111519Sdavidxu	 */
69111519Sdavidxu	addl	$UC_MC_OFFSET, %edx	/* add offset to mcontext */
70111519Sdavidxu	movl	4(%edx), %gs
71111519Sdavidxu	movl	8(%edx), %fs
72111519Sdavidxu	movl	12(%edx), %es
73111519Sdavidxu	movl	16(%edx), %ds
74111519Sdavidxu	movl	76(%edx), %ss
75111519Sdavidxu	movl	20(%edx), %edi
76111519Sdavidxu	movl	24(%edx), %esi
77111519Sdavidxu	movl	28(%edx), %ebp
78111519Sdavidxu	movl	72(%edx), %esp		/* switch to context defined stack */
79111519Sdavidxu	subl	$4, %esp		/* leave space for the return address */
80111519Sdavidxu	movl	60(%edx), %eax		/* put return address at top of stack */
81111519Sdavidxu	movl	%eax, (%esp)
82111519Sdavidxu	cmpl	$0, MC_OWNEDFP_OFFSET(%edx) /* are FP regs valid? */
83111519Sdavidxu	jz	3f
84111519Sdavidxu	frstor	MC_FP_REGS_OFFSET(%edx) /* restore FP regs */
85111519Sdavidxu	jmp	4f
86111519Sdavidxu3:	fninit
87111519Sdavidxu	fldcw	MC_FP_CW_OFFSET(%edx)
88111519Sdavidxu4:	movl	48(%edx), %eax		/* restore ax, bx, cx, dx */
89111519Sdavidxu	pushl	68(%edx)		/* flags on stack */
90111519Sdavidxu	pushl	36(%edx)		/* %ebx on stack */
91111519Sdavidxu	pushl	44(%edx)		/* %ecx on stack */
92111519Sdavidxu	movl	40(%edx), %edx		/* %edx */
93111519Sdavidxu	/*
94111519Sdavidxu	 * all registers are now moved out of mailbox,
95111519Sdavidxu	 * it's safe to set current thread pointer
96111519Sdavidxu	 */
97111519Sdavidxu	movl	%ebx,(%ecx)
98111519Sdavidxu	popl	%ecx			/* %ecx off stack */
99111519Sdavidxu	pop	%ebx			/* %ebx off stack */
100111519Sdavidxu	popf				/* flags off stack */
101111519Sdavidxu5:	ret				/* %eip off stack */
102192760SattilioEND(uts_to_thread)
103111519Sdavidxu
104111519Sdavidxu/*
105111519Sdavidxu * int thread_to_uts(struct kse_thr_mailbox *tm, struct kse_mailbox *km);
106111519Sdavidxu *
107111519Sdavidxu * Does not return on success, returns -1 otherwise.
108111519Sdavidxu */
109111519SdavidxuENTRY(thread_to_uts)
110111519Sdavidxu	movl	4(%esp), %eax		/* get address of context */
111111519Sdavidxu	cmpl	$0, %eax		/* check for null pointer */
112111519Sdavidxu	jne	1f
113111519Sdavidxu	movl	$-1, %eax
114111519Sdavidxu	jmp	2f
115111519Sdavidxu1:	pushl	%edx			/* save value of edx */
116111519Sdavidxu	movl	%eax, %edx		/* get address of context */
117111519Sdavidxu	addl	$UC_MC_OFFSET, %edx	/* add offset to mcontext */
118111519Sdavidxu	movl	%gs, 4(%edx)
119111519Sdavidxu	movl	%fs, 8(%edx)
120111519Sdavidxu	movl	%es, 12(%edx)
121111519Sdavidxu	movl	%ds, 16(%edx)
122111519Sdavidxu	movl	%edi, 20(%edx)
123111519Sdavidxu	movl	%esi, 24(%edx)
124111519Sdavidxu	movl	%ebp, 28(%edx)
125111519Sdavidxu	movl	%ebx, 36(%edx)
126111519Sdavidxu	movl	$0, 48(%edx)		/* store successful return in eax */
127111519Sdavidxu	popl	%eax			/* get saved value of edx */
128111519Sdavidxu	movl	%eax, 40(%edx)		/* save edx */
129111519Sdavidxu	movl	%ecx, 44(%edx)
130111519Sdavidxu	movl	(%esp), %eax		/* get return address */
131111519Sdavidxu	movl	%eax, 60(%edx)		/* save return address */
132111519Sdavidxu	movl	%ss, 76(%edx)
133111519Sdavidxu	/*
134111519Sdavidxu	 * Don't save floating point registers here.
135111519Sdavidxu	 *
136111519Sdavidxu	 * This is an explicit call to get the current context, so
137111519Sdavidxu	 * the caller is done with the floating point registers.
138111519Sdavidxu	 * Contexts formed by involuntary switches, such as signal delivery,
139111519Sdavidxu	 * have floating point registers saved by the kernel.
140111519Sdavidxu	 */
141111519Sdavidxu	fnstcw	MC_FP_CW_OFFSET(%edx)
142111519Sdavidxu	movl	$0, MC_OWNEDFP_OFFSET(%edx) /* no FP */
143111519Sdavidxu	pushfl 				/* get eflags */
144111519Sdavidxu	popl	%eax
145111519Sdavidxu	movl	%eax, 68(%edx)		/* store eflags */
146111519Sdavidxu	movl	%esp, %eax		/* setcontext pushes the return  */
147111519Sdavidxu	addl	$4, %eax		/*   address onto the top of the */
148111519Sdavidxu	movl	%eax, 72(%edx)		/*   stack; account for this     */
149111519Sdavidxu	movl	$MC_SIZE, MC_LEN_OFFSET(%edx) /* context is now valid */
150111519Sdavidxu	movl	8(%esp), %edx		/* get address of mailbox */
151111519Sdavidxu	movl	KM_STACK_SP_OFFSET(%edx), %eax	/* get bottom of stack */
152111519Sdavidxu	addl	KM_STACK_SIZE_OFFSET(%edx), %eax /* add length */
153111519Sdavidxu	movl	%eax, %esp		/* switch to the uts's stack */
154111519Sdavidxu	pushl	%edx			/* push the address of the mailbox */
155111519Sdavidxu	pushl	KM_FUNC_OFFSET(%edx)	/* .. the uts can return to itself */
156111519Sdavidxu	pushl	KM_FUNC_OFFSET(%edx)	/* push the address of the uts func */
157111519Sdavidxu2:	ret
158192760SattilioEND(thread_to_uts)
159111519Sdavidxu
160