brand.c revision 9a5d73e03cd3312ddb571a748c40a63c58bd66e5
/*
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <sys/machbrand.h>
#define SUPPORTED_BRAND_VERSION BRAND_VER_1
#if defined(__sparcv9)
/* sparcv9 uses system wide brand interposition hooks */
static void brand_plat_interposition_enable(void);
static void brand_plat_interposition_disable(void);
struct brand_mach_ops native_mach_ops = {
};
#else /* !__sparcv9 */
struct brand_mach_ops native_mach_ops = {
};
#endif /* !__sparcv9 */
brand_t native_brand = {
"native",
NULL,
};
/*
* Used to maintain a list of all the brands currently loaded into the
* kernel.
*/
struct brand_list {
int bl_refcnt;
struct brand_list *bl_next;
};
/*
* This lock protects the integrity of the brand list.
*/
static kmutex_t brand_list_lock;
void
{
}
int
{
return (EINVAL);
"brand '%s' was built to run on older versions "
"of Solaris.",
} else {
"brand '%s' was built to run on a newer version "
"of Solaris.",
}
return (EINVAL);
}
/* Sanity checks */
return (EINVAL);
}
/* Add the brand to the list of loaded brands. */
/*
* Check to be sure we haven't already registered this brand.
*/
"Invalid attempt to load a second instance of "
return (EINVAL);
}
}
#if defined(__sparcv9)
/* sparcv9 uses system wide brand interposition hooks */
if (brand_list == NULL)
#endif /* __sparcv9 */
brand_list = list;
return (0);
}
/*
* The kernel module implementing this brand is being unloaded, so remove
* it from the list of active brands.
*/
int
{
/* Sanity checks */
return (EINVAL);
}
break;
}
return (EINVAL);
}
return (EBUSY);
}
/* Remove brand from the list */
else
#if defined(__sparcv9)
/* sparcv9 uses system wide brand interposition hooks */
if (brand_list == NULL)
#endif /* __sparcv9 */
return (0);
}
/*
* Record that a zone of this brand has been instantiated. If the kernel
* module implementing this brand's functionality is not present, this
* routine attempts to load the module as a side effect.
*/
brand_t *
{
struct brand_list *l = NULL;
char *modname;
int err = 0;
if (is_system_labeled()) {
"Branded zones are not allowed on labeled systems.");
return (NULL);
}
/*
* We make at most two passes through this loop. The first time
* through, we're looking to see if this is a new user of an
* already loaded brand. If the brand hasn't been loaded, we
* call ddi_modopen() to force it to be loaded and then make a
* second pass through the list of brands. If we don't find the
* brand the second time through it means that the modname
* specified in the brand_attr structure doesn't provide the brand
* specified in the brandname field. This would suggest a bug in
* the brand's config.xml file. We close the module and return
* 'NULL' to the caller.
*/
for (;;) {
/*
* Search list of loaded brands
*/
break;
break;
/*
* We didn't find that the requested brand has been loaded
* yet, so we trigger the load of the appropriate kernel
* module and search the list again.
*/
if (err != 0)
return (NULL);
}
/*
* If we found the matching brand, bump its reference count.
*/
if (l != NULL)
l->bl_refcnt++;
(void) ddi_modclose(hdl);
}
/*
* Return the number of zones currently using this brand.
*/
int
{
struct brand_list *l;
int cnt = 0;
break;
}
return (cnt);
}
void
{
struct brand_list *list;
break;
}
}
}
void
brand_setbrand(proc_t *p)
{
/*
* We should only be called from exec(), when we know the process
* is single-threaded.
*/
ASSERT(PROC_IS_BRANDED(p));
BROP(p)->b_setbrand(p);
}
void
{
/*
* We should only be called from exec_common() or proc_exit(),
* when we know the process is single-threaded.
*/
ASSERT(PROC_IS_BRANDED(p));
p->p_brand = &native_brand;
}
#if defined(__sparcv9)
/*
* Currently, only sparc has system level brand syscall interposition.
* On x86 we're able to enable syscall interposition on a per-cpu basis
* when a branded thread is scheduled to run on a cpu.
*/
/* Local variables needed for dynamic syscall interposition support */
/* Trap Table syscall entry hot patch points */
extern void syscall_trap_patch_point(void);
extern void syscall_trap32_patch_point(void);
/* Alternate syscall entry handlers used when branded zones are running */
extern void syscall_wrapper(void);
extern void syscall_wrapper32(void);
/* Macros used to facilitate sparcv9 instruction generation */
/*ARGSUSED*/
static void
{
/*
* Before we hot patch the kernel save the current instructions
* so that we can restore them later.
*/
/*
* Modify the trap table at the patch points.
*
* We basically replace the first instruction at the patch
* point with a ba,a instruction that will transfer control
* to syscall_wrapper or syscall_wrapper32 for 64-bit and
* 32-bit syscalls respectively. It's important to note that
* the annul bit is set in the branch so we don't execute
* the instruction directly following the one we're patching
* during the branch's delay slot.
*
* It also doesn't matter that we're not atomically updating both
* the 64 and 32 bit syscall paths at the same time since there's
* no actual branded processes running on the system yet.
*/
4);
4);
}
/*ARGSUSED*/
static void
{
/*
* Restore the original instructions at the trap table syscall
* patch points to disable the brand syscall interposition
* mechanism.
*/
}
#endif /* __sparcv9 */