--- /dev/null	2014-01-14 16:17:06.000000000 +0000
+++ new/usr/src/lib/brand/lx/lx_brand/i386/lx_handler.s	2014-01-14 16:17:06.901610539 +0000
@@ -0,0 +1,377 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/asm_linkage.h>
+#include <sys/regset.h>
+#include <sys/segments.h>
+#include <sys/syscall.h>
+#include <sys/lx_brand.h>
+
+#if defined(_ASM)
+#include <sys/lx_signal.h>
+#include <sys/lx_syscall.h>
+#endif	/* _ASM */
+
+#include "assym.h"
+
+#define	PIC_SETUP(r)					\
+	call	9f;					\
+9:	popl	r;					\
+	addl	$_GLOBAL_OFFSET_TABLE_ + [. - 9b], r
+
+/*
+ * Each JMP must occupy 16 bytes
+ */
+#define	JMP	\
+	pushl	$_CONST(. - lx_handler_table); \
+	jmp	lx_handler;	\
+	.align	16;	
+
+#define	JMP4	JMP; JMP; JMP; JMP
+#define JMP16	JMP4; JMP4; JMP4; JMP4
+#define JMP64	JMP16; JMP16; JMP16; JMP16
+#define JMP256	JMP64; JMP64; JMP64; JMP64
+
+/*
+ * Alternate jump table that turns on lx_traceflag before proceeding with
+ * the normal emulation routine.
+ */
+#define	TJMP	\
+	pushl	$_CONST(. - lx_handler_trace_table); \
+	jmp	lx_handler_trace;	\
+	.align	16;	
+
+#define	TJMP4	TJMP; TJMP; TJMP; TJMP
+#define TJMP16	TJMP4; TJMP4; TJMP4; TJMP4
+#define TJMP64	TJMP16; TJMP16; TJMP16; TJMP16
+#define TJMP256	TJMP64; TJMP64; TJMP64; TJMP64
+
+	
+#if defined(lint)
+
+#include <sys/types.h>
+#include <sys/regset.h>
+#include <sys/signal.h>
+
+void
+lx_handler_table(void)
+{}
+
+void
+lx_handler(void)
+{}
+
+/* ARGSUSED */
+void
+lx_setup_clone(uintptr_t gs, void *retaddr, void *stk)
+{}
+
+/* ARGSUSED */
+void
+lx_sigdeliver(int sig, siginfo_t *sip, void *p, size_t stacksz,
+    void (*stack_frame_builder)(void), void (*lx_sighandler)(void),
+    uintptr_t gs)
+{}
+
+/* ARGSUSED */
+void
+lx_sigacthandler(int sig, siginfo_t *s, void *p)
+{}
+
+void
+lx_sigreturn_tramp(void)
+{}
+
+void
+lx_rt_sigreturn_tramp(void)
+{}
+
+/* ARGSUSED */
+void
+lx_sigreturn_tolibc(uintptr_t sp)
+{}
+
+#else	/* lint */
+
+	/*
+	 * On entry to this table, %eax will hold the return address. The
+	 * location where we enter the table is a function of the system
+	 * call number. The table needs the same alignment as the individual
+	 * entries.
+	 */
+	.align	16
+	ENTRY_NP(lx_handler_trace_table)
+	TJMP256
+	TJMP64
+	SET_SIZE(lx_handler_trace_table)
+
+	.align	16
+	ENTRY_NP(lx_handler_table)
+	JMP256
+	JMP64
+	SET_SIZE(lx_handler_table)
+
+	ENTRY_NP(lx_handler_trace)
+	pushl	%esi
+	PIC_SETUP(%esi)
+	movl	lx_traceflag@GOT(%esi), %esi
+	movl	$1, (%esi)
+	popl	%esi
+	/*
+	 * While we could just fall through to lx_handler(), we "tail-call" it
+	 * instead to make ourselves a little more comprehensible to trace
+	 * tools.
+	 */
+	jmp	lx_handler
+	SET_SIZE(lx_handler_trace)
+	
+	ALTENTRY(lx_handler)
+	/*
+	 * %ebp isn't always going to be a frame pointer on Linux, but when
+	 * it is, saving it here lets us have a coherent stack backtrace.
+	 */
+	pushl	%ebp
+
+	/*
+	 * Fill in a lx_regs_t structure on the stack.
+	 */
+	subl	$SIZEOF_LX_REGS_T, %esp
+
+	/*
+	 * Save %ebp and then fill it with what would be its usual value as
+	 * the frame pointer. The value we save for %esp needs to be the
+	 * stack pointer at the time of the interrupt so we need to skip the
+	 * saved %ebp and (what will be) the return address.
+	 */
+	movl	%ebp, LXR_EBP(%esp)
+	movl	%esp, %ebp
+	addl	$_CONST(SIZEOF_LX_REGS_T), %ebp
+	movl	%ebp, LXR_ESP(%esp)
+	addl	$_CONST(_MUL(CPTRSIZE, 2)), LXR_ESP(%esp)
+
+	movl	$0, LXR_GS(%esp)
+	movw	%gs, LXR_GS(%esp)
+	movl	%edi, LXR_EDI(%esp)
+	movl	%esi, LXR_ESI(%esp)
+	movl	%ebx, LXR_EBX(%esp)
+	movl	%edx, LXR_EDX(%esp)
+	movl	%ecx, LXR_ECX(%esp)
+	movl	%eax, LXR_EIP(%esp)
+
+	/*
+	 * The kernel drops us into the middle of one of the tables above
+	 * that then pushes that table offset onto the stack, and calls into
+	 * lx_handler. That offset indicates the system call number while
+	 * %eax holds the return address for the system call. We replace the
+	 * value on the stack with the return address, and use the value to
+	 * compute the system call number by dividing by the table entry size.
+	 */
+	xchgl	CPTRSIZE(%ebp), %eax
+	shrl	$4, %eax
+	movl	%eax, LXR_EAX(%esp)
+
+	/*
+	 * Switch to the Solaris libc's %gs.
+	 */
+	movl	$LWPGS_SEL, %ebx
+	movw	%bx, %gs
+
+	/*
+	 * Call lx_emulate() whose only argument is a pointer to the
+	 * lx_regs_t structure we've placed on the stack.
+	 */
+	pushl	%esp
+	call	lx_emulate
+
+	/*
+	 * We use this global symbol to identify this return site when
+	 * walking the stack backtrace. It needs to remain immediately
+	 * after the call to lx_emulate().
+	 */
+	ALTENTRY(lx_emulate_done)
+
+	/*
+	 * Clean up the argument to lx_emulate().
+	 */
+	addl	$4, %esp
+
+	/*
+	 * Restore the saved register state; we get %ebp, %esp and %esp from
+	 * the ordinary locations rather than the saved state.
+	 */
+	movl	LXR_EDI(%esp), %edi
+	movl	LXR_ESI(%esp), %esi
+	movl	LXR_EBX(%esp), %ebx
+	movl	LXR_EDX(%esp), %edx
+	movl	LXR_ECX(%esp), %ecx
+	movl	LXR_EAX(%esp), %eax
+	movw	LXR_GS(%esp), %gs
+
+	addl	$SIZEOF_LX_REGS_T, %esp
+
+	movl	%ebp, %esp
+	popl	%ebp
+	ret
+	SET_SIZE(lx_handler)
+
+	ENTRY_NP(lx_swap_gs)
+	push	%eax		/* save the current eax value */
+	movl	0xc(%esp),%eax	/* 2nd param is a pointer */
+	movw	%gs,(%eax)	/* use the pointer to save current gs */
+	movl	0x8(%esp),%eax	/* first parameter is the new gs value */
+	movw	%ax, %gs	/* switch to the new gs value */
+	pop	%eax		/* restore eax */
+	ret
+	SET_SIZE(lx_swap_gs)
+
+	ENTRY_NP(lx_setup_clone)
+	xorl	%ebp, %ebp	/* terminating stack */
+	popl	%edx		/* eat the start_clone() return address */
+	popl	%gs		/* Switch back to the Linux libc's %gs */
+	popl	%edx		/* Linux clone() return address */
+	popl	%esp		/* New stack pointer */
+	xorl	%eax, %eax	/* child returns 0 to SYS_clone() */
+	jmp	*%edx		/* return to Linux app. */
+	SET_SIZE(lx_setup_clone)
+
+	/*
+	 * lx_sigdeliver(sig, siginfo_t *, ucontext_t *, stack_size,
+	 *     stack_build_routine, signal_handler, glibc_gs)
+	 *
+	 * This routine allocates stack space for the Linux signal stack,
+	 * calls a routine to build the signal stack and then calls the Linux
+	 * signal handler.  This is written in assembly because of the way
+	 * we need to directly manipulate the stack and pass the resulting
+	 * stack to the signal handler with the Linux signal stack on top.
+	 *
+	 * When the Linux signal handler is called, the stack will look
+	 * like this:
+	 *
+	 * 	=================================================
+	 *	| Linux signal frame built by lx_stackbuilder() |
+	 * 	=================================================
+	 *	| LX_SIGRT_MAGIC				|
+	 * 	=================================================
+	 *	| %ebp						|
+	 * 	=================================================
+	 */
+	ENTRY_NP(lx_sigdeliver)
+	pushl   %ebp
+	movl    %esp, %ebp
+	movl	16(%ebp), %edx		/* pointer to Solaris ucontext_t */
+	pushl	%edx			/* save ucontext_t ptr for later */
+	pushl	$LX_SIGRT_MAGIC		/* marker value for lx_(rt)_sigreturn */
+
+	subl    20(%ebp), %esp		/* create stack buffer */
+	pushl   %esp			/* push stack pointer */
+	pushl   %edx			/* push pointer to ucontext_t */
+	pushl   12(%ebp)		/* push pointer to siginfo_t */
+	pushl   8(%ebp)			/* push signal number */
+	call    *24(%ebp)		/* lx_stackbuilder(sig, sip, ucp, sp) */
+	add     $16, %esp		/* remove args from stack */
+	movw	32(%ebp), %gs		/* only low 16 bits are used */
+
+	mov	4(%ebp),%eax		/* fetch old %ebp from stack */
+	mov	28(%ebp), %edx		/* get address of Linux handler */
+	mov	%eax, %ebp		/* restore old %ebp */
+	jmp	*%edx			/* jmp to the Linux signal handler */
+	SET_SIZE(lx_sigdeliver)
+
+	/*
+	 * Due to the nature of signals, we need to be able to force the %gs
+	 * value to that used by Solaris by running any Solaris code.
+	 *
+	 * This routine does that, then calls a C routine that will save the
+	 * %gs value at the time of the signal off into a thread-specific data
+	 * structure.  Finally, we trampoline to the libc code that would
+	 * normally interpose itself before calling a signal handler.
+	 *
+	 * The libc routine that calls user signal handlers ends with a
+	 * setcontext, so we would never return here even if we used a call
+	 * rather than a jmp.
+	 *
+	 * %esi is used for the PIC as it is guaranteed by the 386 ABI to
+	 * survive the call to lx_sigsavegs.  The downside is we must also
+	 * preserve its value for our caller.
+	 *
+	 * Note that because lx_sigsavegs and libc_sigacthandler are externs,
+	 * they need to be dereferenced via the GOT.
+	 *
+	 * IMPORTANT:  Because libc apparently gets upset if extra data is
+	 *	       left on its stack, this routine needs to be crafted
+	 *	       in assembly so that the jmp to the libc interposer
+	 *	       doesn't leave any cruft lying around.
+	 */
+	ENTRY_NP(lx_sigacthandler)
+	pushl	%esi				/* save %esi */
+	pushl	%gs				/* push the Linux %gs */
+	pushl	$LWPGS_SEL
+	popl	%gs				/* install the Solaris %gs */
+
+	PIC_SETUP(%esi)
+	movl	lx_sigsavegs@GOT(%esi), %eax
+	call	*%eax				/* save the Linux %gs */
+	movl    libc_sigacthandler@GOT(%esi), %eax 
+	add	$4, %esp			/* clear Linux %gs from stack */
+	popl	%esi				/* restore %esi */
+	jmp     *(%eax)				/* jmp to libc's interposer */
+	SET_SIZE(lx_sigacthandler)
+
+	/*
+	 * Trampoline code is called by the return at the end of a Linux
+	 * signal handler to return control to the interrupted application
+	 * via the lx_sigreturn() or lx_rt_sigreturn() syscalls.
+	 *
+	 * (lx_sigreturn() is called for legacy signal handling, and
+	 * lx_rt_sigreturn() is called for "new"-style signals.)
+	 *
+	 * These two routines must consist of the EXACT code sequences below
+	 * as gdb looks at the sequence of instructions a routine will return
+	 * to determine whether it is in a signal handler or not.
+	 */
+	ENTRY_NP(lx_sigreturn_tramp)
+	popl	%eax
+	movl	$LX_SYS_sigreturn, %eax
+	int	$0x80
+	SET_SIZE(lx_sigreturn_tramp)
+
+	ENTRY_NP(lx_rt_sigreturn_tramp)
+	movl	$LX_SYS_rt_sigreturn, %eax
+	int	$0x80
+	SET_SIZE(lx_rt_sigreturn_tramp)
+
+	/*
+	 * Manipulate the stack in the way necessary for it to appear to libc
+	 * that the signal handler it invoked via call_user_handler() is
+	 * returning.
+	 */
+	ENTRY_NP(lx_sigreturn_tolibc)
+	movl	4(%esp), %esp		/* set %esp to passed value */
+	popl	%ebp			/* restore proper %ebp */
+	ret				/* return to libc interposer */
+	SET_SIZE(lx_sigreturn_tolibc)
+#endif	/* lint */
