changeset 11685:95082903303d

6887823 brandz on x86 should ignore %gs and simplify brand hooks
author <gerald.jelinek@sun.com>
date Thu, 18 Feb 2010 07:03:00 -0700
parents e1daec51bef4
children ee97d7ce1deb
files usr/src/uts/common/brand/lx/os/lx_misc.c usr/src/uts/common/brand/lx/sys/lx_brand.h usr/src/uts/i86pc/ml/syscall_asm.s usr/src/uts/i86pc/ml/syscall_asm_amd64.s usr/src/uts/intel/brand/common/brand_asm.h usr/src/uts/intel/brand/lx/lx_brand_asm.s usr/src/uts/intel/brand/sn1/sn1_brand_asm.s usr/src/uts/intel/brand/solaris10/s10_brand_asm.s usr/src/uts/intel/genassym/offsets.in
diffstat 9 files changed, 414 insertions(+), 740 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/brand/lx/os/lx_misc.c	Thu Feb 18 13:36:37 2010 +0000
+++ b/usr/src/uts/common/brand/lx/os/lx_misc.c	Thu Feb 18 07:03:00 2010 -0700
@@ -19,12 +19,10 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/errno.h>
 #include <sys/systm.h>
 #include <sys/archsystm.h>
@@ -341,24 +339,14 @@
 
 /*
  * Brand-specific routine to check if given non-Solaris standard segment
- * register values should be used as-is or if they should be modified to other
- * values.
+ * register values should be modified to other values.
  */
 /*ARGSUSED*/
 greg_t
 lx_fixsegreg(greg_t sr, model_t datamodel)
 {
-	struct lx_lwp_data *lxlwp = ttolxlwp(curthread);
-
-	/*
-	 * If the segreg is the same as the %gs the brand callback was last
-	 * entered with, allow it to be used unmodified.
-	 */
 	ASSERT(sr == (sr & 0xffff));
 
-	if (sr == (lxlwp->br_ugs & 0xffff))
-		return (sr);
-
 	/*
 	 * Force the SR into the LDT in ring 3 for 32-bit processes.
 	 *
--- a/usr/src/uts/common/brand/lx/sys/lx_brand.h	Thu Feb 18 13:36:37 2010 +0000
+++ b/usr/src/uts/common/brand/lx/sys/lx_brand.h	Thu Feb 18 07:03:00 2010 -0700
@@ -19,15 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #ifndef _LX_BRAND_H
 #define	_LX_BRAND_H
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #ifndef _ASM
 #include <sys/types.h>
 #include <sys/cpuvar.h>
@@ -199,12 +197,6 @@
 	 */
 	void	 *br_clone_args;
 
-	/*
-	 * Space to save off userland Linux %gs pointer so we can restore it
-	 * before calling signal handlers.
-	 */
-	greg_t	br_ugs;
-
 	uint_t	br_ptrace;		/* ptrace is active for this LWP */
 } lx_lwp_data_t;
 
--- a/usr/src/uts/i86pc/ml/syscall_asm.s	Thu Feb 18 13:36:37 2010 +0000
+++ b/usr/src/uts/i86pc/ml/syscall_asm.s	Thu Feb 18 07:03:00 2010 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -115,28 +115,35 @@
 
 /*
  * Check if a brand_mach_ops callback is defined for the specified callback_id
- * type.  If so invoke it with the kernel's %gs value loaded and the following
+ * type.  If so invoke it with the user's %gs value loaded and the following
  * data on the stack:
  *	   --------------------------------------
- *         | 'scratch space'			|
- *         | user's %ebx			|
- *         | user's %gs selector		|
- *    |    | kernel's %gs selector		|
- *    |    | lwp pointer			|
- *    v    | user return address		|
+ *         | user's %ss                         |
+ *    |    | user's %esp                        |
+ *    |    | EFLAGS register                    |
+ *    |    | user's %cs                         |
+ *    |    | user's %eip (user return address)  |
+ *    |    | 'scratch space'			|
+ *    |    | user's %ebx			|
+ *    |    | user's %gs selector		|
+ *    v    | lwp pointer			|
  *         | callback wrapper return addr 	|
  *         --------------------------------------
  *
- * The lx brand (at least) uses each of these fields.
  * If the brand code returns, we assume that we are meant to execute the
  * normal system call path.
+ *
+ * The interface to the brand callbacks on the 32-bit kernel assumes %ebx
+ * is available as a scratch register within the callback.  If the callback
+ * returns within the kernel then this macro will restore %ebx.  If the
+ * callback is going to return directly to userland then it should restore
+ * %ebx before returning to userland.
  */
 #define	BRAND_CALLBACK(callback_id)					    \
 	subl	$4, %esp		/* save some scratch space	*/ ;\
 	pushl	%ebx			/* save %ebx to use for scratch	*/ ;\
 	pushl	%gs			/* save the user %gs		*/ ;\
 	movl	$KGS_SEL, %ebx						   ;\
-	pushl	%ebx			/* push kernel's %gs		*/ ;\
 	movw	%bx, %gs		/* switch to the kernel's %gs	*/ ;\
 	movl	%gs:CPU_THREAD, %ebx	/* load the thread pointer	*/ ;\
 	movl	T_LWP(%ebx), %ebx	/* load the lwp pointer		*/ ;\
@@ -147,15 +154,14 @@
 	movl	_CONST(_MUL(callback_id, CPTRSIZE))(%ebx), %ebx		   ;\
 	cmpl	$0, %ebx						   ;\
 	je	1f							   ;\
-	movl	%ebx, 16(%esp)		/* save callback to scratch	*/ ;\
-	movl	12(%esp), %ebx		/* restore %ebx			*/ ;\
-	pushl	20(%esp)		/* push the return address	*/ ;\
-	call	*20(%esp)		/* call callback		*/ ;\
-	addl	$4, %esp		/* get rid of ret addr		*/ ;\
-1:	movl	8(%esp), %ebx		/* grab the the user %gs	*/ ;\
+	movl	%ebx, 12(%esp)		/* save callback to scratch	*/ ;\
+	movl	4(%esp), %ebx		/* grab the user %gs		*/ ;\
 	movw	%bx, %gs		/* restore the user %gs		*/ ;\
-	movl	12(%esp), %ebx		/* restore user's %ebx		*/ ;\
-	addl	$20, %esp		/* restore stack ptr		*/ 
+	call	*12(%esp)		/* call callback in scratch	*/ ;\
+1:	movl	4(%esp), %ebx		/* restore user %gs (re-do if	*/ ;\
+	movw	%bx, %gs		/* branch due to no callback)	*/ ;\
+	movl	8(%esp), %ebx		/* restore user's %ebx		*/ ;\
+	addl	$16, %esp		/* restore stack ptr		*/ 
 
 #define	MSTATE_TRANSITION(from, to)		\
 	pushl	$to;				\
--- a/usr/src/uts/i86pc/ml/syscall_asm_amd64.s	Thu Feb 18 13:36:37 2010 +0000
+++ b/usr/src/uts/i86pc/ml/syscall_asm_amd64.s	Thu Feb 18 07:03:00 2010 -0700
@@ -132,7 +132,6 @@
  * data on the stack:
  *
  * stack:  --------------------------------------
- *      40 | user %gs				|
  *      32 | callback pointer			|
  *    | 24 | user (or interrupt) stack pointer	|
  *    | 16 | lwp pointer			|
@@ -161,6 +160,12 @@
  * BRAND_URET_FROM_REG or BRAND_URET_FROM_INTR_STACK macro.  These macros are
  * used to generate the proper code to get the userland return address for
  * each syscall entry point.
+ *
+ * The interface to the brand callbacks on the 64-bit kernel assumes %r15
+ * is available as a scratch register within the callback.  If the callback
+ * returns within the kernel then this macro will restore %r15.  If the
+ * callback is going to return directly to userland then it should restore
+ * %r15 before returning to userland.
  */
 #define BRAND_URET_FROM_REG(rip_reg)					\
 	pushq	rip_reg			/* push the return address	*/
@@ -178,7 +183,7 @@
 	movq	%r15, %gs:CPU_RTMP_R15	/* save %r15			*/ ;\
 	movq	%gs:CPU_THREAD, %r15	/* load the thread pointer	*/ ;\
 	movq	T_STACK(%r15), %rsp	/* switch to the kernel stack	*/ ;\
-	subq	$24, %rsp		/* save space for 3 pointers	*/ ;\
+	subq	$16, %rsp		/* save space for 2 pointers	*/ ;\
 	pushq	%r14			/* save %r14			*/ ;\
 	movq	%gs:CPU_RTMP_RSP, %r14					   ;\
 	movq	%r14, 8(%rsp)		/* stash the user stack pointer	*/ ;\
@@ -193,11 +198,6 @@
 	je	1f							   ;\
 	movq	%r15, 16(%rsp)		/* save the callback pointer	*/ ;\
 	push_userland_ret		/* push the return address	*/ ;\
-	SWAPGS				/* user gsbase			*/ ;\
-	mov	%gs, %r15		/* get %gs			*/ ;\
-	movq	%r15, 32(%rsp)		/* save %gs on stack		*/ ;\
-	SWAPGS				/* kernel gsbase		*/ ;\
-	movq	%gs:CPU_RTMP_R15, %r15	/* restore %r15			*/ ;\
 	call	*24(%rsp)		/* call callback		*/ ;\
 1:	movq	%gs:CPU_RTMP_R15, %r15	/* restore %r15			*/ ;\
 	movq	%gs:CPU_RTMP_RSP, %rsp	/* restore the stack pointer	*/
@@ -425,18 +425,13 @@
 	SWAPGS				/* kernel gsbase */
 	XPV_SYSCALL_PROD
 	BRAND_CALLBACK(BRAND_CB_SYSCALL, BRAND_URET_FROM_REG(%rcx))
-	SWAPGS				/* user gsbase */
+	jmp	noprod_sys_syscall
 
-#if defined(__xpv)
-	jmp	noprod_sys_syscall
-#endif
-	
 	ALTENTRY(sys_syscall)
 	SWAPGS				/* kernel gsbase */
 	XPV_SYSCALL_PROD
 
 noprod_sys_syscall:
-
 	movq	%r15, %gs:CPU_RTMP_R15
 	movq	%rsp, %gs:CPU_RTMP_RSP
 
@@ -702,20 +697,13 @@
 	SWAPGS				/* kernel gsbase */
 	XPV_TRAP_POP
 	BRAND_CALLBACK(BRAND_CB_SYSCALL32, BRAND_URET_FROM_REG(%rcx))
-	SWAPGS				/* user gsbase */
-
-#if defined(__xpv)
 	jmp	nopop_sys_syscall32
-#endif
 
 	ALTENTRY(sys_syscall32)
 	SWAPGS				/* kernel gsbase */
+	XPV_TRAP_POP
 
-#if defined(__xpv)
-	XPV_TRAP_POP
 nopop_sys_syscall32:
-#endif
-
 	movl	%esp, %r10d
 	movq	%gs:CPU_THREAD, %r15
 	movq	T_STACK(%r15), %rsp
@@ -1162,9 +1150,7 @@
 	XPV_TRAP_POP
 	BRAND_CALLBACK(BRAND_CB_INT80, BRAND_URET_FROM_INTR_STACK())
 	SWAPGS				/* user gsbase */
-#if defined(__xpv)
 	jmp	nopop_int80
-#endif
 
 	ENTRY_NP(sys_int80)
 	/*
@@ -1175,10 +1161,8 @@
 	 * to undo the XPV_TRAP_POP and push rcx and r11 back on the stack
 	 * because gptrap will pop them again with its own XPV_TRAP_POP.
 	 */
-#if defined(__xpv)
 	XPV_TRAP_POP
 nopop_int80:
-#endif
 	subq	$2, (%rsp)	/* int insn 2-bytes */
 	pushq	$_CONST(_MUL(T_INT80, GATE_DESC_SIZE) + 2)
 #if defined(__xpv)
@@ -1209,20 +1193,13 @@
 	SWAPGS				/* kernel gsbase */
 	XPV_TRAP_POP
 	BRAND_CALLBACK(BRAND_CB_INT91, BRAND_URET_FROM_INTR_STACK())
-	SWAPGS				/* user gsbase */
-
-#if defined(__xpv)
 	jmp	nopop_syscall_int
-#endif
 
 	ALTENTRY(sys_syscall_int)
 	SWAPGS				/* kernel gsbase */
+	XPV_TRAP_POP
 
-#if defined(__xpv)
-	XPV_TRAP_POP
 nopop_syscall_int:
-#endif
-
 	movq	%gs:CPU_THREAD, %r15
 	movq	T_STACK(%r15), %rsp
 	movl	%eax, %eax
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/intel/brand/common/brand_asm.h	Thu Feb 18 07:03:00 2010 -0700
@@ -0,0 +1,304 @@
+/*
+ * 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 2010 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _COMMON_BRAND_ASM_H
+#define	_COMMON_BRAND_ASM_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#ifndef	lint
+
+#include <sys/asm_linkage.h>
+#include <sys/privregs.h>
+#include <sys/segments.h>
+#include "assym.h"
+
+#endif	/* lint */
+
+#ifdef _ASM	/* The remainder of this file is only for assembly files */
+
+#if defined(__amd64)
+/*
+ * Common to all 64-bit callbacks:
+ *
+ * We're running on the kernel's %gs.
+ *
+ * We return directly to userland, bypassing the _update_sregs logic, so
+ * the routine must NOT do anything that could cause a context switch.
+ *
+ * %rax - syscall number
+ *
+ * When called, all general registers, except for %r15, are as they were when
+ * the user process made the system call.  %r15 is available to the callback as
+ * a scratch register.  If the callback returns to the kernel path, %r15 does
+ * not have to be restored to the user value.  If the callback returns to the
+ * userlevel emulation code, the callback should restore %r15 if the emulation
+ * depends on the original userlevel value.
+ *
+ * 64-BIT INTERPOSITION STACK
+ * On entry to the callback the stack looks like this:
+ *         --------------------------------------
+ *      32 | callback pointer			|
+ *      24 | saved stack pointer		|
+ *    | 16 | lwp pointer			|
+ *    v  8 | user return address		|
+ *       0 | BRAND_CALLBACK()'s return addr 	|
+ *         --------------------------------------
+ */
+
+#define	V_COUNT	5
+#define	V_END		(CLONGSIZE * 5)
+#define	V_SSP		(CLONGSIZE * 3)
+#define	V_LWP		(CLONGSIZE * 2)
+#define	V_URET_ADDR	(CLONGSIZE * 1)
+#define	V_CB_ADDR	(CLONGSIZE * 0)
+
+#define	SP_REG		%rsp
+#define	SCR_REG		%r15
+#define	SCR_REGB	%r15b
+#define	SYSCALL_REG	%rax
+
+/*
+ * 64-BIT INT STACK
+ * For int callbacks (e.g. int91) the saved stack pointer (V_SSP) points at
+ * the state saved when we took the interrupt:
+ *	   --------------------------------------
+ *    | 32 | user's %ss				|
+ *    | 24 | user's %esp			|
+ *    | 16 | EFLAGS register			|
+ *    v  8 | user's %cs				|
+ *       0 | user's %eip (user return address)	|
+ *	   --------------------------------------
+ */
+#define	V_U_EIP		(CLONGSIZE * 0)
+
+#else	/* !__amd64 */
+/*
+ * 32-BIT INTERPOSITION STACK
+ * When our syscall interposition callback entry point gets invoked the
+ * stack looks like this:
+ *         --------------------------------------
+ *    | 16 | 'scratch space'			|
+ *    | 12 | user's %ebx			|
+ *    |  8 | user's %gs selector		|
+ *    v  4 | lwp pointer			|
+ *       0 | callback wrapper return addr	|
+ *         --------------------------------------
+ */
+
+#define	V_COUNT	5
+#define	V_END		(CLONGSIZE * 5)
+#define	V_U_EBX		(CLONGSIZE * 3)
+#define	V_LWP		(CLONGSIZE * 1)
+#define	V_CB_ADDR	(CLONGSIZE * 0)
+
+#define	SP_REG		%esp
+#define	SCR_REG		%ebx
+#define	SCR_REGB	%bl
+#define	SYSCALL_REG	%eax
+
+/*
+ * 32-BIT INT STACK
+ * For the lcall handler for 32-bit OS (i.e. xxx_brand_syscall_callback)
+ * above the stack contents common to all callbacks is the int/lcall-specific
+ * state:
+ *	   --------------------------------------
+ *    | 36 | user's %ss				|
+ *    | 32 | user's %esp			|
+ *    | 28 | EFLAGS register			|
+ *    v 24 | user's %cs				|
+ *      20 | user's %eip (user return address)	|
+ *	   --------------------------------------
+ */
+#define	V_U_EIP		(V_END + (CLONGSIZE * 0))
+
+#endif	/* !__amd64 */
+
+/*
+ * The following macros allow us to access to variables/parameters passed
+ * in on the stack.  They take the following variables:
+ *	sp	- a register with the current stack pointer value
+ *	pcnt	- the number of words currently pushed onto the stack
+ *	var	- the variable to lookup
+ *	reg	- a register to read the variable into, or
+ *		  a register to write to the variable
+ */
+#define	V_OFFSET(pcnt, var)						\
+	(var + (pcnt * CLONGSIZE))
+
+#define	GET_V(sp, pcnt, var, reg)					\
+	mov	V_OFFSET(pcnt, var)(sp), reg
+
+#define	SET_V(sp, pcnt, var, reg)					\
+	mov	reg, V_OFFSET(pcnt, var)(sp)
+
+#define	GET_PROCP(sp, pcnt, reg)					\
+	GET_V(sp, pcnt, V_LWP, reg);		/* get lwp pointer */	\
+	mov	LWP_PROCP(reg), reg		/* get proc pointer */
+
+#define	GET_P_BRAND_DATA(sp, pcnt, reg)					\
+	GET_PROCP(sp, pcnt, reg);					\
+	mov	P_BRAND_DATA(reg), reg		/* get p_brand_data */
+
+/*
+ * Each of the following macros returns to the standard syscall codepath if
+ * it detects that this process is not able, or intended, to emulate this
+ * system call.  They all assume that the routine provides a 'bail-out'
+ * label of '9'.
+ */
+
+/*
+ * See if this process has a user-space handler registered for it.  For the
+ * brand, the per-process brand data holds the address of the handler.
+ * As shown in the stack diagrams above, the callback code leaves the lwp
+ * pointer at well-defined offsets, so check if proc_data_t->X_handler is
+ * non-NULL.  For each brand, the handler parameter refers to the brand's
+ * user-space handler variable name.
+ */
+#define	CHECK_FOR_HANDLER(scr, handler)					\
+	GET_P_BRAND_DATA(SP_REG, 0, scr);	/* get p_brand_data */	\
+	cmp	$0, scr;						\
+	je	9f;							\
+	cmp	$0, handler(scr);		/* check handler */	\
+	je	9f
+
+/*
+ * If the system call number is >= 1024, then it is coming from the
+ * emulation support library.  As such we should handle it natively instead
+ * of sending it back to the emulation library.
+ */
+#define	CHECK_FOR_NATIVE(reg)		\
+	cmp	$1024, reg;		\
+	jl	1f;			\
+	sub	$1024, reg;		\
+	jmp	9f;			\
+1:
+
+/*
+ * Check to see if we want to interpose on this system call.  If not, we
+ * jump back into the normal syscall path and pretend nothing happened.
+ * This macro is usable for brands which have the same number of syscalls
+ * as the base OS.
+ */
+#define	CHECK_FOR_INTERPOSITION(emul_table, call, scr, scr_low)		\
+	cmp	$NSYSCALL, call;	/* is 0 <= syscall <= MAX? */	\
+	ja	9f;			/* no, take normal ret path */	\
+	lea	emul_table, scr;					\
+	/*CSTYLED*/							\
+	mov	(scr), scr;						\
+	add	call, scr;						\
+	/*CSTYLED*/							\
+	movb	(scr), scr_low;						\
+	cmpb	$0, scr_low;						\
+	je	9f			/* no, take normal ret path */
+
+#define	CALLBACK_PROLOGUE(emul_table, handler, call, scr, scr_low)	\
+	CHECK_FOR_HANDLER(scr, handler);				\
+	CHECK_FOR_NATIVE(call);						\
+	CHECK_FOR_INTERPOSITION(emul_table, call, scr, scr_low)
+
+/*
+ * Rather than returning to the instruction after the syscall, we need to
+ * transfer control into the brand library's handler table at
+ * table_addr + (16 * syscall_num), thus encoding the system call number in the
+ * instruction pointer.  The CALC_TABLE_ADDR macro performs that calculation.
+ *
+ * This macro assumes the syscall number is in SYSCALL_REG and it clobbers
+ * that register.  It leaves the calculated handler table return address in
+ * the scratch reg.
+ */
+#define	CALC_TABLE_ADDR(scr, handler)					\
+	GET_P_BRAND_DATA(SP_REG, 0, scr); /* get p_brand_data ptr */	\
+	mov	handler(scr), scr;	/* get p_brand_data->XX_handler */ \
+	shl	$4, SYSCALL_REG;	/* syscall_num * 16 */		\
+	add	SYSCALL_REG, scr	/* leave return addr in scr reg. */
+
+#if defined(__amd64)
+
+/*
+ * To 'return' to our user-space handler, we just need to place its address
+ * into 'retreg'.  The original return address is passed back in SYSCALL_REG.
+ */
+#define	SYSCALL_EMUL(emul_table, handler, retreg)			\
+	CALLBACK_PROLOGUE(emul_table, handler, SYSCALL_REG, SCR_REG, SCR_REGB);\
+	CALC_TABLE_ADDR(SCR_REG, handler);				\
+	mov	retreg, SYSCALL_REG; /* save orig return addr in syscall_reg */\
+	mov	SCR_REG, retreg;	/* place new return addr in retreg */\
+	mov	%gs:CPU_RTMP_R15, SCR_REG; /* restore scratch register */\
+	mov	V_SSP(SP_REG), SP_REG	/* restore user stack pointer */
+
+/*
+ * To 'return' to our user-space handler we need to update the user's %eip
+ * pointer in the saved interrupt state on the stack.  The interrupt state was
+ * pushed onto our stack automatically when the interrupt occured; see the
+ * comments above.  The original return address is passed back in SYSCALL_REG.
+ */
+#define	INT_EMUL(emul_table, handler)					\
+	CALLBACK_PROLOGUE(emul_table, handler, SYSCALL_REG, SCR_REG, SCR_REGB);\
+	CALC_TABLE_ADDR(SCR_REG, handler); /* new return addr is in scratch */ \
+	mov	SCR_REG, SYSCALL_REG;	/* place new ret addr in syscallreg */ \
+	mov	%gs:CPU_RTMP_R15, SCR_REG; /* restore scratch register */ \
+	mov	V_SSP(SP_REG), SP_REG;	/* restore intr stack pointer */ \
+	/*CSTYLED*/							\
+	xchg	(SP_REG), SYSCALL_REG	/* swap new and orig. return addrs */
+
+#else	/* !__amd64 */
+
+/*
+ * To 'return' to our user-space handler, we just need to place its address
+ * into 'retreg'.  The original return address is passed back in SYSCALL_REG.
+ */
+#define	SYSCALL_EMUL(emul_table, handler, retreg)			\
+	CALLBACK_PROLOGUE(emul_table, handler, SYSCALL_REG, SCR_REG, SCR_REGB);\
+	mov	retreg, SCR_REG;	/* save orig return addr in scr reg */ \
+	CALC_TABLE_ADDR(retreg, handler); /* new return addr is in retreg */ \
+	mov	SCR_REG, SYSCALL_REG;	/* save orig return addr in %eax */ \
+	GET_V(SP_REG, 0, V_U_EBX, SCR_REG) /* restore scratch register */
+
+/*
+ * To 'return' to our user-space handler, we need to replace the
+ * iret target address.
+ * The original return address is passed back in %eax.
+ */
+#define	INT_EMUL(emul_table, handler)					\
+	CALLBACK_PROLOGUE(emul_table, handler, SYSCALL_REG, SCR_REG, SCR_REGB);\
+	CALC_TABLE_ADDR(SCR_REG, handler); /* new return addr is in scratch */ \
+	mov	SCR_REG, SYSCALL_REG;	/* place new ret addr in syscallreg */ \
+	GET_V(SP_REG, 0, V_U_EBX, SCR_REG); /* restore scratch register */ \
+	add	$V_END, SP_REG;		/* restore intr stack pointer */ \
+	/*CSTYLED*/							\
+	xchg	(SP_REG), SYSCALL_REG	/* swap new and orig. return addrs */
+
+#endif	/* !__amd64 */
+
+#endif	/* _ASM */
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif	/* _COMMON_BRAND_ASM_H */
--- a/usr/src/uts/intel/brand/lx/lx_brand_asm.s	Thu Feb 18 13:36:37 2010 +0000
+++ b/usr/src/uts/intel/brand/lx/lx_brand_asm.s	Thu Feb 18 07:03:00 2010 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -30,11 +30,8 @@
 
 #else	/* __lint */
 
-#include <sys/asm_linkage.h>
-#include <sys/privregs.h>
-#include <sys/segments.h>
-#include "assym.h"
 #include "genassym.h"
+#include "../common/brand_asm.h"
 
 #endif	/* __lint */
 
@@ -48,70 +45,29 @@
 #else	/* __lint */
 
 #if defined(__amd64)
-	/*
-	 * lx brand callback for the int $0x80 trap handler.
-	 *
-	 * We're running on the kernel's %gs.
-	 *
-	 * We return directly to userland, bypassing the _update_sregs logic, so
-	 * this	routine must NOT do anything that could cause a context switch.
-	 *
-	 * %rax - syscall number
-	 * 
-	 * When called, all general registers are as they were when
-	 * the user process made the system call.  The %gs register has the
-	 * kernel value.  The stack looks like this:
-	 *
-	 *  	   --------------------------------------
-	 *      40 | user %gs				|
-	 *      32 | callback pointer			|
-	 *      24 | saved stack pointer		|
-	 *    | 16 | lwp pointer			|
-	 *    v  8 | user return address (*)		|
-	 *       0 | caller's return addr (sys_int80)	|
-	 *         -------------------------------------
-	 */
-	ENTRY(lx_brand_int80_callback)
-	movq	16(%rsp), %r15			/* grab the lwp */
-	movq	LWP_PROCP(%r15), %r15		/* grab the proc pointer */
-	pushq	%r15				/* push the proc pointer */
+
+/*
+ * See "64-BIT INTERPOSITION STACK" in brand_asm.h.
+ */
+ENTRY(lx_brand_int80_callback)
+	GET_PROCP(SP_REG, 0, %r15)
 	movq	P_ZONE(%r15), %r15		/* grab the zone pointer */
+	/* grab the 'max syscall num' for this process from 'zone brand data' */
 	movq	ZONE_BRAND_DATA(%r15), %r15	/* grab the zone brand ptr */
-	pushq	%rax				/* save the syscall num */
-	movl	LXZD_MAX_SYSCALL(%r15), %eax	/* load the 'max sysnum' word */
-	xchgq	(%rsp), %rax			/* swap %rax and stack value */
-	movq	32(%rsp), %r15			/* re-load the lwp pointer */
-	movq	LWP_BRAND(%r15), %r15		/* grab the lwp brand data */
-	pushq   %rax				/* save %rax on stack */
-	movq	64(%rsp), %rax			/* get user %gs */
-	mov	%eax, BR_UGS(%r15)		/* save user %gs */
-	popq	%rax				/* restore %rax from stack */
-
-	/* grab the 'max syscall num' for this process from 'zone brand data' */
-	cmpq	(%rsp), %rax			/* is 0 <= syscall <= MAX? */
+	movl	LXZD_MAX_SYSCALL(%r15), %r15d	/* get the 'max sysnum' word */
+	cmpq	%r15, %rax			/* is 0 <= syscall <= MAX? */
 	jbe	0f				/* yes, syscall is OK */
 	xorl    %eax, %eax			/* no, zero syscall number */
 0:
-	movq	8(%rsp), %r15			/* get the proc pointer */
-	movq	P_BRAND_DATA(%r15), %r15	/* grab the proc brand data */
 
 .lx_brand_int80_patch_point:
 	jmp	.lx_brand_int80_notrace
 
 .lx_brand_int80_notrace:
-	movq	L_HANDLER(%r15), %r15		/* load the base address */
-	
+	CALC_TABLE_ADDR(%r15, L_HANDLER)
 1:
-	/*
-	 * Rather than returning to the instruction after the int 80, we
-	 * transfer control into the brand library's handler table at
-	 * table_addr + (16 * syscall_num) thus encoding the system
-	 * call number in the instruction pointer. The original return address
-	 * is passed in %eax.
-	 */
-	shlq	$4, %rax
-	addq	%r15, %rax
-	movq	40(%rsp), %rsp		/* restore user stack pointer */
+	movq	%r15, %rax
+	GET_V(%rsp, 0, V_SSP, %rsp)	/* restore intr. stack pointer */
 	xchgq	(%rsp), %rax		/* swap %rax and return addr */
 	jmp	sys_sysint_swapgs_iret
 
@@ -120,100 +76,68 @@
 	 * If tracing is active, we vector to an alternate trace-enabling
 	 * handler table instead.
 	 */
-	movq	L_TRACEHANDLER(%r15), %r15	/* load trace handler address */
+	CALC_TABLE_ADDR(%r15, L_TRACEHANDLER)
 	jmp	1b
-	SET_SIZE(lx_brand_int80_callback)
+SET_SIZE(lx_brand_int80_callback)
 
 #define	PATCH_POINT	_CONST(.lx_brand_int80_patch_point + 1)
 #define	PATCH_VAL	_CONST(.lx_brand_int80_trace - .lx_brand_int80_notrace)
 
-	ENTRY(lx_brand_int80_enable)
+ENTRY(lx_brand_int80_enable)
 	movl	$1, lx_systrace_brand_enabled(%rip)
 	movq	$PATCH_POINT, %r8
 	movb	$PATCH_VAL, (%r8)
 	ret
-	SET_SIZE(lx_brand_int80_enable)
+SET_SIZE(lx_brand_int80_enable)
 
-	ENTRY(lx_brand_int80_disable)
+ENTRY(lx_brand_int80_disable)
 	movq	$PATCH_POINT, %r8
 	movb	$0, (%r8)
 	movl	$0, lx_systrace_brand_enabled(%rip)
 	ret
-	SET_SIZE(lx_brand_int80_disable)
+SET_SIZE(lx_brand_int80_disable)
 
 
 #elif defined(__i386)
-	/*
-	 * %eax - syscall number
-	 *
-	 * When called, all general registers are as they were when
-	 * the user process made the system call.  The %gs register has the
-	 * kernel value.  The stack looks like this:
-	 *
-	 *	   --------------------------------------
-	 *    | 44 | user's %ss				|
-	 *    | 40 | user's %esp			|
-	 *    | 36 | EFLAGS register			|
-	 *    | 32 | user's %cs				|
-	 *    | 28 | user's %eip			|
-	 *    | 24 | 'scratch space'			|
-	 *    | 20 | user's %ebx			|
-	 *    | 16 | user's %gs selector		|
-	 *    | 12 | kernel's %gs selector		|
-	 *    |  8 | lwp pointer			|
-	 *    v  4 | user return address		|
-	 *       0 | callback wrapper return addr	|
-	 *         -------------------------------------
-	 */
-	ENTRY(lx_brand_int80_callback)
-	pushl	%ebx				/* save for use as scratch */
-	movl	12(%esp), %ebx			/* grab the lwp pointer */
-	movl	LWP_PROCP(%ebx), %ebx		/* grab the proc pointer */
-	pushl	%ebx				/* push the proc pointer */
+
+/*
+ * See "32-BIT INTERPOSITION STACK" in brand_asm.h.
+ */
+ENTRY(lx_brand_int80_callback)
+	GET_PROCP(SP_REG, 0, %ebx)
 	movl	P_ZONE(%ebx), %ebx		/* grab the zone pointer */
+	/* grab the 'max syscall num' for this process from 'zone brand data' */
 	movl	ZONE_BRAND_DATA(%ebx), %ebx	/* grab the zone brand data */
-	pushl	LXZD_MAX_SYSCALL(%ebx)		/* push the max sysnum */
-	movl	28(%esp), %ebx			/* grab the the user %gs */
-	movw	%bx, %gs			/* restore the user %gs */
-	movl	20(%esp), %ebx			/* re-load the lwp pointer */
-	movl	LWP_BRAND(%ebx), %ebx		/* grab the lwp brand data */
-	movw	%gs, BR_UGS(%ebx)		/* save user %gs */
+	movl	LXZD_MAX_SYSCALL(%ebx), %ebx	/* get the max sysnum */
 
-	/* grab the 'max syscall num' for this process from 'zone brand data' */
-	cmpl	(%esp), %eax 			/* is 0 <= syscall <= MAX? */
+	cmpl	%ebx, %eax 			/* is 0 <= syscall <= MAX? */
 	jbe	0f				/* yes, syscall is OK */
 	xorl    %eax, %eax		     	/* no, zero syscall number */	
 0:
-	movl	4(%esp), %ebx			/* get the proc pointer */
-	movl	P_BRAND_DATA(%ebx), %ebx	/* grab the proc brand data */
 
 .lx_brand_int80_patch_point:
 	jmp	.lx_brand_int80_notrace
 
 .lx_brand_int80_notrace:
-	movl	L_HANDLER(%ebx), %ebx		/* load the base address */
+	CALC_TABLE_ADDR(%ebx, L_HANDLER)
 
 1:
-	/*
-	 * See the corresponding comment in the amd64 version above.
-	 */
-	shll	$4, %eax
-	addl	%ebx, %eax
-	movl	8(%esp), %ebx			/* restore %ebx */
-	addl	$40, %esp
-	xchgl	(%esp), %eax			/* swap %eax and return addr */
+	movl	%ebx, %eax
+	GET_V(%esp, 0, V_U_EBX, %ebx)		/* restore scratch register */
+	addl	$V_END, %esp		/* restore intr. stack ptr */
+	xchgl	(%esp), %eax		/* swap new and orig. return addrs */
 	jmp	nopop_sys_rtt_syscall
 
 .lx_brand_int80_trace:
-	movl	L_TRACEHANDLER(%ebx), %ebx	/* load trace handler address */
+	CALC_TABLE_ADDR(%ebx, L_TRACEHANDLER)
 	jmp	1b
-	SET_SIZE(lx_brand_int80_callback)
+SET_SIZE(lx_brand_int80_callback)
 
 
 #define	PATCH_POINT	_CONST(.lx_brand_int80_patch_point + 1)
 #define	PATCH_VAL	_CONST(.lx_brand_int80_trace - .lx_brand_int80_notrace)
 
-	ENTRY(lx_brand_int80_enable)
+ENTRY(lx_brand_int80_enable)
 	pushl	%ebx
 	pushl	%eax
 	movl	$1, lx_systrace_brand_enabled
@@ -223,16 +147,16 @@
 	popl	%eax
 	popl	%ebx
 	ret
-	SET_SIZE(lx_brand_int80_enable)
+SET_SIZE(lx_brand_int80_enable)
 
-	ENTRY(lx_brand_int80_disable)
+ENTRY(lx_brand_int80_disable)
 	pushl	%ebx
 	movl	$PATCH_POINT, %ebx
 	movb	$0, (%ebx)
 	movl	$0, lx_systrace_brand_enabled
 	popl	%ebx
 	ret
-	SET_SIZE(lx_brand_int80_disable)
+SET_SIZE(lx_brand_int80_disable)
 
 #endif	/* __i386 */
 #endif	/* __lint */
--- a/usr/src/uts/intel/brand/sn1/sn1_brand_asm.s	Thu Feb 18 13:36:37 2010 +0000
+++ b/usr/src/uts/intel/brand/sn1/sn1_brand_asm.s	Thu Feb 18 07:03:00 2010 -0700
@@ -29,11 +29,8 @@
 
 #else	/* lint */
 
-#include <sys/asm_linkage.h>
-#include <sys/privregs.h>
-#include <sys/segments.h>
 #include <sn1_offsets.h>
-#include "assym.h"
+#include "../common/brand_asm.h"
 
 #endif	/* lint */
 
@@ -64,325 +61,72 @@
 #else	/* lint */
 
 #if defined(__amd64)
-/*
- * When our syscall interposition callback entry point gets invoked the
- * stack looks like this:
- *         --------------------------------------
- *      40 | user %gs				|
- *      32 | callback pointer			|
- *      24 | saved stack pointer		|
- *    | 16 | lwp pointer			|
- *    v  8 | user return address		|
- *       0 | BRAND_CALLBACK()'s return addr 	|
- *         --------------------------------------
- */
-
-#define	V_COUNT	6
-#define	V_END		(CLONGSIZE * 6)
-#define	V_SSP		(CLONGSIZE * 3)
-#define	V_LWP		(CLONGSIZE * 2)
-#define	V_URET_ADDR	(CLONGSIZE * 1)
-#define	V_CB_ADDR	(CLONGSIZE * 0)
-
-#define	SP_REG		%rsp
-#define	SYSCALL_REG	%rax
-
-#else	/* !__amd64 */
-/*
- * When our syscall interposition callback entry point gets invoked the
- * stack looks like this:
- *         --------------------------------------
- *    | 24 | 'scratch space'			|
- *    | 20 | user's %ebx			|
- *    | 16 | user's %gs selector		|
- *    | 12 | kernel's %gs selector		|
- *    |  8 | lwp pointer			|
- *    v  4 | user return address		|
- *       0 | callback wrapper return addr	|
- *         --------------------------------------
- */
-
-#define	V_COUNT	7
-#define	V_END		(CLONGSIZE * 7)
-#define	V_U_GS		(CLONGSIZE * 4)
-#define	V_K_GS		(CLONGSIZE * 3)
-#define	V_LWP		(CLONGSIZE * 2)
-#define	V_URET_ADDR	(CLONGSIZE * 1)
-#define	V_CB_ADDR	(CLONGSIZE * 0)
-
-#define	SP_REG		%esp
-#define	SYSCALL_REG	%eax
-
-#endif	/* !__amd64 */
-
-/*
- * The following macros allow us to access to variables/parameters passed
- * in on the stack.  They take the following variables:
- *	sp	- a register with the current stack pointer value
- *	pcnt	- the number of words currently pushed onto the stack
- *	var	- the variable to lookup
- *	reg	- a register to read the variable into, or
- *		  a register to write to the variable
- */
-#define V_OFFSET(pcnt, var)						 \
-	(var + (pcnt * CLONGSIZE))
-
-#define GET_V(sp, pcnt, var, reg)					 \
-	mov	V_OFFSET(pcnt, var)(sp), reg
-
-#define SET_V(sp, pcnt, var, reg)					 \
-	mov	reg, V_OFFSET(pcnt, var)(sp)
-
-#define GET_PROCP(sp, pcnt, reg)					 \
-	GET_V(sp, pcnt, V_LWP, reg)		/* get lwp pointer */	;\
-	mov	LWP_PROCP(reg), reg		/* get proc pointer */
-
-#define GET_P_BRAND_DATA(sp, pcnt, reg)					 \
-	GET_PROCP(sp, pcnt, reg)					;\
-	mov	P_BRAND_DATA(reg), reg		/* get p_brand_data */
-
-/*
- * Each of the following macros returns to the standard syscall codepath if
- * it detects that this process is not able, or intended, to emulate this
- * system call.  They all assume that the routine provides a 'bail-out'
- * label of '9'.
- */
-
-/*
- * See if this process has a user-space hdlr registered for it.  For the
- * sn1 brand, the per-process brand data holds the address of the handler.
- * As shown in the stack diagrams below, the callback code leaves that data
- * at these offsets.  So check if sn1_proc_data_t->spd_handler is non-NULL.
- */
-#define	CHECK_FOR_HANDLER(scr)						 \
-	GET_P_BRAND_DATA(SP_REG, 1, scr)	/* get p_brand_data */	;\
-	cmp	$0, scr							;\
-	je	9f							;\
-	cmp	$0, SPD_HANDLER(scr)		/* check spd_handler */ ;\
-	je	9f
-
-/*
- * If the system call number is >= 1024, then it is coming from the
- * emulation support library.  As such we should handle it natively instead
- * of sending it back to the emulation library.
- */
-#define	CHECK_FOR_NATIVE(reg)		 \
-	cmp	$1024, reg		;\
-	jl	1f			;\
-	sub	$1024, reg		;\
-	jmp	9f			;\
-1:
-
-/*
- * Check to see if we want to interpose on this system call.  If not, we
- * jump back into the normal syscall path and pretend nothing happened.
- */
-#define CHECK_FOR_INTERPOSITION(sysr, scr, scr_low)		 \
-	cmp	$NSYSCALL, sysr	/* is 0 <= syscall <= MAX? */	;\
-	ja	9f		/* no, take normal err path */	;\
-	lea	sn1_emulation_table, scr			;\
-	mov	(scr), scr					;\
-	add	sysr, scr					;\
-	movb	(scr), scr_low					;\
-	cmpb	$0, scr_low					;\
-	je	9f
-
-#define	CALLBACK_PROLOGUE(call, scr, scr_low)			 \
-	push	scr		/* Save scratch register */	;\
-	CHECK_FOR_HANDLER(scr)					;\
-	CHECK_FOR_NATIVE(call)					;\
-	CHECK_FOR_INTERPOSITION(call, scr, scr_low)
-
-/*
- * Rather than returning to the instruction after the syscall, we need to
- * transfer control into the brand library's handler table at
- * table_addr + (16 * syscall_num), thus encoding the system call number in the
- * instruction pointer.  The CALC_TABLE_ADDR macro performs that calculation.
- *
- * This macro assumes the syscall number is in SYSCALL_REG and it clobbers
- * that register.  It leaves the calculated handler table return address in
- * the scratch reg.
- */
-#define CALC_TABLE_ADDR(scr)						 \
-	GET_P_BRAND_DATA(SP_REG, 1, scr) /* get p_brand_data ptr */	;\
-	mov	SPD_HANDLER(scr), scr	/* get p_brand_data->spd_handler */ ;\
-	shl	$4, SYSCALL_REG		/* syscall_num * 16 */		;\
-	add	SYSCALL_REG, scr	/* leave return addr in scr reg. */
-
-/*
- * To 'return' to our user-space handler, we just need to place its address
- * into 'retreg'.  The original return address is passed in SYSCALL_REG.
- */
-#define SETUP_RET_DATA(scr, retreg)					 \
-	CALC_TABLE_ADDR(scr)					 	;\
-	mov	retreg, SYSCALL_REG /* save orig return addr in %rax */	;\
-	mov	scr, retreg	/* save new return addr in ret reg */	;\
-	pop	scr		/* restore scratch register */
-
-/*
- * The callback routines:
- */
-
-#if defined(__amd64)
 
 /*
  * syscall handler for 32-bit user processes:
- *	%rax - syscall number
- *	%ecx - the address of the instruction after the syscall
+ *	%rcx - the address of the instruction after the syscall
+ * See "64-BIT INTERPOSITION STACK" in brand_asm.h.
  */
 ENTRY(sn1_brand_syscall32_callback)
-
-	CALLBACK_PROLOGUE(%rax, %r15, %r15b)
-
-	SETUP_RET_DATA(%r15, %rcx)
-	GET_V(%rsp, 0, V_SSP, %rsp)	/* restore user's stack pointer	*/
+	SYSCALL_EMUL(sn1_emulation_table, SPD_HANDLER, %rcx)
 	jmp	nopop_sys_syscall32_swapgs_sysretl
 9:
-	popq	%r15
 	retq
 SET_SIZE(sn1_brand_syscall32_callback)
 
 /*
  * syscall handler for 64-bit user processes:
- *     %rax - syscall number
- *     %rcx - user space %rip
+ *	%rcx - the address of the instruction after the syscall
+ * See "64-BIT INTERPOSITION STACK" in brand_asm.h.
  */
 ENTRY(sn1_brand_syscall_callback)
-
-	CALLBACK_PROLOGUE(%rax, %r15, %r15b)
-
-	SETUP_RET_DATA(%r15, %rcx)
-	GET_V(%rsp, 0, V_SSP, %rsp)	/* restore user's stack pointer	*/
+	SYSCALL_EMUL(sn1_emulation_table, SPD_HANDLER, %rcx)
 	jmp	nopop_sys_syscall_swapgs_sysretq
 9:
-	popq	%r15
 	retq
-
 SET_SIZE(sn1_brand_syscall_callback)
 
 /*
- * %eax - syscall number
- * %ecx - user space %esp
- * %edx - user space return address
+ * %rdx - user space return address
+ * See "64-BIT INTERPOSITION STACK" in brand_asm.h.
  */
 ENTRY(sn1_brand_sysenter_callback)
-
-	CALLBACK_PROLOGUE(%rax, %r15, %r15b)
-
-	SETUP_RET_DATA(%r15, %rdx)
+	SYSCALL_EMUL(sn1_emulation_table, SPD_HANDLER, %rdx)
 	jmp	sys_sysenter_swapgs_sysexit
 9:
-	popq	%r15
 	ret
 SET_SIZE(sn1_brand_sysenter_callback)
 
 /*
- * The saved stack pointer points at the state saved when we took
- * the interrupt:
- *	   --------------------------------------
- *    | 32 | user's %ss				|
- *    | 24 | user's %esp			|
- *    | 16 | EFLAGS register			|
- *    v  8 | user's %cs				|
- *       0 | user's %eip			|
- *	   --------------------------------------
+ * See "64-BIT INTERPOSITION STACK" and "64-BIT INT STACK" in brand_asm.h.
  */
-#define	V_U_EIP		(CLONGSIZE * 0)
-
 ENTRY(sn1_brand_int91_callback)
-
-	CALLBACK_PROLOGUE(%rax, %r15, %r15b)
-
-	/*
-	 * To 'return' to our user-space handler we need to update the user's
-	 * %eip pointer in the saved interrupt state.  The interrupt state was
-	 * pushed onto our stack automatically when the interrupt occured; see
-	 * the comments above.  The original return address is passed in %rax.
-	 */
-	CALC_TABLE_ADDR(%r15)
-	GET_V(%rsp, 1, V_SSP, %rax)	/* get saved stack pointer */
-	SET_V(%rax, 0, V_U_EIP, %r15)	/* save new return addr in %eip */ 
-	GET_V(%rsp, 1, V_URET_ADDR, %rax) /* %rax has orig. return addr. */
-
-	popq	%r15			/* Restore scratch register	*/
-	movq	V_SSP(%rsp), %rsp	/* Remove callback stuff from stack */
+	INT_EMUL(sn1_emulation_table, SPD_HANDLER)
 	jmp	sys_sysint_swapgs_iret
 9:
-	popq	%r15
 	retq
 SET_SIZE(sn1_brand_int91_callback)
 
 #else	/* !__amd64 */
 
 /*
- * lcall handler for 32-bit OS
- *     %eax - syscall number
- *
- * Above the stack contents common to all callbacks is the
- * int/lcall-specific state:
- *	   --------------------------------------
- *    | 44 | user's %ss				|
- *    | 40 | user's %esp			|
- *    | 36 | EFLAGS register			|
- *    v 32 | user's %cs				|
- *      28 | user's %eip			|
- *	   --------------------------------------
+ * See "32-BIT INTERPOSITION STACK" and "32-BIT INT STACK" in brand_asm.h.
  */
-#define	V_U_SS		(V_END + (CLONGSIZE * 4))
-#define	V_U_ESP		(V_END + (CLONGSIZE * 3))
-#define	V_EFLAGS	(V_END + (CLONGSIZE * 2))
-#define	V_U_CS		(V_END + (CLONGSIZE * 1))
-#define	V_U_EIP		(V_END + (CLONGSIZE * 0))
-
 ENTRY(sn1_brand_syscall_callback)
-
-	CALLBACK_PROLOGUE(%eax, %ebx, %bl)
-
-	/*
-  	 * To 'return' to our user-space handler, we need to replace the
-	 * iret target address.
-	 * The original return address is passed in %eax.
-	 */
-	CALC_TABLE_ADDR(%ebx)		/* new return addr is in %ebx */
-	SET_V(%esp, 1, V_U_EIP, %ebx)	/* set iret target address to hdlr */
-	GET_V(%esp, 1, V_URET_ADDR, %eax) /* save orig return addr in %eax */
-
-	GET_V(%esp, 1, V_U_GS, %ebx)	/* grab the the user %gs	*/
-	movw	%bx, %gs		/* restore the user %gs	*/
-
-	popl	%ebx			/* Restore scratch register	*/
-	addl	$V_END, %esp	/* Remove all callback stuff from stack	*/
+	INT_EMUL(sn1_emulation_table, SPD_HANDLER)
 	jmp	nopop_sys_rtt_syscall
 9:
-	popl	%ebx
 	ret
 SET_SIZE(sn1_brand_syscall_callback)
 
 /*
- * %eax - syscall number
- * %ecx - user space %esp
  * %edx - user space return address
+ * See "32-BIT INTERPOSITION STACK" in brand_asm.h.
  */
 ENTRY(sn1_brand_sysenter_callback)
-
-	CALLBACK_PROLOGUE(%eax, %ebx, %bl)
-
-	/*
-  	 * To 'return' to our user-space handler, we just need to place its
-	 * address into %edx.
-	 * The original return address is passed in %eax.
-	 */
-	movl    %edx, %ebx		/* save orig return addr in tmp reg */
-	CALC_TABLE_ADDR(%edx)		/* new return addr is in %edx */
-	movl    %ebx, %eax		/* save orig return addr in %eax */
-
-	GET_V(%esp, 1, V_U_GS, %ebx)	/* grab the the user %gs	*/
-	movw	%bx, %gs		/* restore the user %gs	*/
-
-	popl	%ebx			/* restore scratch register	*/
+	SYSCALL_EMUL(sn1_emulation_table, SPD_HANDLER, %edx)
 	sysexit
 9:
-	popl	%ebx
 	ret
 SET_SIZE(sn1_brand_sysenter_callback)
 
--- a/usr/src/uts/intel/brand/solaris10/s10_brand_asm.s	Thu Feb 18 13:36:37 2010 +0000
+++ b/usr/src/uts/intel/brand/solaris10/s10_brand_asm.s	Thu Feb 18 07:03:00 2010 -0700
@@ -29,11 +29,8 @@
 
 #else	/* lint */
 
-#include <sys/asm_linkage.h>
-#include <sys/privregs.h>
-#include <sys/segments.h>
 #include <s10_offsets.h>
-#include "assym.h"
+#include "../common/brand_asm.h"
 
 #endif	/* lint */
 
@@ -64,325 +61,72 @@
 #else	/* lint */
 
 #if defined(__amd64)
-/*
- * When our syscall interposition callback entry point gets invoked the
- * stack looks like this:
- *         --------------------------------------
- *      40 | user %gs				|
- *      32 | callback pointer			|
- *      24 | saved stack pointer		|
- *    | 16 | lwp pointer			|
- *    v  8 | user return address		|
- *       0 | BRAND_CALLBACK()'s return addr 	|
- *         --------------------------------------
- */
-
-#define	V_COUNT	6
-#define	V_END		(CLONGSIZE * 6)
-#define	V_SSP		(CLONGSIZE * 3)
-#define	V_LWP		(CLONGSIZE * 2)
-#define	V_URET_ADDR	(CLONGSIZE * 1)
-#define	V_CB_ADDR	(CLONGSIZE * 0)
-
-#define	SP_REG		%rsp
-#define	SYSCALL_REG	%rax
-
-#else	/* !__amd64 */
-/*
- * When our syscall interposition callback entry point gets invoked the
- * stack looks like this:
- *         --------------------------------------
- *    | 24 | 'scratch space'			|
- *    | 20 | user's %ebx			|
- *    | 16 | user's %gs selector		|
- *    | 12 | kernel's %gs selector		|
- *    |  8 | lwp pointer			|
- *    v  4 | user return address		|
- *       0 | callback wrapper return addr	|
- *         --------------------------------------
- */
-
-#define	V_COUNT	7
-#define	V_END		(CLONGSIZE * 7)
-#define	V_U_GS		(CLONGSIZE * 4)
-#define	V_K_GS		(CLONGSIZE * 3)
-#define	V_LWP		(CLONGSIZE * 2)
-#define	V_URET_ADDR	(CLONGSIZE * 1)
-#define	V_CB_ADDR	(CLONGSIZE * 0)
-
-#define	SP_REG		%esp
-#define	SYSCALL_REG	%eax
-
-#endif	/* !__amd64 */
-
-/*
- * The following macros allow us to access to variables/parameters passed
- * in on the stack.  They take the following variables:
- *	sp	- a register with the current stack pointer value
- *	pcnt	- the number of words currently pushed onto the stack
- *	var	- the variable to lookup
- *	reg	- a register to read the variable into, or
- *		  a register to write to the variable
- */
-#define V_OFFSET(pcnt, var)						 \
-	(var + (pcnt * CLONGSIZE))
-
-#define GET_V(sp, pcnt, var, reg)					 \
-	mov	V_OFFSET(pcnt, var)(sp), reg
-
-#define SET_V(sp, pcnt, var, reg)					 \
-	mov	reg, V_OFFSET(pcnt, var)(sp)
-
-#define GET_PROCP(sp, pcnt, reg)					 \
-	GET_V(sp, pcnt, V_LWP, reg)		/* get lwp pointer */	;\
-	mov	LWP_PROCP(reg), reg		/* get proc pointer */
-
-#define GET_P_BRAND_DATA(sp, pcnt, reg)					 \
-	GET_PROCP(sp, pcnt, reg)					;\
-	mov	P_BRAND_DATA(reg), reg		/* get p_brand_data */
-
-/*
- * Each of the following macros returns to the standard syscall codepath if
- * it detects that this process is not able, or intended, to emulate this
- * system call.  They all assume that the routine provides a 'bail-out'
- * label of '9'.
- */
-
-/*
- * See if this process has a user-space hdlr registered for it.  For the
- * s10 brand, the per-process brand data holds the address of the handler.
- * As shown in the stack diagrams below, the callback code leaves that data
- * at these offsets.  So check if s10_proc_data_t->spd_handler is non-NULL.
- */
-#define	CHECK_FOR_HANDLER(scr)						 \
-	GET_P_BRAND_DATA(SP_REG, 1, scr)	/* get p_brand_data */	;\
-	cmp	$0, scr							;\
-	je	9f							;\
-	cmp	$0, SPD_HANDLER(scr)		/* check spd_handler */ ;\
-	je	9f
-
-/*
- * If the system call number is >= 1024, then it is coming from the
- * emulation support library.  As such we should handle it natively instead
- * of sending it back to the emulation library.
- */
-#define	CHECK_FOR_NATIVE(reg)		 \
-	cmp	$1024, reg		;\
-	jl	1f			;\
-	sub	$1024, reg		;\
-	jmp	9f			;\
-1:
-
-/*
- * Check to see if we want to interpose on this system call.  If not, we
- * jump back into the normal syscall path and pretend nothing happened.
- */
-#define CHECK_FOR_INTERPOSITION(sysr, scr, scr_low)		 \
-	cmp	$NSYSCALL, sysr	/* is 0 <= syscall <= MAX? */	;\
-	ja	9f		/* no, take normal err path */	;\
-	lea	s10_emulation_table, scr			;\
-	mov	(scr), scr					;\
-	add	sysr, scr					;\
-	movb	(scr), scr_low					;\
-	cmpb	$0, scr_low					;\
-	je	9f
-
-#define	CALLBACK_PROLOGUE(call, scr, scr_low)			 \
-	push	scr		/* Save scratch register */	;\
-	CHECK_FOR_HANDLER(scr)					;\
-	CHECK_FOR_NATIVE(call)					;\
-	CHECK_FOR_INTERPOSITION(call, scr, scr_low)
-
-/*
- * Rather than returning to the instruction after the syscall, we need to
- * transfer control into the brand library's handler table at
- * table_addr + (16 * syscall_num), thus encoding the system call number in the
- * instruction pointer.  The CALC_TABLE_ADDR macro performs that calculation.
- *
- * This macro assumes the syscall number is in SYSCALL_REG and it clobbers
- * that register.  It leaves the calculated handler table return address in
- * the scratch reg.
- */
-#define CALC_TABLE_ADDR(scr)						 \
-	GET_P_BRAND_DATA(SP_REG, 1, scr) /* get p_brand_data ptr */	;\
-	mov	SPD_HANDLER(scr), scr	/* get p_brand_data->spd_handler */ ;\
-	shl	$4, SYSCALL_REG		/* syscall_num * 16 */		;\
-	add	SYSCALL_REG, scr	/* leave return addr in scr reg. */
-
-/*
- * To 'return' to our user-space handler, we just need to place its address
- * into 'retreg'.  The original return address is passed in SYSCALL_REG.
- */
-#define SETUP_RET_DATA(scr, retreg)					 \
-	CALC_TABLE_ADDR(scr)					 	;\
-	mov	retreg, SYSCALL_REG /* save orig return addr in %rax */	;\
-	mov	scr, retreg	/* save new return addr in ret reg */	;\
-	pop	scr		/* restore scratch register */
-
-/*
- * The callback routines:
- */
-
-#if defined(__amd64)
 
 /*
  * syscall handler for 32-bit user processes:
- *	%rax - syscall number
- *	%ecx - the address of the instruction after the syscall
+ *	%rcx - the address of the instruction after the syscall
+ * See "64-BIT INTERPOSITION STACK" in brand_asm.h.
  */
 ENTRY(s10_brand_syscall32_callback)
-
-	CALLBACK_PROLOGUE(%rax, %r15, %r15b)
-
-	SETUP_RET_DATA(%r15, %rcx)
-	GET_V(%rsp, 0, V_SSP, %rsp)	/* restore user's stack pointer	*/
+	SYSCALL_EMUL(s10_emulation_table, SPD_HANDLER, %rcx)
 	jmp	nopop_sys_syscall32_swapgs_sysretl
 9:
-	popq	%r15
 	retq
 SET_SIZE(s10_brand_syscall32_callback)
 
 /*
  * syscall handler for 64-bit user processes:
- *     %rax - syscall number
- *     %rcx - user space %rip
+ *	%rcx - the address of the instruction after the syscall
+ * See "64-BIT INTERPOSITION STACK" in brand_asm.h.
  */
 ENTRY(s10_brand_syscall_callback)
-
-	CALLBACK_PROLOGUE(%rax, %r15, %r15b)
-
-	SETUP_RET_DATA(%r15, %rcx)
-	GET_V(%rsp, 0, V_SSP, %rsp)	/* restore user's stack pointer	*/
+	SYSCALL_EMUL(s10_emulation_table, SPD_HANDLER, %rcx)
 	jmp	nopop_sys_syscall_swapgs_sysretq
 9:
-	popq	%r15
 	retq
-
 SET_SIZE(s10_brand_syscall_callback)
 
 /*
- * %eax - syscall number
- * %ecx - user space %esp
- * %edx - user space return address
+ * %rdx - user space return address
+ * See "64-BIT INTERPOSITION STACK" in brand_asm.h.
  */
 ENTRY(s10_brand_sysenter_callback)
-
-	CALLBACK_PROLOGUE(%rax, %r15, %r15b)
-
-	SETUP_RET_DATA(%r15, %rdx)
+	SYSCALL_EMUL(s10_emulation_table, SPD_HANDLER, %rdx)
 	jmp	sys_sysenter_swapgs_sysexit
 9:
-	popq	%r15
 	ret
 SET_SIZE(s10_brand_sysenter_callback)
 
 /*
- * The saved stack pointer points at the state saved when we took
- * the interrupt:
- *	   --------------------------------------
- *    | 32 | user's %ss				|
- *    | 24 | user's %esp			|
- *    | 16 | EFLAGS register			|
- *    v  8 | user's %cs				|
- *       0 | user's %eip			|
- *	   --------------------------------------
+ * See "64-BIT INTERPOSITION STACK" and "64-BIT INT STACK" in brand_asm.h.
  */
-#define	V_U_EIP		(CLONGSIZE * 0)
-
 ENTRY(s10_brand_int91_callback)
-
-	CALLBACK_PROLOGUE(%rax, %r15, %r15b)
-
-	/*
-	 * To 'return' to our user-space handler we need to update the user's
-	 * %eip pointer in the saved interrupt state.  The interrupt state was
-	 * pushed onto our stack automatically when the interrupt occured; see
-	 * the comments above.  The original return address is passed in %rax.
-	 */
-	CALC_TABLE_ADDR(%r15)
-	GET_V(%rsp, 1, V_SSP, %rax)	/* get saved stack pointer */
-	SET_V(%rax, 0, V_U_EIP, %r15)	/* save new return addr in %eip */ 
-	GET_V(%rsp, 1, V_URET_ADDR, %rax) /* %rax has orig. return addr. */
-
-	popq	%r15			/* Restore scratch register	*/
-	movq	V_SSP(%rsp), %rsp	/* Remove callback stuff from stack */
+	INT_EMUL(s10_emulation_table, SPD_HANDLER)
 	jmp	sys_sysint_swapgs_iret
 9:
-	popq	%r15
 	retq
 SET_SIZE(s10_brand_int91_callback)
 
 #else	/* !__amd64 */
 
 /*
- * lcall handler for 32-bit OS
- *     %eax - syscall number
- *
- * Above the stack contents common to all callbacks is the
- * int/lcall-specific state:
- *	   --------------------------------------
- *    | 44 | user's %ss				|
- *    | 40 | user's %esp			|
- *    | 36 | EFLAGS register			|
- *    v 32 | user's %cs				|
- *      28 | user's %eip			|
- *	   --------------------------------------
+ * See "32-BIT INTERPOSITION STACK" and "32-BIT INT STACK" in brand_asm.h.
  */
-#define	V_U_SS		(V_END + (CLONGSIZE * 4))
-#define	V_U_ESP		(V_END + (CLONGSIZE * 3))
-#define	V_EFLAGS	(V_END + (CLONGSIZE * 2))
-#define	V_U_CS		(V_END + (CLONGSIZE * 1))
-#define	V_U_EIP		(V_END + (CLONGSIZE * 0))
-
 ENTRY(s10_brand_syscall_callback)
-
-	CALLBACK_PROLOGUE(%eax, %ebx, %bl)
-
-	/*
-  	 * To 'return' to our user-space handler, we need to replace the
-	 * iret target address.
-	 * The original return address is passed in %eax.
-	 */
-	CALC_TABLE_ADDR(%ebx)		/* new return addr is in %ebx */
-	SET_V(%esp, 1, V_U_EIP, %ebx)	/* set iret target address to hdlr */
-	GET_V(%esp, 1, V_URET_ADDR, %eax) /* save orig return addr in %eax */
-
-	GET_V(%esp, 1, V_U_GS, %ebx)	/* grab the the user %gs	*/
-	movw	%bx, %gs		/* restore the user %gs	*/
-
-	popl	%ebx			/* Restore scratch register	*/
-	addl	$V_END, %esp	/* Remove all callback stuff from stack	*/
+	INT_EMUL(s10_emulation_table, SPD_HANDLER)
 	jmp	nopop_sys_rtt_syscall
 9:
-	popl	%ebx
 	ret
 SET_SIZE(s10_brand_syscall_callback)
 
 /*
- * %eax - syscall number
- * %ecx - user space %esp
  * %edx - user space return address
+ * See "32-BIT INTERPOSITION STACK" in brand_asm.h.
  */
 ENTRY(s10_brand_sysenter_callback)
-
-	CALLBACK_PROLOGUE(%eax, %ebx, %bl)
-
-	/*
-  	 * To 'return' to our user-space handler, we just need to place its
-	 * address into %edx.
-	 * The original return address is passed in %eax.
-	 */
-	movl    %edx, %ebx		/* save orig return addr in tmp reg */
-	CALC_TABLE_ADDR(%edx)		/* new return addr is in %edx */
-	movl    %ebx, %eax		/* save orig return addr in %eax */
-
-	GET_V(%esp, 1, V_U_GS, %ebx)	/* grab the the user %gs	*/
-	movw	%bx, %gs		/* restore the user %gs	*/
-
-	popl	%ebx			/* restore scratch register	*/
+	SYSCALL_EMUL(s10_emulation_table, SPD_HANDLER, %edx)
 	sysexit
 9:
-	popl	%ebx
 	ret
 SET_SIZE(s10_brand_sysenter_callback)
 
--- a/usr/src/uts/intel/genassym/offsets.in	Thu Feb 18 13:36:37 2010 +0000
+++ b/usr/src/uts/intel/genassym/offsets.in	Thu Feb 18 07:03:00 2010 -0700
@@ -19,12 +19,10 @@
 \ CDDL HEADER END
 \
 \
-\ Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+\ Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
 \ Use is subject to license terms.
 \
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 \
 \ offsets.in: input file to produce the architecture-dependent genassym.h
 \ using the ctfstabs program
@@ -36,9 +34,6 @@
 
 #include <sys/lx_brand.h>
 
-lx_lwp_data
-	br_ugs
-
 lx_proc_data
 	l_handler
 	l_tracehandler