sn1_brand.c revision 8fd04b8338ed5093ec2d1e668fa620b7de44c177
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2010 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/archsystm.h>
#include <sys/pathname.h>
#include <sys/machbrand.h>
#include "sn1_brand.h"
char *sn1_emulation_table = NULL;
void sn1_init_brand_data(zone_t *);
void sn1_free_brand_data(zone_t *);
void sn1_setbrand(proc_t *);
void sn1_exec();
int sn1_initlwp(klwp_t *);
void sn1_freelwp(klwp_t *);
void sn1_lwpexit(klwp_t *);
/* sn1 brand */
};
#ifdef sparc
struct brand_mach_ops sn1_mops = {
};
#else /* sparc */
#ifdef __amd64
struct brand_mach_ops sn1_mops = {
NULL,
};
#else /* ! __amd64 */
struct brand_mach_ops sn1_mops = {
NULL,
NULL,
NULL,
};
#endif /* __amd64 */
#endif /* _sparc */
"sn1",
};
&mod_brandops, /* type of module */
"Solaris N-1 Brand", /* description of module */
&sn1_brand /* driver ops */
};
static struct modlinkage modlinkage = {
};
void
sn1_setbrand(proc_t *p)
{
/*
* We should only be called from exec(), when we know the process
* is single-threaded.
*/
}
/* ARGSUSED */
int
{
return (EINVAL);
}
/* ARGSUSED */
int
{
return (EINVAL);
}
/*
* Get the address of the user-space system call handler from the user
* process and attach it to the proc structure.
*/
/*ARGSUSED*/
int
{
int err;
*rval = 0;
/*
* There is one operation that is suppored for non-branded
* process. B_EXEC_BRAND. This brand operaion is redundant
* since the kernel assumes a native process doing an exec
* in a branded zone is going to run a branded processes.
* hence we don't support this operation.
*/
if (cmd == B_EXEC_BRAND)
return (ENOSYS);
/* For all other operations this must be a branded process. */
if (p->p_brand == &native_brand)
return (ENOSYS);
switch (cmd) {
case B_EXEC_NATIVE:
err = exec_common(
return (err);
case B_REGISTER:
if (p->p_model == DATAMODEL_NATIVE) {
return (EFAULT);
#if defined(_LP64)
} else {
return (EFAULT);
#endif /* _LP64 */
}
return (ENOTSUP);
return (0);
case B_ELFDATA:
if (p->p_model == DATAMODEL_NATIVE) {
sizeof (sn1_elf_data_t)) != 0)
return (EFAULT);
#if defined(_LP64)
} else {
return (EFAULT);
#endif /* _LP64 */
}
return (0);
}
return (EINVAL);
}
/*
* Copy the per-process brand data from a parent proc to a child.
*/
void
{
/* Just duplicate all the proc data of the parent for the child */
}
/*ARGSUSED*/
void
{
/*
* We should only be called from proc_exit(), when we know that
* process is single-threaded.
*/
/* upon exit, free our lwp brand data */
/* upon exit, free our proc brand data */
p->p_brand_data = NULL;
}
void
sn1_exec()
{
/*
* We should only be called from exec(), when we know the process
* is single-threaded.
*/
/* Upon exec, reset our lwp brand data. */
/*
* Upon exec, reset all the proc brand data, except for the elf
* data associated with the executable we are exec'ing.
*/
}
/*ARGSUSED*/
int
sn1_initlwp(klwp_t *l)
{
l->lwp_brand = (void *)-1;
return (0);
}
/*ARGSUSED*/
void
{
/* Both LWPs have already had been initialized via sn1_initlwp() */
}
/*ARGSUSED*/
void
sn1_freelwp(klwp_t *l)
{
}
/*ARGSUSED*/
void
sn1_lwpexit(klwp_t *l)
{
/*
* We should never be called for the last thread in a process.
* (That case is handled by sn1_proc_exit().) There for this lwp
* must be exiting from a multi-threaded process.
*/
}
/*ARGSUSED*/
void
{
}
/*ARGSUSED*/
void
{
}
#if defined(_LP64)
static void
{
}
#endif /* _LP64 */
int
int brand_action)
{
int interp;
int i, err;
char *linker;
/*
* We will exec the brand library and then map in the target
* application and (optionally) the brand's default linker.
*/
linker = SN1_LINKER;
#if defined(_LP64)
} else {
#endif /* _LP64 */
}
&nvp)) != 0) {
return (err);
}
#if defined(_LP64)
} else {
#endif /* _LP64 */
}
if (err != 0)
return (err);
/*
* The u_auxv vectors are set up by elfexec to point to the brand
* emulation library and linker. Save these so they can be copied to
* the specific brand aux vectors.
*/
for (i = 0; i < __KERN_NAUXV_IMPL; i++) {
case AT_SUN_LDDATA:
break;
case AT_BASE:
break;
case AT_ENTRY:
break;
case AT_PHDR:
break;
case AT_PHENT:
break;
case AT_PHNUM:
break;
default:
break;
}
}
/* Make sure the emulator has an entry point */
#if defined(_LP64)
} else {
else
#endif /* _LP64 */
}
if (err != 0)
return (err);
/*
* Save off the important properties of the executable. The brand
* library will ask us for this data later, when it is initializing
* and getting ready to transfer control to the brand application.
*/
else
if (interp) {
/*
* This is a shared object executable, so we need to
* pick a reasonable place to put the heap. Just don't
* use the first page.
*/
}
/*
* If the program needs an interpreter (most do), map it in and
* store relevant information about it in the aux vector, where
* the brand library can find it.
*/
return (err);
}
#if defined(_LP64)
} else {
else
#endif /* _LP64 */
}
if (err != 0)
return (err);
/*
* Now that we know the base address of the brand's linker,
* place it in the aux vector.
*/
} else {
/*
* This program has no interpreter. The brand library will
* jump to the address in the AT_SUN_BRAND_LDENTRY aux vector,
* so in this case, put the entry point of the main executable
* there.
*/
/*
* An executable with no interpreter, this must be a
* statically linked executable, which means we loaded
* it at the address specified in the elf header, in
* which case the e_entry field of the elf header is an
* absolute address.
*/
} else {
/*
* A shared object with no interpreter, we use the
* calculated address from above.
*/
/*
* Delay setting the brkbase until the first
* call to brk(); see elfexec() for details.
*/
env.ex_brksize = 0;
}
}
}
setexecenv(&env);
/*
* It's time to manipulate the process aux vectors. First
* we need to update the AT_SUN_AUXFLAGS aux vector to set
* the AF_SUN_NOPLM flag.
*/
sizeof (auxflags_auxv)) != 0)
return (EFAULT);
sizeof (auxflags_auxv)) != 0)
return (EFAULT);
#if defined(_LP64)
} else {
sizeof (auxflags_auxv32)) != 0)
return (EFAULT);
sizeof (auxflags_auxv32)) != 0)
return (EFAULT);
#endif /* _LP64 */
}
/* Second, copy out the brand specific aux vectors. */
{ AT_SUN_BRAND_AUX1, 0 },
{ AT_SUN_BRAND_AUX2, 0 },
{ AT_SUN_BRAND_AUX3, 0 }
};
sizeof (sn1_auxv)) != 0)
return (EFAULT);
#if defined(_LP64)
} else {
auxv32_t sn1_auxv32[] = {
{ AT_SUN_BRAND_AUX1, 0 },
{ AT_SUN_BRAND_AUX2, 0 },
{ AT_SUN_BRAND_AUX3, 0 }
};
sizeof (sn1_auxv32)) != 0)
return (EFAULT);
#endif /* _LP64 */
}
/*
* Third, the the /proc aux vectors set up by elfexec() point to brand
* emulation library and it's linker. Copy these to the /proc brand
* specific aux vector, and update the regular /proc aux vectors to
* point to the executable (and it's linker). This will enable
* debuggers to access the executable via the usual /proc or elf notes
* aux vectors.
*
* The brand emulation library's linker will get it's aux vectors off
* the stack, and then update the stack with the executable's aux
* vectors before jumping to the executable's linker.
*
* Debugging the brand emulation library must be done from
* the global zone, where the librtld_db module knows how to fetch the
* brand specific aux vectors to access the brand emulation libraries
* linker.
*/
for (i = 0; i < __KERN_NAUXV_IMPL; i++) {
case AT_SUN_BRAND_SN1_LDDATA:
continue;
case AT_BASE:
break;
case AT_ENTRY:
break;
case AT_PHDR:
break;
case AT_PHENT:
break;
case AT_PHNUM:
break;
case AT_SUN_LDDATA:
break;
default:
continue;
}
/* Hide the entry for static binaries */
}
}
/*
* The last thing we do here is clear spd->spd_handler. This is
* important because if we're already a branded process and if this
* exec succeeds, there is a window between when the exec() first
* returns to the userland of the new process and when our brand
* library get's initialized, during which we don't want system
* calls to be re-directed to our brand library since it hasn't
* been initialized yet.
*/
return (0);
}
int
_init(void)
{
int err;
/*
* Set up the table indicating which system calls we want to
* interpose on. We should probably build this automatically from
* a list of system calls that is shared with the user-space
* library.
*/
if (err) {
}
return (err);
}
int
{
}
int
_fini(void)
{
int err;
/*
* If there are any zones using this brand, we can't allow it to be
* unloaded.
*/
if (brand_zone_count(&sn1_brand))
return (EBUSY);
if (err)
return (err);
}