#include <sys/kmem.h>
#include <sys/errno.h>
#include <sys/systm.h>
#include <sys/cmn_err.h>
#include <sys/brand.h>
#include <sys/machbrand.h>
#include <sys/modctl.h>
#include <sys/rwlock.h>
#include <sys/zone.h>
#include <sys/pathname.h>
#define SUPPORTED_BRAND_VERSION BRAND_VER_1
#if defined(__sparcv9)
static void brand_plat_interposition_enable(void);
static void brand_plat_interposition_disable(void);
struct brand_mach_ops native_mach_ops = {
NULL, NULL
};
#else
struct brand_mach_ops native_mach_ops = {
NULL, NULL, NULL, NULL
};
#endif
brand_t native_brand = {
BRAND_VER_1,
"native",
NULL,
&native_mach_ops
};
struct brand_list {
int bl_refcnt;
struct brand_list *bl_next;
brand_t *bl_brand;
};
static struct brand_list *brand_list = NULL;
static kmutex_t brand_list_lock;
void
brand_init()
{
mutex_init(&brand_list_lock, NULL, MUTEX_DEFAULT, NULL);
p0.p_brand = &native_brand;
}
int
brand_register(brand_t *brand)
{
struct brand_list *list, *scan;
if (brand == NULL)
return (EINVAL);
if (brand->b_version != SUPPORTED_BRAND_VERSION) {
if (brand->b_version < SUPPORTED_BRAND_VERSION) {
cmn_err(CE_WARN,
"brand '%s' was built to run on older versions "
"of Solaris.",
brand->b_name);
} else {
cmn_err(CE_WARN,
"brand '%s' was built to run on a newer version "
"of Solaris.",
brand->b_name);
}
return (EINVAL);
}
if (brand->b_name == NULL || brand->b_ops == NULL ||
brand->b_ops->b_brandsys == NULL) {
cmn_err(CE_WARN, "Malformed brand");
return (EINVAL);
}
list = kmem_alloc(sizeof (struct brand_list), KM_SLEEP);
mutex_enter(&brand_list_lock);
for (scan = brand_list; scan != NULL; scan = scan->bl_next) {
if (strcmp(brand->b_name, scan->bl_brand->b_name) == 0) {
cmn_err(CE_WARN,
"Invalid attempt to load a second instance of "
"brand %s", brand->b_name);
mutex_exit(&brand_list_lock);
kmem_free(list, sizeof (struct brand_list));
return (EINVAL);
}
}
#if defined(__sparcv9)
if (brand_list == NULL)
brand_plat_interposition_enable();
#endif
list->bl_brand = brand;
list->bl_refcnt = 0;
list->bl_next = brand_list;
brand_list = list;
mutex_exit(&brand_list_lock);
return (0);
}
int
brand_unregister(brand_t *brand)
{
struct brand_list *list, *prev;
if (brand == NULL || brand->b_name == NULL) {
cmn_err(CE_WARN, "Malformed brand");
return (EINVAL);
}
prev = NULL;
mutex_enter(&brand_list_lock);
for (list = brand_list; list != NULL; list = list->bl_next) {
if (list->bl_brand == brand)
break;
prev = list;
}
if (list == NULL) {
cmn_err(CE_WARN, "Brand %s wasn't registered", brand->b_name);
mutex_exit(&brand_list_lock);
return (EINVAL);
}
if (list->bl_refcnt > 0) {
cmn_err(CE_WARN, "Unregistering brand %s which is still in use",
brand->b_name);
mutex_exit(&brand_list_lock);
return (EBUSY);
}
if (prev != NULL)
prev->bl_next = list->bl_next;
else
brand_list = list->bl_next;
#if defined(__sparcv9)
if (brand_list == NULL)
brand_plat_interposition_disable();
#endif
mutex_exit(&brand_list_lock);
kmem_free(list, sizeof (struct brand_list));
return (0);
}
brand_t *
brand_register_zone(struct brand_attr *attr)
{
struct brand_list *l = NULL;
ddi_modhandle_t hdl = NULL;
char *modname;
int err = 0;
if (is_system_labeled()) {
cmn_err(CE_WARN,
"Branded zones are not allowed on labeled systems.");
return (NULL);
}
for (;;) {
mutex_enter(&brand_list_lock);
for (l = brand_list; l != NULL; l = l->bl_next)
if (strcmp(attr->ba_brandname,
l->bl_brand->b_name) == 0)
break;
if ((l != NULL) || (hdl != NULL))
break;
mutex_exit(&brand_list_lock);
modname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
(void) strcpy(modname, "brand/");
(void) strcat(modname, attr->ba_modname);
hdl = ddi_modopen(modname, KRTLD_MODE_FIRST, &err);
kmem_free(modname, MAXPATHLEN);
if (err != 0)
return (NULL);
}
if (l != NULL)
l->bl_refcnt++;
mutex_exit(&brand_list_lock);
if (hdl != NULL)
(void) ddi_modclose(hdl);
return ((l != NULL) ? l->bl_brand : NULL);
}
int
brand_zone_count(struct brand *bp)
{
struct brand_list *l;
int cnt = 0;
mutex_enter(&brand_list_lock);
for (l = brand_list; l != NULL; l = l->bl_next)
if (l->bl_brand == bp) {
cnt = l->bl_refcnt;
break;
}
mutex_exit(&brand_list_lock);
return (cnt);
}
void
brand_unregister_zone(struct brand *bp)
{
struct brand_list *list;
mutex_enter(&brand_list_lock);
for (list = brand_list; list != NULL; list = list->bl_next) {
if (list->bl_brand == bp) {
ASSERT(list->bl_refcnt > 0);
list->bl_refcnt--;
break;
}
}
mutex_exit(&brand_list_lock);
}
void
brand_setbrand(proc_t *p)
{
brand_t *bp = p->p_zone->zone_brand;
ASSERT(bp != NULL);
ASSERT(p->p_brand == &native_brand);
ASSERT(p->p_tlist == p->p_tlist->t_forw);
p->p_brand = bp;
ASSERT(PROC_IS_BRANDED(p));
BROP(p)->b_setbrand(p);
}
void
brand_clearbrand(proc_t *p, boolean_t no_lwps)
{
brand_t *bp = p->p_zone->zone_brand;
klwp_t *lwp = NULL;
ASSERT(bp != NULL);
ASSERT(!no_lwps || (p->p_tlist == NULL));
if (!no_lwps) {
ASSERT(p->p_tlist == p->p_tlist->t_forw);
lwp = p->p_tlist->t_lwp;
}
ASSERT(PROC_IS_BRANDED(p));
BROP(p)->b_proc_exit(p, lwp);
p->p_brand = &native_brand;
}
#if defined(__sparcv9)
static uint32_t syscall_trap_patch_instr_orig;
static uint32_t syscall_trap32_patch_instr_orig;
extern void syscall_trap_patch_point(void);
extern void syscall_trap32_patch_point(void);
extern void syscall_wrapper(void);
extern void syscall_wrapper32(void);
#define BA_A_INSTR 0x30800000
#define DISP22(from, to) \
((((uintptr_t)(to) - (uintptr_t)(from)) >> 2) & 0x3fffff)
static void
brand_plat_interposition_enable(void)
{
ASSERT(MUTEX_HELD(&brand_list_lock));
syscall_trap_patch_instr_orig =
*(uint32_t *)syscall_trap_patch_point;
syscall_trap32_patch_instr_orig =
*(uint32_t *)syscall_trap32_patch_point;
hot_patch_kernel_text((caddr_t)syscall_trap_patch_point,
BA_A_INSTR | DISP22(syscall_trap_patch_point, syscall_wrapper),
4);
hot_patch_kernel_text((caddr_t)syscall_trap32_patch_point,
BA_A_INSTR | DISP22(syscall_trap32_patch_point, syscall_wrapper32),
4);
}
static void
brand_plat_interposition_disable(void)
{
ASSERT(MUTEX_HELD(&brand_list_lock));
hot_patch_kernel_text((caddr_t)syscall_trap_patch_point,
syscall_trap_patch_instr_orig, 4);
hot_patch_kernel_text((caddr_t)syscall_trap32_patch_point,
syscall_trap32_patch_instr_orig, 4);
}
#endif
#if defined(_LP64)
static void
Ehdr32to64(Elf32_Ehdr *src, Ehdr *dst)
{
bcopy(src->e_ident, dst->e_ident, sizeof (src->e_ident));
dst->e_type = src->e_type;
dst->e_machine = src->e_machine;
dst->e_version = src->e_version;
dst->e_entry = src->e_entry;
dst->e_phoff = src->e_phoff;
dst->e_shoff = src->e_shoff;
dst->e_flags = src->e_flags;
dst->e_ehsize = src->e_ehsize;
dst->e_phentsize = src->e_phentsize;
dst->e_phnum = src->e_phnum;
dst->e_shentsize = src->e_shentsize;
dst->e_shnum = src->e_shnum;
dst->e_shstrndx = src->e_shstrndx;
}
#endif
int
brand_solaris_cmd(int cmd, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3,
struct brand *pbrand, int brandvers)
{
brand_proc_data_t *spd;
brand_proc_reg_t reg;
proc_t *p = curproc;
int err;
if (cmd == B_EXEC_BRAND)
return (ENOSYS);
if (p->p_brand == &native_brand)
return (ENOSYS);
ASSERT(p->p_brand == pbrand);
ASSERT(p->p_brand_data != NULL);
spd = (brand_proc_data_t *)p->p_brand_data;
switch ((cmd)) {
case B_EXEC_NATIVE:
err = exec_common((char *)arg1, (const char **)arg2,
(const char **)arg3, NULL, EBA_NATIVE);
return (err);
case B_REGISTER:
if (p->p_model == DATAMODEL_NATIVE) {
if (copyin((void *)arg1, ®, sizeof (reg)) != 0)
return (EFAULT);
}
#if defined(_LP64)
else {
brand_common_reg32_t reg32;
if (copyin((void *)arg1, ®32, sizeof (reg32)) != 0)
return (EFAULT);
reg.sbr_version = reg32.sbr_version;
reg.sbr_handler = (caddr_t)(uintptr_t)reg32.sbr_handler;
}
#endif
if (reg.sbr_version != brandvers)
return (ENOTSUP);
spd->spd_handler = reg.sbr_handler;
return (0);
case B_ELFDATA:
if (p->p_model == DATAMODEL_NATIVE) {
if (copyout(&spd->spd_elf_data, (void *)arg1,
sizeof (brand_elf_data_t)) != 0)
return (EFAULT);
}
#if defined(_LP64)
else {
brand_elf_data32_t sed32;
sed32.sed_phdr = spd->spd_elf_data.sed_phdr;
sed32.sed_phent = spd->spd_elf_data.sed_phent;
sed32.sed_phnum = spd->spd_elf_data.sed_phnum;
sed32.sed_entry = spd->spd_elf_data.sed_entry;
sed32.sed_base = spd->spd_elf_data.sed_base;
sed32.sed_ldentry = spd->spd_elf_data.sed_ldentry;
sed32.sed_lddata = spd->spd_elf_data.sed_lddata;
if (copyout(&sed32, (void *)arg1, sizeof (sed32))
!= 0)
return (EFAULT);
}
#endif
return (0);
case B_TRUSS_POINT:
return ((arg2 == 0) ? 0 : set_errno((uint_t)arg2));
}
return (-1);
}
void
brand_solaris_copy_procdata(proc_t *child, proc_t *parent, struct brand *pbrand)
{
brand_proc_data_t *spd;
ASSERT(parent->p_brand == pbrand);
ASSERT(child->p_brand == pbrand);
ASSERT(parent->p_brand_data != NULL);
ASSERT(child->p_brand_data == NULL);
spd = kmem_alloc(sizeof (brand_proc_data_t), KM_SLEEP);
bcopy(parent->p_brand_data, spd, sizeof (brand_proc_data_t));
child->p_brand_data = spd;
}
static void
restoreexecenv(struct execenv *ep, stack_t *sp)
{
klwp_t *lwp = ttolwp(curthread);
setexecenv(ep);
lwp->lwp_sigaltstack.ss_sp = sp->ss_sp;
lwp->lwp_sigaltstack.ss_size = sp->ss_size;
lwp->lwp_sigaltstack.ss_flags = sp->ss_flags;
}
int
brand_solaris_elfexec(vnode_t *vp, execa_t *uap, uarg_t *args,
intpdata_t *idatap, int level, size_t *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)
{
vnode_t *nvp;
Ehdr ehdr;
Addr uphdr_vaddr;
intptr_t voffset;
int interp;
int i, err;
struct execenv env;
struct execenv origenv;
stack_t orig_sigaltstack;
struct user *up = PTOU(curproc);
proc_t *p = ttoproc(curthread);
klwp_t *lwp = ttolwp(curthread);
brand_proc_data_t *spd;
brand_elf_data_t sed, *sedp;
char *linker;
uintptr_t lddata;
ASSERT(curproc->p_brand == pbrand);
ASSERT(curproc->p_brand_data != NULL);
spd = (brand_proc_data_t *)curproc->p_brand_data;
sedp = &spd->spd_elf_data;
args->brandname = bname;
if (args->to_model == DATAMODEL_NATIVE) {
args->emulator = brandlib;
linker = brandlinker;
}
#if defined(_LP64)
else {
args->emulator = brandlib32;
linker = brandlinker32;
}
#endif
if ((err = lookupname(args->emulator, UIO_SYSSPACE, FOLLOW,
NULLVPP, &nvp)) != 0) {
uprintf("%s: not found.", args->emulator);
return (err);
}
origenv.ex_bssbase = p->p_bssbase;
origenv.ex_brkbase = p->p_brkbase;
origenv.ex_brksize = p->p_brksize;
origenv.ex_vp = p->p_exec;
orig_sigaltstack.ss_sp = lwp->lwp_sigaltstack.ss_sp;
orig_sigaltstack.ss_size = lwp->lwp_sigaltstack.ss_size;
orig_sigaltstack.ss_flags = lwp->lwp_sigaltstack.ss_flags;
if (args->to_model == DATAMODEL_NATIVE) {
err = elfexec(nvp, uap, args, idatap, INTP_MAXDEPTH + 1, execsz,
setid, exec_file, cred, brand_action);
}
#if defined(_LP64)
else {
err = elf32exec(nvp, uap, args, idatap, INTP_MAXDEPTH + 1,
execsz, setid, exec_file, cred, brand_action);
}
#endif
VN_RELE(nvp);
if (err != 0) {
restoreexecenv(&origenv, &orig_sigaltstack);
return (err);
}
bzero(&sed, sizeof (sed));
for (i = 0; i < __KERN_NAUXV_IMPL; i++) {
switch (up->u_auxv[i].a_type) {
case AT_SUN_LDDATA:
sed.sed_lddata = up->u_auxv[i].a_un.a_val;
break;
case AT_BASE:
sed.sed_base = up->u_auxv[i].a_un.a_val;
break;
case AT_ENTRY:
sed.sed_entry = up->u_auxv[i].a_un.a_val;
break;
case AT_PHDR:
sed.sed_phdr = up->u_auxv[i].a_un.a_val;
break;
case AT_PHENT:
sed.sed_phent = up->u_auxv[i].a_un.a_val;
break;
case AT_PHNUM:
sed.sed_phnum = up->u_auxv[i].a_un.a_val;
break;
default:
break;
}
}
ASSERT(sed.sed_entry != 0);
ASSERT(sed.sed_phdr != 0);
bzero(&env, sizeof (env));
if (args->to_model == DATAMODEL_NATIVE) {
err = mapexec_brand(vp, args, &ehdr, &uphdr_vaddr,
&voffset, exec_file, &interp, &env.ex_bssbase,
&env.ex_brkbase, &env.ex_brksize, NULL);
}
#if defined(_LP64)
else {
Elf32_Ehdr ehdr32;
Elf32_Addr uphdr_vaddr32;
err = mapexec32_brand(vp, args, &ehdr32, &uphdr_vaddr32,
&voffset, exec_file, &interp, &env.ex_bssbase,
&env.ex_brkbase, &env.ex_brksize, NULL);
Ehdr32to64(&ehdr32, &ehdr);
if (uphdr_vaddr32 == (Elf32_Addr)-1)
uphdr_vaddr = (Addr)-1;
else
uphdr_vaddr = uphdr_vaddr32;
}
#endif
if (err != 0) {
restoreexecenv(&origenv, &orig_sigaltstack);
return (err);
}
if (uphdr_vaddr == (Addr)-1)
sedp->sed_phdr = voffset + ehdr.e_phoff;
else
sedp->sed_phdr = voffset + uphdr_vaddr;
sedp->sed_entry = voffset + ehdr.e_entry;
sedp->sed_phent = ehdr.e_phentsize;
sedp->sed_phnum = ehdr.e_phnum;
if (interp) {
if (ehdr.e_type == ET_DYN) {
env.ex_brkbase = (caddr_t)PAGESIZE;
env.ex_bssbase = (caddr_t)PAGESIZE;
}
if ((err = lookupname(linker, UIO_SYSSPACE,
FOLLOW, NULLVPP, &nvp)) != 0) {
uprintf("%s: not found.", brandlinker);
restoreexecenv(&origenv, &orig_sigaltstack);
return (err);
}
if (args->to_model == DATAMODEL_NATIVE) {
err = mapexec_brand(nvp, args, &ehdr,
&uphdr_vaddr, &voffset, exec_file, &interp,
NULL, NULL, NULL, &lddata);
}
#if defined(_LP64)
else {
Elf32_Ehdr ehdr32;
Elf32_Addr uphdr_vaddr32;
err = mapexec32_brand(nvp, args, &ehdr32,
&uphdr_vaddr32, &voffset, exec_file, &interp,
NULL, NULL, NULL, &lddata);
Ehdr32to64(&ehdr32, &ehdr);
if (uphdr_vaddr32 == (Elf32_Addr)-1)
uphdr_vaddr = (Addr)-1;
else
uphdr_vaddr = uphdr_vaddr32;
}
#endif
VN_RELE(nvp);
if (err != 0) {
restoreexecenv(&origenv, &orig_sigaltstack);
return (err);
}
sedp->sed_base = voffset;
sedp->sed_ldentry = voffset + ehdr.e_entry;
sedp->sed_lddata = voffset + lddata;
} else {
if (ehdr.e_type == ET_EXEC) {
sedp->sed_ldentry = ehdr.e_entry;
sedp->sed_entry = ehdr.e_entry;
sedp->sed_lddata = 0;
sedp->sed_base = 0;
} else {
sedp->sed_ldentry = sedp->sed_entry;
sedp->sed_entry = 0;
sedp->sed_phdr = 0;
sedp->sed_phent = 0;
sedp->sed_phnum = 0;
sedp->sed_lddata = 0;
sedp->sed_base = voffset;
if (ehdr.e_type == ET_DYN) {
env.ex_bssbase = (caddr_t)0;
env.ex_brkbase = (caddr_t)0;
env.ex_brksize = 0;
}
}
}
env.ex_magic = elfmagic;
env.ex_vp = vp;
setexecenv(&env);
if (args->to_model == DATAMODEL_NATIVE) {
auxv_t auxflags_auxv;
if (copyin(args->auxp_auxflags, &auxflags_auxv,
sizeof (auxflags_auxv)) != 0)
return (EFAULT);
ASSERT(auxflags_auxv.a_type == AT_SUN_AUXFLAGS);
auxflags_auxv.a_un.a_val |= AF_SUN_NOPLM;
if (copyout(&auxflags_auxv, args->auxp_auxflags,
sizeof (auxflags_auxv)) != 0)
return (EFAULT);
}
#if defined(_LP64)
else {
auxv32_t auxflags_auxv32;
if (copyin(args->auxp_auxflags, &auxflags_auxv32,
sizeof (auxflags_auxv32)) != 0)
return (EFAULT);
ASSERT(auxflags_auxv32.a_type == AT_SUN_AUXFLAGS);
auxflags_auxv32.a_un.a_val |= AF_SUN_NOPLM;
if (copyout(&auxflags_auxv32, args->auxp_auxflags,
sizeof (auxflags_auxv32)) != 0)
return (EFAULT);
}
#endif
if (args->to_model == DATAMODEL_NATIVE) {
auxv_t brand_auxv[] = {
{ AT_SUN_BRAND_AUX1, 0 },
{ AT_SUN_BRAND_AUX2, 0 },
{ AT_SUN_BRAND_AUX3, 0 }
};
ASSERT(brand_auxv[0].a_type ==
AT_SUN_BRAND_COMMON_LDDATA);
brand_auxv[0].a_un.a_val = sed.sed_lddata;
if (copyout(&brand_auxv, args->auxp_brand,
sizeof (brand_auxv)) != 0)
return (EFAULT);
}
#if defined(_LP64)
else {
auxv32_t brand_auxv32[] = {
{ AT_SUN_BRAND_AUX1, 0 },
{ AT_SUN_BRAND_AUX2, 0 },
{ AT_SUN_BRAND_AUX3, 0 }
};
ASSERT(brand_auxv32[0].a_type == AT_SUN_BRAND_COMMON_LDDATA);
brand_auxv32[0].a_un.a_val = (uint32_t)sed.sed_lddata;
if (copyout(&brand_auxv32, args->auxp_brand,
sizeof (brand_auxv32)) != 0)
return (EFAULT);
}
#endif
for (i = 0; i < __KERN_NAUXV_IMPL; i++) {
ulong_t val;
switch (up->u_auxv[i].a_type) {
case AT_SUN_BRAND_COMMON_LDDATA:
up->u_auxv[i].a_un.a_val = sed.sed_lddata;
continue;
case AT_BASE:
val = sedp->sed_base;
break;
case AT_ENTRY:
val = sedp->sed_entry;
break;
case AT_PHDR:
val = sedp->sed_phdr;
break;
case AT_PHENT:
val = sedp->sed_phent;
break;
case AT_PHNUM:
val = sedp->sed_phnum;
break;
case AT_SUN_LDDATA:
val = sedp->sed_lddata;
break;
default:
continue;
}
up->u_auxv[i].a_un.a_val = val;
if (val == 0) {
up->u_auxv[i].a_type = AT_IGNORE;
}
}
spd->spd_handler = NULL;
return (0);
}
void
brand_solaris_exec(struct brand *pbrand)
{
brand_proc_data_t *spd = curproc->p_brand_data;
ASSERT(curproc->p_brand == pbrand);
ASSERT(curproc->p_brand_data != NULL);
ASSERT(ttolwp(curthread)->lwp_brand != NULL);
ASSERT(curproc->p_tlist == curproc->p_tlist->t_forw);
(void) brand_solaris_freelwp(ttolwp(curthread), pbrand);
(void) brand_solaris_initlwp(ttolwp(curthread), pbrand);
spd->spd_handler = NULL;
}
int
brand_solaris_fini(char **emul_table, struct modlinkage *modlinkage,
struct brand *pbrand)
{
int err;
if (brand_zone_count(pbrand))
return (EBUSY);
kmem_free(*emul_table, NSYSCALL);
*emul_table = NULL;
err = mod_remove(modlinkage);
if (err)
cmn_err(CE_WARN, "Couldn't unload brand module");
return (err);
}
void
brand_solaris_forklwp(klwp_t *p, klwp_t *c, struct brand *pbrand)
{
ASSERT(p->lwp_procp->p_brand == pbrand);
ASSERT(c->lwp_procp->p_brand == pbrand);
ASSERT(p->lwp_procp->p_brand_data != NULL);
ASSERT(c->lwp_procp->p_brand_data != NULL);
ASSERT(p->lwp_brand != NULL);
ASSERT(c->lwp_brand != NULL);
}
void
brand_solaris_freelwp(klwp_t *l, struct brand *pbrand)
{
ASSERT(l->lwp_procp->p_brand == pbrand);
ASSERT(l->lwp_procp->p_brand_data != NULL);
ASSERT(l->lwp_brand != NULL);
l->lwp_brand = NULL;
}
int
brand_solaris_initlwp(klwp_t *l, struct brand *pbrand)
{
ASSERT(l->lwp_procp->p_brand == pbrand);
ASSERT(l->lwp_procp->p_brand_data != NULL);
ASSERT(l->lwp_brand == NULL);
l->lwp_brand = (void *)-1;
return (0);
}
void
brand_solaris_lwpexit(klwp_t *l, struct brand *pbrand)
{
proc_t *p = l->lwp_procp;
ASSERT(l->lwp_procp->p_brand == pbrand);
ASSERT(l->lwp_procp->p_brand_data != NULL);
ASSERT(l->lwp_brand != NULL);
ASSERT(p->p_tlist != p->p_tlist->t_forw);
l->lwp_brand = NULL;
}
void
brand_solaris_proc_exit(struct proc *p, klwp_t *l, struct brand *pbrand)
{
ASSERT(p->p_brand == pbrand);
ASSERT(p->p_brand_data != NULL);
if (l != NULL) {
ASSERT(p->p_tlist == p->p_tlist->t_forw);
ASSERT(p->p_tlist->t_lwp == l);
(void) brand_solaris_freelwp(l, pbrand);
}
kmem_free(p->p_brand_data, sizeof (brand_proc_data_t));
p->p_brand_data = NULL;
}
void
brand_solaris_setbrand(proc_t *p, struct brand *pbrand)
{
ASSERT(p->p_brand == pbrand);
ASSERT(p->p_brand_data == NULL);
ASSERT(p->p_tlist == p->p_tlist->t_forw);
p->p_brand_data = kmem_zalloc(sizeof (brand_proc_data_t), KM_SLEEP);
(void) brand_solaris_initlwp(p->p_tlist->t_lwp, pbrand);
}