1103581Smini/* 2103581Smini * Copyright (c) 2002 Jonathan Mini <mini@freebsd.org>. 3103581Smini * Copyright (c) 2001 Daniel Eischen <deischen@freebsd.org>. 4103581Smini * All rights reserved. 5103581Smini * 6103581Smini * Redistribution and use in source and binary forms, with or without 7103581Smini * modification, are permitted provided that the following conditions 8103581Smini * are met: 9103581Smini * 1. Redistributions of source code must retain the above copyright 10103581Smini * notice, this list of conditions and the following disclaimer. 11103581Smini * 2. Neither the name of the author nor the names of its contributors 12103581Smini * may be used to endorse or promote products derived from this software 13103581Smini * without specific prior written permission. 14103581Smini * 15103581Smini * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS'' AND 16103581Smini * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17103581Smini * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18103581Smini * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19103581Smini * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20103581Smini * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21103581Smini * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22103581Smini * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23103581Smini * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24103581Smini * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25103581Smini * SUCH DAMAGE. 26103581Smini * 2799073Sjulian * $FreeBSD$ 2899073Sjulian */ 2999073Sjulian 30103581Smini#include <machine/asm.h> 31103581Smini__FBSDID("$FreeBSD$"); 3299073Sjulian 33103581Smini/* 34103581Smini * Where do we define these? 35103581Smini */ 36103581Smini#define MC_SIZE 640 /* sizeof mcontext_t */ 37103581Smini#define UC_MC_OFFSET 16 /* offset to mcontext from ucontext */ 38103581Smini#define UC_MC_LEN_OFFSET 96 /* offset to mc_len from mcontext */ 39103581Smini#define MC_LEN_OFFSET 80 /* offset to mc_len from mcontext */ 40103581Smini#define MC_FP_REGS_OFFSET 96 /* offset to FP regs from mcontext */ 41103581Smini#define MC_FP_CW_OFFSET 96 /* offset to FP control word */ 42103581Smini#define MC_OWNEDFP_OFFSET 88 /* offset to mc_ownedfp from mcontext */ 43107035Sdavidxu#define KM_STACK_SP_OFFSET 36 /* offset to km_stack.ss_sp */ 44107035Sdavidxu#define KM_STACK_SIZE_OFFSET 40 /* offset to km_stack.ss_sp */ 45107035Sdavidxu#define KM_FUNC_OFFSET 32 /* offset to km_func */ 46103581Smini 47103581Smini/* 48103973Sarchie * int uts_to_thread(struct kse_thr_mailbox *tdp, 49103973Sarchie * struct kse_thr_mailbox **curthreadp); 50103581Smini * 51103581Smini * Does not return on success, returns -1 otherwise. 52103581Smini */ 53103581SminiENTRY(uts_to_thread) 54103973Sarchie movl 4(%esp), %edx /* get address of kse_thr_mailbox */ 55103581Smini /* .. ucontext_t is at offset 0 */ 56103581Smini cmpl $0, %edx /* check for null pointer */ 57103581Smini jne 1f 58103581Smini movl $-1, %eax 59103581Smini jmp 5f 60103581Smini1: cmpl $MC_SIZE, UC_MC_LEN_OFFSET(%edx) /* is context valid? */ 61103581Smini je 2f 62103581Smini movl $-1, %eax /* bzzzt, invalid context */ 63103581Smini jmp 5f 64107167Sdavidxu2: movl 8(%esp), %ecx /* get address of curthreadp */ 65107165Sjulian movl %edx, %ebx /* save the pointer for later */ 66103581Smini /* 67103581Smini * From here on, we don't touch the old stack. 68103581Smini */ 69103581Smini addl $UC_MC_OFFSET, %edx /* add offset to mcontext */ 70103581Smini movl 4(%edx), %gs 71103581Smini movl 8(%edx), %fs 72103581Smini movl 12(%edx), %es 73103581Smini movl 16(%edx), %ds 74103581Smini movl 76(%edx), %ss 75103581Smini movl 20(%edx), %edi 76103581Smini movl 24(%edx), %esi 77103581Smini movl 28(%edx), %ebp 78103581Smini movl 72(%edx), %esp /* switch to context defined stack */ 79103581Smini subl $4, %esp /* leave space for the return address */ 80103581Smini movl 60(%edx), %eax /* put return address at top of stack */ 81103581Smini movl %eax, (%esp) 82103581Smini cmpl $0, MC_OWNEDFP_OFFSET(%edx) /* are FP regs valid? */ 83103581Smini jz 3f 84103581Smini frstor MC_FP_REGS_OFFSET(%edx) /* restore FP regs */ 85103581Smini jmp 4f 86103581Smini3: fninit 87103581Smini fldcw MC_FP_CW_OFFSET(%edx) 88107167Sdavidxu4: movl 48(%edx), %eax /* restore ax, bx, cx, dx */ 89107167Sdavidxu pushl 68(%edx) /* flags on stack */ 90107167Sdavidxu pushl 36(%edx) /* %ebx on stack */ 91107167Sdavidxu pushl 44(%edx) /* %ecx on stack */ 92107183Sdavidxu movl 40(%edx), %edx /* %edx */ 93107167Sdavidxu /* 94107183Sdavidxu * all registers are now moved out of mailbox, 95107183Sdavidxu * it's safe to set current thread pointer 96107167Sdavidxu */ 97107167Sdavidxu movl %ebx,(%ecx) 98107167Sdavidxu popl %ecx /* %ecx off stack */ 99107167Sdavidxu pop %ebx /* %ebx off stack */ 100107167Sdavidxu popf /* flags off stack */ 101107167Sdavidxu5: ret /* %eip off stack */ 102192760SattilioEND(uts_to_thread) 10399073Sjulian 10499073Sjulian/* 105103973Sarchie * int thread_to_uts(struct kse_thr_mailbox *tm, struct kse_mailbox *km); 106103581Smini * 107103581Smini * Does not return on success, returns -1 otherwise. 10899073Sjulian */ 109103581SminiENTRY(thread_to_uts) 110103581Smini movl 4(%esp), %eax /* get address of context */ 111103581Smini cmpl $0, %eax /* check for null pointer */ 112103581Smini jne 1f 113103581Smini movl $-1, %eax 114103581Smini jmp 2f 115103581Smini1: pushl %edx /* save value of edx */ 116103581Smini movl %eax, %edx /* get address of context */ 117103581Smini addl $UC_MC_OFFSET, %edx /* add offset to mcontext */ 118103581Smini movl %gs, 4(%edx) 119103581Smini movl %fs, 8(%edx) 120103581Smini movl %es, 12(%edx) 121103581Smini movl %ds, 16(%edx) 122103581Smini movl %edi, 20(%edx) 123103581Smini movl %esi, 24(%edx) 124103581Smini movl %ebp, 28(%edx) 125103581Smini movl %ebx, 36(%edx) 126103581Smini movl $0, 48(%edx) /* store successful return in eax */ 127103581Smini popl %eax /* get saved value of edx */ 128103581Smini movl %eax, 40(%edx) /* save edx */ 129103581Smini movl %ecx, 44(%edx) 130103581Smini movl (%esp), %eax /* get return address */ 131103581Smini movl %eax, 60(%edx) /* save return address */ 132103581Smini movl %ss, 76(%edx) 133103581Smini /* 134103581Smini * Don't save floating point registers here. 135103581Smini * 136103581Smini * This is an explicit call to get the current context, so 137103581Smini * the caller is done with the floating point registers. 138103581Smini * Contexts formed by involuntary switches, such as signal delivery, 139103581Smini * have floating point registers saved by the kernel. 140103581Smini */ 141103581Smini fnstcw MC_FP_CW_OFFSET(%edx) 142103581Smini movl $0, MC_OWNEDFP_OFFSET(%edx) /* no FP */ 143107138Sdavidxu pushfl /* get eflags */ 144107138Sdavidxu popl %eax 145103581Smini movl %eax, 68(%edx) /* store eflags */ 146103581Smini movl %esp, %eax /* setcontext pushes the return */ 147103581Smini addl $4, %eax /* address onto the top of the */ 148103581Smini movl %eax, 72(%edx) /* stack; account for this */ 149103581Smini movl $MC_SIZE, MC_LEN_OFFSET(%edx) /* context is now valid */ 150103581Smini movl 8(%esp), %edx /* get address of mailbox */ 151103581Smini movl KM_STACK_SP_OFFSET(%edx), %eax /* get bottom of stack */ 152103581Smini addl KM_STACK_SIZE_OFFSET(%edx), %eax /* add length */ 153103581Smini movl %eax, %esp /* switch to the uts's stack */ 154103581Smini pushl %edx /* push the address of the mailbox */ 155103581Smini pushl KM_FUNC_OFFSET(%edx) /* .. the uts can return to itself */ 156103581Smini pushl KM_FUNC_OFFSET(%edx) /* push the address of the uts func */ 157103581Smini2: ret 158192760SattilioEND(thread_to_uts) 15999073Sjulian 160