19acbbeafSnn /*
29acbbeafSnn * CDDL HEADER START
39acbbeafSnn *
49acbbeafSnn * The contents of this file are subject to the terms of the
59acbbeafSnn * Common Development and Distribution License (the "License").
69acbbeafSnn * You may not use this file except in compliance with the License.
79acbbeafSnn *
89acbbeafSnn * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99acbbeafSnn * or http://www.opensolaris.org/os/licensing.
109acbbeafSnn * See the License for the specific language governing permissions
119acbbeafSnn * and limitations under the License.
129acbbeafSnn *
139acbbeafSnn * When distributing Covered Code, include this CDDL HEADER in each
149acbbeafSnn * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159acbbeafSnn * If applicable, add the following below this CDDL HEADER, with the
169acbbeafSnn * fields enclosed by brackets "[]" replaced with your own identifying
179acbbeafSnn * information: Portions Copyright [yyyy] [name of copyright owner]
189acbbeafSnn *
199acbbeafSnn * CDDL HEADER END
209acbbeafSnn */
219acbbeafSnn /*
2280e2ca85S * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
239acbbeafSnn */
249acbbeafSnn
259acbbeafSnn #include <sys/kmem.h>
269acbbeafSnn #include <sys/errno.h>
279acbbeafSnn #include <sys/systm.h>
289acbbeafSnn #include <sys/cmn_err.h>
299acbbeafSnn #include <sys/brand.h>
309acbbeafSnn #include <sys/machbrand.h>
319acbbeafSnn #include <sys/modctl.h>
329acbbeafSnn #include <sys/rwlock.h>
339acbbeafSnn #include <sys/zone.h>
3480e2ca85S #include <sys/pathname.h>
359acbbeafSnn
369acbbeafSnn #define SUPPORTED_BRAND_VERSION BRAND_VER_1
379acbbeafSnn
389acbbeafSnn #if defined(__sparcv9)
39725deb8fSedp /* sparcv9 uses system wide brand interposition hooks */
40725deb8fSedp static void brand_plat_interposition_enable(void);
41725deb8fSedp static void brand_plat_interposition_disable(void);
42725deb8fSedp
439acbbeafSnn struct brand_mach_ops native_mach_ops = {
449acbbeafSnn NULL, NULL
459acbbeafSnn };
4659f2ff5cSedp #else /* !__sparcv9 */
479acbbeafSnn struct brand_mach_ops native_mach_ops = {
48eb5a5c78SSurya Prakki NULL, NULL, NULL, NULL
499acbbeafSnn };
5059f2ff5cSedp #endif /* !__sparcv9 */
519acbbeafSnn
529acbbeafSnn brand_t native_brand = {
539acbbeafSnn BRAND_VER_1,
549acbbeafSnn "native",
559acbbeafSnn NULL,
569acbbeafSnn &native_mach_ops
579acbbeafSnn };
589acbbeafSnn
599acbbeafSnn /*
609acbbeafSnn * Used to maintain a list of all the brands currently loaded into the
619acbbeafSnn * kernel.
629acbbeafSnn */
639acbbeafSnn struct brand_list {
649acbbeafSnn int bl_refcnt;
659acbbeafSnn struct brand_list *bl_next;
669acbbeafSnn brand_t *bl_brand;
679acbbeafSnn };
689acbbeafSnn
699acbbeafSnn static struct brand_list *brand_list = NULL;
709acbbeafSnn
719acbbeafSnn /*
729acbbeafSnn * This lock protects the integrity of the brand list.
739acbbeafSnn */
749acbbeafSnn static kmutex_t brand_list_lock;
759acbbeafSnn
769acbbeafSnn void
brand_init()779acbbeafSnn brand_init()
789acbbeafSnn {
799acbbeafSnn mutex_init(&brand_list_lock, NULL, MUTEX_DEFAULT, NULL);
809acbbeafSnn p0.p_brand = &native_brand;
819acbbeafSnn }
829acbbeafSnn
839acbbeafSnn int
brand_register(brand_t * brand)849acbbeafSnn brand_register(brand_t *brand)
859acbbeafSnn {
869acbbeafSnn struct brand_list *list, *scan;
879acbbeafSnn
889acbbeafSnn if (brand == NULL)
899acbbeafSnn return (EINVAL);
909acbbeafSnn
919acbbeafSnn if (brand->b_version != SUPPORTED_BRAND_VERSION) {
929acbbeafSnn if (brand->b_version < SUPPORTED_BRAND_VERSION) {
939acbbeafSnn cmn_err(CE_WARN,
949acbbeafSnn "brand '%s' was built to run on older versions "
959acbbeafSnn "of Solaris.",
969acbbeafSnn brand->b_name);
979acbbeafSnn } else {
989acbbeafSnn cmn_err(CE_WARN,
999acbbeafSnn "brand '%s' was built to run on a newer version "
1009acbbeafSnn "of Solaris.",
1019acbbeafSnn brand->b_name);
1029acbbeafSnn }
1039acbbeafSnn return (EINVAL);
1049acbbeafSnn }
1059acbbeafSnn
1069acbbeafSnn /* Sanity checks */
1079acbbeafSnn if (brand->b_name == NULL || brand->b_ops == NULL ||
1089acbbeafSnn brand->b_ops->b_brandsys == NULL) {
1099acbbeafSnn cmn_err(CE_WARN, "Malformed brand");
1109acbbeafSnn return (EINVAL);
1119acbbeafSnn }
1129acbbeafSnn
1139acbbeafSnn list = kmem_alloc(sizeof (struct brand_list), KM_SLEEP);
1149acbbeafSnn
1159acbbeafSnn /* Add the brand to the list of loaded brands. */
1169acbbeafSnn mutex_enter(&brand_list_lock);
1179acbbeafSnn
1189acbbeafSnn /*
1199acbbeafSnn * Check to be sure we haven't already registered this brand.
1209acbbeafSnn */
1219acbbeafSnn for (scan = brand_list; scan != NULL; scan = scan->bl_next) {
1229acbbeafSnn if (strcmp(brand->b_name, scan->bl_brand->b_name) == 0) {
1239acbbeafSnn cmn_err(CE_WARN,
1249acbbeafSnn "Invalid attempt to load a second instance of "
1259acbbeafSnn "brand %s", brand->b_name);
1269acbbeafSnn mutex_exit(&brand_list_lock);
1279acbbeafSnn kmem_free(list, sizeof (struct brand_list));
1289acbbeafSnn return (EINVAL);
1299acbbeafSnn }
1309acbbeafSnn }
1319acbbeafSnn
132725deb8fSedp #if defined(__sparcv9)
133725deb8fSedp /* sparcv9 uses system wide brand interposition hooks */
134725deb8fSedp if (brand_list == NULL)
135725deb8fSedp brand_plat_interposition_enable();
136725deb8fSedp #endif /* __sparcv9 */
137725deb8fSedp
1389acbbeafSnn list->bl_brand = brand;
1399acbbeafSnn list->bl_refcnt = 0;
1409acbbeafSnn list->bl_next = brand_list;
1419acbbeafSnn brand_list = list;
142725deb8fSedp
1439acbbeafSnn mutex_exit(&brand_list_lock);
1449acbbeafSnn
1459acbbeafSnn return (0);
1469acbbeafSnn }
1479acbbeafSnn
1489acbbeafSnn /*
1499acbbeafSnn * The kernel module implementing this brand is being unloaded, so remove
1509acbbeafSnn * it from the list of active brands.
1519acbbeafSnn */
1529acbbeafSnn int
brand_unregister(brand_t * brand)1539acbbeafSnn brand_unregister(brand_t *brand)
1549acbbeafSnn {
1559acbbeafSnn struct brand_list *list, *prev;
1569acbbeafSnn
1579acbbeafSnn /* Sanity checks */
1589acbbeafSnn if (brand == NULL || brand->b_name == NULL) {
1599acbbeafSnn cmn_err(CE_WARN, "Malformed brand");
1609acbbeafSnn return (EINVAL);
1619acbbeafSnn }
1629acbbeafSnn
1639acbbeafSnn prev = NULL;
1649acbbeafSnn mutex_enter(&brand_list_lock);
1659acbbeafSnn
1669acbbeafSnn for (list = brand_list; list != NULL; list = list->bl_next) {
1679acbbeafSnn if (list->bl_brand == brand)
1689acbbeafSnn break;
1699acbbeafSnn prev = list;
1709acbbeafSnn }
1719acbbeafSnn
1729acbbeafSnn if (list == NULL) {
1739acbbeafSnn cmn_err(CE_WARN, "Brand %s wasn't registered", brand->b_name);
1749acbbeafSnn mutex_exit(&brand_list_lock);
1759acbbeafSnn return (EINVAL);
1769acbbeafSnn }
1779acbbeafSnn
1789acbbeafSnn if (list->bl_refcnt > 0) {
1799acbbeafSnn cmn_err(CE_WARN, "Unregistering brand %s which is still in use",
1809acbbeafSnn brand->b_name);
1819acbbeafSnn mutex_exit(&brand_list_lock);
1829acbbeafSnn return (EBUSY);
1839acbbeafSnn }
1849acbbeafSnn
1859acbbeafSnn /* Remove brand from the list */
1869acbbeafSnn if (prev != NULL)
1879acbbeafSnn prev->bl_next = list->bl_next;
1889acbbeafSnn else
1899acbbeafSnn brand_list = list->bl_next;
1909acbbeafSnn
191725deb8fSedp #if defined(__sparcv9)
192725deb8fSedp /* sparcv9 uses system wide brand interposition hooks */
193725deb8fSedp if (brand_list == NULL)
194725deb8fSedp brand_plat_interposition_disable();
195725deb8fSedp #endif /* __sparcv9 */
196725deb8fSedp
1979acbbeafSnn mutex_exit(&brand_list_lock);
1989acbbeafSnn
1999acbbeafSnn kmem_free(list, sizeof (struct brand_list));
2009acbbeafSnn
2019acbbeafSnn return (0);
2029acbbeafSnn }
2039acbbeafSnn
2049acbbeafSnn /*
2059acbbeafSnn * Record that a zone of this brand has been instantiated. If the kernel
2069acbbeafSnn * module implementing this brand's functionality is not present, this
2079acbbeafSnn * routine attempts to load the module as a side effect.
2089acbbeafSnn */
2099acbbeafSnn brand_t *
brand_register_zone(struct brand_attr * attr)2109acbbeafSnn brand_register_zone(struct brand_attr *attr)
2119acbbeafSnn {
2129acbbeafSnn struct brand_list *l = NULL;
2139acbbeafSnn ddi_modhandle_t hdl = NULL;
2149acbbeafSnn char *modname;
2159acbbeafSnn int err = 0;
2169acbbeafSnn
2179acbbeafSnn if (is_system_labeled()) {
2189acbbeafSnn cmn_err(CE_WARN,
2199acbbeafSnn "Branded zones are not allowed on labeled systems.");
2209acbbeafSnn return (NULL);
2219acbbeafSnn }
2229acbbeafSnn
2239acbbeafSnn /*
2249acbbeafSnn * We make at most two passes through this loop. The first time
2259acbbeafSnn * through, we're looking to see if this is a new user of an
2269acbbeafSnn * already loaded brand. If the brand hasn't been loaded, we
2279acbbeafSnn * call ddi_modopen() to force it to be loaded and then make a
2289acbbeafSnn * second pass through the list of brands. If we don't find the
2299acbbeafSnn * brand the second time through it means that the modname
2309acbbeafSnn * specified in the brand_attr structure doesn't provide the brand
2319acbbeafSnn * specified in the brandname field. This would suggest a bug in
2329acbbeafSnn * the brand's config.xml file. We close the module and return
2339acbbeafSnn * 'NULL' to the caller.
2349acbbeafSnn */
2359acbbeafSnn for (;;) {
2369acbbeafSnn /*
2379acbbeafSnn * Search list of loaded brands
2389acbbeafSnn */
2399acbbeafSnn mutex_enter(&brand_list_lock);
2409acbbeafSnn for (l = brand_list; l != NULL; l = l->bl_next)
2419acbbeafSnn if (strcmp(attr->ba_brandname,
2429acbbeafSnn l->bl_brand->b_name) == 0)
2439acbbeafSnn break;
2449acbbeafSnn if ((l != NULL) || (hdl != NULL))
2459acbbeafSnn break;
2469acbbeafSnn mutex_exit(&brand_list_lock);
2479acbbeafSnn
2489acbbeafSnn /*
2499acbbeafSnn * We didn't find that the requested brand has been loaded
2509acbbeafSnn * yet, so we trigger the load of the appropriate kernel
2519acbbeafSnn * module and search the list again.
2529acbbeafSnn */
2539acbbeafSnn modname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
2549acbbeafSnn (void) strcpy(modname, "brand/");
2559acbbeafSnn (void) strcat(modname, attr->ba_modname);
2569acbbeafSnn hdl = ddi_modopen(modname, KRTLD_MODE_FIRST, &err);
2579acbbeafSnn kmem_free(modname, MAXPATHLEN);
2589acbbeafSnn
2599acbbeafSnn if (err != 0)
2609acbbeafSnn return (NULL);
2619acbbeafSnn }
2629acbbeafSnn
2639acbbeafSnn /*
2649acbbeafSnn * If we found the matching brand, bump its reference count.
2659acbbeafSnn */
2669acbbeafSnn if (l != NULL)
2679acbbeafSnn l->bl_refcnt++;
2689acbbeafSnn
2699acbbeafSnn mutex_exit(&brand_list_lock);
2709acbbeafSnn
2719acbbeafSnn if (hdl != NULL)
2729acbbeafSnn (void) ddi_modclose(hdl);
2739acbbeafSnn
2749acbbeafSnn return ((l != NULL) ? l->bl_brand : NULL);
2759acbbeafSnn }
2769acbbeafSnn
2779acbbeafSnn /*
2789acbbeafSnn * Return the number of zones currently using this brand.
2799acbbeafSnn */
2809acbbeafSnn int
brand_zone_count(struct brand * bp)2819acbbeafSnn brand_zone_count(struct brand *bp)
2829acbbeafSnn {
2839acbbeafSnn struct brand_list *l;
2849acbbeafSnn int cnt = 0;
2859acbbeafSnn
2869acbbeafSnn mutex_enter(&brand_list_lock);
2879acbbeafSnn for (l = brand_list; l != NULL; l = l->bl_next)
2889acbbeafSnn if (l->bl_brand == bp) {
2899acbbeafSnn cnt = l->bl_refcnt;
2909acbbeafSnn break;
2919acbbeafSnn }
2929acbbeafSnn mutex_exit(&brand_list_lock);
2939acbbeafSnn
2949acbbeafSnn return (cnt);
2959acbbeafSnn }
2969acbbeafSnn
2979acbbeafSnn void
brand_unregister_zone(struct brand * bp)2989acbbeafSnn brand_unregister_zone(struct brand *bp)
2999acbbeafSnn {
3009acbbeafSnn struct brand_list *list;
3019acbbeafSnn
3029acbbeafSnn mutex_enter(&brand_list_lock);
3039acbbeafSnn for (list = brand_list; list != NULL; list = list->bl_next) {
3049acbbeafSnn if (list->bl_brand == bp) {
3059acbbeafSnn ASSERT(list->bl_refcnt > 0);
3069acbbeafSnn list->bl_refcnt--;
3079acbbeafSnn break;
3089acbbeafSnn }
3099acbbeafSnn }
3109acbbeafSnn mutex_exit(&brand_list_lock);
3119acbbeafSnn }
3129acbbeafSnn
3139acbbeafSnn void
brand_setbrand(proc_t * p)3149acbbeafSnn brand_setbrand(proc_t *p)
3159acbbeafSnn {
3169acbbeafSnn brand_t *bp = p->p_zone->zone_brand;
3179acbbeafSnn
3189acbbeafSnn ASSERT(bp != NULL);
3199acbbeafSnn ASSERT(p->p_brand == &native_brand);
3209acbbeafSnn
3219acbbeafSnn /*
3229acbbeafSnn * We should only be called from exec(), when we know the process
3239acbbeafSnn * is single-threaded.
3249acbbeafSnn */
3259acbbeafSnn ASSERT(p->p_tlist == p->p_tlist->t_forw);
3269acbbeafSnn
3279acbbeafSnn p->p_brand = bp;
328fd9e7635Sedp ASSERT(PROC_IS_BRANDED(p));
329fd9e7635Sedp BROP(p)->b_setbrand(p);
330fd9e7635Sedp }
331fd9e7635Sedp
332fd9e7635Sedp void
brand_clearbrand(proc_t * p,boolean_t no_lwps)333e9f7cbf0SVamsi Nagineni brand_clearbrand(proc_t *p, boolean_t no_lwps)
334fd9e7635Sedp {
335fd9e7635Sedp brand_t *bp = p->p_zone->zone_brand;
336e9f7cbf0SVamsi Nagineni klwp_t *lwp = NULL;
337fd9e7635Sedp ASSERT(bp != NULL);
338e9f7cbf0SVamsi Nagineni ASSERT(!no_lwps || (p->p_tlist == NULL));
339fd9e7635Sedp
340fd9e7635Sedp /*
341e9f7cbf0SVamsi Nagineni * If called from exec_common() or proc_exit(),
342e9f7cbf0SVamsi Nagineni * we know the process is single-threaded.
343e9f7cbf0SVamsi Nagineni * If called from fork_fail, p_tlist is NULL.
344fd9e7635Sedp */
345e9f7cbf0SVamsi Nagineni if (!no_lwps) {
346e9f7cbf0SVamsi Nagineni ASSERT(p->p_tlist == p->p_tlist->t_forw);
347e9f7cbf0SVamsi Nagineni lwp = p->p_tlist->t_lwp;
348e9f7cbf0SVamsi Nagineni }
349fd9e7635Sedp
350fd9e7635Sedp ASSERT(PROC_IS_BRANDED(p));
351e9f7cbf0SVamsi Nagineni BROP(p)->b_proc_exit(p, lwp);
352fd9e7635Sedp p->p_brand = &native_brand;
3539acbbeafSnn }
35459f2ff5cSedp
35559f2ff5cSedp #if defined(__sparcv9)
35659f2ff5cSedp /*
357725deb8fSedp * Currently, only sparc has system level brand syscall interposition.
35859f2ff5cSedp * On x86 we're able to enable syscall interposition on a per-cpu basis
35959f2ff5cSedp * when a branded thread is scheduled to run on a cpu.
36059f2ff5cSedp */
36159f2ff5cSedp
36259f2ff5cSedp /* Local variables needed for dynamic syscall interposition support */
36359f2ff5cSedp static uint32_t syscall_trap_patch_instr_orig;
36459f2ff5cSedp static uint32_t syscall_trap32_patch_instr_orig;
36559f2ff5cSedp
36659f2ff5cSedp /* Trap Table syscall entry hot patch points */
36759f2ff5cSedp extern void syscall_trap_patch_point(void);
36859f2ff5cSedp extern void syscall_trap32_patch_point(void);
36959f2ff5cSedp
37059f2ff5cSedp /* Alternate syscall entry handlers used when branded zones are running */
37159f2ff5cSedp extern void syscall_wrapper(void);
37259f2ff5cSedp extern void syscall_wrapper32(void);
37359f2ff5cSedp
37459f2ff5cSedp /* Macros used to facilitate sparcv9 instruction generation */
37559f2ff5cSedp #define BA_A_INSTR 0x30800000 /* ba,a addr */
37659f2ff5cSedp #define DISP22(from, to) \
37759f2ff5cSedp ((((uintptr_t)(to) - (uintptr_t)(from)) >> 2) & 0x3fffff)
37859f2ff5cSedp
37959f2ff5cSedp /*ARGSUSED*/
380725deb8fSedp static void
brand_plat_interposition_enable(void)381725deb8fSedp brand_plat_interposition_enable(void)
38259f2ff5cSedp {
383725deb8fSedp ASSERT(MUTEX_HELD(&brand_list_lock));
38459f2ff5cSedp
38559f2ff5cSedp /*
38659f2ff5cSedp * Before we hot patch the kernel save the current instructions
387725deb8fSedp * so that we can restore them later.
38859f2ff5cSedp */
38959f2ff5cSedp syscall_trap_patch_instr_orig =
39059f2ff5cSedp *(uint32_t *)syscall_trap_patch_point;
39159f2ff5cSedp syscall_trap32_patch_instr_orig =
39259f2ff5cSedp *(uint32_t *)syscall_trap32_patch_point;
39359f2ff5cSedp
39459f2ff5cSedp /*
39559f2ff5cSedp * Modify the trap table at the patch points.
39659f2ff5cSedp *
39759f2ff5cSedp * We basically replace the first instruction at the patch
39859f2ff5cSedp * point with a ba,a instruction that will transfer control
39959f2ff5cSedp * to syscall_wrapper or syscall_wrapper32 for 64-bit and
40059f2ff5cSedp * 32-bit syscalls respectively. It's important to note that
40159f2ff5cSedp * the annul bit is set in the branch so we don't execute
40259f2ff5cSedp * the instruction directly following the one we're patching
40359f2ff5cSedp * during the branch's delay slot.
40459f2ff5cSedp *
40559f2ff5cSedp * It also doesn't matter that we're not atomically updating both
40659f2ff5cSedp * the 64 and 32 bit syscall paths at the same time since there's
40759f2ff5cSedp * no actual branded processes running on the system yet.
40859f2ff5cSedp */
40959f2ff5cSedp hot_patch_kernel_text((caddr_t)syscall_trap_patch_point,
41059f2ff5cSedp BA_A_INSTR | DISP22(syscall_trap_patch_point, syscall_wrapper),
41159f2ff5cSedp 4);
41259f2ff5cSedp hot_patch_kernel_text((caddr_t)syscall_trap32_patch_point,
41359f2ff5cSedp BA_A_INSTR | DISP22(syscall_trap32_patch_point, syscall_wrapper32),
41459f2ff5cSedp 4);
41559f2ff5cSedp }
41659f2ff5cSedp
41759f2ff5cSedp /*ARGSUSED*/
418725deb8fSedp static void
brand_plat_interposition_disable(void)419725deb8fSedp brand_plat_interposition_disable(void)
42059f2ff5cSedp {
421725deb8fSedp ASSERT(MUTEX_HELD(&brand_list_lock));
42259f2ff5cSedp
42359f2ff5cSedp /*
42459f2ff5cSedp * Restore the original instructions at the trap table syscall
42559f2ff5cSedp * patch points to disable the brand syscall interposition
42659f2ff5cSedp * mechanism.
42759f2ff5cSedp */
42859f2ff5cSedp hot_patch_kernel_text((caddr_t)syscall_trap_patch_point,
42959f2ff5cSedp syscall_trap_patch_instr_orig, 4);
43059f2ff5cSedp hot_patch_kernel_text((caddr_t)syscall_trap32_patch_point,
43159f2ff5cSedp syscall_trap32_patch_instr_orig, 4);
43259f2ff5cSedp }
43359f2ff5cSedp #endif /* __sparcv9 */
43480e2ca85S
43580e2ca85S /*
43680e2ca85S * The following functions can be shared among kernel brand modules which
43780e2ca85S * implement Solaris-derived brands, all of which need to do similar tasks
43880e2ca85S * to manage the brand.
43980e2ca85S */
44080e2ca85S
44180e2ca85S #if defined(_LP64)
44280e2ca85S static void
Ehdr32to64(Elf32_Ehdr * src,Ehdr * dst)44380e2ca85S Ehdr32to64(Elf32_Ehdr *src, Ehdr *dst)
44480e2ca85S {
44580e2ca85S bcopy(src->e_ident, dst->e_ident, sizeof (src->e_ident));
44680e2ca85S dst->e_type = src->e_type;
44780e2ca85S dst->e_machine = src->e_machine;
44880e2ca85S dst->e_version = src->e_version;
44980e2ca85S dst->e_entry = src->e_entry;
45080e2ca85S dst->e_phoff = src->e_phoff;
45180e2ca85S dst->e_shoff = src->e_shoff;
45280e2ca85S dst->e_flags = src->e_flags;
45380e2ca85S dst->e_ehsize = src->e_ehsize;
45480e2ca85S dst->e_phentsize = src->e_phentsize;
45580e2ca85S dst->e_phnum = src->e_phnum;
45680e2ca85S dst->e_shentsize = src->e_shentsize;
45780e2ca85S dst->e_shnum = src->e_shnum;
45880e2ca85S dst->e_shstrndx = src->e_shstrndx;
45980e2ca85S }
46080e2ca85S #endif /* _LP64 */
46180e2ca85S
46280e2ca85S /*
46380e2ca85S * Return -1 if the cmd was not handled by this function.
46480e2ca85S */
46580e2ca85S /*ARGSUSED*/
46680e2ca85S int
brand_solaris_cmd(int cmd,uintptr_t arg1,uintptr_t arg2,uintptr_t arg3,struct brand * pbrand,int brandvers)46780e2ca85S brand_solaris_cmd(int cmd, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3,
46880e2ca85S struct brand *pbrand, int brandvers)
46980e2ca85S {
47080e2ca85S brand_proc_data_t *spd;
47180e2ca85S brand_proc_reg_t reg;
472