6613318 can't restart init in branded zones
authoredp
Tue, 01 Jul 2008 13:21:08 -0700
changeset 6994 f537e4b46012
parent 6993 ccf0a8c4b9a5
child 6995 2a8390c0bf12
6613318 can't restart init in branded zones 6703962 sn1 brand is broken on x86 post b75
usr/src/uts/common/brand/sn1/sn1_brand.c
usr/src/uts/common/os/brand.c
usr/src/uts/common/os/exec.c
usr/src/uts/common/os/exit.c
usr/src/uts/common/sys/brand.h
usr/src/uts/common/sys/proc.h
usr/src/uts/intel/brand/sn1/sn1_brand_asm.s
usr/src/uts/intel/ia32/os/sundep.c
usr/src/uts/intel/sn1_brand/Makefile
usr/src/uts/sun4/os/machdep.c
--- a/usr/src/uts/common/brand/sn1/sn1_brand.c	Tue Jul 01 12:52:38 2008 -0700
+++ b/usr/src/uts/common/brand/sn1/sn1_brand.c	Tue Jul 01 13:21:08 2008 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -133,8 +133,16 @@
 void
 sn1_setbrand(proc_t *p)
 {
+	ASSERT(p->p_brand == &sn1_brand);
+	ASSERT(p->p_brand_data == NULL);
 	p->p_brand_data = NULL;
-	p->p_brand = &sn1_brand;
+
+	/*
+	 * We should only be called from exec(), when we know the process
+	 * is single-threaded.
+	 */
+	ASSERT(p->p_tlist == p->p_tlist->t_forw);
+	(void) sn1_initlwp(p->p_tlist->t_lwp);
 }
 
 /* ARGSUSED */
@@ -163,14 +171,28 @@
 	proc_t *p = curproc;
 	*rval = 0;
 
+	/*
+	 * There is one operation that is suppored for non-branded
+	 * process.  B_EXEC_BRAND.  This brand operaion is redundant
+	 * since the kernel assumes a native process doing an exec
+	 * in a branded zone is going to run a branded processes.
+	 * hence we don't support this operation.
+	 */
+	if (cmd == B_EXEC_BRAND)
+		return (ENOSYS);
+
+	/* For all other operations this must be a branded process. */
+	if (p->p_brand == &native_brand)
+		return (ENOSYS);
+
+	ASSERT(p->p_brand == &sn1_brand);
+
 	if (cmd == B_REGISTER) {
-		p->p_brand = &sn1_brand;
-		p->p_brand_data = (void *) arg1;
+		ASSERT(p->p_brand_data == NULL);
+		p->p_brand_data = (void *)arg1;
 		return (0);
 	}
 
-	ASSERT(p->p_brand == &sn1_brand);
-
 	return (EINVAL);
 }
 
@@ -182,20 +204,41 @@
 void
 sn1_copy_procdata(proc_t *child, proc_t *parent)
 {
-	child->p_brand_data = parent->p_brand_data;
+	ASSERT(parent->p_brand == &sn1_brand);
+	ASSERT(child->p_brand == &sn1_brand);
+
+	child->p_brand_data = NULL;
 }
 
 /*ARGSUSED*/
 void
 sn1_proc_exit(struct proc *p, klwp_t *l)
 {
+	ASSERT(p->p_brand == &sn1_brand);
+
+	/*
+	 * We should only be called from proc_exit(), when we know that
+	 * process is single-threaded.
+	 */
+	ASSERT(p->p_tlist == p->p_tlist->t_forw);
+
 	p->p_brand_data = NULL;
-	p->p_brand = &native_brand;
+	l->lwp_brand = NULL;
 }
 
 void
 sn1_exec()
 {
+	ASSERT(curproc->p_brand == &sn1_brand);
+	ASSERT(ttolwp(curthread)->lwp_brand != NULL);
+
+	/*
+	 * We should only be called from exec(), when we know the process
+	 * is single-threaded.
+	 */
+	ASSERT(curproc->p_tlist == curproc->p_tlist->t_forw);
+
+	/* upon exec, reset our user-land handler callback entry point */
 	curproc->p_brand_data = NULL;
 }
 
@@ -203,11 +246,55 @@
 int
 sn1_initlwp(klwp_t *l)
 {
+	ASSERT(l->lwp_procp->p_brand == &sn1_brand);
+	ASSERT(l->lwp_brand == NULL);
+	l->lwp_brand = (void *)-1;
 	return (0);
 }
 
 /*ARGSUSED*/
 void
+sn1_forklwp(klwp_t *p, klwp_t *c)
+{
+	ASSERT(p->lwp_procp->p_brand == &sn1_brand);
+	ASSERT(c->lwp_procp->p_brand == &sn1_brand);
+
+	/* Both LWPs have already had been initialized via sn1_initlwp() */
+	ASSERT(p->lwp_brand != NULL);
+	ASSERT(c->lwp_brand != NULL);
+}
+
+/*ARGSUSED*/
+void
+sn1_freelwp(klwp_t *l)
+{
+	/* This lwp died during birth */
+	ASSERT(l->lwp_procp->p_brand == &sn1_brand);
+	ASSERT(l->lwp_brand != NULL);
+	l->lwp_brand = NULL;
+}
+
+/*ARGSUSED*/
+void
+sn1_lwpexit(klwp_t *l)
+{
+	proc_t	*p = l->lwp_procp;
+
+	ASSERT(l->lwp_procp->p_brand == &sn1_brand);
+	ASSERT(l->lwp_brand != NULL);
+
+	/*
+	 * We should never be called for the last thread in a process.
+	 * (That case is handled by sn1_proc_exit().)  There for this lwp
+	 * must be exiting from a multi-threaded process.
+	 */
+	ASSERT(p->p_tlist != p->p_tlist->t_forw);
+
+	l->lwp_brand = NULL;
+}
+
+/*ARGSUSED*/
+void
 sn1_init_brand_data(zone_t *zone)
 {
 }
@@ -218,24 +305,6 @@
 {
 }
 
-/*ARGSUSED*/
-void
-sn1_forklwp(klwp_t *p, klwp_t *c)
-{
-}
-
-/*ARGSUSED*/
-void
-sn1_freelwp(klwp_t *l)
-{
-}
-
-/*ARGSUSED*/
-void
-sn1_lwpexit(klwp_t *l)
-{
-}
-
 int
 sn1_elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
 	int level, long *execsz, int setid, caddr_t exec_file, cred_t *cred,
--- a/usr/src/uts/common/os/brand.c	Tue Jul 01 12:52:38 2008 -0700
+++ b/usr/src/uts/common/os/brand.c	Tue Jul 01 13:21:08 2008 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -333,10 +333,25 @@
 	ASSERT(p->p_tlist == p->p_tlist->t_forw);
 
 	p->p_brand = bp;
-	if (PROC_IS_BRANDED(p)) {
-		BROP(p)->b_setbrand(p);
-		lwp_attach_brand_hdlrs(p->p_tlist->t_lwp);
-	}
+	ASSERT(PROC_IS_BRANDED(p));
+	BROP(p)->b_setbrand(p);
+}
+
+void
+brand_clearbrand(proc_t *p)
+{
+	brand_t *bp = p->p_zone->zone_brand;
+	ASSERT(bp != NULL);
+
+	/*
+	 * We should only be called from exec_common() or proc_exit(),
+	 * when we know the process is single-threaded.
+	 */
+	ASSERT(p->p_tlist == p->p_tlist->t_forw);
+
+	ASSERT(PROC_IS_BRANDED(p));
+	BROP(p)->b_proc_exit(p, p->p_tlist->t_lwp);
+	p->p_brand = &native_brand;
 }
 
 #if defined(__sparcv9)
--- a/usr/src/uts/common/os/exec.c	Tue Jul 01 12:52:38 2008 -0700
+++ b/usr/src/uts/common/os/exec.c	Tue Jul 01 13:21:08 2008 -0700
@@ -138,7 +138,7 @@
 	lwpdir_t **old_tidhash;
 	uint_t old_tidhash_sz;
 	lwpent_t *lep;
-	int brandme = 0;
+	boolean_t brandme = B_FALSE;
 
 	/*
 	 * exec() is not supported for the /proc agent lwp.
@@ -162,7 +162,7 @@
 			/* Only unbranded processes can be branded */
 			if (PROC_IS_BRANDED(p))
 				return (ENOTSUP);
-			brandme = 1;
+			brandme = B_TRUE;
 		}
 	} else {
 		/*
@@ -172,7 +172,7 @@
 		 * process as it exec()s the new binary.
 		 */
 		if (ZONE_IS_BRANDED(p->p_zone) && !PROC_IS_BRANDED(p))
-			brandme = 1;
+			brandme = B_TRUE;
 	}
 
 	/*
@@ -276,13 +276,13 @@
 	ua.envp = envp;
 
 	/* If necessary, brand this process before we start the exec. */
-	if (brandme != 0)
+	if (brandme)
 		brand_setbrand(p);
 
 	if ((error = gexec(&vp, &ua, &args, NULL, 0, &execsz,
 	    exec_file, p->p_cred, brand_action)) != 0) {
-		if (brandme != 0)
-			BROP(p)->b_proc_exit(p, lwp);
+		if (brandme)
+			brand_clearbrand(p);
 		VN_RELE(vp);
 		if (dir != NULL)
 			VN_RELE(dir);
@@ -396,10 +396,9 @@
 	close_exec(P_FINFO(p));
 	TRACE_2(TR_FAC_PROC, TR_PROC_EXEC, "proc_exec:p %p up %p", p, up);
 
-	/* Unbrand ourself if requested. */
-	if (brand_action == EBA_NATIVE)
-		BROP(p)->b_proc_exit(p, lwp);
-	ASSERT((brand_action != EBA_NATIVE) || !PROC_IS_BRANDED(p));
+	/* Unbrand ourself if necessary. */
+	if (PROC_IS_BRANDED(p) && (brand_action == EBA_NATIVE))
+		brand_clearbrand(p);
 
 	setregs(&args);
 
--- a/usr/src/uts/common/os/exit.c	Tue Jul 01 12:52:38 2008 -0700
+++ b/usr/src/uts/common/os/exit.c	Tue Jul 01 13:21:08 2008 -0700
@@ -375,8 +375,10 @@
 	 * is always the last lwp, will also perform lwp_exit and free brand
 	 * data
 	 */
-	if (PROC_IS_BRANDED(p))
-		BROP(p)->b_proc_exit(p, lwp);
+	if (PROC_IS_BRANDED(p)) {
+		lwp_detach_brand_hdlrs(lwp);
+		brand_clearbrand(p);
+	}
 
 	/*
 	 * Don't let init exit unless zone_start_init() failed its exec, or
--- a/usr/src/uts/common/sys/brand.h	Tue Jul 01 12:52:38 2008 -0700
+++ b/usr/src/uts/common/sys/brand.h	Tue Jul 01 13:21:08 2008 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -127,6 +127,7 @@
 extern void	brand_unregister_zone(brand_t *);
 extern int	brand_zone_count(brand_t *);
 extern void	brand_setbrand(proc_t *);
+extern void	brand_clearbrand(proc_t *);
 #endif	/* _KERNEL */
 
 #ifdef	__cplusplus
--- a/usr/src/uts/common/sys/proc.h	Tue Jul 01 12:52:38 2008 -0700
+++ b/usr/src/uts/common/sys/proc.h	Tue Jul 01 13:21:08 2008 -0700
@@ -748,6 +748,7 @@
 extern	int	lwp_setprivate(klwp_t *, int, uintptr_t);
 extern	void	lwp_stat_update(lwp_stat_id_t, long);
 extern	void	lwp_attach_brand_hdlrs(klwp_t *);
+extern	void	lwp_detach_brand_hdlrs(klwp_t *);
 
 /*
  * Signal queue function prototypes. Must be here due to header ordering
--- a/usr/src/uts/intel/brand/sn1/sn1_brand_asm.s	Tue Jul 01 12:52:38 2008 -0700
+++ b/usr/src/uts/intel/brand/sn1/sn1_brand_asm.s	Tue Jul 01 13:21:08 2008 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -34,6 +34,7 @@
 #include <sys/asm_linkage.h>
 #include <sys/privregs.h>
 #include <sys/segments.h>
+#include "assym.h"
 
 #endif	/* lint */
 
@@ -63,6 +64,81 @@
 
 #else	/* lint */
 
+#if defined(__amd64)
+/*
+ * When our syscall interposition callback entry point gets invoked the
+ * stack looks like this:
+ *         --------------------------------------
+ *      24 | saved stack pointer		|
+ *    | 16 | lwp pointer			|
+ *    v  8 | user return address (*)		|
+ *       0 | BRAND_CALLBACK()'s return addr 	|
+ *         --------------------------------------
+ *   (*) This is actually just the bottom value from the user's
+ *       stack.  syscall puts this in %rcx instead of the stack,
+ *       so it's just garbage for that entry point.
+ */
+
+#define	V_COUNT	4
+#define	V_END		(CLONGSIZE * 4)
+#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
+
+#else	/* !__amd64 */
+/*
+ * When our syscall interposition callback entry point gets invoked the
+ * stack looks like this:
+ *         --------------------------------------
+ *    | 24 | 'scatch 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_LWP		(CLONGSIZE * 2)
+#define	V_URET_ADDR	(CLONGSIZE * 1)
+#define	V_CB_ADDR	(CLONGSIZE * 0)
+
+#define	SP_REG		%esp
+
+#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
@@ -71,27 +147,22 @@
  */
 
 /*
- * See if this process has a user-space handler registered for it.  For the
+ * 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
+ * As shown in the stack diagrams above, the callback code leaves that data
  * at these offsets.
  */
-#if defined(__amd64)
-#define	CHECK_FOR_HANDLER		 \
-	cmpq	$0, 24(%rsp)		;\
-	je	9f		
-#else
-#define	CHECK_FOR_HANDLER		 \
-	cmpl	$0, 12(%esp)		;\
-	je	9f		
-#endif	/* __amd64 */
+#define	CHECK_FOR_HANDLER(scr)						  \
+	GET_PROCP(SP_REG, 1, scr)		/* get proc pointer */   ;\
+	cmp	$0, P_BRAND_DATA(scr)		/* check p_brand_data */ ;\
+	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)		\
+#define	CHECK_FOR_NATIVE(reg)		 \
 	cmp	$1024, reg		;\
 	jl	1f			;\
 	sub	$1024, reg		;\
@@ -102,17 +173,17 @@
  * 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)		\
+#define CHECK_FOR_INTERPOSITION(sysr, scr, scr_low)		 \
 	lea	sn1_emulation_table, scr			;\
 	mov	(scr), scr					;\
 	add	sysr, scr					;\
 	movb	(scr), scr_low					;\
 	cmpb	$0, scr_low					;\
-	je	9f						;\
+	je	9f
 
-#define	CALLBACK_PROLOGUE(call, scr, scr_low)			;\
+#define	CALLBACK_PROLOGUE(call, scr, scr_low)			 \
 	push	scr		/* Save scratch register */	;\
-	CHECK_FOR_HANDLER					;\
+	CHECK_FOR_HANDLER(scr)					;\
 	CHECK_FOR_NATIVE(call)					;\
 	CHECK_FOR_INTERPOSITION(call, scr, scr_low)
 
@@ -121,120 +192,104 @@
  */
 
 #if defined(__amd64)
-	/* 
-	 * When we get into any of these callback routines, the stack
-	 * looks like this:
-	 *  	   --------------------------------------
-	 *      32 | saved stack pointer		|
-	 *    | 24 | lwp brand data			|
-	 *    | 16 | proc brand data			|
-	 *    v  8 | user return address (*)		|
-	 *       0 | BRAND_CALLBACK()'s return addr 	|
-	 *         --------------------------------------
-	 *   (*) This is actually just the bottom value from the user's
-	 *       stack.  syscall puts this in %rcx instead of the stack,
-	 *       so it's just garbage for that entry point.
-	 */
 
-	/*
-	 * syscall handler for 32-bit user processes:
-	 *
-	 * %ecx contains the address of the instruction after the syscall
-	 */
-	ENTRY(sn1_brand_syscall32_callback)
+/*
+ * syscall handler for 32-bit user processes:
+ *	%rax - syscall number
+ *	%ecx - the address of the instruction after the syscall
+ */
+ENTRY(sn1_brand_syscall32_callback)
 
 	CALLBACK_PROLOGUE(%rax, %r15, %r15b)
-
 	movq	%rsp, %r15	/* save our stack pointer */
 
 	/*
-	 * Adjust the user's stack so that the 'ret' from our userspace
-	 * handler takes us to the post-syscall instruction instead of to
+	 * Adjust the user's stack so that the 'ret' from our user-space
+	 * hdlr takes us to the post-syscall instruction instead of to
 	 * the routine that called the system call.
 	 */
-	movq	40(%rsp), %rsp	/* restore user's stack pointer 	*/
+	GET_V(%r15, 1, V_SSP, %rsp) /* restore user's stack pointer	*/
 	subq	$4, %rsp	/* save room for the post-syscall addr	*/
 	movl	%ecx, (%rsp)	/* Save post-syscall addr on stack	*/
 
 	/*
-	 * To 'return' to our user-space handler, we just need to copy
-	 * its address into %ecx.
+	 * To 'return' to our user-space hdlr, we just need to copy
+	 * its address into %ecx.  user-space hdlr == p_brand_data for sn1
 	 */
-	movq	24(%r15), %rcx	/* user-space handler == proc_data for sn1 */
+	GET_P_BRAND_DATA(%r15, 1, %rcx);
 	movq	(%r15), %r15	/* Restore scratch register */
 	jmp	nopop_sys_syscall32_sysretl
 9:
 	popq	%r15
 	retq
-	SET_SIZE(sn1_brand_syscall32_callback)
+SET_SIZE(sn1_brand_syscall32_callback)
 
-	/*
-	 * syscall handler for 64-bit user processes:
-	 *     %rax - syscall number
-	 *     %rcx - user space %rip
-	 */
-	ENTRY(sn1_brand_syscall_callback)
+/*
+ * syscall handler for 64-bit user processes:
+ *     %rax - syscall number
+ *     %rcx - user space %rip
+ */
+ENTRY(sn1_brand_syscall_callback)
 
 	CALLBACK_PROLOGUE(%rax, %r15, %r15b)
-
 	movq	%rsp, %r15	/* save our stack pointer */
 
-	movq	40(%rsp), %rsp	/* restore user's stack pointer 	*/
+	GET_V(%r15, 1, V_SSP, %rsp) /* restore user's stack pointer	*/
 	subq	$8, %rsp	/* save room for the post-syscall addr	*/
 	movq	%rcx, (%rsp)	/* Save post-syscall addr on stack	*/
 
 	/*
-	 * To 'return' to our user-space handler, we just need to copy
-	 * its address into %ecx.
+	 * To 'return' to our user-space hdlr, we just need to copy
+	 * its address into %ecx.  user-space hdlr == p_brand_data for sn1
 	 */
-	movq	24(%r15), %rcx	/* user-space handler == proc_data for sn1 */
+	GET_P_BRAND_DATA(%r15, 1, %rcx);
 	movq	(%r15), %r15	/* Restore scratch register */
 	jmp	nopop_sys_syscall_sysretq
 9:
 	popq	%r15
 	retq
-	
-	SET_SIZE(sn1_brand_syscall_callback)
+
+SET_SIZE(sn1_brand_syscall_callback)
 
-	/*
-	 * %rax - syscall number
-	 * %rcx - user space %esp
-	 * %rdx - user space return address
-	 *
-	 * XXX: not tested yet.  Need a Nocona machine first.
-	 */
-	ENTRY(sn1_brand_sysenter_callback)
+/*
+ * %rax - syscall number
+ * %rcx - user space %esp
+ * %rdx - user space return address
+ *
+ * XXX: not tested yet.  Need a Nocona machine first.
+ */
+ENTRY(sn1_brand_sysenter_callback)
 
 	CALLBACK_PROLOGUE(%rax, %r15, %r15b)
 
-	subq	$4, %rcx	/* Save room for user ret addr	*/
-	movq	%rdx, (%rcx)	/* Save current return addr	*/
-	movq	24(%rsp), %rdx	/* user-space handler == proc_data for sn1 */
-	popq	%r15
+	subq	$4, %rcx		/* Save room for user ret addr	*/
+	movq	%rdx, (%rcx)		/* Save current return addr	*/
+	GET_P_BRAND_DATA(%rsp, 1, %rdx)	/* get p_brand_data */
+	popq	%r15			/* Restore scratch register	*/
 	sysexit
 9:
 	popq	%r15
 	ret
-	SET_SIZE(sn1_brand_sysenter_callback)
+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			|
-	 *	   --------------------------------------
-	 */
-	ENTRY(sn1_brand_int91_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			|
+ *	   --------------------------------------
+ */
+ENTRY(sn1_brand_int91_callback)
 
 	CALLBACK_PROLOGUE(%rax, %r15, %r15b)
+	pushq	%rax				/* Save scratch register */
 
-	movq	24(%rsp), %r15	/* user-space handler == proc_data for sn1 */
-	pushq	%rax		/* Save scratch register		*/
-	movq	48(%rsp), %rax	/* Get saved %esp			*/
+	GET_P_BRAND_DATA(%rsp, 2, %r15)		/* get p_brand_data */
+	GET_V(%rsp, 2, V_SSP, %rax)		/* Get saved %esp */
 	movq	%r15, (%rax)	/* replace iret target address with hdlr */
 
 	/*
@@ -245,96 +300,88 @@
 	movq	24(%rax), %r15	/* Get user's %esp			*/
 	subq	$4, %r15	/* Make room for new ret addr		*/
 	movq	%r15, 24(%rax)	/* Replace current with updated %esp	*/
-	movl	24(%rsp), %eax	/* Get post-syscall address		*/
+
+	GET_V(%rsp, 2, V_URET_ADDR, %rax)
 	movl	%eax, (%r15)	/* Put it on the user's stack		*/
 
-	popq	%rax		/* Restore scratch register		*/
-	popq	%r15		/* Restore scratch register		*/
-	movq	32(%rsp), %rsp	/* Remove all callback stuff from stack	*/
+	popq	%rax			/* Restore scratch register	*/
+	popq	%r15			/* Restore scratch register	*/
+	movq	V_SSP(%rsp), %rsp	/* Remove callback stuff from stack */
 	jmp	nopop_sys_rtt_syscall32
 9:
 	popq	%r15
 	retq
-	SET_SIZE(sn1_brand_int91_callback)
+SET_SIZE(sn1_brand_int91_callback)
 
-#else	/* __amd64 */
+#else	/* !__amd64 */
 
-	/*
-	 * When we get into any of these callback routines, the stack
-	 * looks like this:
-	 *	   --------------------------------------
-	 *    | 28 | 'scatch space'			|
-	 *    | 24 | user's %ebx			|
-	 *    | 20 | user's %gs selector		|
-	 *    | 16 | kernel's %gs selector		|
-	 *    | 12 | lwp brand data			|
-	 *    |  8 | proc brand data			|
-	 *    v  4 | user return address		|
-	 *       0 | callback wrapper return addr	|
-	 *         --------------------------------------
-	 */
+/*
+ * 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			|
+ *	   --------------------------------------
+ */
+#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))
 
-	/*
-	 * lcall handler for 32-bit OS
-	 *     %eax - syscall number
-	 *
-	 * Above the stack contents common to all callbacks is the
-	 * int/lcall-specific state:
-	 *	   --------------------------------------
-	 *    | 48 | user's %ss				|
-	 *    | 44 | user's %esp			|
-	 *    | 40 | EFLAGS register			|
-	 *    v 36 | user's %cs				|
-	 *      32 | user's %eip			|
-	 *	   --------------------------------------
-	 */
-	ENTRY(sn1_brand_syscall_callback)
+ENTRY(sn1_brand_syscall_callback)
 
 	CALLBACK_PROLOGUE(%eax, %ebx, %bl)
+	pushl	%eax				/* Save scratch register */
 
-	movl	12(%esp), %ebx	/* user-space handler == proc_data for sn1 */
-	movl	%ebx, 36(%esp)	/* replace iret target address with hdlr */
+	/* replace iret target address with user-space hdlr */
+	GET_P_BRAND_DATA(%esp, 2, %ebx)
+	SET_V(%esp, 2, V_U_EIP, %ebx)
 
 	/*
 	 * Adjust the caller's stack so we return to the instruction after
 	 * the syscall on the next 'ret' in userspace - not to the parent
 	 * routine.
 	 */
-	pushl	%eax		/* Save scratch register		*/
-	movl	52(%esp), %eax	/* Get current %esp			*/
-	subl	$4, %eax	/* Make room for new ret addr		*/
-	movl	%eax, 52(%esp)	/* Replace current with updated %esp	*/
-	movl	12(%esp), %ebx	/* Get post-syscall address		*/
-	movl	%ebx, (%eax)	/* Put it on the user's stack		*/
+	GET_V(%esp, 2, V_URET_ADDR, %ebx) /* Get new post-syscall ret addr  */
+	GET_V(%esp, 2, V_U_ESP, %eax)	  /* Get user %esp		    */
+	subl	$4, %eax		  /* Make room for new ret addr	    */
+	SET_V(%esp, 2, V_U_ESP, %eax)	  /* Updated user %esp		    */
+	movl	%ebx, (%eax)		  /* Put new ret addr on user stack */
+
 	popl	%eax		/* Restore scratch register 		*/
-
 	popl	%ebx		/* Restore scratch register 		*/
-	addl	$32, %esp	/* Remove all callback stuff from stack	*/
+	addl	$V_END, %esp	/* Remove all callback stuff from stack	*/
 	jmp	nopop_sys_rtt_syscall
 9:
 	popl	%ebx
 	ret
-	SET_SIZE(sn1_brand_syscall_callback)
+SET_SIZE(sn1_brand_syscall_callback)
 
-	/*
-	 * %eax - syscall number
-	 * %ecx - user space %esp
-	 * %edx - user space return address
-	 */
-	ENTRY(sn1_brand_sysenter_callback)
+/*
+ * %eax - syscall number
+ * %ecx - user space %esp
+ * %edx - user space return address
+ */
+ENTRY(sn1_brand_sysenter_callback)
 
 	CALLBACK_PROLOGUE(%eax, %ebx, %bl)
 
-	subl	$4, %ecx	/* Save room for user ret addr	*/
-	movl	%edx, (%ecx)	/* Save current return addr	*/
-	movl	12(%esp), %edx	/* Return to user-space handler	*/
-	popl	%ebx		/* Restore scratch register	*/
+	subl	$4, %ecx		/* Save room for user ret addr	*/
+	movl	%edx, (%ecx)		/* Save current return addr	*/
+	GET_P_BRAND_DATA(%esp, 1, %edx)	/* get p_brand_data */
+	popl	%ebx			/* Restore scratch register	*/
 	sysexit
 9:
 	popl	%ebx
 	ret
-	SET_SIZE(sn1_brand_sysenter_callback)
+SET_SIZE(sn1_brand_sysenter_callback)
 
-#endif	/* __amd64 */
+#endif	/* !__amd64 */
 #endif	/* lint */
-
--- a/usr/src/uts/intel/ia32/os/sundep.c	Tue Jul 01 12:52:38 2008 -0700
+++ b/usr/src/uts/intel/ia32/os/sundep.c	Tue Jul 01 13:21:08 2008 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -738,10 +738,10 @@
 	kthread_t *t = lwptot(lwp);
 
 	ASSERT(PROC_IS_BRANDED(lwptoproc(lwp)));
+
 	ASSERT(removectx(t, NULL, brand_interpositioning_disable,
 	    brand_interpositioning_enable, NULL, NULL,
 	    brand_interpositioning_disable, NULL) == 0);
-
 	installctx(t, NULL, brand_interpositioning_disable,
 	    brand_interpositioning_enable, NULL, NULL,
 	    brand_interpositioning_disable, NULL);
@@ -754,6 +754,32 @@
 }
 
 /*
+ * If this is a process in a branded zone, then we want it to disable the
+ * brand syscall entry points.  This routine must be called when the last
+ * lwp in a process is exiting in proc_exit().
+ */
+void
+lwp_detach_brand_hdlrs(klwp_t *lwp)
+{
+	kthread_t *t = lwptot(lwp);
+
+	ASSERT(PROC_IS_BRANDED(lwptoproc(lwp)));
+	if (t == curthread)
+		kpreempt_disable();
+
+	/* Remove the original context handlers */
+	VERIFY(removectx(t, NULL, brand_interpositioning_disable,
+	    brand_interpositioning_enable, NULL, NULL,
+	    brand_interpositioning_disable, NULL) != 0);
+
+	if (t == curthread) {
+		/* Cleanup our MSR and IDT entries. */
+		brand_interpositioning_disable();
+		kpreempt_enable();
+	}
+}
+
+/*
  * Add any lwp-associated context handlers to the lwp at the beginning
  * of the lwp's useful life.
  *
--- a/usr/src/uts/intel/sn1_brand/Makefile	Tue Jul 01 12:52:38 2008 -0700
+++ b/usr/src/uts/intel/sn1_brand/Makefile	Tue Jul 01 13:21:08 2008 -0700
@@ -19,7 +19,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #ident	"%Z%%M%	%I%	%E% SMI"
@@ -53,7 +53,19 @@
 LINT_TARGET	= $(MODULE).lint
 INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
 
-INC_PATH   += -I$(UTSBASE)/common/brand/sn1
+INC_PATH	+= -I$(UTSBASE)/common/brand/sn1
+AS_INC_PATH	+= -I$(UTSBASE)/i86pc/genassym/$(OBJS_DIR)
+
+#
+# Ugh, this is a gross hack.  Sn1_brand_asm.s uses lots of defines
+# to simplify variable access.  All these defines work fine for amd64
+# compiles because when compiling for amd64 we use the GNU assembler,
+# gas.  For 32-bit code we use the Sun assembler, as.  Unfortunatly
+# as does not handle certian constructs that gas does.  So rather than
+# make our code less readable, we'll just use gas to compile our 32-bit
+# code as well.
+#
+i386_AS		= $(amd64_AS)
 
 #
 #	Default build targets.
--- a/usr/src/uts/sun4/os/machdep.c	Tue Jul 01 12:52:38 2008 -0700
+++ b/usr/src/uts/sun4/os/machdep.c	Tue Jul 01 13:21:08 2008 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -263,13 +263,18 @@
 }
 
 /*
- * This function is currently unused on sparc.
+ * These function are currently unused on sparc.
  */
 /*ARGSUSED*/
 void
 lwp_attach_brand_hdlrs(klwp_t *lwp)
 {}
 
+/*ARGSUSED*/
+void
+lwp_detach_brand_hdlrs(klwp_t *lwp)
+{}
+
 /*
  * fill in the extra register state area specified with the
  * specified lwp's platform-dependent non-floating-point extra