xref: /freebsd/sys/kern/kern_module.c (revision df38ada2931f95d07b65b19fcfb4c9845d656ba9)
1cea6c86cSDoug Rabson /*-
28a36da99SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
38a36da99SPedro F. Giffuni  *
4cea6c86cSDoug Rabson  * Copyright (c) 1997 Doug Rabson
5cea6c86cSDoug Rabson  * All rights reserved.
6cea6c86cSDoug Rabson  *
7cea6c86cSDoug Rabson  * Redistribution and use in source and binary forms, with or without
8cea6c86cSDoug Rabson  * modification, are permitted provided that the following conditions
9cea6c86cSDoug Rabson  * are met:
10cea6c86cSDoug Rabson  * 1. Redistributions of source code must retain the above copyright
11cea6c86cSDoug Rabson  *    notice, this list of conditions and the following disclaimer.
12cea6c86cSDoug Rabson  * 2. Redistributions in binary form must reproduce the above copyright
13cea6c86cSDoug Rabson  *    notice, this list of conditions and the following disclaimer in the
14cea6c86cSDoug Rabson  *    documentation and/or other materials provided with the distribution.
15cea6c86cSDoug Rabson  *
16cea6c86cSDoug Rabson  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17cea6c86cSDoug Rabson  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18cea6c86cSDoug Rabson  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19cea6c86cSDoug Rabson  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20cea6c86cSDoug Rabson  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21cea6c86cSDoug Rabson  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22cea6c86cSDoug Rabson  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23cea6c86cSDoug Rabson  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24cea6c86cSDoug Rabson  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25cea6c86cSDoug Rabson  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26cea6c86cSDoug Rabson  * SUCH DAMAGE.
27cea6c86cSDoug Rabson  */
28cea6c86cSDoug Rabson 
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 
49cea6c86cSDoug Rabson struct module {
50e3975643SJake Burkholder 	TAILQ_ENTRY(module)	link;	/* chain together all modules */
51e3975643SJake Burkholder 	TAILQ_ENTRY(module)	flink;	/* all modules in a file */
52cea6c86cSDoug Rabson 	struct linker_file	*file;	/* file which contains this module */
53cea6c86cSDoug Rabson 	int			refs;	/* reference count */
54cea6c86cSDoug Rabson 	int 			id;	/* unique id number */
55cea6c86cSDoug Rabson 	char 			*name;	/* module name */
56cea6c86cSDoug Rabson 	modeventhand_t 		handler;	/* event handler */
57cea6c86cSDoug Rabson 	void 			*arg;	/* argument for handler */
58a35261efSDoug Rabson 	modspecific_t 		data;	/* module specific data */
59cea6c86cSDoug Rabson };
60cea6c86cSDoug Rabson 
61cea6c86cSDoug Rabson #define MOD_EVENT(mod, type)	(mod)->handler((mod), (type), (mod)->arg)
62cea6c86cSDoug Rabson 
6357c15380SAttilio Rao static TAILQ_HEAD(modulelist, module) modules;
649b3851e9SAndrew R. Reiter struct sx modules_sx;
65cea6c86cSDoug Rabson static int nextid = 1;
66fcb893a8SMike Smith static void module_shutdown(void *, int);
67cea6c86cSDoug Rabson 
68845ccef4SPeter Wemm static int
69845ccef4SPeter Wemm modevent_nop(module_t mod, int what, void *arg)
70845ccef4SPeter Wemm {
71e2ad640eSPoul-Henning Kamp 
72e2ad640eSPoul-Henning Kamp 	switch(what) {
73e2ad640eSPoul-Henning Kamp 	case MOD_LOAD:
74b65420f9SAndrew R. Reiter 		return (0);
75e2ad640eSPoul-Henning Kamp 	case MOD_UNLOAD:
76e2ad640eSPoul-Henning Kamp 		return (EBUSY);
77e2ad640eSPoul-Henning Kamp 	default:
78e2ad640eSPoul-Henning Kamp 		return (EOPNOTSUPP);
79e2ad640eSPoul-Henning Kamp 	}
80845ccef4SPeter Wemm }
81845ccef4SPeter Wemm 
82cea6c86cSDoug Rabson static void
83cea6c86cSDoug Rabson module_init(void *arg)
84cea6c86cSDoug Rabson {
85287698b4SAndrew R. Reiter 
869b3851e9SAndrew R. Reiter 	sx_init(&modules_sx, "module subsystem sx lock");
87cea6c86cSDoug Rabson 	TAILQ_INIT(&modules);
882488f309SPeter Wemm 	EVENTHANDLER_REGISTER(shutdown_final, module_shutdown, NULL,
89fcb893a8SMike Smith 	    SHUTDOWN_PRI_DEFAULT);
90cea6c86cSDoug Rabson }
91cea6c86cSDoug Rabson 
92891cf3edSEd Maste SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, NULL);
93cea6c86cSDoug Rabson 
94cea6c86cSDoug Rabson static void
95fcb893a8SMike Smith module_shutdown(void *arg1, int arg2)
96cea6c86cSDoug Rabson {
97cea6c86cSDoug Rabson 	module_t mod;
98cea6c86cSDoug Rabson 
991a1c04b6SDon Lewis 	if (arg2 & RB_NOSYNC)
1001a1c04b6SDon Lewis 		return;
101c94ce032SJohn Baldwin 	mtx_lock(&Giant);
1029b3851e9SAndrew R. Reiter 	MOD_SLOCK;
10357c15380SAttilio Rao 	TAILQ_FOREACH_REVERSE(mod, &modules, modulelist, link)
104cea6c86cSDoug Rabson 		MOD_EVENT(mod, MOD_SHUTDOWN);
1059b3851e9SAndrew R. Reiter 	MOD_SUNLOCK;
106c94ce032SJohn Baldwin 	mtx_unlock(&Giant);
107cea6c86cSDoug Rabson }
108cea6c86cSDoug Rabson 
109cea6c86cSDoug Rabson void
1103cfc69e6SMatthew Dillon module_register_init(const void *arg)
111cea6c86cSDoug Rabson {
1123cfc69e6SMatthew Dillon 	const moduledata_t *data = (const moduledata_t *)arg;
113cea6c86cSDoug Rabson 	int error;
114b5b15c3fSPeter Wemm 	module_t mod;
115cea6c86cSDoug Rabson 
116c94ce032SJohn Baldwin 	mtx_lock(&Giant);
1179b3851e9SAndrew R. Reiter 	MOD_SLOCK;
118b5b15c3fSPeter Wemm 	mod = module_lookupbyname(data->name);
119b5b15c3fSPeter Wemm 	if (mod == NULL)
120287698b4SAndrew R. Reiter 		panic("module_register_init: module named %s not found\n",
121287698b4SAndrew R. Reiter 		    data->name);
1229b3851e9SAndrew R. Reiter 	MOD_SUNLOCK;
123b5b15c3fSPeter Wemm 	error = MOD_EVENT(mod, MOD_LOAD);
124b5b15c3fSPeter Wemm 	if (error) {
125b5b15c3fSPeter Wemm 		MOD_EVENT(mod, MOD_UNLOAD);
1269b3851e9SAndrew R. Reiter 		MOD_XLOCK;
127b5b15c3fSPeter Wemm 		module_release(mod);
1289b3851e9SAndrew R. Reiter 		MOD_XUNLOCK;
129bd47bef5SPeter Wemm 		printf("module_register_init: MOD_LOAD (%s, %p, %p) error"
130bd47bef5SPeter Wemm 		    " %d\n", data->name, (void *)data->evhand, data->priv,
131287698b4SAndrew R. Reiter 		    error);
13275444a85SJohn Baldwin 	} else {
13375444a85SJohn Baldwin 		MOD_XLOCK;
13475444a85SJohn Baldwin 		if (mod->file) {
13575444a85SJohn Baldwin 			/*
136dda66918SJohn Baldwin 			 * Once a module is successfully loaded, move
13775444a85SJohn Baldwin 			 * it to the head of the module list for this
13875444a85SJohn Baldwin 			 * linker file.  This resorts the list so that
13975444a85SJohn Baldwin 			 * when the kernel linker iterates over the
14075444a85SJohn Baldwin 			 * modules to unload them, it will unload them
14175444a85SJohn Baldwin 			 * in the reverse order they were loaded.
14275444a85SJohn Baldwin 			 */
14375444a85SJohn Baldwin 			TAILQ_REMOVE(&mod->file->modules, mod, flink);
14475444a85SJohn Baldwin 			TAILQ_INSERT_HEAD(&mod->file->modules, mod, flink);
14575444a85SJohn Baldwin 		}
14675444a85SJohn Baldwin 		MOD_XUNLOCK;
147cea6c86cSDoug Rabson 	}
148c94ce032SJohn Baldwin 	mtx_unlock(&Giant);
149b5b15c3fSPeter Wemm }
150cea6c86cSDoug Rabson 
151cea6c86cSDoug Rabson int
152b5b15c3fSPeter Wemm module_register(const moduledata_t *data, linker_file_t container)
153cea6c86cSDoug Rabson {
154cea6c86cSDoug Rabson 	size_t namelen;
155cea6c86cSDoug Rabson 	module_t newmod;
156cea6c86cSDoug Rabson 
157059d68deSMaxim Konovalov 	MOD_XLOCK;
158b5b15c3fSPeter Wemm 	newmod = module_lookupbyname(data->name);
159b5b15c3fSPeter Wemm 	if (newmod != NULL) {
160059d68deSMaxim Konovalov 		MOD_XUNLOCK;
161b9a5c7b5SEdward Tomasz Napierala 		printf("%s: cannot register %s from %s; already loaded from %s\n",
162b9a5c7b5SEdward Tomasz Napierala 		    __func__, data->name, container->filename, newmod->file->filename);
163b65420f9SAndrew R. Reiter 		return (EEXIST);
164b5b15c3fSPeter Wemm 	}
165b5b15c3fSPeter Wemm 	namelen = strlen(data->name) + 1;
166a163d034SWarner Losh 	newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK);
167cea6c86cSDoug Rabson 	newmod->refs = 1;
168cea6c86cSDoug Rabson 	newmod->id = nextid++;
169cea6c86cSDoug Rabson 	newmod->name = (char *)(newmod + 1);
170b5b15c3fSPeter Wemm 	strcpy(newmod->name, data->name);
171845ccef4SPeter Wemm 	newmod->handler = data->evhand ? data->evhand : modevent_nop;
172b5b15c3fSPeter Wemm 	newmod->arg = data->priv;
173a35261efSDoug Rabson 	bzero(&newmod->data, sizeof(newmod->data));
174cea6c86cSDoug Rabson 	TAILQ_INSERT_TAIL(&modules, newmod, link);
175cea6c86cSDoug Rabson 
176b5b15c3fSPeter Wemm 	if (container)
177f3b0d442SPeter Wemm 		TAILQ_INSERT_TAIL(&container->modules, newmod, flink);
1781d23cba9SPeter Wemm 	newmod->file = container;
1799b3851e9SAndrew R. Reiter 	MOD_XUNLOCK;
180b65420f9SAndrew R. Reiter 	return (0);
181cea6c86cSDoug Rabson }
182cea6c86cSDoug Rabson 
183cea6c86cSDoug Rabson void
184cea6c86cSDoug Rabson module_reference(module_t mod)
185cea6c86cSDoug Rabson {
186cea6c86cSDoug Rabson 
1879b3851e9SAndrew R. Reiter 	MOD_XLOCK_ASSERT;
1889b3851e9SAndrew R. Reiter 
189287698b4SAndrew R. Reiter 	MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
190cea6c86cSDoug Rabson 	mod->refs++;
191cea6c86cSDoug Rabson }
192cea6c86cSDoug Rabson 
193cea6c86cSDoug Rabson void
194cea6c86cSDoug Rabson module_release(module_t mod)
195cea6c86cSDoug Rabson {
196287698b4SAndrew R. Reiter 
1979b3851e9SAndrew R. Reiter 	MOD_XLOCK_ASSERT;
1989b3851e9SAndrew R. Reiter 
199cea6c86cSDoug Rabson 	if (mod->refs <= 0)
200cea6c86cSDoug Rabson 		panic("module_release: bad reference count");
201cea6c86cSDoug Rabson 
202cea6c86cSDoug Rabson 	MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
203cea6c86cSDoug Rabson 
204cea6c86cSDoug Rabson 	mod->refs--;
205cea6c86cSDoug Rabson 	if (mod->refs == 0) {
206cea6c86cSDoug Rabson 		TAILQ_REMOVE(&modules, mod, link);
207287698b4SAndrew R. Reiter 		if (mod->file)
208cea6c86cSDoug Rabson 			TAILQ_REMOVE(&mod->file->modules, mod, flink);
209cea6c86cSDoug Rabson 		free(mod, M_MODULE);
210cea6c86cSDoug Rabson 	}
211cea6c86cSDoug Rabson }
212cea6c86cSDoug Rabson 
213cea6c86cSDoug Rabson module_t
214cea6c86cSDoug Rabson module_lookupbyname(const char *name)
215cea6c86cSDoug Rabson {
216cea6c86cSDoug Rabson 	module_t mod;
217287698b4SAndrew R. Reiter 	int err;
218cea6c86cSDoug Rabson 
2199b3851e9SAndrew R. Reiter 	MOD_LOCK_ASSERT;
2209b3851e9SAndrew R. Reiter 
221fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(mod, &modules, link) {
222287698b4SAndrew R. Reiter 		err = strcmp(mod->name, name);
223287698b4SAndrew R. Reiter 		if (err == 0)
224b65420f9SAndrew R. Reiter 			return (mod);
225cea6c86cSDoug Rabson 	}
226b65420f9SAndrew R. Reiter 	return (NULL);
227cea6c86cSDoug Rabson }
228cea6c86cSDoug Rabson 
229cea6c86cSDoug Rabson module_t
230cea6c86cSDoug Rabson module_lookupbyid(int modid)
231cea6c86cSDoug Rabson {
232cea6c86cSDoug Rabson         module_t mod;
233cea6c86cSDoug Rabson 
2349b3851e9SAndrew R. Reiter         MOD_LOCK_ASSERT;
2359b3851e9SAndrew R. Reiter 
2369b3851e9SAndrew R. Reiter         TAILQ_FOREACH(mod, &modules, link)
237cea6c86cSDoug Rabson                 if (mod->id == modid)
238b65420f9SAndrew R. Reiter                         return(mod);
239b65420f9SAndrew R. Reiter         return (NULL);
240cea6c86cSDoug Rabson }
241cea6c86cSDoug Rabson 
242cea6c86cSDoug Rabson int
243b4824b48SJohn Baldwin module_quiesce(module_t mod)
244cea6c86cSDoug Rabson {
24565a311fcSPoul-Henning Kamp 	int error;
246287698b4SAndrew R. Reiter 
247c94ce032SJohn Baldwin 	mtx_lock(&Giant);
24865a311fcSPoul-Henning Kamp 	error = MOD_EVENT(mod, MOD_QUIESCE);
249b4824b48SJohn Baldwin 	mtx_unlock(&Giant);
2503e019deaSPoul-Henning Kamp 	if (error == EOPNOTSUPP || error == EINVAL)
25165a311fcSPoul-Henning Kamp 		error = 0;
252b4824b48SJohn Baldwin 	return (error);
253b4824b48SJohn Baldwin }
254b4824b48SJohn Baldwin 
255b4824b48SJohn Baldwin int
256b4824b48SJohn Baldwin module_unload(module_t mod)
257b4824b48SJohn Baldwin {
258b4824b48SJohn Baldwin 	int error;
259b4824b48SJohn Baldwin 
260b4824b48SJohn Baldwin 	mtx_lock(&Giant);
261c94ce032SJohn Baldwin 	error = MOD_EVENT(mod, MOD_UNLOAD);
262c94ce032SJohn Baldwin 	mtx_unlock(&Giant);
26365a311fcSPoul-Henning Kamp 	return (error);
264cea6c86cSDoug Rabson }
265cea6c86cSDoug Rabson 
266cea6c86cSDoug Rabson int
267cea6c86cSDoug Rabson module_getid(module_t mod)
268cea6c86cSDoug Rabson {
269287698b4SAndrew R. Reiter 
2709b3851e9SAndrew R. Reiter 	MOD_LOCK_ASSERT;
271b65420f9SAndrew R. Reiter 	return (mod->id);
272cea6c86cSDoug Rabson }
273cea6c86cSDoug Rabson 
274cea6c86cSDoug Rabson module_t
275cea6c86cSDoug Rabson module_getfnext(module_t mod)
276cea6c86cSDoug Rabson {
277287698b4SAndrew R. Reiter 
2789b3851e9SAndrew R. Reiter 	MOD_LOCK_ASSERT;
279b65420f9SAndrew R. Reiter 	return (TAILQ_NEXT(mod, flink));
280cea6c86cSDoug Rabson }
281cea6c86cSDoug Rabson 
282b4824b48SJohn Baldwin const char *
283b4824b48SJohn Baldwin module_getname(module_t mod)
284b4824b48SJohn Baldwin {
285b4824b48SJohn Baldwin 
286b4824b48SJohn Baldwin 	MOD_LOCK_ASSERT;
287b4824b48SJohn Baldwin 	return (mod->name);
288b4824b48SJohn Baldwin }
289b4824b48SJohn Baldwin 
290a35261efSDoug Rabson void
291a35261efSDoug Rabson module_setspecific(module_t mod, modspecific_t *datap)
292a35261efSDoug Rabson {
293287698b4SAndrew R. Reiter 
2949b3851e9SAndrew R. Reiter 	MOD_XLOCK_ASSERT;
295a35261efSDoug Rabson 	mod->data = *datap;
296a35261efSDoug Rabson }
297a35261efSDoug Rabson 
2982971c361SJohn Baldwin linker_file_t
2992971c361SJohn Baldwin module_file(module_t mod)
3002971c361SJohn Baldwin {
3012971c361SJohn Baldwin 
3022971c361SJohn Baldwin 	return (mod->file);
3032971c361SJohn Baldwin }
3042971c361SJohn Baldwin 
305cea6c86cSDoug Rabson /*
306cea6c86cSDoug Rabson  * Syscalls.
307cea6c86cSDoug Rabson  */
308cea6c86cSDoug Rabson int
3098451d0ddSKip Macy sys_modnext(struct thread *td, struct modnext_args *uap)
310cea6c86cSDoug Rabson {
311cea6c86cSDoug Rabson 	module_t mod;
312835a82eeSMatthew Dillon 	int error = 0;
313835a82eeSMatthew Dillon 
314b40ce416SJulian Elischer 	td->td_retval[0] = -1;
315e024f583SAndrew R. Reiter 
3169b3851e9SAndrew R. Reiter 	MOD_SLOCK;
317d1e405c5SAlfred Perlstein 	if (uap->modid == 0) {
318cea6c86cSDoug Rabson 		mod = TAILQ_FIRST(&modules);
319835a82eeSMatthew Dillon 		if (mod)
320b40ce416SJulian Elischer 			td->td_retval[0] = mod->id;
321835a82eeSMatthew Dillon 		else
322835a82eeSMatthew Dillon 			error = ENOENT;
323835a82eeSMatthew Dillon 		goto done2;
324cea6c86cSDoug Rabson 	}
325d1e405c5SAlfred Perlstein 	mod = module_lookupbyid(uap->modid);
326835a82eeSMatthew Dillon 	if (mod == NULL) {
327835a82eeSMatthew Dillon 		error = ENOENT;
328835a82eeSMatthew Dillon 		goto done2;
329835a82eeSMatthew Dillon 	}
330cea6c86cSDoug Rabson 	if (TAILQ_NEXT(mod, link))
331b40ce416SJulian Elischer 		td->td_retval[0] = TAILQ_NEXT(mod, link)->id;
332cea6c86cSDoug Rabson 	else
333b40ce416SJulian Elischer 		td->td_retval[0] = 0;
334835a82eeSMatthew Dillon done2:
3359b3851e9SAndrew R. Reiter 	MOD_SUNLOCK;
336835a82eeSMatthew Dillon 	return (error);
337cea6c86cSDoug Rabson }
338cea6c86cSDoug Rabson 
339cea6c86cSDoug Rabson int
3408451d0ddSKip Macy sys_modfnext(struct thread *td, struct modfnext_args *uap)
341cea6c86cSDoug Rabson {
342cea6c86cSDoug Rabson 	module_t mod;
343835a82eeSMatthew Dillon 	int error;
344cea6c86cSDoug Rabson 
345b40ce416SJulian Elischer 	td->td_retval[0] = -1;
346cea6c86cSDoug Rabson 
3479b3851e9SAndrew R. Reiter 	MOD_SLOCK;
348d1e405c5SAlfred Perlstein 	mod = module_lookupbyid(uap->modid);
349835a82eeSMatthew Dillon 	if (mod == NULL) {
350835a82eeSMatthew Dillon 		error = ENOENT;
351835a82eeSMatthew Dillon 	} else {
352835a82eeSMatthew Dillon 		error = 0;
353cea6c86cSDoug Rabson 		if (TAILQ_NEXT(mod, flink))
354b40ce416SJulian Elischer 			td->td_retval[0] = TAILQ_NEXT(mod, flink)->id;
355cea6c86cSDoug Rabson 		else
356b40ce416SJulian Elischer 			td->td_retval[0] = 0;
357835a82eeSMatthew Dillon 	}
3589b3851e9SAndrew R. Reiter 	MOD_SUNLOCK;
359835a82eeSMatthew Dillon 	return (error);
360cea6c86cSDoug Rabson }
361cea6c86cSDoug Rabson 
362a35261efSDoug Rabson struct module_stat_v1 {
363a35261efSDoug Rabson 	int	version;		/* set to sizeof(struct module_stat) */
364*df38ada2SBjoern A. Zeeb 	char	name[MAXMODNAMEV1V2];
365a35261efSDoug Rabson 	int	refs;
366a35261efSDoug Rabson 	int	id;
367a35261efSDoug Rabson };
368a35261efSDoug Rabson 
369*df38ada2SBjoern A. Zeeb struct module_stat_v2 {
370*df38ada2SBjoern A. Zeeb 	int	version;		/* set to sizeof(struct module_stat) */
371*df38ada2SBjoern A. Zeeb 	char	name[MAXMODNAMEV1V2];
372*df38ada2SBjoern A. Zeeb 	int	refs;
373*df38ada2SBjoern A. Zeeb 	int	id;
374*df38ada2SBjoern A. Zeeb 	modspecific_t	data;
375*df38ada2SBjoern A. Zeeb };
376*df38ada2SBjoern A. Zeeb 
377cea6c86cSDoug Rabson int
3788451d0ddSKip Macy sys_modstat(struct thread *td, struct modstat_args *uap)
379cea6c86cSDoug Rabson {
380cea6c86cSDoug Rabson 	module_t mod;
3819b3851e9SAndrew R. Reiter 	modspecific_t data;
382cea6c86cSDoug Rabson 	int error = 0;
3839b3851e9SAndrew R. Reiter 	int id, namelen, refs, version;
384cea6c86cSDoug Rabson 	struct module_stat *stat;
385*df38ada2SBjoern A. Zeeb 	struct module_stat_v2 *stat_v2;
3869b3851e9SAndrew R. Reiter 	char *name;
387*df38ada2SBjoern A. Zeeb 	bool is_v1v2;
388cea6c86cSDoug Rabson 
3899b3851e9SAndrew R. Reiter 	MOD_SLOCK;
390d1e405c5SAlfred Perlstein 	mod = module_lookupbyid(uap->modid);
391835a82eeSMatthew Dillon 	if (mod == NULL) {
3929b3851e9SAndrew R. Reiter 		MOD_SUNLOCK;
393e024f583SAndrew R. Reiter 		return (ENOENT);
394835a82eeSMatthew Dillon 	}
3959b3851e9SAndrew R. Reiter 	id = mod->id;
3969b3851e9SAndrew R. Reiter 	refs = mod->refs;
3979b3851e9SAndrew R. Reiter 	name = mod->name;
3989b3851e9SAndrew R. Reiter 	data = mod->data;
3999b3851e9SAndrew R. Reiter 	MOD_SUNLOCK;
400d1e405c5SAlfred Perlstein 	stat = uap->stat;
401cea6c86cSDoug Rabson 
402cea6c86cSDoug Rabson 	/*
403cea6c86cSDoug Rabson 	 * Check the version of the user's structure.
404cea6c86cSDoug Rabson 	 */
405d254af07SMatthew Dillon 	if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
406e024f583SAndrew R. Reiter 		return (error);
407*df38ada2SBjoern A. Zeeb 	is_v1v2 = (version == sizeof(struct module_stat_v1) ||
408*df38ada2SBjoern A. Zeeb 	    version == sizeof(struct module_stat_v2));
409*df38ada2SBjoern A. Zeeb 	if (!is_v1v2 && version != sizeof(struct module_stat))
410e024f583SAndrew R. Reiter 		return (EINVAL);
411cea6c86cSDoug Rabson 	namelen = strlen(mod->name) + 1;
412*df38ada2SBjoern A. Zeeb 	if (is_v1v2 && namelen > MAXMODNAMEV1V2)
413*df38ada2SBjoern A. Zeeb 		namelen = MAXMODNAMEV1V2;
414*df38ada2SBjoern A. Zeeb 	else if (namelen > MAXMODNAMEV3)
415*df38ada2SBjoern A. Zeeb 		namelen = MAXMODNAMEV3;
4169b3851e9SAndrew R. Reiter 	if ((error = copyout(name, &stat->name[0], namelen)) != 0)
417e024f583SAndrew R. Reiter 		return (error);
418cea6c86cSDoug Rabson 
419*df38ada2SBjoern A. Zeeb 	/* Extending MAXMODNAME gives an offset change for v3. */
420*df38ada2SBjoern A. Zeeb 	if (is_v1v2) {
421*df38ada2SBjoern A. Zeeb 		stat_v2 = (struct module_stat_v2 *)stat;
422*df38ada2SBjoern A. Zeeb 		if ((error = copyout(&refs, &stat_v2->refs, sizeof(int))) != 0)
423*df38ada2SBjoern A. Zeeb 			return (error);
424*df38ada2SBjoern A. Zeeb 		if ((error = copyout(&id, &stat_v2->id, sizeof(int))) != 0)
425*df38ada2SBjoern A. Zeeb 			return (error);
426*df38ada2SBjoern A. Zeeb 	} else {
4279b3851e9SAndrew R. Reiter 		if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0)
428e024f583SAndrew R. Reiter 			return (error);
4299b3851e9SAndrew R. Reiter 		if ((error = copyout(&id, &stat->id, sizeof(int))) != 0)
430e024f583SAndrew R. Reiter 			return (error);
431*df38ada2SBjoern A. Zeeb 	}
432cea6c86cSDoug Rabson 
433a35261efSDoug Rabson 	/*
434a35261efSDoug Rabson 	 * >v1 stat includes module data.
435a35261efSDoug Rabson 	 */
436*df38ada2SBjoern A. Zeeb 	if (version == sizeof(struct module_stat_v2)) {
437*df38ada2SBjoern A. Zeeb 		if ((error = copyout(&data, &stat_v2->data,
438*df38ada2SBjoern A. Zeeb 		    sizeof(data))) != 0)
439*df38ada2SBjoern A. Zeeb 			return (error);
440*df38ada2SBjoern A. Zeeb 	} else if (version == sizeof(struct module_stat)) {
4419b3851e9SAndrew R. Reiter 		if ((error = copyout(&data, &stat->data,
4429b3851e9SAndrew R. Reiter 		    sizeof(data))) != 0)
443e024f583SAndrew R. Reiter 			return (error);
444*df38ada2SBjoern A. Zeeb 	}
445b40ce416SJulian Elischer 	td->td_retval[0] = 0;
446b65420f9SAndrew R. Reiter 	return (error);
447cea6c86cSDoug Rabson }
448cea6c86cSDoug Rabson 
449cea6c86cSDoug Rabson int
4508451d0ddSKip Macy sys_modfind(struct thread *td, struct modfind_args *uap)
451cea6c86cSDoug Rabson {
452cea6c86cSDoug Rabson 	int error = 0;
453*df38ada2SBjoern A. Zeeb 	char name[MAXMODNAMEV3];
454cea6c86cSDoug Rabson 	module_t mod;
455cea6c86cSDoug Rabson 
456d1e405c5SAlfred Perlstein 	if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0)
457e024f583SAndrew R. Reiter 		return (error);
458cea6c86cSDoug Rabson 
4599b3851e9SAndrew R. Reiter 	MOD_SLOCK;
460cea6c86cSDoug Rabson 	mod = module_lookupbyname(name);
461835a82eeSMatthew Dillon 	if (mod == NULL)
462cea6c86cSDoug Rabson 		error = ENOENT;
463cea6c86cSDoug Rabson 	else
4649b3851e9SAndrew R. Reiter 		td->td_retval[0] = module_getid(mod);
4659b3851e9SAndrew R. Reiter 	MOD_SUNLOCK;
466b65420f9SAndrew R. Reiter 	return (error);
467cea6c86cSDoug Rabson }
4680e214fadSPaul Saab 
46974712770SJohn Baldwin MODULE_VERSION(kernel, __FreeBSD_version);
47074712770SJohn Baldwin 
471841c0c7eSNathan Whitehorn #ifdef COMPAT_FREEBSD32
4720e214fadSPaul Saab #include <sys/mount.h>
47374427aa4SJohn Baldwin #include <sys/socket.h>
4740e214fadSPaul Saab #include <compat/freebsd32/freebsd32_util.h>
4750e214fadSPaul Saab #include <compat/freebsd32/freebsd32.h>
4760e214fadSPaul Saab #include <compat/freebsd32/freebsd32_proto.h>
4770e214fadSPaul Saab 
4780e214fadSPaul Saab typedef union modspecific32 {
4790e214fadSPaul Saab 	int		intval;
48060ae52f7SEd Schouten 	uint32_t	uintval;
4810e214fadSPaul Saab 	int		longval;
48260ae52f7SEd Schouten 	uint32_t	ulongval;
4830e214fadSPaul Saab } modspecific32_t;
4840e214fadSPaul Saab 
485*df38ada2SBjoern A. Zeeb struct module_stat32_v2 {
486*df38ada2SBjoern A. Zeeb 	int		version;
487*df38ada2SBjoern A. Zeeb 	char		name[MAXMODNAMEV1V2];
488*df38ada2SBjoern A. Zeeb 	int		refs;
489*df38ada2SBjoern A. Zeeb 	int		id;
490*df38ada2SBjoern A. Zeeb 	modspecific32_t	data;
491*df38ada2SBjoern A. Zeeb };
492*df38ada2SBjoern A. Zeeb 
4930e214fadSPaul Saab struct module_stat32 {
4940e214fadSPaul Saab 	int		version;
4950e214fadSPaul Saab 	char		name[MAXMODNAME];
4960e214fadSPaul Saab 	int		refs;
4970e214fadSPaul Saab 	int		id;
4980e214fadSPaul Saab 	modspecific32_t	data;
4990e214fadSPaul Saab };
5000e214fadSPaul Saab 
5010e214fadSPaul Saab int
5020e214fadSPaul Saab freebsd32_modstat(struct thread *td, struct freebsd32_modstat_args *uap)
5030e214fadSPaul Saab {
5040e214fadSPaul Saab 	module_t mod;
5050e214fadSPaul Saab 	modspecific32_t data32;
5060e214fadSPaul Saab 	int error = 0;
5070e214fadSPaul Saab 	int id, namelen, refs, version;
5080e214fadSPaul Saab 	struct module_stat32 *stat32;
509*df38ada2SBjoern A. Zeeb 	struct module_stat32_v2 *stat32_v2;
5100e214fadSPaul Saab 	char *name;
511*df38ada2SBjoern A. Zeeb 	bool is_v1v2;
5120e214fadSPaul Saab 
5130e214fadSPaul Saab 	MOD_SLOCK;
5140e214fadSPaul Saab 	mod = module_lookupbyid(uap->modid);
5150e214fadSPaul Saab 	if (mod == NULL) {
5160e214fadSPaul Saab 		MOD_SUNLOCK;
5170e214fadSPaul Saab 		return (ENOENT);
5180e214fadSPaul Saab 	}
5190e214fadSPaul Saab 
5200e214fadSPaul Saab 	id = mod->id;
5210e214fadSPaul Saab 	refs = mod->refs;
5220e214fadSPaul Saab 	name = mod->name;
523b7820945SPaul Saab 	CP(mod->data, data32, intval);
524b7820945SPaul Saab 	CP(mod->data, data32, uintval);
525b7820945SPaul Saab 	CP(mod->data, data32, longval);
526b7820945SPaul Saab 	CP(mod->data, data32, ulongval);
5270e214fadSPaul Saab 	MOD_SUNLOCK;
5280e214fadSPaul Saab 	stat32 = uap->stat;
5290e214fadSPaul Saab 
5300e214fadSPaul Saab 	if ((error = copyin(&stat32->version, &version, sizeof(version))) != 0)
5310e214fadSPaul Saab 		return (error);
532*df38ada2SBjoern A. Zeeb 	is_v1v2 = (version == sizeof(struct module_stat_v1) ||
533*df38ada2SBjoern A. Zeeb 	    version == sizeof(struct module_stat32_v2));
534*df38ada2SBjoern A. Zeeb 	if (!is_v1v2 && version != sizeof(struct module_stat32))
5350e214fadSPaul Saab 		return (EINVAL);
5360e214fadSPaul Saab 	namelen = strlen(mod->name) + 1;
537*df38ada2SBjoern A. Zeeb 	if (is_v1v2 && namelen > MAXMODNAMEV1V2)
538*df38ada2SBjoern A. Zeeb 		namelen = MAXMODNAMEV1V2;
539*df38ada2SBjoern A. Zeeb 	else if (namelen > MAXMODNAMEV3)
540*df38ada2SBjoern A. Zeeb 		namelen = MAXMODNAMEV3;
5410e214fadSPaul Saab 	if ((error = copyout(name, &stat32->name[0], namelen)) != 0)
5420e214fadSPaul Saab 		return (error);
5430e214fadSPaul Saab 
544*df38ada2SBjoern A. Zeeb 	/* Extending MAXMODNAME gives an offset change for v3. */
545*df38ada2SBjoern A. Zeeb 	if (is_v1v2) {
546*df38ada2SBjoern A. Zeeb 		stat32_v2 = (struct module_stat32_v2 *)stat32;
547*df38ada2SBjoern A. Zeeb 		if ((error = copyout(&refs, &stat32_v2->refs, sizeof(int))) != 0)
548*df38ada2SBjoern A. Zeeb 			return (error);
549*df38ada2SBjoern A. Zeeb 		if ((error = copyout(&id, &stat32_v2->id, sizeof(int))) != 0)
550*df38ada2SBjoern A. Zeeb 			return (error);
551*df38ada2SBjoern A. Zeeb 	} else {
5520e214fadSPaul Saab 		if ((error = copyout(&refs, &stat32->refs, sizeof(int))) != 0)
5530e214fadSPaul Saab 			return (error);
5540e214fadSPaul Saab 		if ((error = copyout(&id, &stat32->id, sizeof(int))) != 0)
5550e214fadSPaul Saab 			return (error);
556*df38ada2SBjoern A. Zeeb 	}
5570e214fadSPaul Saab 
5580e214fadSPaul Saab 	/*
5590e214fadSPaul Saab 	 * >v1 stat includes module data.
5600e214fadSPaul Saab 	 */
561*df38ada2SBjoern A. Zeeb 	if (version == sizeof(struct module_stat32_v2)) {
562*df38ada2SBjoern A. Zeeb 		if ((error = copyout(&data32, &stat32_v2->data,
563*df38ada2SBjoern A. Zeeb 		    sizeof(data32))) != 0)
564*df38ada2SBjoern A. Zeeb 			return (error);
565*df38ada2SBjoern A. Zeeb 	} else if (version == sizeof(struct module_stat32)) {
5660e214fadSPaul Saab 		if ((error = copyout(&data32, &stat32->data,
5670e214fadSPaul Saab 		    sizeof(data32))) != 0)
5680e214fadSPaul Saab 			return (error);
569*df38ada2SBjoern A. Zeeb 	}
5700e214fadSPaul Saab 	td->td_retval[0] = 0;
5710e214fadSPaul Saab 	return (error);
5720e214fadSPaul Saab }
5730e214fadSPaul Saab #endif
574