xref: /onnv-gate/usr/src/uts/common/os/brand.c (revision 13045:76bc2e54d54b)
12712Snn35248 /*
22712Snn35248  * CDDL HEADER START
32712Snn35248  *
42712Snn35248  * The contents of this file are subject to the terms of the
52712Snn35248  * Common Development and Distribution License (the "License").
62712Snn35248  * You may not use this file except in compliance with the License.
72712Snn35248  *
82712Snn35248  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92712Snn35248  * or http://www.opensolaris.org/os/licensing.
102712Snn35248  * See the License for the specific language governing permissions
112712Snn35248  * and limitations under the License.
122712Snn35248  *
132712Snn35248  * When distributing Covered Code, include this CDDL HEADER in each
142712Snn35248  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152712Snn35248  * If applicable, add the following below this CDDL HEADER, with the
162712Snn35248  * fields enclosed by brackets "[]" replaced with your own identifying
172712Snn35248  * information: Portions Copyright [yyyy] [name of copyright owner]
182712Snn35248  *
192712Snn35248  * CDDL HEADER END
202712Snn35248  */
212712Snn35248 /*
2212199Sgerald.jelinek@sun.com  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
232712Snn35248  */
242712Snn35248 
252712Snn35248 #include <sys/kmem.h>
262712Snn35248 #include <sys/errno.h>
272712Snn35248 #include <sys/systm.h>
282712Snn35248 #include <sys/cmn_err.h>
292712Snn35248 #include <sys/brand.h>
302712Snn35248 #include <sys/machbrand.h>
312712Snn35248 #include <sys/modctl.h>
322712Snn35248 #include <sys/rwlock.h>
332712Snn35248 #include <sys/zone.h>
3412199Sgerald.jelinek@sun.com #include <sys/pathname.h>
352712Snn35248 
362712Snn35248 #define	SUPPORTED_BRAND_VERSION BRAND_VER_1
372712Snn35248 
382712Snn35248 #if defined(__sparcv9)
394246Sedp /* sparcv9 uses system wide brand interposition hooks */
404246Sedp static void brand_plat_interposition_enable(void);
414246Sedp static void brand_plat_interposition_disable(void);
424246Sedp 
432712Snn35248 struct brand_mach_ops native_mach_ops  = {
442712Snn35248 		NULL, NULL
452712Snn35248 };
464141Sedp #else /* !__sparcv9 */
472712Snn35248 struct brand_mach_ops native_mach_ops  = {
4812613SSurya.Prakki@Sun.COM 		NULL, NULL, NULL, NULL
492712Snn35248 };
504141Sedp #endif /* !__sparcv9 */
512712Snn35248 
522712Snn35248 brand_t native_brand = {
532712Snn35248 		BRAND_VER_1,
542712Snn35248 		"native",
552712Snn35248 		NULL,
562712Snn35248 		&native_mach_ops
572712Snn35248 };
582712Snn35248 
592712Snn35248 /*
602712Snn35248  * Used to maintain a list of all the brands currently loaded into the
612712Snn35248  * kernel.
622712Snn35248  */
632712Snn35248 struct brand_list {
642712Snn35248 	int			bl_refcnt;
652712Snn35248 	struct brand_list	*bl_next;
662712Snn35248 	brand_t			*bl_brand;
672712Snn35248 };
682712Snn35248 
692712Snn35248 static struct brand_list *brand_list = NULL;
702712Snn35248 
712712Snn35248 /*
722712Snn35248  * This lock protects the integrity of the brand list.
732712Snn35248  */
742712Snn35248 static kmutex_t brand_list_lock;
752712Snn35248 
762712Snn35248 void
brand_init()772712Snn35248 brand_init()
782712Snn35248 {
792712Snn35248 	mutex_init(&brand_list_lock, NULL, MUTEX_DEFAULT, NULL);
802712Snn35248 	p0.p_brand = &native_brand;
812712Snn35248 }
822712Snn35248 
832712Snn35248 int
brand_register(brand_t * brand)842712Snn35248 brand_register(brand_t *brand)
852712Snn35248 {
862712Snn35248 	struct brand_list *list, *scan;
872712Snn35248 
882712Snn35248 	if (brand == NULL)
892712Snn35248 		return (EINVAL);
902712Snn35248 
912712Snn35248 	if (brand->b_version != SUPPORTED_BRAND_VERSION) {
922712Snn35248 		if (brand->b_version < SUPPORTED_BRAND_VERSION) {
932712Snn35248 			cmn_err(CE_WARN,
942712Snn35248 			    "brand '%s' was built to run on older versions "
952712Snn35248 			    "of Solaris.",
962712Snn35248 			    brand->b_name);
972712Snn35248 		} else {
982712Snn35248 			cmn_err(CE_WARN,
992712Snn35248 			    "brand '%s' was built to run on a newer version "
1002712Snn35248 			    "of Solaris.",
1012712Snn35248 			    brand->b_name);
1022712Snn35248 		}
1032712Snn35248 		return (EINVAL);
1042712Snn35248 	}
1052712Snn35248 
1062712Snn35248 	/* Sanity checks */
1072712Snn35248 	if (brand->b_name == NULL || brand->b_ops == NULL ||
1082712Snn35248 	    brand->b_ops->b_brandsys == NULL) {
1092712Snn35248 		cmn_err(CE_WARN, "Malformed brand");
1102712Snn35248 		return (EINVAL);
1112712Snn35248 	}
1122712Snn35248 
1132712Snn35248 	list = kmem_alloc(sizeof (struct brand_list), KM_SLEEP);
1142712Snn35248 
1152712Snn35248 	/* Add the brand to the list of loaded brands. */
1162712Snn35248 	mutex_enter(&brand_list_lock);
1172712Snn35248 
1182712Snn35248 	/*
1192712Snn35248 	 * Check to be sure we haven't already registered this brand.
1202712Snn35248 	 */
1212712Snn35248 	for (scan = brand_list; scan != NULL; scan = scan->bl_next) {
1222712Snn35248 		if (strcmp(brand->b_name, scan->bl_brand->b_name) == 0) {
1232712Snn35248 			cmn_err(CE_WARN,
1242712Snn35248 			    "Invalid attempt to load a second instance of "
1252712Snn35248 			    "brand %s", brand->b_name);
1262712Snn35248 			mutex_exit(&brand_list_lock);
1272712Snn35248 			kmem_free(list, sizeof (struct brand_list));
1282712Snn35248 			return (EINVAL);
1292712Snn35248 		}
1302712Snn35248 	}
1312712Snn35248 
1324246Sedp #if defined(__sparcv9)
1334246Sedp 	/* sparcv9 uses system wide brand interposition hooks */
1344246Sedp 	if (brand_list == NULL)
1354246Sedp 		brand_plat_interposition_enable();
1364246Sedp #endif /* __sparcv9 */
1374246Sedp 
1382712Snn35248 	list->bl_brand = brand;
1392712Snn35248 	list->bl_refcnt = 0;
1402712Snn35248 	list->bl_next = brand_list;
1412712Snn35248 	brand_list = list;
1424246Sedp 
1432712Snn35248 	mutex_exit(&brand_list_lock);
1442712Snn35248 
1452712Snn35248 	return (0);
1462712Snn35248 }
1472712Snn35248 
1482712Snn35248 /*
1492712Snn35248  * The kernel module implementing this brand is being unloaded, so remove
1502712Snn35248  * it from the list of active brands.
1512712Snn35248  */
1522712Snn35248 int
brand_unregister(brand_t * brand)1532712Snn35248 brand_unregister(brand_t *brand)
1542712Snn35248 {
1552712Snn35248 	struct brand_list *list, *prev;
1562712Snn35248 
1572712Snn35248 	/* Sanity checks */
1582712Snn35248 	if (brand == NULL || brand->b_name == NULL) {
1592712Snn35248 		cmn_err(CE_WARN, "Malformed brand");
1602712Snn35248 		return (EINVAL);
1612712Snn35248 	}
1622712Snn35248 
1632712Snn35248 	prev = NULL;
1642712Snn35248 	mutex_enter(&brand_list_lock);
1652712Snn35248 
1662712Snn35248 	for (list = brand_list; list != NULL; list = list->bl_next) {
1672712Snn35248 		if (list->bl_brand == brand)
1682712Snn35248 			break;
1692712Snn35248 		prev = list;
1702712Snn35248 	}
1712712Snn35248 
1722712Snn35248 	if (list == NULL) {
1732712Snn35248 		cmn_err(CE_WARN, "Brand %s wasn't registered", brand->b_name);
1742712Snn35248 		mutex_exit(&brand_list_lock);
1752712Snn35248 		return (EINVAL);
1762712Snn35248 	}
1772712Snn35248 
1782712Snn35248 	if (list->bl_refcnt > 0) {
1792712Snn35248 		cmn_err(CE_WARN, "Unregistering brand %s which is still in use",
1802712Snn35248 		    brand->b_name);
1812712Snn35248 		mutex_exit(&brand_list_lock);
1822712Snn35248 		return (EBUSY);
1832712Snn35248 	}
1842712Snn35248 
1852712Snn35248 	/* Remove brand from the list */
1862712Snn35248 	if (prev != NULL)
1872712Snn35248 		prev->bl_next = list->bl_next;
1882712Snn35248 	else
1892712Snn35248 		brand_list = list->bl_next;
1902712Snn35248 
1914246Sedp #if defined(__sparcv9)
1924246Sedp 	/* sparcv9 uses system wide brand interposition hooks */
1934246Sedp 	if (brand_list == NULL)
1944246Sedp 		brand_plat_interposition_disable();
1954246Sedp #endif /* __sparcv9 */
1964246Sedp 
1972712Snn35248 	mutex_exit(&brand_list_lock);
1982712Snn35248 
1992712Snn35248 	kmem_free(list, sizeof (struct brand_list));
2002712Snn35248 
2012712Snn35248 	return (0);
2022712Snn35248 }
2032712Snn35248 
2042712Snn35248 /*
2052712Snn35248  * Record that a zone of this brand has been instantiated.  If the kernel
2062712Snn35248  * module implementing this brand's functionality is not present, this
2072712Snn35248  * routine attempts to load the module as a side effect.
2082712Snn35248  */
2092712Snn35248 brand_t *
brand_register_zone(struct brand_attr * attr)2102712Snn35248 brand_register_zone(struct brand_attr *attr)
2112712Snn35248 {
2122712Snn35248 	struct brand_list *l = NULL;
2132712Snn35248 	ddi_modhandle_t	hdl = NULL;
2142712Snn35248 	char *modname;
2152712Snn35248 	int err = 0;
2162712Snn35248 
2172712Snn35248 	if (is_system_labeled()) {
2182712Snn35248 		cmn_err(CE_WARN,
2192712Snn35248 		    "Branded zones are not allowed on labeled systems.");
2202712Snn35248 		return (NULL);
2212712Snn35248 	}
2222712Snn35248 
2232712Snn35248 	/*
2242712Snn35248 	 * We make at most two passes through this loop.  The first time
2252712Snn35248 	 * through, we're looking to see if this is a new user of an
2262712Snn35248 	 * already loaded brand.  If the brand hasn't been loaded, we
2272712Snn35248 	 * call ddi_modopen() to force it to be loaded and then make a
2282712Snn35248 	 * second pass through the list of brands.  If we don't find the
2292712Snn35248 	 * brand the second time through it means that the modname
2302712Snn35248 	 * specified in the brand_attr structure doesn't provide the brand
2312712Snn35248 	 * specified in the brandname field.  This would suggest a bug in
2322712Snn35248 	 * the brand's config.xml file.  We close the module and return
2332712Snn35248 	 * 'NULL' to the caller.
2342712Snn35248 	 */
2352712Snn35248 	for (;;) {
2362712Snn35248 		/*
2372712Snn35248 		 * Search list of loaded brands
2382712Snn35248 		 */
2392712Snn35248 		mutex_enter(&brand_list_lock);
2402712Snn35248 		for (l = brand_list; l != NULL; l = l->bl_next)
2412712Snn35248 			if (strcmp(attr->ba_brandname,
2422712Snn35248 			    l->bl_brand->b_name) == 0)
2432712Snn35248 				break;
2442712Snn35248 		if ((l != NULL) || (hdl != NULL))
2452712Snn35248 			break;
2462712Snn35248 		mutex_exit(&brand_list_lock);
2472712Snn35248 
2482712Snn35248 		/*
2492712Snn35248 		 * We didn't find that the requested brand has been loaded
2502712Snn35248 		 * yet, so we trigger the load of the appropriate kernel
2512712Snn35248 		 * module and search the list again.
2522712Snn35248 		 */
2532712Snn35248 		modname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
2542712Snn35248 		(void) strcpy(modname, "brand/");
2552712Snn35248 		(void) strcat(modname, attr->ba_modname);
2562712Snn35248 		hdl = ddi_modopen(modname, KRTLD_MODE_FIRST, &err);
2572712Snn35248 		kmem_free(modname, MAXPATHLEN);
2582712Snn35248 
2592712Snn35248 		if (err != 0)
2602712Snn35248 			return (NULL);
2612712Snn35248 	}
2622712Snn35248 
2632712Snn35248 	/*
2642712Snn35248 	 * If we found the matching brand, bump its reference count.
2652712Snn35248 	 */
2662712Snn35248 	if (l != NULL)
2672712Snn35248 		l->bl_refcnt++;
2682712Snn35248 
2692712Snn35248 	mutex_exit(&brand_list_lock);
2702712Snn35248 
2712712Snn35248 	if (hdl != NULL)
2722712Snn35248 		(void) ddi_modclose(hdl);
2732712Snn35248 
2742712Snn35248 	return ((l != NULL) ? l->bl_brand : NULL);
2752712Snn35248 }
2762712Snn35248 
2772712Snn35248 /*
2782712Snn35248  * Return the number of zones currently using this brand.
2792712Snn35248  */
2802712Snn35248 int
brand_zone_count(struct brand * bp)2812712Snn35248 brand_zone_count(struct brand *bp)
2822712Snn35248 {
2832712Snn35248 	struct brand_list *l;
2842712Snn35248 	int cnt = 0;
2852712Snn35248 
2862712Snn35248 	mutex_enter(&brand_list_lock);
2872712Snn35248 	for (l = brand_list; l != NULL; l = l->bl_next)
2882712Snn35248 		if (l->bl_brand == bp) {
2892712Snn35248 			cnt = l->bl_refcnt;
2902712Snn35248 			break;
2912712Snn35248 		}
2922712Snn35248 	mutex_exit(&brand_list_lock);
2932712Snn35248 
2942712Snn35248 	return (cnt);
2952712Snn35248 }
2962712Snn35248 
2972712Snn35248 void
brand_unregister_zone(struct brand * bp)2982712Snn35248 brand_unregister_zone(struct brand *bp)
2992712Snn35248 {
3002712Snn35248 	struct brand_list *list;
3012712Snn35248 
3022712Snn35248 	mutex_enter(&brand_list_lock);
3032712Snn35248 	for (list = brand_list; list != NULL; list = list->bl_next) {
3042712Snn35248 		if (list->bl_brand == bp) {
3052712Snn35248 			ASSERT(list->bl_refcnt > 0);
3062712Snn35248 			list->bl_refcnt--;
3072712Snn35248 			break;
3082712Snn35248 		}
3092712Snn35248 	}
3102712Snn35248 	mutex_exit(&brand_list_lock);
3112712Snn35248 }
3122712Snn35248 
3132712Snn35248 void
brand_setbrand(proc_t * p)3142712Snn35248 brand_setbrand(proc_t *p)
3152712Snn35248 {
3162712Snn35248 	brand_t *bp = p->p_zone->zone_brand;
3172712Snn35248 
3182712Snn35248 	ASSERT(bp != NULL);
3192712Snn35248 	ASSERT(p->p_brand == &native_brand);
3202712Snn35248 
3212712Snn35248 	/*
3222712Snn35248 	 * We should only be called from exec(), when we know the process
3232712Snn35248 	 * is single-threaded.
3242712Snn35248 	 */
3252712Snn35248 	ASSERT(p->p_tlist == p->p_tlist->t_forw);
3262712Snn35248 
3272712Snn35248 	p->p_brand = bp;
3286994Sedp 	ASSERT(PROC_IS_BRANDED(p));
3296994Sedp 	BROP(p)->b_setbrand(p);
3306994Sedp }
3316994Sedp 
3326994Sedp void
brand_clearbrand(proc_t * p,boolean_t no_lwps)333*13045SVamsi.Krishna@Sun.COM brand_clearbrand(proc_t *p, boolean_t no_lwps)
3346994Sedp {
3356994Sedp 	brand_t *bp = p->p_zone->zone_brand;
336*13045SVamsi.Krishna@Sun.COM 	klwp_t *lwp = NULL;
3376994Sedp 	ASSERT(bp != NULL);
338*13045SVamsi.Krishna@Sun.COM 	ASSERT(!no_lwps || (p->p_tlist == NULL));
3396994Sedp 
3406994Sedp 	/*
341*13045SVamsi.Krishna@Sun.COM 	 * If called from exec_common() or proc_exit(),
342*13045SVamsi.Krishna@Sun.COM 	 * we know the process is single-threaded.
343*13045SVamsi.Krishna@Sun.COM 	 * If called from fork_fail, p_tlist is NULL.
3446994Sedp 	 */
345*13045SVamsi.Krishna@Sun.COM 	if (!no_lwps) {
346*13045SVamsi.Krishna@Sun.COM 		ASSERT(p->p_tlist == p->p_tlist->t_forw);
347*13045SVamsi.Krishna@Sun.COM 		lwp = p->p_tlist->t_lwp;
348*13045SVamsi.Krishna@Sun.COM 	}
3496994Sedp 
3506994Sedp 	ASSERT(PROC_IS_BRANDED(p));
351*13045SVamsi.Krishna@Sun.COM 	BROP(p)->b_proc_exit(p, lwp);
3526994Sedp 	p->p_brand = &native_brand;
3532712Snn35248 }
3544141Sedp 
3554141Sedp #if defined(__sparcv9)
3564141Sedp /*
3574246Sedp  * Currently, only sparc has system level brand syscall interposition.
3584141Sedp  * On x86 we're able to enable syscall interposition on a per-cpu basis
3594141Sedp  * when a branded thread is scheduled to run on a cpu.
3604141Sedp  */
3614141Sedp 
3624141Sedp /* Local variables needed for dynamic syscall interposition support */
3634141Sedp static uint32_t	syscall_trap_patch_instr_orig;
3644141Sedp static uint32_t	syscall_trap32_patch_instr_orig;
3654141Sedp 
3664141Sedp /* Trap Table syscall entry hot patch points */
3674141Sedp extern void	syscall_trap_patch_point(void);
3684141Sedp extern void	syscall_trap32_patch_point(void);
3694141Sedp 
3704141Sedp /* Alternate syscall entry handlers used when branded zones are running */
3714141Sedp extern void	syscall_wrapper(void);
3724141Sedp extern void	syscall_wrapper32(void);
3734141Sedp 
3744141Sedp /* Macros used to facilitate sparcv9 instruction generation */
3754141Sedp #define	BA_A_INSTR	0x30800000	/* ba,a addr */
3764141Sedp #define	DISP22(from, to) \
3774141Sedp 	((((uintptr_t)(to) - (uintptr_t)(from)) >> 2) & 0x3fffff)
3784141Sedp 
3794246Sedp /*ARGSUSED*/
3804246Sedp static void
brand_plat_interposition_enable(void)3814246Sedp brand_plat_interposition_enable(void)
3824141Sedp {
3834246Sedp 	ASSERT(MUTEX_HELD(&brand_list_lock));
3844141Sedp 
3854141Sedp 	/*
3864141Sedp 	 * Before we hot patch the kernel save the current instructions
3874246Sedp 	 * so that we can restore them later.
3884141Sedp 	 */
3894141Sedp 	syscall_trap_patch_instr_orig =
3904141Sedp 	    *(uint32_t *)syscall_trap_patch_point;
3914141Sedp 	syscall_trap32_patch_instr_orig =
3924141Sedp 	    *(uint32_t *)syscall_trap32_patch_point;
3934141Sedp 
3944141Sedp 	/*
3954141Sedp 	 * Modify the trap table at the patch points.
3964141Sedp 	 *
3974141Sedp 	 * We basically replace the first instruction at the patch
3984141Sedp 	 * point with a ba,a instruction that will transfer control
3994141Sedp 	 * to syscall_wrapper or syscall_wrapper32 for 64-bit and
4004141Sedp 	 * 32-bit syscalls respectively.  It's important to note that
4014141Sedp 	 * the annul bit is set in the branch so we don't execute
4024141Sedp 	 * the instruction directly following the one we're patching
4034141Sedp 	 * during the branch's delay slot.
4044141Sedp 	 *
4054141Sedp 	 * It also doesn't matter that we're not atomically updating both
4064141Sedp 	 * the 64 and 32 bit syscall paths at the same time since there's
4074141Sedp 	 * no actual branded processes running on the system yet.
4084141Sedp 	 */
4094141Sedp 	hot_patch_kernel_text((caddr_t)syscall_trap_patch_point,
4104141Sedp 	    BA_A_INSTR | DISP22(syscall_trap_patch_point, syscall_wrapper),
4114141Sedp 	    4);
4124141Sedp 	hot_patch_kernel_text((caddr_t)syscall_trap32_patch_point,
4134141Sedp 	    BA_A_INSTR | DISP22(syscall_trap32_patch_point, syscall_wrapper32),
4144141Sedp 	    4);
4154141Sedp }
4164141Sedp 
4174141Sedp /*ARGSUSED*/
4184246Sedp static void
brand_plat_interposition_disable(void)4194246Sedp brand_plat_interposition_disable(void)
4204141Sedp {
4214246Sedp 	ASSERT(MUTEX_HELD(&brand_list_lock));
4224141Sedp 
4234141Sedp 	/*
4244141Sedp 	 * Restore the original instructions at the trap table syscall
4254141Sedp 	 * patch points to disable the brand syscall interposition
4264141Sedp 	 * mechanism.
4274141Sedp 	 */
4284141Sedp 	hot_patch_kernel_text((caddr_t)syscall_trap_patch_point,
4294141Sedp 	    syscall_trap_patch_instr_orig, 4);
4304141Sedp 	hot_patch_kernel_text((caddr_t)syscall_trap32_patch_point,
4314141Sedp 	    syscall_trap32_patch_instr_orig, 4);
4324141Sedp }
4334141Sedp #endif /* __sparcv9 */
43412199Sgerald.jelinek@sun.com 
43512199Sgerald.jelinek@sun.com /*
43612199Sgerald.jelinek@sun.com  * The following functions can be shared among kernel brand modules which
43712199Sgerald.jelinek@sun.com  * implement Solaris-derived brands, all of which need to do similar tasks
43812199Sgerald.jelinek@sun.com  * to manage the brand.
43912199Sgerald.jelinek@sun.com  */
44012199Sgerald.jelinek@sun.com 
44112199Sgerald.jelinek@sun.com #if defined(_LP64)
44212199Sgerald.jelinek@sun.com static void
Ehdr32to64(Elf32_Ehdr * src,Ehdr * dst)44312199Sgerald.jelinek@sun.com Ehdr32to64(Elf32_Ehdr *src, Ehdr *dst)
44412199Sgerald.jelinek@sun.com {
44512199Sgerald.jelinek@sun.com 	bcopy(src->e_ident, dst->e_ident, sizeof (src->e_ident));
44612199Sgerald.jelinek@sun.com 	dst->e_type =		src->e_type;
44712199Sgerald.jelinek@sun.com 	dst->e_machine =	src->e_machine;
44812199Sgerald.jelinek@sun.com 	dst->e_version =	src->e_version;
44912199Sgerald.jelinek@sun.com 	dst->e_entry =		src->e_entry;
45012199Sgerald.jelinek@sun.com 	dst->e_phoff =		src->e_phoff;
45112199Sgerald.jelinek@sun.com 	dst->e_shoff =		src->e_shoff;
45212199Sgerald.jelinek@sun.com 	dst->e_flags =		src->e_flags;
45312199Sgerald.jelinek@sun.com 	dst->e_ehsize =		src->e_ehsize;
45412199Sgerald.jelinek@sun.com 	dst->e_phentsize =	src->e_phentsize;
45512199Sgerald.jelinek@sun.com 	dst->e_phnum =		src->e_phnum;
45612199Sgerald.jelinek@sun.com 	dst->e_shentsize =	src->e_shentsize;
45712199Sgerald.jelinek@sun.com 	dst->e_shnum =		src->e_shnum;
45812199Sgerald.jelinek@sun.com 	dst->e_shstrndx =	src->e_shstrndx;
45912199Sgerald.jelinek@sun.com }
46012199Sgerald.jelinek@sun.com #endif /* _LP64 */
46112199Sgerald.jelinek@sun.com 
46212199Sgerald.jelinek@sun.com /*
46312199Sgerald.jelinek@sun.com  * Return -1 if the cmd was not handled by this function.
46412199Sgerald.jelinek@sun.com  */
46512199Sgerald.jelinek@sun.com /*ARGSUSED*/
46612199Sgerald.jelinek@sun.com int
brand_solaris_cmd(int cmd,uintptr_t arg1,uintptr_t arg2,uintptr_t arg3,struct brand * pbrand,int brandvers)46712199Sgerald.jelinek@sun.com brand_solaris_cmd(int cmd, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3,
46812199Sgerald.jelinek@sun.com     struct brand *pbrand, int brandvers)
46912199Sgerald.jelinek@sun.com {
47012199Sgerald.jelinek@sun.com 	brand_proc_data_t	*spd;
47112199Sgerald.jelinek@sun.com 	brand_proc_reg_t	reg;
47212199Sgerald.jelinek@sun.com 	proc_t			*p = curproc;
47312199Sgerald.jelinek@sun.com 	int			err;
47412199Sgerald.jelinek@sun.com 
47512199Sgerald.jelinek@sun.com 	/*
47612199Sgerald.jelinek@sun.com 	 * There is one operation that is supported for a native
47712199Sgerald.jelinek@sun.com 	 * process; B_EXEC_BRAND.  This brand operaion is redundant
47812199Sgerald.jelinek@sun.com 	 * since the kernel assumes a native process doing an exec
47912199Sgerald.jelinek@sun.com 	 * in a branded zone is going to run a branded processes.
48012199Sgerald.jelinek@sun.com 	 * hence we don't support this operation.
48112199Sgerald.jelinek@sun.com 	 */
48212199Sgerald.jelinek@sun.com 	if (cmd == B_EXEC_BRAND)
48312199Sgerald.jelinek@sun.com 		return (ENOSYS);
48412199Sgerald.jelinek@sun.com 
48512199Sgerald.jelinek@sun.com 	/* For all other operations this must be a branded process. */
48612199Sgerald.jelinek@sun.com 	if (p->p_brand == &native_brand)
48712199Sgerald.jelinek@sun.com 		return (ENOSYS);
48812199Sgerald.jelinek@sun.com 
48912199Sgerald.jelinek@sun.com 	ASSERT(p->p_brand == pbrand);
49012199Sgerald.jelinek@sun.com 	ASSERT(p->p_brand_data != NULL);
49112199Sgerald.jelinek@sun.com 
49212199Sgerald.jelinek@sun.com 	spd = (brand_proc_data_t *)p->p_brand_data;
49312199Sgerald.jelinek@sun.com 
49412199Sgerald.jelinek@sun.com 	switch ((cmd)) {
49512199Sgerald.jelinek@sun.com 	case B_EXEC_NATIVE:
49612199Sgerald.jelinek@sun.com 		err = exec_common((char *)arg1, (const char **)arg2,
49712199Sgerald.jelinek@sun.com 		    (const char **)arg3, EBA_NATIVE);
49812199Sgerald.jelinek@sun.com 		return (err);
49912199Sgerald.jelinek@sun.com 
50012199Sgerald.jelinek@sun.com 	/*
50112199Sgerald.jelinek@sun.com 	 * Get the address of the user-space system call handler from
50212199Sgerald.jelinek@sun.com 	 * the user process and attach it to the proc structure.
50312199Sgerald.jelinek@sun.com 	 */
50412199Sgerald.jelinek@sun.com 	case B_REGISTER:
50512199Sgerald.jelinek@sun.com 		if (p->p_model == DATAMODEL_NATIVE) {
50612199Sgerald.jelinek@sun.com 			if (copyin((void *)arg1, &reg, sizeof (reg)) != 0)
50712199Sgerald.jelinek@sun.com 				return (EFAULT);
50812199Sgerald.jelinek@sun.com 		}
50912199Sgerald.jelinek@sun.com #if defined(_LP64)
51012199Sgerald.jelinek@sun.com 		else {
51112199Sgerald.jelinek@sun.com 			brand_common_reg32_t reg32;
51212199Sgerald.jelinek@sun.com 
51312199Sgerald.jelinek@sun.com 			if (copyin((void *)arg1, &reg32, sizeof (reg32)) != 0)
51412199Sgerald.jelinek@sun.com 				return (EFAULT);
51512199Sgerald.jelinek@sun.com 			reg.sbr_version = reg32.sbr_version;
51612199Sgerald.jelinek@sun.com 			reg.sbr_handler = (caddr_t)(uintptr_t)reg32.sbr_handler;
51712199Sgerald.jelinek@sun.com 		}
51812199Sgerald.jelinek@sun.com #endif /* _LP64 */
51912199Sgerald.jelinek@sun.com 
52012199Sgerald.jelinek@sun.com 		if (reg.sbr_version != brandvers)
52112199Sgerald.jelinek@sun.com 			return (ENOTSUP);
52212199Sgerald.jelinek@sun.com 		spd->spd_handler = reg.sbr_handler;
52312199Sgerald.jelinek@sun.com 		return (0);
52412199Sgerald.jelinek@sun.com 
52512199Sgerald.jelinek@sun.com 	case B_ELFDATA:
52612199Sgerald.jelinek@sun.com 		if (p->p_model == DATAMODEL_NATIVE) {
52712199Sgerald.jelinek@sun.com 			if (copyout(&spd->spd_elf_data, (void *)arg1,
52812199Sgerald.jelinek@sun.com 			    sizeof (brand_elf_data_t)) != 0)
52912199Sgerald.jelinek@sun.com 				return (EFAULT);
53012199Sgerald.jelinek@sun.com 		}
53112199Sgerald.jelinek@sun.com #if defined(_LP64)
53212199Sgerald.jelinek@sun.com 		else {
53312199Sgerald.jelinek@sun.com 			brand_elf_data32_t sed32;
53412199Sgerald.jelinek@sun.com 
53512199Sgerald.jelinek@sun.com 			sed32.sed_phdr = spd->spd_elf_data.sed_phdr;
53612199Sgerald.jelinek@sun.com 			sed32.sed_phent = spd->spd_elf_data.sed_phent;
53712199Sgerald.jelinek@sun.com 			sed32.sed_phnum = spd->spd_elf_data.sed_phnum;
53812199Sgerald.jelinek@sun.com 			sed32.sed_entry = spd->spd_elf_data.sed_entry;
53912199Sgerald.jelinek@sun.com 			sed32.sed_base = spd->spd_elf_data.sed_base;
54012199Sgerald.jelinek@sun.com 			sed32.sed_ldentry = spd->spd_elf_data.sed_ldentry;
54112199Sgerald.jelinek@sun.com 			sed32.sed_lddata = spd->spd_elf_data.sed_lddata;
54212199Sgerald.jelinek@sun.com 			if (copyout(&sed32, (void *)arg1, sizeof (sed32))
54312199Sgerald.jelinek@sun.com 			    != 0)
54412199Sgerald.jelinek@sun.com 				return (EFAULT);
54512199Sgerald.jelinek@sun.com 		}
54612199Sgerald.jelinek@sun.com #endif /* _LP64 */
54712199Sgerald.jelinek@sun.com 		return (0);
54812199Sgerald.jelinek@sun.com 
54912199Sgerald.jelinek@sun.com 	/*
55012199Sgerald.jelinek@sun.com 	 * The B_TRUSS_POINT subcommand exists so that we can see
55112199Sgerald.jelinek@sun.com 	 * truss output from interposed system calls that return
55212199Sgerald.jelinek@sun.com 	 * without first calling any other system call, meaning they
55312199Sgerald.jelinek@sun.com 	 * would be invisible to truss(1).
55412199Sgerald.jelinek@sun.com 	 * If the second argument is set non-zero, set errno to that
55512199Sgerald.jelinek@sun.com 	 * value as well.
55612199Sgerald.jelinek@sun.com 	 *
55712199Sgerald.jelinek@sun.com 	 * Common arguments seen with truss are:
55812199Sgerald.jelinek@sun.com 	 *
55912199Sgerald.jelinek@sun.com 	 *	arg1: syscall number
56012199Sgerald.jelinek@sun.com 	 *	arg2: errno
56112199Sgerald.jelinek@sun.com 	 */
56212199Sgerald.jelinek@sun.com 	case B_TRUSS_POINT:
56312199Sgerald.jelinek@sun.com 		return ((arg2 == 0) ? 0 : set_errno((uint_t)arg2));
56412199Sgerald.jelinek@sun.com 	}
56512199Sgerald.jelinek@sun.com 
56612199Sgerald.jelinek@sun.com 	return (-1);
56712199Sgerald.jelinek@sun.com }
56812199Sgerald.jelinek@sun.com 
56912199Sgerald.jelinek@sun.com /*ARGSUSED*/
57012199Sgerald.jelinek@sun.com void
brand_solaris_copy_procdata(proc_t * child,proc_t * parent,struct brand * pbrand)57112199Sgerald.jelinek@sun.com brand_solaris_copy_procdata(proc_t *child, proc_t *parent, struct brand *pbrand)
57212199Sgerald.jelinek@sun.com {
57312199Sgerald.jelinek@sun.com 	brand_proc_data_t	*spd;
57412199Sgerald.jelinek@sun.com 
57512199Sgerald.jelinek@sun.com 	ASSERT(parent->p_brand == pbrand);
57612199Sgerald.jelinek@sun.com 	ASSERT(child->p_brand == pbrand);
57712199Sgerald.jelinek@sun.com 	ASSERT(parent->p_brand_data != NULL);
57812199Sgerald.jelinek@sun.com 	ASSERT(child->p_brand_data == NULL);
57912199Sgerald.jelinek@sun.com 
58012199Sgerald.jelinek@sun.com 	/*
58112199Sgerald.jelinek@sun.com 	 * Just duplicate all the proc data of the parent for the
58212199Sgerald.jelinek@sun.com 	 * child
58312199Sgerald.jelinek@sun.com 	 */
58412199Sgerald.jelinek@sun.com 	spd = kmem_alloc(sizeof (brand_proc_data_t), KM_SLEEP);
58512199Sgerald.jelinek@sun.com 	bcopy(parent->p_brand_data, spd, sizeof (brand_proc_data_t));
58612199Sgerald.jelinek@sun.com 	child->p_brand_data = spd;
58712199Sgerald.jelinek@sun.com }
58812199Sgerald.jelinek@sun.com 
58912621Sgerald.jelinek@sun.com static void
restoreexecenv(struct execenv * ep,stack_t * sp)59012621Sgerald.jelinek@sun.com restoreexecenv(struct execenv *ep, stack_t *sp)
59112621Sgerald.jelinek@sun.com {
59212621Sgerald.jelinek@sun.com 	klwp_t *lwp = ttolwp(curthread);
59312621Sgerald.jelinek@sun.com 
59412621Sgerald.jelinek@sun.com 	setexecenv(ep);
59512621Sgerald.jelinek@sun.com 	lwp->lwp_sigaltstack.ss_sp = sp->ss_sp;
59612621Sgerald.jelinek@sun.com 	lwp->lwp_sigaltstack.ss_size = sp->ss_size;
59712621Sgerald.jelinek@sun.com 	lwp->lwp_sigaltstack.ss_flags = sp->ss_flags;
59812621Sgerald.jelinek@sun.com }
59912621Sgerald.jelinek@sun.com 
60012199Sgerald.jelinek@sun.com /*ARGSUSED*/
60112199Sgerald.jelinek@sun.com int
brand_solaris_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,int brand_action,struct brand * pbrand,char * bname,char * brandlib,char * brandlib32,char * brandlinker,char * brandlinker32)60212199Sgerald.jelinek@sun.com brand_solaris_elfexec(vnode_t *vp, execa_t *uap, uarg_t *args,
60312199Sgerald.jelinek@sun.com     intpdata_t *idatap, int level, long *execsz, int setid, caddr_t exec_file,
60412199Sgerald.jelinek@sun.com     cred_t *cred, int brand_action, struct brand *pbrand, char *bname,
60512199Sgerald.jelinek@sun.com     char *brandlib, char *brandlib32, char *brandlinker, char *brandlinker32)
60612199Sgerald.jelinek@sun.com {
60712199Sgerald.jelinek@sun.com 
60812199Sgerald.jelinek@sun.com 	vnode_t		*nvp;
60912199Sgerald.jelinek@sun.com 	Ehdr		ehdr;
61012199Sgerald.jelinek@sun.com 	Addr		uphdr_vaddr;
61112199Sgerald.jelinek@sun.com 	intptr_t	voffset;
61212199Sgerald.jelinek@sun.com 	int		interp;
61312199Sgerald.jelinek@sun.com 	int		i, err;
61412199Sgerald.jelinek@sun.com 	struct execenv	env;
61512621Sgerald.jelinek@sun.com 	struct execenv	origenv;
61612621Sgerald.jelinek@sun.com 	stack_t		orig_sigaltstack;
61712199Sgerald.jelinek@sun.com 	struct user	*up = PTOU(curproc);
61812621Sgerald.jelinek@sun.com 	proc_t		*p = ttoproc(curthread);
61912621Sgerald.jelinek@sun.com 	klwp_t		*lwp = ttolwp(curthread);
62012199Sgerald.jelinek@sun.com 	brand_proc_data_t	*spd;
62112199Sgerald.jelinek@sun.com 	brand_elf_data_t sed, *sedp;
62212199Sgerald.jelinek@sun.com 	char		*linker;
62312199Sgerald.jelinek@sun.com 	uintptr_t	lddata; /* lddata of executable's linker */
62412199Sgerald.jelinek@sun.com 
62512199Sgerald.jelinek@sun.com 	ASSERT(curproc->p_brand == pbrand);
62612199Sgerald.jelinek@sun.com 	ASSERT(curproc->p_brand_data != NULL);
62712199Sgerald.jelinek@sun.com 
62812199Sgerald.jelinek@sun.com 	spd = (brand_proc_data_t *)curproc->p_brand_data;
62912199Sgerald.jelinek@sun.com 	sedp = &spd->spd_elf_data;
63012199Sgerald.jelinek@sun.com 
63112199Sgerald.jelinek@sun.com 	args->brandname = bname;
63212199Sgerald.jelinek@sun.com 
63312199Sgerald.jelinek@sun.com 	/*
63412199Sgerald.jelinek@sun.com 	 * We will exec the brand library and then map in the target
63512199Sgerald.jelinek@sun.com 	 * application and (optionally) the brand's default linker.
63612199Sgerald.jelinek@sun.com 	 */
63712199Sgerald.jelinek@sun.com 	if (args->to_model == DATAMODEL_NATIVE) {
63812199Sgerald.jelinek@sun.com 		args->emulator = brandlib;
63912199Sgerald.jelinek@sun.com 		linker = brandlinker;
64012199Sgerald.jelinek@sun.com 	}
64112199Sgerald.jelinek@sun.com #if defined(_LP64)
64212199Sgerald.jelinek@sun.com 	else {
64312199Sgerald.jelinek@sun.com 		args->emulator = brandlib32;
64412199Sgerald.jelinek@sun.com 		linker = brandlinker32;
64512199Sgerald.jelinek@sun.com 	}
64612199Sgerald.jelinek@sun.com #endif  /* _LP64 */
64712199Sgerald.jelinek@sun.com 
64812199Sgerald.jelinek@sun.com 	if ((err = lookupname(args->emulator, UIO_SYSSPACE, FOLLOW,
64912199Sgerald.jelinek@sun.com 	    NULLVPP, &nvp)) != 0) {
65012199Sgerald.jelinek@sun.com 		uprintf("%s: not found.", args->emulator);
65112199Sgerald.jelinek@sun.com 		return (err);
65212199Sgerald.jelinek@sun.com 	}
65312199Sgerald.jelinek@sun.com 
65412621Sgerald.jelinek@sun.com 	/*
65512621Sgerald.jelinek@sun.com 	 * The following elf{32}exec call changes the execenv in the proc
65612621Sgerald.jelinek@sun.com 	 * struct which includes changing the p_exec member to be the vnode
65712621Sgerald.jelinek@sun.com 	 * for the brand library (e.g. /.SUNWnative/usr/lib/s10_brand.so.1).
65812621Sgerald.jelinek@sun.com 	 * We will eventually set the p_exec member to be the vnode for the new
65912621Sgerald.jelinek@sun.com 	 * executable when we call setexecenv().  However, if we get an error
66012621Sgerald.jelinek@sun.com 	 * before that call we need to restore the execenv to its original
66112621Sgerald.jelinek@sun.com 	 * values so that when we return to the caller fop_close() works
66212621Sgerald.jelinek@sun.com 	 * properly while cleaning up from the failed exec().  Restoring the
66312621Sgerald.jelinek@sun.com 	 * original value will also properly decrement the 2nd VN_RELE that we
66412621Sgerald.jelinek@sun.com 	 * took on the brand library.
66512621Sgerald.jelinek@sun.com 	 */
66612621Sgerald.jelinek@sun.com 	origenv.ex_bssbase = p->p_bssbase;
66712621Sgerald.jelinek@sun.com 	origenv.ex_brkbase = p->p_brkbase;
66812621Sgerald.jelinek@sun.com 	origenv.ex_brksize = p->p_brksize;
66912621Sgerald.jelinek@sun.com 	origenv.ex_vp = p->p_exec;
67012621Sgerald.jelinek@sun.com 	orig_sigaltstack.ss_sp = lwp->lwp_sigaltstack.ss_sp;
67112621Sgerald.jelinek@sun.com 	orig_sigaltstack.ss_size = lwp->lwp_sigaltstack.ss_size;
67212621Sgerald.jelinek@sun.com 	orig_sigaltstack.ss_flags = lwp->lwp_sigaltstack.ss_flags;
67312621Sgerald.jelinek@sun.com 
67412199Sgerald.jelinek@sun.com 	if (args->to_model == DATAMODEL_NATIVE) {
67512199Sgerald.jelinek@sun.com 		err = elfexec(nvp, uap, args, idatap, level + 1, execsz,
67612199Sgerald.jelinek@sun.com 		    setid, exec_file, cred, brand_action);
67712199Sgerald.jelinek@sun.com 	}
67812199Sgerald.jelinek@sun.com #if defined(_LP64)
67912199Sgerald.jelinek@sun.com 	else {
68012199Sgerald.jelinek@sun.com 		err = elf32exec(nvp, uap, args, idatap, level + 1, execsz,
68112199Sgerald.jelinek@sun.com 		    setid, exec_file, cred, brand_action);
68212199Sgerald.jelinek@sun.com 	}
68312199Sgerald.jelinek@sun.com #endif  /* _LP64 */
68412199Sgerald.jelinek@sun.com 	VN_RELE(nvp);
68512621Sgerald.jelinek@sun.com 	if (err != 0) {
68612621Sgerald.jelinek@sun.com 		restoreexecenv(&origenv, &orig_sigaltstack);
68712199Sgerald.jelinek@sun.com 		return (err);
68812621Sgerald.jelinek@sun.com 	}
68912199Sgerald.jelinek@sun.com 
69012199Sgerald.jelinek@sun.com 	/*
69112199Sgerald.jelinek@sun.com 	 * The u_auxv veCTors are set up by elfexec to point to the
69212199Sgerald.jelinek@sun.com 	 * brand emulation library and linker.  Save these so they can
69312199Sgerald.jelinek@sun.com 	 * be copied to the specific brand aux vectors.
69412199Sgerald.jelinek@sun.com 	 */
69512199Sgerald.jelinek@sun.com 	bzero(&sed, sizeof (sed));
69612199Sgerald.jelinek@sun.com 	for (i = 0; i < __KERN_NAUXV_IMPL; i++) {
69712199Sgerald.jelinek@sun.com 		switch (up->u_auxv[i].a_type) {
69812199Sgerald.jelinek@sun.com 		case AT_SUN_LDDATA:
69912199Sgerald.jelinek@sun.com 			sed.sed_lddata = up->u_auxv[i].a_un.a_val;
70012199Sgerald.jelinek@sun.com 			break;
70112199Sgerald.jelinek@sun.com 		case AT_BASE:
70212199Sgerald.jelinek@sun.com 			sed.sed_base = up->u_auxv[i].a_un.a_val;
70312199Sgerald.jelinek@sun.com 			break;
70412199Sgerald.jelinek@sun.com 		case AT_ENTRY:
70512199Sgerald.jelinek@sun.com 			sed.sed_entry = up->u_auxv[i].a_un.a_val;
70612199Sgerald.jelinek@sun.com 			break;
70712199Sgerald.jelinek@sun.com 		case AT_PHDR:
70812199Sgerald.jelinek@sun.com 			sed.sed_phdr = up->u_auxv[i].a_un.a_val;
70912199Sgerald.jelinek@sun.com 			break;
71012199Sgerald.jelinek@sun.com 		case AT_PHENT:
71112199Sgerald.jelinek@sun.com 			sed.sed_phent = up->u_auxv[i].a_un.a_val;
71212199Sgerald.jelinek@sun.com 			break;
71312199Sgerald.jelinek@sun.com 		case AT_PHNUM:
71412199Sgerald.jelinek@sun.com 			sed.sed_phnum = up->u_auxv[i].a_un.a_val;
71512199Sgerald.jelinek@sun.com 			break;
71612199Sgerald.jelinek@sun.com 		default:
71712199Sgerald.jelinek@sun.com 			break;
71812199Sgerald.jelinek@sun.com 		}
71912199Sgerald.jelinek@sun.com 	}
72012199Sgerald.jelinek@sun.com 	/* Make sure the emulator has an entry point */
72112199Sgerald.jelinek@sun.com 	ASSERT(sed.sed_entry != NULL);
72212199Sgerald.jelinek@sun.com 	ASSERT(sed.sed_phdr != NULL);
72312199Sgerald.jelinek@sun.com 
72412199Sgerald.jelinek@sun.com 	bzero(&env, sizeof (env));
72512199Sgerald.jelinek@sun.com 	if (args->to_model == DATAMODEL_NATIVE) {
72612199Sgerald.jelinek@sun.com 		err = mapexec_brand(vp, args, &ehdr, &uphdr_vaddr,
72712199Sgerald.jelinek@sun.com 		    &voffset, exec_file, &interp, &env.ex_bssbase,
72812199Sgerald.jelinek@sun.com 		    &env.ex_brkbase, &env.ex_brksize, NULL);
72912199Sgerald.jelinek@sun.com 	}
73012199Sgerald.jelinek@sun.com #if defined(_LP64)
73112199Sgerald.jelinek@sun.com 	else {
73212199Sgerald.jelinek@sun.com 		Elf32_Ehdr ehdr32;
73312199Sgerald.jelinek@sun.com 		Elf32_Addr uphdr_vaddr32;
73412199Sgerald.jelinek@sun.com 		err = mapexec32_brand(vp, args, &ehdr32, &uphdr_vaddr32,
73512199Sgerald.jelinek@sun.com 		    &voffset, exec_file, &interp, &env.ex_bssbase,
73612199Sgerald.jelinek@sun.com 		    &env.ex_brkbase, &env.ex_brksize, NULL);
73712199Sgerald.jelinek@sun.com 		Ehdr32to64(&ehdr32, &ehdr);
73812199Sgerald.jelinek@sun.com 
73912199Sgerald.jelinek@sun.com 		if (uphdr_vaddr32 == (Elf32_Addr)-1)
74012199Sgerald.jelinek@sun.com 			uphdr_vaddr = (Addr)-1;
74112199Sgerald.jelinek@sun.com 		else
74212199Sgerald.jelinek@sun.com 			uphdr_vaddr = uphdr_vaddr32;
74312199Sgerald.jelinek@sun.com 	}
74412199Sgerald.jelinek@sun.com #endif  /* _LP64 */
74512621Sgerald.jelinek@sun.com 	if (err != 0) {
74612621Sgerald.jelinek@sun.com 		restoreexecenv(&origenv, &orig_sigaltstack);
74712199Sgerald.jelinek@sun.com 		return (err);
74812621Sgerald.jelinek@sun.com 	}
74912199Sgerald.jelinek@sun.com 
75012199Sgerald.jelinek@sun.com 	/*
75112199Sgerald.jelinek@sun.com 	 * Save off the important properties of the executable. The
75212199Sgerald.jelinek@sun.com 	 * brand library will ask us for this data later, when it is
75312199Sgerald.jelinek@sun.com 	 * initializing and getting ready to transfer control to the
75412199Sgerald.jelinek@sun.com 	 * brand application.
75512199Sgerald.jelinek@sun.com 	 */
75612199Sgerald.jelinek@sun.com 	if (uphdr_vaddr == (Addr)-1)
75712199Sgerald.jelinek@sun.com 		sedp->sed_phdr = voffset + ehdr.e_phoff;
75812199Sgerald.jelinek@sun.com 	else
75912199Sgerald.jelinek@sun.com 		sedp->sed_phdr = voffset + uphdr_vaddr;
76012199Sgerald.jelinek@sun.com 	sedp->sed_entry = voffset + ehdr.e_entry;
76112199Sgerald.jelinek@sun.com 	sedp->sed_phent = ehdr.e_phentsize;
76212199Sgerald.jelinek@sun.com 	sedp->sed_phnum = ehdr.e_phnum;
76312199Sgerald.jelinek@sun.com 
76412199Sgerald.jelinek@sun.com 	if (interp) {
76512199Sgerald.jelinek@sun.com 		if (ehdr.e_type == ET_DYN) {
76612199Sgerald.jelinek@sun.com 			/*
76712199Sgerald.jelinek@sun.com 			 * This is a shared object executable, so we
76812199Sgerald.jelinek@sun.com 			 * need to pick a reasonable place to put the
76912199Sgerald.jelinek@sun.com 			 * heap. Just don't use the first page.
77012199Sgerald.jelinek@sun.com 			 */
77112199Sgerald.jelinek@sun.com 			env.ex_brkbase = (caddr_t)PAGESIZE;
77212199Sgerald.jelinek@sun.com 			env.ex_bssbase = (caddr_t)PAGESIZE;
77312199Sgerald.jelinek@sun.com 		}
77412199Sgerald.jelinek@sun.com 
77512199Sgerald.jelinek@sun.com 		/*
77612199Sgerald.jelinek@sun.com 		 * If the program needs an interpreter (most do), map
77712199Sgerald.jelinek@sun.com 		 * it in and store relevant information about it in the
77812199Sgerald.jelinek@sun.com 		 * aux vector, where the brand library can find it.
77912199Sgerald.jelinek@sun.com 		 */
78012199Sgerald.jelinek@sun.com 		if ((err = lookupname(linker, UIO_SYSSPACE,
78112199Sgerald.jelinek@sun.com 		    FOLLOW, NULLVPP, &nvp)) != 0) {
78212199Sgerald.jelinek@sun.com 			uprintf("%s: not found.", brandlinker);
78312621Sgerald.jelinek@sun.com 			restoreexecenv(&origenv, &orig_sigaltstack);
78412199Sgerald.jelinek@sun.com 			return (err);
78512199Sgerald.jelinek@sun.com 		}
78612199Sgerald.jelinek@sun.com 		if (args->to_model == DATAMODEL_NATIVE) {
78712199Sgerald.jelinek@sun.com 			err = mapexec_brand(nvp, args, &ehdr,
78812199Sgerald.jelinek@sun.com 			    &uphdr_vaddr, &voffset, exec_file, &interp,
78912199Sgerald.jelinek@sun.com 			    NULL, NULL, NULL, &lddata);
79012199Sgerald.jelinek@sun.com 		}
79112199Sgerald.jelinek@sun.com #if defined(_LP64)
79212199Sgerald.jelinek@sun.com 		else {
79312199Sgerald.jelinek@sun.com 			Elf32_Ehdr ehdr32;
79412199Sgerald.jelinek@sun.com 			Elf32_Addr uphdr_vaddr32;
79512199Sgerald.jelinek@sun.com 			err = mapexec32_brand(nvp, args, &ehdr32,
79612199Sgerald.jelinek@sun.com 			    &uphdr_vaddr32, &voffset, exec_file, &interp,
79712199Sgerald.jelinek@sun.com 			    NULL, NULL, NULL, &lddata);
79812199Sgerald.jelinek@sun.com 			Ehdr32to64(&ehdr32, &ehdr);
79912199Sgerald.jelinek@sun.com 
80012199Sgerald.jelinek@sun.com 			if (uphdr_vaddr32 == (Elf32_Addr)-1)
80112199Sgerald.jelinek@sun.com 				uphdr_vaddr = (Addr)-1;
80212199Sgerald.jelinek@sun.com 			else
80312199Sgerald.jelinek@sun.com 				uphdr_vaddr = uphdr_vaddr32;
80412199Sgerald.jelinek@sun.com 		}
80512199Sgerald.jelinek@sun.com #endif  /* _LP64 */
80612199Sgerald.jelinek@sun.com 		VN_RELE(nvp);
80712621Sgerald.jelinek@sun.com 		if (err != 0) {
80812621Sgerald.jelinek@sun.com 			restoreexecenv(&origenv, &orig_sigaltstack);
80912199Sgerald.jelinek@sun.com 			return (err);
81012621Sgerald.jelinek@sun.com 		}
81112199Sgerald.jelinek@sun.com 
81212199Sgerald.jelinek@sun.com 		/*
81312199Sgerald.jelinek@sun.com 		 * Now that we know the base address of the brand's
81412199Sgerald.jelinek@sun.com 		 * linker, place it in the aux vector.
81512199Sgerald.jelinek@sun.com 		 */
81612199Sgerald.jelinek@sun.com 		sedp->sed_base = voffset;
81712199Sgerald.jelinek@sun.com 		sedp->sed_ldentry = voffset + ehdr.e_entry;
81812199Sgerald.jelinek@sun.com 		sedp->sed_lddata = voffset + lddata;
81912199Sgerald.jelinek@sun.com 	} else {
82012199Sgerald.jelinek@sun.com 		/*
82112199Sgerald.jelinek@sun.com 		 * This program has no interpreter. The brand library
82212199Sgerald.jelinek@sun.com 		 * will jump to the address in the AT_SUN_BRAND_LDENTRY
82312199Sgerald.jelinek@sun.com 		 * aux vector, so in this case, put the entry point of
82412199Sgerald.jelinek@sun.com 		 * the main executable there.
82512199Sgerald.jelinek@sun.com 		 */
82612199Sgerald.jelinek@sun.com 		if (ehdr.e_type == ET_EXEC) {
82712199Sgerald.jelinek@sun.com 			/*
82812199Sgerald.jelinek@sun.com 			 * An executable with no interpreter, this must
82912199Sgerald.jelinek@sun.com 			 * be a statically linked executable, which
83012199Sgerald.jelinek@sun.com 			 * means we loaded it at the address specified
83112199Sgerald.jelinek@sun.com 			 * in the elf header, in which case the e_entry
83212199Sgerald.jelinek@sun.com 			 * field of the elf header is an absolute
83312199Sgerald.jelinek@sun.com 			 * address.
83412199Sgerald.jelinek@sun.com 			 */
83512199Sgerald.jelinek@sun.com 			sedp->sed_ldentry = ehdr.e_entry;
83612199Sgerald.jelinek@sun.com 			sedp->sed_entry = ehdr.e_entry;
83712199Sgerald.jelinek@sun.com 			sedp->sed_lddata = NULL;
83812199Sgerald.jelinek@sun.com 			sedp->sed_base = NULL;
83912199Sgerald.jelinek@sun.com 		} else {
84012199Sgerald.jelinek@sun.com 			/*
84112199Sgerald.jelinek@sun.com 			 * A shared object with no interpreter, we use
84212199Sgerald.jelinek@sun.com 			 * the calculated address from above.
84312199Sgerald.jelinek@sun.com 			 */
84412199Sgerald.jelinek@sun.com 			sedp->sed_ldentry = sedp->sed_entry;
84512199Sgerald.jelinek@sun.com 			sedp->sed_entry = NULL;
84612199Sgerald.jelinek@sun.com 			sedp->sed_phdr = NULL;
84712199Sgerald.jelinek@sun.com 			sedp->sed_phent = NULL;
84812199Sgerald.jelinek@sun.com 			sedp->sed_phnum = NULL;
84912199Sgerald.jelinek@sun.com 			sedp->sed_lddata = NULL;
85012199Sgerald.jelinek@sun.com 			sedp->sed_base = voffset;
85112199Sgerald.jelinek@sun.com 
85212199Sgerald.jelinek@sun.com 			if (ehdr.e_type == ET_DYN) {
85312199Sgerald.jelinek@sun.com 				/*
85412199Sgerald.jelinek@sun.com 				 * Delay setting the brkbase until the
85512199Sgerald.jelinek@sun.com 				 * first call to brk(); see elfexec()
85612199Sgerald.jelinek@sun.com 				 * for details.
85712199Sgerald.jelinek@sun.com 				 */
85812199Sgerald.jelinek@sun.com 				env.ex_bssbase = (caddr_t)0;
85912199Sgerald.jelinek@sun.com 				env.ex_brkbase = (caddr_t)0;
86012199Sgerald.jelinek@sun.com 				env.ex_brksize = 0;
86112199Sgerald.jelinek@sun.com 			}
86212199Sgerald.jelinek@sun.com 		}
86312199Sgerald.jelinek@sun.com 	}
86412199Sgerald.jelinek@sun.com 
86512199Sgerald.jelinek@sun.com 	env.ex_magic = elfmagic;
86612199Sgerald.jelinek@sun.com 	env.ex_vp = vp;
86712199Sgerald.jelinek@sun.com 	setexecenv(&env);
86812199Sgerald.jelinek@sun.com 
86912199Sgerald.jelinek@sun.com 	/*
87012199Sgerald.jelinek@sun.com 	 * It's time to manipulate the process aux vectors.  First
87112199Sgerald.jelinek@sun.com 	 * we need to update the AT_SUN_AUXFLAGS aux vector to set
87212199Sgerald.jelinek@sun.com 	 * the AF_SUN_NOPLM flag.
87312199Sgerald.jelinek@sun.com 	 */
87412199Sgerald.jelinek@sun.com 	if (args->to_model == DATAMODEL_NATIVE) {
87512199Sgerald.jelinek@sun.com 		auxv_t		auxflags_auxv;
87612199Sgerald.jelinek@sun.com 
87712199Sgerald.jelinek@sun.com 		if (copyin(args->auxp_auxflags, &auxflags_auxv,
87812199Sgerald.jelinek@sun.com 		    sizeof (auxflags_auxv)) != 0)
87912199Sgerald.jelinek@sun.com 			return (EFAULT);
88012199Sgerald.jelinek@sun.com 
88112199Sgerald.jelinek@sun.com 		ASSERT(auxflags_auxv.a_type == AT_SUN_AUXFLAGS);
88212199Sgerald.jelinek@sun.com 		auxflags_auxv.a_un.a_val |= AF_SUN_NOPLM;
88312199Sgerald.jelinek@sun.com 		if (copyout(&auxflags_auxv, args->auxp_auxflags,
88412199Sgerald.jelinek@sun.com 		    sizeof (auxflags_auxv)) != 0)
88512199Sgerald.jelinek@sun.com 			return (EFAULT);
88612199Sgerald.jelinek@sun.com 	}
88712199Sgerald.jelinek@sun.com #if defined(_LP64)
88812199Sgerald.jelinek@sun.com 	else {
88912199Sgerald.jelinek@sun.com 		auxv32_t	auxflags_auxv32;
89012199Sgerald.jelinek@sun.com 
89112199Sgerald.jelinek@sun.com 		if (copyin(args->auxp_auxflags, &auxflags_auxv32,
89212199Sgerald.jelinek@sun.com 		    sizeof (auxflags_auxv32)) != 0)
89312199Sgerald.jelinek@sun.com 			return (EFAULT);
89412199Sgerald.jelinek@sun.com 
89512199Sgerald.jelinek@sun.com 		ASSERT(auxflags_auxv32.a_type == AT_SUN_AUXFLAGS);
89612199Sgerald.jelinek@sun.com 		auxflags_auxv32.a_un.a_val |= AF_SUN_NOPLM;
89712199Sgerald.jelinek@sun.com 		if (copyout(&auxflags_auxv32, args->auxp_auxflags,
89812199Sgerald.jelinek@sun.com 		    sizeof (auxflags_auxv32)) != 0)
89912199Sgerald.jelinek@sun.com 			return (EFAULT);
90012199Sgerald.jelinek@sun.com 	}
90112199Sgerald.jelinek@sun.com #endif  /* _LP64 */
90212199Sgerald.jelinek@sun.com 
90312199Sgerald.jelinek@sun.com 	/* Second, copy out the brand specific aux vectors. */
90412199Sgerald.jelinek@sun.com 	if (args->to_model == DATAMODEL_NATIVE) {
90512199Sgerald.jelinek@sun.com 		auxv_t brand_auxv[] = {
90612199Sgerald.jelinek@sun.com 		    { AT_SUN_BRAND_AUX1, 0 },
90712199Sgerald.jelinek@sun.com 		    { AT_SUN_BRAND_AUX2, 0 },
90812199Sgerald.jelinek@sun.com 		    { AT_SUN_BRAND_AUX3, 0 }
90912199Sgerald.jelinek@sun.com 		};
91012199Sgerald.jelinek@sun.com 
91112199Sgerald.jelinek@sun.com 		ASSERT(brand_auxv[0].a_type ==
91212199Sgerald.jelinek@sun.com 		    AT_SUN_BRAND_COMMON_LDDATA);
91312199Sgerald.jelinek@sun.com 		brand_auxv[0].a_un.a_val = sed.sed_lddata;
91412199Sgerald.jelinek@sun.com 
91512199Sgerald.jelinek@sun.com 		if (copyout(&brand_auxv, args->auxp_brand,
91612199Sgerald.jelinek@sun.com 		    sizeof (brand_auxv)) != 0)
91712199Sgerald.jelinek@sun.com 			return (EFAULT);
91812199Sgerald.jelinek@sun.com 	}
91912199Sgerald.jelinek@sun.com #if defined(_LP64)
92012199Sgerald.jelinek@sun.com 	else {
92112199Sgerald.jelinek@sun.com 		auxv32_t brand_auxv32[] = {
92212199Sgerald.jelinek@sun.com 		    { AT_SUN_BRAND_AUX1, 0 },
92312199Sgerald.jelinek@sun.com 		    { AT_SUN_BRAND_AUX2, 0 },
92412199Sgerald.jelinek@sun.com 		    { AT_SUN_BRAND_AUX3, 0 }
92512199Sgerald.jelinek@sun.com 		};
92612199Sgerald.jelinek@sun.com 
92712199Sgerald.jelinek@sun.com 		ASSERT(brand_auxv32[0].a_type == AT_SUN_BRAND_COMMON_LDDATA);
92812199Sgerald.jelinek@sun.com 		brand_auxv32[0].a_un.a_val = (uint32_t)sed.sed_lddata;
92912199Sgerald.jelinek@sun.com 		if (copyout(&brand_auxv32, args->auxp_brand,
93012199Sgerald.jelinek@sun.com 		    sizeof (brand_auxv32)) != 0)
93112199Sgerald.jelinek@sun.com 			return (EFAULT);
93212199Sgerald.jelinek@sun.com 	}
93312199Sgerald.jelinek@sun.com #endif  /* _LP64 */
93412199Sgerald.jelinek@sun.com 
93512199Sgerald.jelinek@sun.com 	/*
93612199Sgerald.jelinek@sun.com 	 * Third, the /proc aux vectors set up by elfexec() point to
93712199Sgerald.jelinek@sun.com 	 * brand emulation library and it's linker.  Copy these to the
93812199Sgerald.jelinek@sun.com 	 * /proc brand specific aux vector, and update the regular
93912199Sgerald.jelinek@sun.com 	 * /proc aux vectors to point to the executable (and it's
94012199Sgerald.jelinek@sun.com 	 * linker).  This will enable debuggers to access the
94112199Sgerald.jelinek@sun.com 	 * executable via the usual /proc or elf notes aux vectors.
94212199Sgerald.jelinek@sun.com 	 *
94312199Sgerald.jelinek@sun.com 	 * The brand emulation library's linker will get it's aux
94412199Sgerald.jelinek@sun.com 	 * vectors off the stack, and then update the stack with the
94512199Sgerald.jelinek@sun.com 	 * executable's aux vectors before jumping to the executable's
94612199Sgerald.jelinek@sun.com 	 * linker.
94712199Sgerald.jelinek@sun.com 	 *
94812199Sgerald.jelinek@sun.com 	 * Debugging the brand emulation library must be done from
94912199Sgerald.jelinek@sun.com 	 * the global zone, where the librtld_db module knows how to
95012199Sgerald.jelinek@sun.com 	 * fetch the brand specific aux vectors to access the brand
95112199Sgerald.jelinek@sun.com 	 * emulation libraries linker.
95212199Sgerald.jelinek@sun.com 	 */
95312199Sgerald.jelinek@sun.com 	for (i = 0; i < __KERN_NAUXV_IMPL; i++) {
95412199Sgerald.jelinek@sun.com 		ulong_t val;
95512199Sgerald.jelinek@sun.com 
95612199Sgerald.jelinek@sun.com 		switch (up->u_auxv[i].a_type) {
95712199Sgerald.jelinek@sun.com 		case AT_SUN_BRAND_COMMON_LDDATA:
95812199Sgerald.jelinek@sun.com 			up->u_auxv[i].a_un.a_val = sed.sed_lddata;
95912199Sgerald.jelinek@sun.com 			continue;
96012199Sgerald.jelinek@sun.com 		case AT_BASE:
96112199Sgerald.jelinek@sun.com 			val = sedp->sed_base;
96212199Sgerald.jelinek@sun.com 			break;
96312199Sgerald.jelinek@sun.com 		case AT_ENTRY:
96412199Sgerald.jelinek@sun.com 			val = sedp->sed_entry;
96512199Sgerald.jelinek@sun.com 			break;
96612199Sgerald.jelinek@sun.com 		case AT_PHDR:
96712199Sgerald.jelinek@sun.com 			val = sedp->sed_phdr;
96812199Sgerald.jelinek@sun.com 			break;
96912199Sgerald.jelinek@sun.com 		case AT_PHENT:
97012199Sgerald.jelinek@sun.com 			val = sedp->sed_phent;
97112199Sgerald.jelinek@sun.com 			break;
97212199Sgerald.jelinek@sun.com 		case AT_PHNUM:
97312199Sgerald.jelinek@sun.com 			val = sedp->sed_phnum;
97412199Sgerald.jelinek@sun.com 			break;
97512199Sgerald.jelinek@sun.com 		case AT_SUN_LDDATA:
97612199Sgerald.jelinek@sun.com 			val = sedp->sed_lddata;
97712199Sgerald.jelinek@sun.com 			break;
97812199Sgerald.jelinek@sun.com 		default:
97912199Sgerald.jelinek@sun.com 			continue;
98012199Sgerald.jelinek@sun.com 		}
98112199Sgerald.jelinek@sun.com 
98212199Sgerald.jelinek@sun.com 		up->u_auxv[i].a_un.a_val = val;
98312199Sgerald.jelinek@sun.com 		if (val == NULL) {
98412199Sgerald.jelinek@sun.com 			/* Hide the entry for static binaries */
98512199Sgerald.jelinek@sun.com 			up->u_auxv[i].a_type = AT_IGNORE;
98612199Sgerald.jelinek@sun.com 		}
98712199Sgerald.jelinek@sun.com 	}
98812199Sgerald.jelinek@sun.com 
98912199Sgerald.jelinek@sun.com 	/*
99012199Sgerald.jelinek@sun.com 	 * The last thing we do here is clear spd->spd_handler.  This
99112199Sgerald.jelinek@sun.com 	 * is important because if we're already a branded process and
99212199Sgerald.jelinek@sun.com 	 * if this exec succeeds, there is a window between when the
99312199Sgerald.jelinek@sun.com 	 * exec() first returns to the userland of the new process and
99412199Sgerald.jelinek@sun.com 	 * when our brand library get's initialized, during which we
99512199Sgerald.jelinek@sun.com 	 * don't want system calls to be re-directed to our brand
99612199Sgerald.jelinek@sun.com 	 * library since it hasn't been initialized yet.
99712199Sgerald.jelinek@sun.com 	 */
99812199Sgerald.jelinek@sun.com 	spd->spd_handler = NULL;
99912199Sgerald.jelinek@sun.com 
100012199Sgerald.jelinek@sun.com 	return (0);
100112199Sgerald.jelinek@sun.com }
100212199Sgerald.jelinek@sun.com 
100312199Sgerald.jelinek@sun.com void
brand_solaris_exec(struct brand * pbrand)100412199Sgerald.jelinek@sun.com brand_solaris_exec(struct brand *pbrand)
100512199Sgerald.jelinek@sun.com {
100612199Sgerald.jelinek@sun.com 	brand_proc_data_t	*spd = curproc->p_brand_data;
100712199Sgerald.jelinek@sun.com 
100812199Sgerald.jelinek@sun.com 	ASSERT(curproc->p_brand == pbrand);
100912199Sgerald.jelinek@sun.com 	ASSERT(curproc->p_brand_data != NULL);
101012199Sgerald.jelinek@sun.com 	ASSERT(ttolwp(curthread)->lwp_brand != NULL);
101112199Sgerald.jelinek@sun.com 
101212199Sgerald.jelinek@sun.com 	/*
101312199Sgerald.jelinek@sun.com 	 * We should only be called from exec(), when we know the process
101412199Sgerald.jelinek@sun.com 	 * is single-threaded.
101512199Sgerald.jelinek@sun.com 	 */
101612199Sgerald.jelinek@sun.com 	ASSERT(curproc->p_tlist == curproc->p_tlist->t_forw);
101712199Sgerald.jelinek@sun.com 
101812199Sgerald.jelinek@sun.com 	/* Upon exec, reset our lwp brand data. */
101912199Sgerald.jelinek@sun.com 	(void) brand_solaris_freelwp(ttolwp(curthread), pbrand);
102012199Sgerald.jelinek@sun.com 	(void) brand_solaris_initlwp(ttolwp(curthread), pbrand);
102112199Sgerald.jelinek@sun.com 
102212199Sgerald.jelinek@sun.com 	/*
102312199Sgerald.jelinek@sun.com 	 * Upon exec, reset all the proc brand data, except for the elf
102412199Sgerald.jelinek@sun.com 	 * data associated with the executable we are exec'ing.
102512199Sgerald.jelinek@sun.com 	 */
102612199Sgerald.jelinek@sun.com 	spd->spd_handler = NULL;
102712199Sgerald.jelinek@sun.com }
102812199Sgerald.jelinek@sun.com 
102912199Sgerald.jelinek@sun.com int
brand_solaris_fini(char ** emul_table,struct modlinkage * modlinkage,struct brand * pbrand)103012199Sgerald.jelinek@sun.com brand_solaris_fini(char **emul_table, struct modlinkage *modlinkage,
103112199Sgerald.jelinek@sun.com     struct brand *pbrand)
103212199Sgerald.jelinek@sun.com {
103312199Sgerald.jelinek@sun.com 	int err;
103412199Sgerald.jelinek@sun.com 
103512199Sgerald.jelinek@sun.com 	/*
103612199Sgerald.jelinek@sun.com 	 * If there are any zones using this brand, we can't allow it
103712199Sgerald.jelinek@sun.com 	 * to be unloaded.
103812199Sgerald.jelinek@sun.com 	 */
103912199Sgerald.jelinek@sun.com 	if (brand_zone_count(pbrand))
104012199Sgerald.jelinek@sun.com 		return (EBUSY);
104112199Sgerald.jelinek@sun.com 
104212199Sgerald.jelinek@sun.com 	kmem_free(*emul_table, NSYSCALL);
104312199Sgerald.jelinek@sun.com 	*emul_table = NULL;
104412199Sgerald.jelinek@sun.com 
104512199Sgerald.jelinek@sun.com 	err = mod_remove(modlinkage);
104612199Sgerald.jelinek@sun.com 	if (err)
104712199Sgerald.jelinek@sun.com 		cmn_err(CE_WARN, "Couldn't unload brand module");
104812199Sgerald.jelinek@sun.com 
104912199Sgerald.jelinek@sun.com 	return (err);
105012199Sgerald.jelinek@sun.com }
105112199Sgerald.jelinek@sun.com 
105212199Sgerald.jelinek@sun.com /*ARGSUSED*/
105312199Sgerald.jelinek@sun.com void
brand_solaris_forklwp(klwp_t * p,klwp_t * c,struct brand * pbrand)105412199Sgerald.jelinek@sun.com brand_solaris_forklwp(klwp_t *p, klwp_t *c, struct brand *pbrand)
105512199Sgerald.jelinek@sun.com {
105612199Sgerald.jelinek@sun.com 	ASSERT(p->lwp_procp->p_brand == pbrand);
105712199Sgerald.jelinek@sun.com 	ASSERT(c->lwp_procp->p_brand == pbrand);
105812199Sgerald.jelinek@sun.com 
105912199Sgerald.jelinek@sun.com 	ASSERT(p->lwp_procp->p_brand_data != NULL);
106012199Sgerald.jelinek@sun.com 	ASSERT(c->lwp_procp->p_brand_data != NULL);
106112199Sgerald.jelinek@sun.com 
106212199Sgerald.jelinek@sun.com 	/*
106312199Sgerald.jelinek@sun.com 	 * Both LWPs have already had been initialized via
106412199Sgerald.jelinek@sun.com 	 * brand_solaris_initlwp().
106512199Sgerald.jelinek@sun.com 	 */
106612199Sgerald.jelinek@sun.com 	ASSERT(p->lwp_brand != NULL);
106712199Sgerald.jelinek@sun.com 	ASSERT(c->lwp_brand != NULL);
106812199Sgerald.jelinek@sun.com }
106912199Sgerald.jelinek@sun.com 
107012199Sgerald.jelinek@sun.com /*ARGSUSED*/
107112199Sgerald.jelinek@sun.com void
brand_solaris_freelwp(klwp_t * l,struct brand * pbrand)107212199Sgerald.jelinek@sun.com brand_solaris_freelwp(klwp_t *l, struct brand *pbrand)
107312199Sgerald.jelinek@sun.com {
107412199Sgerald.jelinek@sun.com 	ASSERT(l->lwp_procp->p_brand == pbrand);
107512199Sgerald.jelinek@sun.com 	ASSERT(l->lwp_procp->p_brand_data != NULL);
107612199Sgerald.jelinek@sun.com 	ASSERT(l->lwp_brand != NULL);
107712199Sgerald.jelinek@sun.com 	l->lwp_brand = NULL;
107812199Sgerald.jelinek@sun.com }
107912199Sgerald.jelinek@sun.com 
108012199Sgerald.jelinek@sun.com /*ARGSUSED*/
108112199Sgerald.jelinek@sun.com int
brand_solaris_initlwp(klwp_t * l,struct brand * pbrand)108212199Sgerald.jelinek@sun.com brand_solaris_initlwp(klwp_t *l, struct brand *pbrand)
108312199Sgerald.jelinek@sun.com {
108412199Sgerald.jelinek@sun.com 	ASSERT(l->lwp_procp->p_brand == pbrand);
108512199Sgerald.jelinek@sun.com 	ASSERT(l->lwp_procp->p_brand_data != NULL);
108612199Sgerald.jelinek@sun.com 	ASSERT(l->lwp_brand == NULL);
108712199Sgerald.jelinek@sun.com 	l->lwp_brand = (void *)-1;
108812199Sgerald.jelinek@sun.com 	return (0);
108912199Sgerald.jelinek@sun.com }
109012199Sgerald.jelinek@sun.com 
109112199Sgerald.jelinek@sun.com /*ARGSUSED*/
109212199Sgerald.jelinek@sun.com void
brand_solaris_lwpexit(klwp_t * l,struct brand * pbrand)109312199Sgerald.jelinek@sun.com brand_solaris_lwpexit(klwp_t *l, struct brand *pbrand)
109412199Sgerald.jelinek@sun.com {
109512199Sgerald.jelinek@sun.com 	proc_t  *p = l->lwp_procp;
109612199Sgerald.jelinek@sun.com 
109712199Sgerald.jelinek@sun.com 	ASSERT(l->lwp_procp->p_brand == pbrand);
109812199Sgerald.jelinek@sun.com 	ASSERT(l->lwp_procp->p_brand_data != NULL);
109912199Sgerald.jelinek@sun.com 	ASSERT(l->lwp_brand != NULL);
110012199Sgerald.jelinek@sun.com 
110112199Sgerald.jelinek@sun.com 	/*
110212199Sgerald.jelinek@sun.com 	 * We should never be called for the last thread in a process.
110312199Sgerald.jelinek@sun.com 	 * (That case is handled by brand_solaris_proc_exit().)
110412199Sgerald.jelinek@sun.com 	 * Therefore this lwp must be exiting from a multi-threaded
110512199Sgerald.jelinek@sun.com 	 * process.
110612199Sgerald.jelinek@sun.com 	 */
110712199Sgerald.jelinek@sun.com 	ASSERT(p->p_tlist != p->p_tlist->t_forw);
110812199Sgerald.jelinek@sun.com 
110912199Sgerald.jelinek@sun.com 	l->lwp_brand = NULL;
111012199Sgerald.jelinek@sun.com }
111112199Sgerald.jelinek@sun.com 
111212199Sgerald.jelinek@sun.com /*ARGSUSED*/
111312199Sgerald.jelinek@sun.com void
brand_solaris_proc_exit(struct proc * p,klwp_t * l,struct brand * pbrand)111412199Sgerald.jelinek@sun.com brand_solaris_proc_exit(struct proc *p, klwp_t *l, struct brand *pbrand)
111512199Sgerald.jelinek@sun.com {
111612199Sgerald.jelinek@sun.com 	ASSERT(p->p_brand == pbrand);
111712199Sgerald.jelinek@sun.com 	ASSERT(p->p_brand_data != NULL);
111812199Sgerald.jelinek@sun.com 
111912199Sgerald.jelinek@sun.com 	/*
1120*13045SVamsi.Krishna@Sun.COM 	 * When called from proc_exit(), we know that process is
1121*13045SVamsi.Krishna@Sun.COM 	 * single-threaded and free our lwp brand data.
1122*13045SVamsi.Krishna@Sun.COM 	 * otherwise just free p_brand_data and return.
112312199Sgerald.jelinek@sun.com 	 */
1124*13045SVamsi.Krishna@Sun.COM 	if (l != NULL) {
1125*13045SVamsi.Krishna@Sun.COM 		ASSERT(p->p_tlist == p->p_tlist->t_forw);
1126*13045SVamsi.Krishna@Sun.COM 		ASSERT(p->p_tlist->t_lwp == l);
1127*13045SVamsi.Krishna@Sun.COM 		(void) brand_solaris_freelwp(l, pbrand);
1128*13045SVamsi.Krishna@Sun.COM 	}
112912199Sgerald.jelinek@sun.com 
113012199Sgerald.jelinek@sun.com 	/* upon exit, free our proc brand data */
113112199Sgerald.jelinek@sun.com 	kmem_free(p->p_brand_data, sizeof (brand_proc_data_t));
113212199Sgerald.jelinek@sun.com 	p->p_brand_data = NULL;
113312199Sgerald.jelinek@sun.com }
113412199Sgerald.jelinek@sun.com 
113512199Sgerald.jelinek@sun.com void
brand_solaris_setbrand(proc_t * p,struct brand * pbrand)113612199Sgerald.jelinek@sun.com brand_solaris_setbrand(proc_t *p, struct brand *pbrand)
113712199Sgerald.jelinek@sun.com {
113812199Sgerald.jelinek@sun.com 	ASSERT(p->p_brand == pbrand);
113912199Sgerald.jelinek@sun.com 	ASSERT(p->p_brand_data == NULL);
114012199Sgerald.jelinek@sun.com 
114112199Sgerald.jelinek@sun.com 	/*
114212199Sgerald.jelinek@sun.com 	 * We should only be called from exec(), when we know the process
114312199Sgerald.jelinek@sun.com 	 * is single-threaded.
114412199Sgerald.jelinek@sun.com 	 */
114512199Sgerald.jelinek@sun.com 	ASSERT(p->p_tlist == p->p_tlist->t_forw);
114612199Sgerald.jelinek@sun.com 
114712199Sgerald.jelinek@sun.com 	p->p_brand_data = kmem_zalloc(sizeof (brand_proc_data_t), KM_SLEEP);
114812199Sgerald.jelinek@sun.com 	(void) brand_solaris_initlwp(p->p_tlist->t_lwp, pbrand);
114912199Sgerald.jelinek@sun.com }
1150