xref: /freebsd/sys/kern/kern_module.c (revision 059d68dea6538607311da1414fae1b373e4ce74d)
1cea6c86cSDoug Rabson /*-
2cea6c86cSDoug Rabson  * Copyright (c) 1997 Doug Rabson
3cea6c86cSDoug Rabson  * All rights reserved.
4cea6c86cSDoug Rabson  *
5cea6c86cSDoug Rabson  * Redistribution and use in source and binary forms, with or without
6cea6c86cSDoug Rabson  * modification, are permitted provided that the following conditions
7cea6c86cSDoug Rabson  * are met:
8cea6c86cSDoug Rabson  * 1. Redistributions of source code must retain the above copyright
9cea6c86cSDoug Rabson  *    notice, this list of conditions and the following disclaimer.
10cea6c86cSDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
11cea6c86cSDoug Rabson  *    notice, this list of conditions and the following disclaimer in the
12cea6c86cSDoug Rabson  *    documentation and/or other materials provided with the distribution.
13cea6c86cSDoug Rabson  *
14cea6c86cSDoug Rabson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15cea6c86cSDoug Rabson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16cea6c86cSDoug Rabson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17cea6c86cSDoug Rabson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18cea6c86cSDoug Rabson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19cea6c86cSDoug Rabson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20cea6c86cSDoug Rabson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21cea6c86cSDoug Rabson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22cea6c86cSDoug Rabson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23cea6c86cSDoug Rabson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24cea6c86cSDoug Rabson  * SUCH DAMAGE.
25cea6c86cSDoug Rabson  */
26cea6c86cSDoug Rabson 
270e214fadSPaul Saab #include "opt_compat.h"
280e214fadSPaul Saab 
29677b542eSDavid E. O'Brien #include <sys/cdefs.h>
30677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
31677b542eSDavid E. O'Brien 
32cea6c86cSDoug Rabson #include <sys/param.h>
33cea6c86cSDoug Rabson #include <sys/kernel.h>
34cea6c86cSDoug Rabson #include <sys/systm.h>
35fcb893a8SMike Smith #include <sys/eventhandler.h>
36cea6c86cSDoug Rabson #include <sys/malloc.h>
37cea6c86cSDoug Rabson #include <sys/sysproto.h>
38cea6c86cSDoug Rabson #include <sys/sysent.h>
39cb226aaaSPoul-Henning Kamp #include <sys/proc.h>
40835a82eeSMatthew Dillon #include <sys/lock.h>
41835a82eeSMatthew Dillon #include <sys/mutex.h>
421a1c04b6SDon Lewis #include <sys/reboot.h>
439b3851e9SAndrew R. Reiter #include <sys/sx.h>
449b3851e9SAndrew R. Reiter #include <sys/module.h>
459b3851e9SAndrew R. Reiter #include <sys/linker.h>
46cea6c86cSDoug Rabson 
47959b7375SPoul-Henning Kamp static MALLOC_DEFINE(M_MODULE, "module", "module data structures");
48cea6c86cSDoug Rabson 
49e3975643SJake Burkholder typedef TAILQ_HEAD(, module) modulelist_t;
50cea6c86cSDoug Rabson struct module {
51e3975643SJake Burkholder 	TAILQ_ENTRY(module)	link;	/* chain together all modules */
52e3975643SJake Burkholder 	TAILQ_ENTRY(module)	flink;	/* all modules in a file */
53cea6c86cSDoug Rabson 	struct linker_file	*file;	/* file which contains this module */
54cea6c86cSDoug Rabson 	int			refs;	/* reference count */
55cea6c86cSDoug Rabson 	int 			id;	/* unique id number */
56cea6c86cSDoug Rabson 	char 			*name;	/* module name */
57cea6c86cSDoug Rabson 	modeventhand_t 		handler;	/* event handler */
58cea6c86cSDoug Rabson 	void 			*arg;	/* argument for handler */
59a35261efSDoug Rabson 	modspecific_t 		data;	/* module specific data */
60cea6c86cSDoug Rabson };
61cea6c86cSDoug Rabson 
62cea6c86cSDoug Rabson #define MOD_EVENT(mod, type)	(mod)->handler((mod), (type), (mod)->arg)
63cea6c86cSDoug Rabson 
64cea6c86cSDoug Rabson static modulelist_t modules;
659b3851e9SAndrew R. Reiter struct sx modules_sx;
66cea6c86cSDoug Rabson static int nextid = 1;
67fcb893a8SMike Smith static void module_shutdown(void *, int);
68cea6c86cSDoug Rabson 
69845ccef4SPeter Wemm static int
70845ccef4SPeter Wemm modevent_nop(module_t mod, int what, void *arg)
71845ccef4SPeter Wemm {
72e2ad640eSPoul-Henning Kamp 
73e2ad640eSPoul-Henning Kamp 	switch(what) {
74e2ad640eSPoul-Henning Kamp 	case MOD_LOAD:
75b65420f9SAndrew R. Reiter 		return (0);
76e2ad640eSPoul-Henning Kamp 	case MOD_UNLOAD:
77e2ad640eSPoul-Henning Kamp 		return (EBUSY);
78e2ad640eSPoul-Henning Kamp 	default:
79e2ad640eSPoul-Henning Kamp 		return (EOPNOTSUPP);
80e2ad640eSPoul-Henning Kamp 	}
81845ccef4SPeter Wemm }
82845ccef4SPeter Wemm 
83cea6c86cSDoug Rabson static void
84cea6c86cSDoug Rabson module_init(void *arg)
85cea6c86cSDoug Rabson {
86287698b4SAndrew R. Reiter 
879b3851e9SAndrew R. Reiter 	sx_init(&modules_sx, "module subsystem sx lock");
88cea6c86cSDoug Rabson 	TAILQ_INIT(&modules);
892488f309SPeter Wemm 	EVENTHANDLER_REGISTER(shutdown_final, module_shutdown, NULL,
90fcb893a8SMike Smith 	    SHUTDOWN_PRI_DEFAULT);
91cea6c86cSDoug Rabson }
92cea6c86cSDoug Rabson 
93287698b4SAndrew R. Reiter SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0)
94cea6c86cSDoug Rabson 
95cea6c86cSDoug Rabson static void
96fcb893a8SMike Smith module_shutdown(void *arg1, int arg2)
97cea6c86cSDoug Rabson {
98cea6c86cSDoug Rabson 	module_t mod;
99cea6c86cSDoug Rabson 
1001a1c04b6SDon Lewis 	if (arg2 & RB_NOSYNC)
1011a1c04b6SDon Lewis 		return;
1029b3851e9SAndrew R. Reiter 	MOD_SLOCK;
103fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(mod, &modules, link)
104cea6c86cSDoug Rabson 		MOD_EVENT(mod, MOD_SHUTDOWN);
1059b3851e9SAndrew R. Reiter 	MOD_SUNLOCK;
106cea6c86cSDoug Rabson }
107cea6c86cSDoug Rabson 
108cea6c86cSDoug Rabson void
1093cfc69e6SMatthew Dillon module_register_init(const void *arg)
110cea6c86cSDoug Rabson {
1113cfc69e6SMatthew Dillon 	const moduledata_t *data = (const moduledata_t *)arg;
112cea6c86cSDoug Rabson 	int error;
113b5b15c3fSPeter Wemm 	module_t mod;
114cea6c86cSDoug Rabson 
1159b3851e9SAndrew R. Reiter 	MOD_SLOCK;
116b5b15c3fSPeter Wemm 	mod = module_lookupbyname(data->name);
117b5b15c3fSPeter Wemm 	if (mod == NULL)
118287698b4SAndrew R. Reiter 		panic("module_register_init: module named %s not found\n",
119287698b4SAndrew R. Reiter 		    data->name);
1209b3851e9SAndrew R. Reiter 	MOD_SUNLOCK;
121b5b15c3fSPeter Wemm 	error = MOD_EVENT(mod, MOD_LOAD);
122b5b15c3fSPeter Wemm 	if (error) {
123b5b15c3fSPeter Wemm 		MOD_EVENT(mod, MOD_UNLOAD);
1249b3851e9SAndrew R. Reiter 		MOD_XLOCK;
125b5b15c3fSPeter Wemm 		module_release(mod);
1269b3851e9SAndrew R. Reiter 		MOD_XUNLOCK;
127bd47bef5SPeter Wemm 		printf("module_register_init: MOD_LOAD (%s, %p, %p) error"
128bd47bef5SPeter Wemm 		    " %d\n", data->name, (void *)data->evhand, data->priv,
129287698b4SAndrew R. Reiter 		    error);
130cea6c86cSDoug Rabson 	}
131b5b15c3fSPeter Wemm }
132cea6c86cSDoug Rabson 
133cea6c86cSDoug Rabson int
134b5b15c3fSPeter Wemm module_register(const moduledata_t *data, linker_file_t container)
135cea6c86cSDoug Rabson {
136cea6c86cSDoug Rabson 	size_t namelen;
137cea6c86cSDoug Rabson 	module_t newmod;
138cea6c86cSDoug Rabson 
139059d68deSMaxim Konovalov 	MOD_XLOCK;
140b5b15c3fSPeter Wemm 	newmod = module_lookupbyname(data->name);
141b5b15c3fSPeter Wemm 	if (newmod != NULL) {
142059d68deSMaxim Konovalov 		MOD_XUNLOCK;
143287698b4SAndrew R. Reiter 		printf("module_register: module %s already exists!\n",
144287698b4SAndrew R. Reiter 		    data->name);
145b65420f9SAndrew R. Reiter 		return (EEXIST);
146b5b15c3fSPeter Wemm 	}
147b5b15c3fSPeter Wemm 	namelen = strlen(data->name) + 1;
148a163d034SWarner Losh 	newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK);
149059d68deSMaxim Konovalov 	if (newmod == NULL) {
150059d68deSMaxim Konovalov 		MOD_XUNLOCK;
151b65420f9SAndrew R. Reiter 		return (ENOMEM);
152059d68deSMaxim Konovalov 	}
153cea6c86cSDoug Rabson 	newmod->refs = 1;
154cea6c86cSDoug Rabson 	newmod->id = nextid++;
155cea6c86cSDoug Rabson 	newmod->name = (char *)(newmod + 1);
156b5b15c3fSPeter Wemm 	strcpy(newmod->name, data->name);
157845ccef4SPeter Wemm 	newmod->handler = data->evhand ? data->evhand : modevent_nop;
158b5b15c3fSPeter Wemm 	newmod->arg = data->priv;
159a35261efSDoug Rabson 	bzero(&newmod->data, sizeof(newmod->data));
160cea6c86cSDoug Rabson 	TAILQ_INSERT_TAIL(&modules, newmod, link);
161cea6c86cSDoug Rabson 
162b5b15c3fSPeter Wemm 	if (container)
163f3b0d442SPeter Wemm 		TAILQ_INSERT_TAIL(&container->modules, newmod, flink);
1641d23cba9SPeter Wemm 	newmod->file = container;
1659b3851e9SAndrew R. Reiter 	MOD_XUNLOCK;
166b65420f9SAndrew R. Reiter 	return (0);
167cea6c86cSDoug Rabson }
168cea6c86cSDoug Rabson 
169cea6c86cSDoug Rabson void
170cea6c86cSDoug Rabson module_reference(module_t mod)
171cea6c86cSDoug Rabson {
172cea6c86cSDoug Rabson 
1739b3851e9SAndrew R. Reiter 	MOD_XLOCK_ASSERT;
1749b3851e9SAndrew R. Reiter 
175287698b4SAndrew R. Reiter 	MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
176cea6c86cSDoug Rabson 	mod->refs++;
177cea6c86cSDoug Rabson }
178cea6c86cSDoug Rabson 
179cea6c86cSDoug Rabson void
180cea6c86cSDoug Rabson module_release(module_t mod)
181cea6c86cSDoug Rabson {
182287698b4SAndrew R. Reiter 
1839b3851e9SAndrew R. Reiter 	MOD_XLOCK_ASSERT;
1849b3851e9SAndrew R. Reiter 
185cea6c86cSDoug Rabson 	if (mod->refs <= 0)
186cea6c86cSDoug Rabson 		panic("module_release: bad reference count");
187cea6c86cSDoug Rabson 
188cea6c86cSDoug Rabson 	MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
189cea6c86cSDoug Rabson 
190cea6c86cSDoug Rabson 	mod->refs--;
191cea6c86cSDoug Rabson 	if (mod->refs == 0) {
192cea6c86cSDoug Rabson 		TAILQ_REMOVE(&modules, mod, link);
193287698b4SAndrew R. Reiter 		if (mod->file)
194cea6c86cSDoug Rabson 			TAILQ_REMOVE(&mod->file->modules, mod, flink);
1959b3851e9SAndrew R. Reiter 		MOD_XUNLOCK;
196cea6c86cSDoug Rabson 		free(mod, M_MODULE);
1979b3851e9SAndrew R. Reiter 		MOD_XLOCK;
198cea6c86cSDoug Rabson 	}
199cea6c86cSDoug Rabson }
200cea6c86cSDoug Rabson 
201cea6c86cSDoug Rabson module_t
202cea6c86cSDoug Rabson module_lookupbyname(const char *name)
203cea6c86cSDoug Rabson {
204cea6c86cSDoug Rabson 	module_t mod;
205287698b4SAndrew R. Reiter 	int err;
206cea6c86cSDoug Rabson 
2079b3851e9SAndrew R. Reiter 	MOD_LOCK_ASSERT;
2089b3851e9SAndrew R. Reiter 
209fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(mod, &modules, link) {
210287698b4SAndrew R. Reiter 		err = strcmp(mod->name, name);
211287698b4SAndrew R. Reiter 		if (err == 0)
212b65420f9SAndrew R. Reiter 			return (mod);
213cea6c86cSDoug Rabson 	}
214b65420f9SAndrew R. Reiter 	return (NULL);
215cea6c86cSDoug Rabson }
216cea6c86cSDoug Rabson 
217cea6c86cSDoug Rabson module_t
218cea6c86cSDoug Rabson module_lookupbyid(int modid)
219cea6c86cSDoug Rabson {
220cea6c86cSDoug Rabson         module_t mod;
221cea6c86cSDoug Rabson 
2229b3851e9SAndrew R. Reiter         MOD_LOCK_ASSERT;
2239b3851e9SAndrew R. Reiter 
2249b3851e9SAndrew R. Reiter         TAILQ_FOREACH(mod, &modules, link)
225cea6c86cSDoug Rabson                 if (mod->id == modid)
226b65420f9SAndrew R. Reiter                         return(mod);
227b65420f9SAndrew R. Reiter         return (NULL);
228cea6c86cSDoug Rabson }
229cea6c86cSDoug Rabson 
230cea6c86cSDoug Rabson int
23165a311fcSPoul-Henning Kamp module_unload(module_t mod, int flags)
232cea6c86cSDoug Rabson {
23365a311fcSPoul-Henning Kamp 	int error;
234287698b4SAndrew R. Reiter 
23565a311fcSPoul-Henning Kamp 	error = MOD_EVENT(mod, MOD_QUIESCE);
2363e019deaSPoul-Henning Kamp 	if (error == EOPNOTSUPP || error == EINVAL)
23765a311fcSPoul-Henning Kamp 		error = 0;
23865a311fcSPoul-Henning Kamp 	if (flags == LINKER_UNLOAD_NORMAL && error != 0)
23965a311fcSPoul-Henning Kamp 		return (error);
240b65420f9SAndrew R. Reiter         return (MOD_EVENT(mod, MOD_UNLOAD));
241cea6c86cSDoug Rabson }
242cea6c86cSDoug Rabson 
243cea6c86cSDoug Rabson int
244cea6c86cSDoug Rabson module_getid(module_t mod)
245cea6c86cSDoug Rabson {
246287698b4SAndrew R. Reiter 
2479b3851e9SAndrew R. Reiter 	MOD_LOCK_ASSERT;
248b65420f9SAndrew R. Reiter 	return (mod->id);
249cea6c86cSDoug Rabson }
250cea6c86cSDoug Rabson 
251cea6c86cSDoug Rabson module_t
252cea6c86cSDoug Rabson module_getfnext(module_t mod)
253cea6c86cSDoug Rabson {
254287698b4SAndrew R. Reiter 
2559b3851e9SAndrew R. Reiter 	MOD_LOCK_ASSERT;
256b65420f9SAndrew R. Reiter 	return (TAILQ_NEXT(mod, flink));
257cea6c86cSDoug Rabson }
258cea6c86cSDoug Rabson 
259a35261efSDoug Rabson void
260a35261efSDoug Rabson module_setspecific(module_t mod, modspecific_t *datap)
261a35261efSDoug Rabson {
262287698b4SAndrew R. Reiter 
2639b3851e9SAndrew R. Reiter 	MOD_XLOCK_ASSERT;
264a35261efSDoug Rabson 	mod->data = *datap;
265a35261efSDoug Rabson }
266a35261efSDoug Rabson 
2672971c361SJohn Baldwin linker_file_t
2682971c361SJohn Baldwin module_file(module_t mod)
2692971c361SJohn Baldwin {
2702971c361SJohn Baldwin 
2712971c361SJohn Baldwin 	return (mod->file);
2722971c361SJohn Baldwin }
2732971c361SJohn Baldwin 
274cea6c86cSDoug Rabson /*
275cea6c86cSDoug Rabson  * Syscalls.
276cea6c86cSDoug Rabson  */
277835a82eeSMatthew Dillon /*
278835a82eeSMatthew Dillon  * MPSAFE
279835a82eeSMatthew Dillon  */
280cea6c86cSDoug Rabson int
281b40ce416SJulian Elischer modnext(struct thread *td, struct modnext_args *uap)
282cea6c86cSDoug Rabson {
283cea6c86cSDoug Rabson 	module_t mod;
284835a82eeSMatthew Dillon 	int error = 0;
285835a82eeSMatthew Dillon 
286b40ce416SJulian Elischer 	td->td_retval[0] = -1;
287e024f583SAndrew R. Reiter 
2889b3851e9SAndrew R. Reiter 	MOD_SLOCK;
289d1e405c5SAlfred Perlstein 	if (uap->modid == 0) {
290cea6c86cSDoug Rabson 		mod = TAILQ_FIRST(&modules);
291835a82eeSMatthew Dillon 		if (mod)
292b40ce416SJulian Elischer 			td->td_retval[0] = mod->id;
293835a82eeSMatthew Dillon 		else
294835a82eeSMatthew Dillon 			error = ENOENT;
295835a82eeSMatthew Dillon 		goto done2;
296cea6c86cSDoug Rabson 	}
297d1e405c5SAlfred Perlstein 	mod = module_lookupbyid(uap->modid);
298835a82eeSMatthew Dillon 	if (mod == NULL) {
299835a82eeSMatthew Dillon 		error = ENOENT;
300835a82eeSMatthew Dillon 		goto done2;
301835a82eeSMatthew Dillon 	}
302cea6c86cSDoug Rabson 	if (TAILQ_NEXT(mod, link))
303b40ce416SJulian Elischer 		td->td_retval[0] = TAILQ_NEXT(mod, link)->id;
304cea6c86cSDoug Rabson 	else
305b40ce416SJulian Elischer 		td->td_retval[0] = 0;
306835a82eeSMatthew Dillon done2:
3079b3851e9SAndrew R. Reiter 	MOD_SUNLOCK;
308835a82eeSMatthew Dillon 	return (error);
309cea6c86cSDoug Rabson }
310cea6c86cSDoug Rabson 
311835a82eeSMatthew Dillon /*
312835a82eeSMatthew Dillon  * MPSAFE
313835a82eeSMatthew Dillon  */
314cea6c86cSDoug Rabson int
315b40ce416SJulian Elischer modfnext(struct thread *td, struct modfnext_args *uap)
316cea6c86cSDoug Rabson {
317cea6c86cSDoug Rabson 	module_t mod;
318835a82eeSMatthew Dillon 	int error;
319cea6c86cSDoug Rabson 
320b40ce416SJulian Elischer 	td->td_retval[0] = -1;
321cea6c86cSDoug Rabson 
3229b3851e9SAndrew R. Reiter 	MOD_SLOCK;
323d1e405c5SAlfred Perlstein 	mod = module_lookupbyid(uap->modid);
324835a82eeSMatthew Dillon 	if (mod == NULL) {
325835a82eeSMatthew Dillon 		error = ENOENT;
326835a82eeSMatthew Dillon 	} else {
327835a82eeSMatthew Dillon 		error = 0;
328cea6c86cSDoug Rabson 		if (TAILQ_NEXT(mod, flink))
329b40ce416SJulian Elischer 			td->td_retval[0] = TAILQ_NEXT(mod, flink)->id;
330cea6c86cSDoug Rabson 		else
331b40ce416SJulian Elischer 			td->td_retval[0] = 0;
332835a82eeSMatthew Dillon 	}
3339b3851e9SAndrew R. Reiter 	MOD_SUNLOCK;
334835a82eeSMatthew Dillon 	return (error);
335cea6c86cSDoug Rabson }
336cea6c86cSDoug Rabson 
337a35261efSDoug Rabson struct module_stat_v1 {
338a35261efSDoug Rabson 	int	version;		/* set to sizeof(struct module_stat) */
339a35261efSDoug Rabson 	char	name[MAXMODNAME];
340a35261efSDoug Rabson 	int	refs;
341a35261efSDoug Rabson 	int	id;
342a35261efSDoug Rabson };
343a35261efSDoug Rabson 
344835a82eeSMatthew Dillon /*
345835a82eeSMatthew Dillon  * MPSAFE
346835a82eeSMatthew Dillon  */
347cea6c86cSDoug Rabson int
348b40ce416SJulian Elischer modstat(struct thread *td, struct modstat_args *uap)
349cea6c86cSDoug Rabson {
350cea6c86cSDoug Rabson 	module_t mod;
3519b3851e9SAndrew R. Reiter 	modspecific_t data;
352cea6c86cSDoug Rabson 	int error = 0;
3539b3851e9SAndrew R. Reiter 	int id, namelen, refs, version;
354cea6c86cSDoug Rabson 	struct module_stat *stat;
3559b3851e9SAndrew R. Reiter 	char *name;
356cea6c86cSDoug Rabson 
3579b3851e9SAndrew R. Reiter 	MOD_SLOCK;
358d1e405c5SAlfred Perlstein 	mod = module_lookupbyid(uap->modid);
359835a82eeSMatthew Dillon 	if (mod == NULL) {
3609b3851e9SAndrew R. Reiter 		MOD_SUNLOCK;
361e024f583SAndrew R. Reiter 		return (ENOENT);
362835a82eeSMatthew Dillon 	}
3639b3851e9SAndrew R. Reiter 	id = mod->id;
3649b3851e9SAndrew R. Reiter 	refs = mod->refs;
3659b3851e9SAndrew R. Reiter 	name = mod->name;
3669b3851e9SAndrew R. Reiter 	data = mod->data;
3679b3851e9SAndrew R. Reiter 	MOD_SUNLOCK;
368d1e405c5SAlfred Perlstein 	stat = uap->stat;
369cea6c86cSDoug Rabson 
370cea6c86cSDoug Rabson 	/*
371cea6c86cSDoug Rabson 	 * Check the version of the user's structure.
372cea6c86cSDoug Rabson 	 */
373d254af07SMatthew Dillon 	if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
374e024f583SAndrew R. Reiter 		return (error);
375a35261efSDoug Rabson 	if (version != sizeof(struct module_stat_v1)
376e024f583SAndrew R. Reiter 	    && version != sizeof(struct module_stat))
377e024f583SAndrew R. Reiter 		return (EINVAL);
378cea6c86cSDoug Rabson 	namelen = strlen(mod->name) + 1;
379cea6c86cSDoug Rabson 	if (namelen > MAXMODNAME)
380cea6c86cSDoug Rabson 		namelen = MAXMODNAME;
3819b3851e9SAndrew R. Reiter 	if ((error = copyout(name, &stat->name[0], namelen)) != 0)
382e024f583SAndrew R. Reiter 		return (error);
383cea6c86cSDoug Rabson 
3849b3851e9SAndrew R. Reiter 	if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0)
385e024f583SAndrew R. Reiter 		return (error);
3869b3851e9SAndrew R. Reiter 	if ((error = copyout(&id, &stat->id, sizeof(int))) != 0)
387e024f583SAndrew R. Reiter 		return (error);
388cea6c86cSDoug Rabson 
389a35261efSDoug Rabson 	/*
390a35261efSDoug Rabson 	 * >v1 stat includes module data.
391a35261efSDoug Rabson 	 */
392e024f583SAndrew R. Reiter 	if (version == sizeof(struct module_stat))
3939b3851e9SAndrew R. Reiter 		if ((error = copyout(&data, &stat->data,
3949b3851e9SAndrew R. Reiter 		    sizeof(data))) != 0)
395e024f583SAndrew R. Reiter 			return (error);
396b40ce416SJulian Elischer 	td->td_retval[0] = 0;
397b65420f9SAndrew R. Reiter 	return (error);
398cea6c86cSDoug Rabson }
399cea6c86cSDoug Rabson 
400835a82eeSMatthew Dillon /*
401835a82eeSMatthew Dillon  * MPSAFE
402835a82eeSMatthew Dillon  */
403cea6c86cSDoug Rabson int
404b40ce416SJulian Elischer modfind(struct thread *td, struct modfind_args *uap)
405cea6c86cSDoug Rabson {
406cea6c86cSDoug Rabson 	int error = 0;
407cea6c86cSDoug Rabson 	char name[MAXMODNAME];
408cea6c86cSDoug Rabson 	module_t mod;
409cea6c86cSDoug Rabson 
410d1e405c5SAlfred Perlstein 	if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0)
411e024f583SAndrew R. Reiter 		return (error);
412cea6c86cSDoug Rabson 
4139b3851e9SAndrew R. Reiter 	MOD_SLOCK;
414cea6c86cSDoug Rabson 	mod = module_lookupbyname(name);
415835a82eeSMatthew Dillon 	if (mod == NULL)
416cea6c86cSDoug Rabson 		error = ENOENT;
417cea6c86cSDoug Rabson 	else
4189b3851e9SAndrew R. Reiter 		td->td_retval[0] = module_getid(mod);
4199b3851e9SAndrew R. Reiter 	MOD_SUNLOCK;
420b65420f9SAndrew R. Reiter 	return (error);
421cea6c86cSDoug Rabson }
4220e214fadSPaul Saab 
4230e214fadSPaul Saab #ifdef COMPAT_IA32
4240e214fadSPaul Saab #include <sys/mount.h>
4250e214fadSPaul Saab #include <compat/freebsd32/freebsd32_util.h>
4260e214fadSPaul Saab #include <compat/freebsd32/freebsd32.h>
4270e214fadSPaul Saab #include <compat/freebsd32/freebsd32_proto.h>
4280e214fadSPaul Saab 
4290e214fadSPaul Saab typedef union modspecific32 {
4300e214fadSPaul Saab 	int		intval;
4310e214fadSPaul Saab 	u_int32_t	uintval;
4320e214fadSPaul Saab 	int		longval;
4330e214fadSPaul Saab 	u_int32_t	ulongval;
4340e214fadSPaul Saab } modspecific32_t;
4350e214fadSPaul Saab 
4360e214fadSPaul Saab struct module_stat32 {
4370e214fadSPaul Saab 	int		version;
4380e214fadSPaul Saab 	char		name[MAXMODNAME];
4390e214fadSPaul Saab 	int		refs;
4400e214fadSPaul Saab 	int		id;
4410e214fadSPaul Saab 	modspecific32_t	data;
4420e214fadSPaul Saab };
4430e214fadSPaul Saab 
4440e214fadSPaul Saab /*
4450e214fadSPaul Saab  * MPSAFE
4460e214fadSPaul Saab  */
4470e214fadSPaul Saab int
4480e214fadSPaul Saab freebsd32_modstat(struct thread *td, struct freebsd32_modstat_args *uap)
4490e214fadSPaul Saab {
4500e214fadSPaul Saab 	module_t mod;
4510e214fadSPaul Saab 	modspecific32_t data32;
4520e214fadSPaul Saab 	int error = 0;
4530e214fadSPaul Saab 	int id, namelen, refs, version;
4540e214fadSPaul Saab 	struct module_stat32 *stat32;
4550e214fadSPaul Saab 	char *name;
4560e214fadSPaul Saab 
4570e214fadSPaul Saab 	MOD_SLOCK;
4580e214fadSPaul Saab 	mod = module_lookupbyid(uap->modid);
4590e214fadSPaul Saab 	if (mod == NULL) {
4600e214fadSPaul Saab 		MOD_SUNLOCK;
4610e214fadSPaul Saab 		return (ENOENT);
4620e214fadSPaul Saab 	}
4630e214fadSPaul Saab 
4640e214fadSPaul Saab 	id = mod->id;
4650e214fadSPaul Saab 	refs = mod->refs;
4660e214fadSPaul Saab 	name = mod->name;
467b7820945SPaul Saab 	CP(mod->data, data32, intval);
468b7820945SPaul Saab 	CP(mod->data, data32, uintval);
469b7820945SPaul Saab 	CP(mod->data, data32, longval);
470b7820945SPaul Saab 	CP(mod->data, data32, ulongval);
4710e214fadSPaul Saab 	MOD_SUNLOCK;
4720e214fadSPaul Saab 	stat32 = uap->stat;
4730e214fadSPaul Saab 
4740e214fadSPaul Saab 	if ((error = copyin(&stat32->version, &version, sizeof(version))) != 0)
4750e214fadSPaul Saab 		return (error);
4760e214fadSPaul Saab 	if (version != sizeof(struct module_stat_v1)
4770e214fadSPaul Saab 	    && version != sizeof(struct module_stat32))
4780e214fadSPaul Saab 		return (EINVAL);
4790e214fadSPaul Saab 	namelen = strlen(mod->name) + 1;
4800e214fadSPaul Saab 	if (namelen > MAXMODNAME)
4810e214fadSPaul Saab 		namelen = MAXMODNAME;
4820e214fadSPaul Saab 	if ((error = copyout(name, &stat32->name[0], namelen)) != 0)
4830e214fadSPaul Saab 		return (error);
4840e214fadSPaul Saab 
4850e214fadSPaul Saab 	if ((error = copyout(&refs, &stat32->refs, sizeof(int))) != 0)
4860e214fadSPaul Saab 		return (error);
4870e214fadSPaul Saab 	if ((error = copyout(&id, &stat32->id, sizeof(int))) != 0)
4880e214fadSPaul Saab 		return (error);
4890e214fadSPaul Saab 
4900e214fadSPaul Saab 	/*
4910e214fadSPaul Saab 	 * >v1 stat includes module data.
4920e214fadSPaul Saab 	 */
4930e214fadSPaul Saab 	if (version == sizeof(struct module_stat32))
4940e214fadSPaul Saab 		if ((error = copyout(&data32, &stat32->data,
4950e214fadSPaul Saab 		    sizeof(data32))) != 0)
4960e214fadSPaul Saab 			return (error);
4970e214fadSPaul Saab 	td->td_retval[0] = 0;
4980e214fadSPaul Saab 	return (error);
4990e214fadSPaul Saab }
5000e214fadSPaul Saab #endif
501