1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/errno.h>
29 #include <sys/exec.h>
30 #include <sys/kmem.h>
31 #include <sys/modctl.h>
32 #include <sys/model.h>
33 #include <sys/proc.h>
34 #include <sys/syscall.h>
35 #include <sys/systm.h>
36 #include <sys/thread.h>
37 #include <sys/cmn_err.h>
38 #include <sys/archsystm.h>
39 
40 #include <sys/machbrand.h>
41 #include <sys/brand.h>
42 #include "sn1_brand.h"
43 
44 char *sn1_emulation_table = NULL;
45 
46 void	sn1_setbrand(proc_t *);
47 int	sn1_getattr(zone_t *, int, void *, size_t *);
48 int	sn1_setattr(zone_t *, int, void *, size_t);
49 int	sn1_brandsys(int, int64_t *, uintptr_t, uintptr_t, uintptr_t,
50 		uintptr_t, uintptr_t, uintptr_t);
51 void	sn1_copy_procdata(proc_t *, proc_t *);
52 void	sn1_proc_exit(struct proc *, klwp_t *);
53 void	sn1_exec();
54 int	sn1_initlwp(klwp_t *);
55 void	sn1_forklwp(klwp_t *, klwp_t *);
56 void	sn1_freelwp(klwp_t *);
57 void	sn1_lwpexit(klwp_t *);
58 int	sn1_elfexec(vnode_t *, execa_t *, uarg_t *, intpdata_t *, int,
59 	long *, int, caddr_t, cred_t *, int);
60 
61 /* sn1 brand */
62 struct brand_ops sn1_brops = {
63 	sn1_brandsys,
64 	sn1_setbrand,
65 	sn1_getattr,
66 	sn1_setattr,
67 	sn1_copy_procdata,
68 	sn1_proc_exit,
69 	sn1_exec,
70 	lwp_setrval,
71 	sn1_initlwp,
72 	sn1_forklwp,
73 	sn1_freelwp,
74 	sn1_lwpexit,
75 	sn1_elfexec
76 };
77 
78 #ifdef	sparc
79 
80 struct brand_mach_ops sn1_mops = {
81 	sn1_brand_syscall_callback,
82 	sn1_brand_syscall_callback
83 };
84 
85 #else	/* sparc */
86 
87 #ifdef	__amd64
88 
89 struct brand_mach_ops sn1_mops = {
90 	sn1_brand_sysenter_callback,
91 	NULL,
92 	sn1_brand_int91_callback,
93 	sn1_brand_syscall_callback,
94 	sn1_brand_syscall32_callback,
95 	NULL
96 };
97 
98 #else	/* ! __amd64 */
99 
100 struct brand_mach_ops sn1_mops = {
101 	sn1_brand_sysenter_callback,
102 	NULL,
103 	NULL,
104 	sn1_brand_syscall_callback,
105 	NULL,
106 	NULL
107 };
108 #endif	/* __amd64 */
109 
110 #endif	/* _sparc */
111 
112 struct brand	sn1_brand = {
113 	BRAND_VER_1,
114 	"sn1",
115 	&sn1_brops,
116 	&sn1_mops
117 };
118 
119 static struct modlbrand modlbrand = {
120 	&mod_brandops, "Solaris N-1 Brand %I%", &sn1_brand
121 };
122 
123 static struct modlinkage modlinkage = {
124 	MODREV_1, (void *)&modlbrand, NULL
125 };
126 
127 void
128 sn1_setbrand(proc_t *p)
129 {
130 	p->p_brand_data = NULL;
131 	p->p_brand = &sn1_brand;
132 }
133 
134 /* ARGSUSED */
135 int
136 sn1_getattr(zone_t *zone, int attr, void *buf, size_t *bufsize)
137 {
138 	return (EINVAL);
139 }
140 
141 /* ARGSUSED */
142 int
143 sn1_setattr(zone_t *zone, int attr, void *buf, size_t bufsize)
144 {
145 	return (EINVAL);
146 }
147 
148 /*
149  * Get the address of the user-space system call handler from the user
150  * process and attach it to the proc structure.
151  */
152 /*ARGSUSED*/
153 int
154 sn1_brandsys(int cmd, int64_t *rval, uintptr_t arg1, uintptr_t arg2,
155     uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, uintptr_t arg6)
156 {
157 	proc_t *p = curproc;
158 	*rval = 0;
159 
160 	if (cmd == B_REGISTER) {
161 		p->p_brand = &sn1_brand;
162 		p->p_brand_data = (void *) arg1;
163 		return (0);
164 	}
165 
166 	ASSERT(p->p_brand == &sn1_brand);
167 
168 	return (EINVAL);
169 }
170 
171 /*
172  * Copy the per-process brand data from a parent proc to a child.  In the
173  * sn1 brand, the only per-process state is the address of the user-space
174  * handler.
175  */
176 void
177 sn1_copy_procdata(proc_t *child, proc_t *parent)
178 {
179 	child->p_brand_data = parent->p_brand_data;
180 }
181 
182 /*ARGSUSED*/
183 void
184 sn1_proc_exit(struct proc *p, klwp_t *l)
185 {
186 	p->p_brand_data = NULL;
187 	p->p_brand = &native_brand;
188 }
189 
190 void
191 sn1_exec()
192 {
193 	curproc->p_brand_data = NULL;
194 }
195 
196 /*ARGSUSED*/
197 int
198 sn1_initlwp(klwp_t *l)
199 {
200 	return (0);
201 }
202 
203 /*ARGSUSED*/
204 void
205 sn1_forklwp(klwp_t *p, klwp_t *c)
206 {
207 }
208 
209 /*ARGSUSED*/
210 void
211 sn1_freelwp(klwp_t *l)
212 {
213 }
214 
215 /*ARGSUSED*/
216 void
217 sn1_lwpexit(klwp_t *l)
218 {
219 }
220 
221 int
222 sn1_elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
223 	int level, long *execsz, int setid, caddr_t exec_file, cred_t *cred,
224 	int brand_action)
225 {
226 	args->brandname = "sn1";
227 	return ((args->execswp->exec_func)(vp, uap, args, idatap, level + 1,
228 	    execsz, setid, exec_file, cred, brand_action));
229 }
230 
231 
232 int
233 _init(void)
234 {
235 	int err;
236 
237 #if defined(sparc) && !defined(DEBUG)
238 	cmn_err(CE_WARN, "The sn1 brand is only supported on DEBUG kernels.");
239 	return (ENOTSUP);
240 #else
241 
242 	/*
243 	 * Set up the table indicating which system calls we want to
244 	 * interpose on.  We should probably build this automatically from
245 	 * a list of system calls that is shared with the user-space
246 	 * library.
247 	 */
248 	sn1_emulation_table = kmem_zalloc(NSYSCALL, KM_SLEEP);
249 	sn1_emulation_table[SYS_uname] = 1;
250 	sn1_emulation_table[SYS_fork1] = 1;
251 
252 	err = mod_install(&modlinkage);
253 	if (err) {
254 		cmn_err(CE_WARN, "Couldn't install brand module");
255 		kmem_free(sn1_emulation_table, NSYSCALL);
256 	}
257 
258 	return (err);
259 #endif
260 }
261 
262 int
263 _info(struct modinfo *modinfop)
264 {
265 	return (mod_info(&modlinkage, modinfop));
266 }
267 
268 int
269 _fini(void)
270 {
271 	int err;
272 
273 	/*
274 	 * If there are any zones using this brand, we can't allow it to be
275 	 * unloaded.
276 	 */
277 	if (brand_zone_count(&sn1_brand))
278 		return (EBUSY);
279 
280 	kmem_free(sn1_emulation_table, NSYSCALL);
281 	sn1_emulation_table = NULL;
282 
283 	err = mod_remove(&modlinkage);
284 	if (err)
285 		cmn_err(CE_WARN, "Couldn't unload sn1 brand module");
286 
287 	return (err);
288 }
289