xref: /freebsd/sys/kern/kern_module.c (revision cea6c86c11f5264ab880e5d253986982d5644dd0)
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  *	$Id$
27cea6c86cSDoug Rabson  */
28cea6c86cSDoug Rabson 
29cea6c86cSDoug Rabson #include <sys/param.h>
30cea6c86cSDoug Rabson #include <sys/kernel.h>
31cea6c86cSDoug Rabson #include <sys/systm.h>
32cea6c86cSDoug Rabson #include <sys/sysctl.h>
33cea6c86cSDoug Rabson #include <sys/queue.h>
34cea6c86cSDoug Rabson #include <sys/libkern.h>
35cea6c86cSDoug Rabson #include <sys/malloc.h>
36cea6c86cSDoug Rabson #include <sys/sysproto.h>
37cea6c86cSDoug Rabson #include <sys/sysent.h>
38cea6c86cSDoug Rabson #include <sys/module.h>
39cea6c86cSDoug Rabson #include <sys/linker.h>
40cea6c86cSDoug Rabson 
41cea6c86cSDoug Rabson #define M_MODULE	M_TEMP		/* XXX */
42cea6c86cSDoug Rabson 
43cea6c86cSDoug Rabson typedef TAILQ_HEAD(, module) modulelist_t;
44cea6c86cSDoug Rabson struct module {
45cea6c86cSDoug Rabson     TAILQ_ENTRY(module)	link;		/* chain together all modules */
46cea6c86cSDoug Rabson     TAILQ_ENTRY(module)	flink;		/* all modules in a file */
47cea6c86cSDoug Rabson     struct linker_file*	file;		/* file which contains this module */
48cea6c86cSDoug Rabson     int			refs;		/* reference count */
49cea6c86cSDoug Rabson     int			id;		/* unique id number */
50cea6c86cSDoug Rabson     char		*name;		/* module name */
51cea6c86cSDoug Rabson     modeventhand_t	handler;	/* event handler */
52cea6c86cSDoug Rabson     void		*arg;		/* argument for handler */
53cea6c86cSDoug Rabson };
54cea6c86cSDoug Rabson 
55cea6c86cSDoug Rabson #define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg)
56cea6c86cSDoug Rabson 
57cea6c86cSDoug Rabson static modulelist_t modules;
58cea6c86cSDoug Rabson static int nextid = 1;
59cea6c86cSDoug Rabson 
60cea6c86cSDoug Rabson static void module_shutdown(int, void*);
61cea6c86cSDoug Rabson 
62cea6c86cSDoug Rabson static void
63cea6c86cSDoug Rabson module_init(void* arg)
64cea6c86cSDoug Rabson {
65cea6c86cSDoug Rabson     TAILQ_INIT(&modules);
66cea6c86cSDoug Rabson     at_shutdown(module_shutdown, 0, SHUTDOWN_POST_SYNC);
67cea6c86cSDoug Rabson }
68cea6c86cSDoug Rabson 
69cea6c86cSDoug Rabson SYSINIT(module, SI_SUB_KMEM, SI_ORDER_ANY, module_init, 0);
70cea6c86cSDoug Rabson 
71cea6c86cSDoug Rabson static void
72cea6c86cSDoug Rabson module_shutdown(int arg1, void* arg2)
73cea6c86cSDoug Rabson {
74cea6c86cSDoug Rabson     module_t mod;
75cea6c86cSDoug Rabson     int error;
76cea6c86cSDoug Rabson 
77cea6c86cSDoug Rabson     for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link))
78cea6c86cSDoug Rabson 	MOD_EVENT(mod, MOD_SHUTDOWN);
79cea6c86cSDoug Rabson }
80cea6c86cSDoug Rabson 
81cea6c86cSDoug Rabson void
82cea6c86cSDoug Rabson module_register_static(void *arg)
83cea6c86cSDoug Rabson {
84cea6c86cSDoug Rabson     moduledata_t* data = (moduledata_t*) arg;
85cea6c86cSDoug Rabson     int error;
86cea6c86cSDoug Rabson 
87cea6c86cSDoug Rabson     if (error = module_register(data->name, data->evhand, data->priv))
88cea6c86cSDoug Rabson 	printf("module_register_static: module_register(%s, %x, %x) returned %d",
89cea6c86cSDoug Rabson 	       data->name, data->evhand, data->priv, error);
90cea6c86cSDoug Rabson }
91cea6c86cSDoug Rabson 
92cea6c86cSDoug Rabson int
93cea6c86cSDoug Rabson module_register(const char* name, modeventhand_t handler, void* arg)
94cea6c86cSDoug Rabson {
95cea6c86cSDoug Rabson     size_t namelen;
96cea6c86cSDoug Rabson     module_t newmod;
97cea6c86cSDoug Rabson     int error;
98cea6c86cSDoug Rabson 
99cea6c86cSDoug Rabson     namelen = strlen(name) + 1;
100cea6c86cSDoug Rabson     newmod = (module_t) malloc(sizeof(struct module) + namelen,
101cea6c86cSDoug Rabson 			       M_MODULE, M_WAITOK);
102cea6c86cSDoug Rabson     if (newmod == 0)
103cea6c86cSDoug Rabson 	return ENOMEM;
104cea6c86cSDoug Rabson 
105cea6c86cSDoug Rabson     newmod->refs = 1;
106cea6c86cSDoug Rabson     newmod->id = nextid++;
107cea6c86cSDoug Rabson     newmod->name = (char *) (newmod + 1);
108cea6c86cSDoug Rabson     strcpy(newmod->name, name);
109cea6c86cSDoug Rabson     newmod->handler = handler;
110cea6c86cSDoug Rabson     newmod->arg = arg;
111cea6c86cSDoug Rabson     TAILQ_INSERT_TAIL(&modules, newmod, link);
112cea6c86cSDoug Rabson 
113cea6c86cSDoug Rabson     if (linker_current_file) {
114cea6c86cSDoug Rabson 	TAILQ_INSERT_TAIL(&linker_current_file->modules, newmod, flink);
115cea6c86cSDoug Rabson 	newmod->file = linker_current_file;
116cea6c86cSDoug Rabson     } else
117cea6c86cSDoug Rabson 	newmod->file = 0;
118cea6c86cSDoug Rabson 
119cea6c86cSDoug Rabson     if (error = MOD_EVENT(newmod, MOD_LOAD)) {
120cea6c86cSDoug Rabson 	module_release(newmod);
121cea6c86cSDoug Rabson 	return error;
122cea6c86cSDoug Rabson     }
123cea6c86cSDoug Rabson 
124cea6c86cSDoug Rabson     return 0;
125cea6c86cSDoug Rabson }
126cea6c86cSDoug Rabson 
127cea6c86cSDoug Rabson void
128cea6c86cSDoug Rabson module_reference(module_t mod)
129cea6c86cSDoug Rabson {
130cea6c86cSDoug Rabson     MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
131cea6c86cSDoug Rabson 
132cea6c86cSDoug Rabson     mod->refs++;
133cea6c86cSDoug Rabson }
134cea6c86cSDoug Rabson 
135cea6c86cSDoug Rabson void
136cea6c86cSDoug Rabson module_release(module_t mod)
137cea6c86cSDoug Rabson {
138cea6c86cSDoug Rabson     if (mod->refs <= 0)
139cea6c86cSDoug Rabson 	panic("module_release: bad reference count");
140cea6c86cSDoug Rabson 
141cea6c86cSDoug Rabson     MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
142cea6c86cSDoug Rabson 
143cea6c86cSDoug Rabson     mod->refs--;
144cea6c86cSDoug Rabson     if (mod->refs == 0) {
145cea6c86cSDoug Rabson 	TAILQ_REMOVE(&modules, mod, link);
146cea6c86cSDoug Rabson 	if (mod->file) {
147cea6c86cSDoug Rabson 	    TAILQ_REMOVE(&mod->file->modules, mod, flink);
148cea6c86cSDoug Rabson 	}
149cea6c86cSDoug Rabson 	free(mod, M_MODULE);
150cea6c86cSDoug Rabson     }
151cea6c86cSDoug Rabson }
152cea6c86cSDoug Rabson 
153cea6c86cSDoug Rabson module_t
154cea6c86cSDoug Rabson module_lookupbyname(const char* name)
155cea6c86cSDoug Rabson {
156cea6c86cSDoug Rabson     module_t mod;
157cea6c86cSDoug Rabson 
158cea6c86cSDoug Rabson     for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) {
159cea6c86cSDoug Rabson 	if (!strcmp(mod->name, name))
160cea6c86cSDoug Rabson 	    return mod;
161cea6c86cSDoug Rabson     }
162cea6c86cSDoug Rabson 
163cea6c86cSDoug Rabson     return 0;
164cea6c86cSDoug Rabson }
165cea6c86cSDoug Rabson 
166cea6c86cSDoug Rabson module_t
167cea6c86cSDoug Rabson module_lookupbyid(int modid)
168cea6c86cSDoug Rabson {
169cea6c86cSDoug Rabson     module_t mod;
170cea6c86cSDoug Rabson 
171cea6c86cSDoug Rabson     for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) {
172cea6c86cSDoug Rabson 	if (mod->id == modid)
173cea6c86cSDoug Rabson 	    return mod;
174cea6c86cSDoug Rabson     }
175cea6c86cSDoug Rabson 
176cea6c86cSDoug Rabson     return 0;
177cea6c86cSDoug Rabson }
178cea6c86cSDoug Rabson 
179cea6c86cSDoug Rabson int
180cea6c86cSDoug Rabson module_unload(module_t mod)
181cea6c86cSDoug Rabson {
182cea6c86cSDoug Rabson     return MOD_EVENT(mod, MOD_UNLOAD);
183cea6c86cSDoug Rabson }
184cea6c86cSDoug Rabson 
185cea6c86cSDoug Rabson int
186cea6c86cSDoug Rabson module_getid(module_t mod)
187cea6c86cSDoug Rabson {
188cea6c86cSDoug Rabson     return mod->id;
189cea6c86cSDoug Rabson }
190cea6c86cSDoug Rabson 
191cea6c86cSDoug Rabson module_t
192cea6c86cSDoug Rabson module_getfnext(module_t mod)
193cea6c86cSDoug Rabson {
194cea6c86cSDoug Rabson     return TAILQ_NEXT(mod, flink);
195cea6c86cSDoug Rabson }
196cea6c86cSDoug Rabson 
197cea6c86cSDoug Rabson /*
198cea6c86cSDoug Rabson  * Syscalls.
199cea6c86cSDoug Rabson  */
200cea6c86cSDoug Rabson int
201cea6c86cSDoug Rabson modnext(struct proc* p, struct modnext_args* uap, int* retval)
202cea6c86cSDoug Rabson {
203cea6c86cSDoug Rabson     module_t mod;
204cea6c86cSDoug Rabson 
205cea6c86cSDoug Rabson     *retval = -1;
206cea6c86cSDoug Rabson     if (SCARG(uap, modid) == 0) {
207cea6c86cSDoug Rabson 	mod = TAILQ_FIRST(&modules);
208cea6c86cSDoug Rabson 	if (mod) {
209cea6c86cSDoug Rabson 	    *retval = mod->id;
210cea6c86cSDoug Rabson 	    return 0;
211cea6c86cSDoug Rabson 	} else
212cea6c86cSDoug Rabson 	    return ENOENT;
213cea6c86cSDoug Rabson     }
214cea6c86cSDoug Rabson 
215cea6c86cSDoug Rabson     mod = module_lookupbyid(SCARG(uap, modid));
216cea6c86cSDoug Rabson     if (!mod)
217cea6c86cSDoug Rabson 	return ENOENT;
218cea6c86cSDoug Rabson 
219cea6c86cSDoug Rabson     if (TAILQ_NEXT(mod, link))
220cea6c86cSDoug Rabson 	*retval = TAILQ_NEXT(mod, link)->id;
221cea6c86cSDoug Rabson     else
222cea6c86cSDoug Rabson 	*retval = 0;
223cea6c86cSDoug Rabson     return 0;
224cea6c86cSDoug Rabson }
225cea6c86cSDoug Rabson 
226cea6c86cSDoug Rabson int
227cea6c86cSDoug Rabson modfnext(struct proc* p, struct modfnext_args* uap, int* retval)
228cea6c86cSDoug Rabson {
229cea6c86cSDoug Rabson     module_t mod;
230cea6c86cSDoug Rabson 
231cea6c86cSDoug Rabson     *retval = -1;
232cea6c86cSDoug Rabson 
233cea6c86cSDoug Rabson     mod = module_lookupbyid(SCARG(uap, modid));
234cea6c86cSDoug Rabson     if (!mod)
235cea6c86cSDoug Rabson 	return ENOENT;
236cea6c86cSDoug Rabson 
237cea6c86cSDoug Rabson     if (TAILQ_NEXT(mod, flink))
238cea6c86cSDoug Rabson 	*retval = TAILQ_NEXT(mod, flink)->id;
239cea6c86cSDoug Rabson     else
240cea6c86cSDoug Rabson 	*retval = 0;
241cea6c86cSDoug Rabson     return 0;
242cea6c86cSDoug Rabson }
243cea6c86cSDoug Rabson 
244cea6c86cSDoug Rabson int
245cea6c86cSDoug Rabson modstat(struct proc* p, struct modstat_args* uap, int* retval)
246cea6c86cSDoug Rabson {
247cea6c86cSDoug Rabson     module_t mod;
248cea6c86cSDoug Rabson     int error = 0;
249cea6c86cSDoug Rabson     int namelen;
250cea6c86cSDoug Rabson     int version;
251cea6c86cSDoug Rabson     struct module_stat* stat;
252cea6c86cSDoug Rabson 
253cea6c86cSDoug Rabson     mod = module_lookupbyid(SCARG(uap, modid));
254cea6c86cSDoug Rabson     if (!mod)
255cea6c86cSDoug Rabson 	return ENOENT;
256cea6c86cSDoug Rabson 
257cea6c86cSDoug Rabson     stat = SCARG(uap, stat);
258cea6c86cSDoug Rabson 
259cea6c86cSDoug Rabson     /*
260cea6c86cSDoug Rabson      * Check the version of the user's structure.
261cea6c86cSDoug Rabson      */
262cea6c86cSDoug Rabson     if (error = copyin(&stat->version, &version, sizeof(version)))
263cea6c86cSDoug Rabson 	goto out;
264cea6c86cSDoug Rabson     if (version != sizeof(struct module_stat)) {
265cea6c86cSDoug Rabson 	error = EINVAL;
266cea6c86cSDoug Rabson 	goto out;
267cea6c86cSDoug Rabson     }
268cea6c86cSDoug Rabson 
269cea6c86cSDoug Rabson     namelen = strlen(mod->name) + 1;
270cea6c86cSDoug Rabson     if (namelen > MAXMODNAME)
271cea6c86cSDoug Rabson 	namelen = MAXMODNAME;
272cea6c86cSDoug Rabson     if (error = copyout(mod->name, &stat->name[0], namelen))
273cea6c86cSDoug Rabson 	goto out;
274cea6c86cSDoug Rabson 
275cea6c86cSDoug Rabson     if (error = copyout(&mod->refs, &stat->refs, sizeof(int)))
276cea6c86cSDoug Rabson 	goto out;
277cea6c86cSDoug Rabson     if (error = copyout(&mod->id, &stat->id, sizeof(int)))
278cea6c86cSDoug Rabson 	goto out;
279cea6c86cSDoug Rabson 
280cea6c86cSDoug Rabson     *retval = 0;
281cea6c86cSDoug Rabson 
282cea6c86cSDoug Rabson out:
283cea6c86cSDoug Rabson     return error;
284cea6c86cSDoug Rabson }
285cea6c86cSDoug Rabson 
286cea6c86cSDoug Rabson int
287cea6c86cSDoug Rabson modfind(struct proc* p, struct modfind_args* uap, int* retval)
288cea6c86cSDoug Rabson {
289cea6c86cSDoug Rabson     int error = 0;
290cea6c86cSDoug Rabson     char name[MAXMODNAME];
291cea6c86cSDoug Rabson     module_t mod;
292cea6c86cSDoug Rabson 
293cea6c86cSDoug Rabson     if (error = copyinstr(SCARG(uap, name), name, sizeof name, 0))
294cea6c86cSDoug Rabson 	goto out;
295cea6c86cSDoug Rabson 
296cea6c86cSDoug Rabson     mod = module_lookupbyname(name);
297cea6c86cSDoug Rabson     if (!mod)
298cea6c86cSDoug Rabson 	error = ENOENT;
299cea6c86cSDoug Rabson     else
300cea6c86cSDoug Rabson 	*retval = mod->id;
301cea6c86cSDoug Rabson 
302cea6c86cSDoug Rabson out:
303cea6c86cSDoug Rabson     return error;
304cea6c86cSDoug Rabson }
305