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 2007 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_init_brand_data(zone_t *);
47 void	sn1_free_brand_data(zone_t *);
48 void	sn1_setbrand(proc_t *);
49 int	sn1_getattr(zone_t *, int, void *, size_t *);
50 int	sn1_setattr(zone_t *, int, void *, size_t);
51 int	sn1_brandsys(int, int64_t *, uintptr_t, uintptr_t, uintptr_t,
52 		uintptr_t, uintptr_t, uintptr_t);
53 void	sn1_copy_procdata(proc_t *, proc_t *);
54 void	sn1_proc_exit(struct proc *, klwp_t *);
55 void	sn1_exec();
56 int	sn1_initlwp(klwp_t *);
57 void	sn1_forklwp(klwp_t *, klwp_t *);
58 void	sn1_freelwp(klwp_t *);
59 void	sn1_lwpexit(klwp_t *);
60 int	sn1_elfexec(vnode_t *, execa_t *, uarg_t *, intpdata_t *, int,
61 	long *, int, caddr_t, cred_t *, int);
62 
63 /* sn1 brand */
64 struct brand_ops sn1_brops = {
65 	sn1_init_brand_data,
66 	sn1_free_brand_data,
67 	sn1_brandsys,
68 	sn1_setbrand,
69 	sn1_getattr,
70 	sn1_setattr,
71 	sn1_copy_procdata,
72 	sn1_proc_exit,
73 	sn1_exec,
74 	lwp_setrval,
75 	sn1_initlwp,
76 	sn1_forklwp,
77 	sn1_freelwp,
78 	sn1_lwpexit,
79 	sn1_elfexec
80 };
81 
82 #ifdef	sparc
83 
84 struct brand_mach_ops sn1_mops = {
85 	sn1_brand_syscall_callback,
86 	sn1_brand_syscall_callback
87 };
88 
89 #else	/* sparc */
90 
91 #ifdef	__amd64
92 
93 struct brand_mach_ops sn1_mops = {
94 	sn1_brand_sysenter_callback,
95 	NULL,
96 	sn1_brand_int91_callback,
97 	sn1_brand_syscall_callback,
98 	sn1_brand_syscall32_callback,
99 	NULL
100 };
101 
102 #else	/* ! __amd64 */
103 
104 struct brand_mach_ops sn1_mops = {
105 	sn1_brand_sysenter_callback,
106 	NULL,
107 	NULL,
108 	sn1_brand_syscall_callback,
109 	NULL,
110 	NULL
111 };
112 #endif	/* __amd64 */
113 
114 #endif	/* _sparc */
115 
116 struct brand	sn1_brand = {
117 	BRAND_VER_1,
118 	"sn1",
119 	&sn1_brops,
120 	&sn1_mops
121 };
122 
123 static struct modlbrand modlbrand = {
124 	&mod_brandops,		/* type of module */
125 	"Solaris N-1 Brand",	/* description of module */
126 	&sn1_brand		/* driver ops */
127 };
128 
129 static struct modlinkage modlinkage = {
130 	MODREV_1, (void *)&modlbrand, NULL
131 };
132 
133 void
134 sn1_setbrand(proc_t *p)
135 {
136 	p->p_brand_data = NULL;
137 	p->p_brand = &sn1_brand;
138 }
139 
140 /* ARGSUSED */
141 int
142 sn1_getattr(zone_t *zone, int attr, void *buf, size_t *bufsize)
143 {
144 	return (EINVAL);
145 }
146 
147 /* ARGSUSED */
148 int
149 sn1_setattr(zone_t *zone, int attr, void *buf, size_t bufsize)
150 {
151 	return (EINVAL);
152 }
153 
154 /*
155  * Get the address of the user-space system call handler from the user
156  * process and attach it to the proc structure.
157  */
158 /*ARGSUSED*/
159 int
160 sn1_brandsys(int cmd, int64_t *rval, uintptr_t arg1, uintptr_t arg2,
161     uintptr_t arg3, uintptr_t arg4, uintptr_t arg5, uintptr_t arg6)
162 {
163 	proc_t *p = curproc;
164 	*rval = 0;
165 
166 	if (cmd == B_REGISTER) {
167 		p->p_brand = &sn1_brand;
168 		p->p_brand_data = (void *) arg1;
169 		return (0);
170 	}
171 
172 	ASSERT(p->p_brand == &sn1_brand);
173 
174 	return (EINVAL);
175 }
176 
177 /*
178  * Copy the per-process brand data from a parent proc to a child.  In the
179  * sn1 brand, the only per-process state is the address of the user-space
180  * handler.
181  */
182 void
183 sn1_copy_procdata(proc_t *child, proc_t *parent)
184 {
185 	child->p_brand_data = parent->p_brand_data;
186 }
187 
188 /*ARGSUSED*/
189 void
190 sn1_proc_exit(struct proc *p, klwp_t *l)
191 {
192 	p->p_brand_data = NULL;
193 	p->p_brand = &native_brand;
194 }
195 
196 void
197 sn1_exec()
198 {
199 	curproc->p_brand_data = NULL;
200 }
201 
202 /*ARGSUSED*/
203 int
204 sn1_initlwp(klwp_t *l)
205 {
206 	return (0);
207 }
208 
209 /*ARGSUSED*/
210 void
211 sn1_init_brand_data(zone_t *zone)
212 {
213 }
214 
215 /*ARGSUSED*/
216 void
217 sn1_free_brand_data(zone_t *zone)
218 {
219 }
220 
221 /*ARGSUSED*/
222 void
223 sn1_forklwp(klwp_t *p, klwp_t *c)
224 {
225 }
226 
227 /*ARGSUSED*/
228 void
229 sn1_freelwp(klwp_t *l)
230 {
231 }
232 
233 /*ARGSUSED*/
234 void
235 sn1_lwpexit(klwp_t *l)
236 {
237 }
238 
239 int
240 sn1_elfexec(vnode_t *vp, execa_t *uap, uarg_t *args, intpdata_t *idatap,
241 	int level, long *execsz, int setid, caddr_t exec_file, cred_t *cred,
242 	int brand_action)
243 {
244 	args->brandname = "sn1";
245 	return ((args->execswp->exec_func)(vp, uap, args, idatap, level + 1,
246 	    execsz, setid, exec_file, cred, brand_action));
247 }
248 
249 
250 int
251 _init(void)
252 {
253 	int err;
254 
255 	/*
256 	 * Set up the table indicating which system calls we want to
257 	 * interpose on.  We should probably build this automatically from
258 	 * a list of system calls that is shared with the user-space
259 	 * library.
260 	 */
261 	sn1_emulation_table = kmem_zalloc(NSYSCALL, KM_SLEEP);
262 	sn1_emulation_table[SYS_uname] = 1;
263 
264 	err = mod_install(&modlinkage);
265 	if (err) {
266 		cmn_err(CE_WARN, "Couldn't install brand module");
267 		kmem_free(sn1_emulation_table, NSYSCALL);
268 	}
269 
270 	return (err);
271 }
272 
273 int
274 _info(struct modinfo *modinfop)
275 {
276 	return (mod_info(&modlinkage, modinfop));
277 }
278 
279 int
280 _fini(void)
281 {
282 	int err;
283 
284 	/*
285 	 * If there are any zones using this brand, we can't allow it to be
286 	 * unloaded.
287 	 */
288 	if (brand_zone_count(&sn1_brand))
289 		return (EBUSY);
290 
291 	kmem_free(sn1_emulation_table, NSYSCALL);
292 	sn1_emulation_table = NULL;
293 
294 	err = mod_remove(&modlinkage);
295 	if (err)
296 		cmn_err(CE_WARN, "Couldn't unload sn1 brand module");
297 
298 	return (err);
299 }
300