kern_module.c revision 60833
1/*-
2 * Copyright (c) 1997 Doug Rabson
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/sys/kern/kern_module.c 60833 2000-05-23 20:41:01Z jake $
27 */
28
29#include <sys/param.h>
30#include <sys/kernel.h>
31#include <sys/systm.h>
32#include <sys/eventhandler.h>
33#include <sys/malloc.h>
34#include <sys/sysproto.h>
35#include <sys/sysent.h>
36#include <sys/module.h>
37#include <sys/linker.h>
38#include <sys/proc.h>
39
40MALLOC_DEFINE(M_MODULE, "module", "module data structures");
41
42typedef TAILQ_HEAD(, struct module) modulelist_t;
43struct module {
44    TAILQ_ENTRY(struct module)	link;		/* chain together all modules */
45    TAILQ_ENTRY(struct module)	flink;		/* all modules in a file */
46    struct linker_file*	file;		/* file which contains this module */
47    int			refs;		/* reference count */
48    int			id;		/* unique id number */
49    char		*name;		/* module name */
50    modeventhand_t	handler;	/* event handler */
51    void		*arg;		/* argument for handler */
52    modspecific_t	data;		/* module specific data */
53};
54
55#define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg)
56
57static modulelist_t modules;
58static int nextid = 1;
59
60static void module_shutdown(void*, int);
61
62static int
63modevent_nop(module_t mod, int what, void* arg)
64{
65	return 0;
66}
67
68
69static void
70module_init(void* arg)
71{
72    TAILQ_INIT(&modules);
73    EVENTHANDLER_REGISTER(shutdown_post_sync, module_shutdown, NULL,
74			  SHUTDOWN_PRI_DEFAULT);
75}
76
77SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0);
78
79static void
80module_shutdown(void* arg1, int arg2)
81{
82    module_t mod;
83
84    for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link))
85	MOD_EVENT(mod, MOD_SHUTDOWN);
86}
87
88void
89module_register_init(const void *arg)
90{
91    const moduledata_t* data = (const moduledata_t*) arg;
92    int error;
93    module_t mod;
94
95    mod = module_lookupbyname(data->name);
96    if (mod == NULL)
97	panic("module_register_init: module named %s not found\n", data->name);
98    error = MOD_EVENT(mod, MOD_LOAD);
99    if (error) {
100	MOD_EVENT(mod, MOD_UNLOAD);
101	module_release(mod);
102	printf("module_register_init: MOD_LOAD (%s, %lx, %p) error %d\n",
103	       data->name, (u_long)(uintfptr_t)data->evhand, data->priv, error);
104    }
105}
106
107int
108module_register(const moduledata_t *data, linker_file_t container)
109{
110    size_t namelen;
111    module_t newmod;
112
113    newmod = module_lookupbyname(data->name);
114    if (newmod != NULL) {
115	printf("module_register: module %s already exists!\n", data->name);
116	return EEXIST;
117    }
118    namelen = strlen(data->name) + 1;
119    newmod = (module_t) malloc(sizeof(struct module) + namelen,
120			       M_MODULE, M_WAITOK);
121    if (newmod == 0)
122	return ENOMEM;
123
124    newmod->refs = 1;
125    newmod->id = nextid++;
126    newmod->name = (char *) (newmod + 1);
127    strcpy(newmod->name, data->name);
128    newmod->handler = data->evhand ? data->evhand : modevent_nop;
129    newmod->arg = data->priv;
130    bzero(&newmod->data, sizeof(newmod->data));
131    TAILQ_INSERT_TAIL(&modules, newmod, link);
132
133    if (container)
134	TAILQ_INSERT_TAIL(&container->modules, newmod, flink);
135    newmod->file = container;
136
137    return 0;
138}
139
140void
141module_reference(module_t mod)
142{
143    MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
144
145    mod->refs++;
146}
147
148void
149module_release(module_t mod)
150{
151    if (mod->refs <= 0)
152	panic("module_release: bad reference count");
153
154    MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
155
156    mod->refs--;
157    if (mod->refs == 0) {
158	TAILQ_REMOVE(&modules, mod, link);
159	if (mod->file) {
160	    TAILQ_REMOVE(&mod->file->modules, mod, flink);
161	}
162	free(mod, M_MODULE);
163    }
164}
165
166module_t
167module_lookupbyname(const char* name)
168{
169    module_t mod;
170
171    for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) {
172	if (!strcmp(mod->name, name))
173	    return mod;
174    }
175
176    return 0;
177}
178
179module_t
180module_lookupbyid(int modid)
181{
182    module_t mod;
183
184    for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) {
185	if (mod->id == modid)
186	    return mod;
187    }
188
189    return 0;
190}
191
192int
193module_unload(module_t mod)
194{
195    return MOD_EVENT(mod, MOD_UNLOAD);
196}
197
198int
199module_getid(module_t mod)
200{
201    return mod->id;
202}
203
204module_t
205module_getfnext(module_t mod)
206{
207    return TAILQ_NEXT(mod, flink);
208}
209
210void
211module_setspecific(module_t mod, modspecific_t *datap)
212{
213    mod->data = *datap;
214}
215
216/*
217 * Syscalls.
218 */
219int
220modnext(struct proc* p, struct modnext_args* uap)
221{
222    module_t mod;
223
224    p->p_retval[0] = -1;
225    if (SCARG(uap, modid) == 0) {
226	mod = TAILQ_FIRST(&modules);
227	if (mod) {
228	    p->p_retval[0] = mod->id;
229	    return 0;
230	} else
231	    return ENOENT;
232    }
233
234    mod = module_lookupbyid(SCARG(uap, modid));
235    if (!mod)
236	return ENOENT;
237
238    if (TAILQ_NEXT(mod, link))
239	p->p_retval[0] = TAILQ_NEXT(mod, link)->id;
240    else
241	p->p_retval[0] = 0;
242    return 0;
243}
244
245int
246modfnext(struct proc* p, struct modfnext_args* uap)
247{
248    module_t mod;
249
250    p->p_retval[0] = -1;
251
252    mod = module_lookupbyid(SCARG(uap, modid));
253    if (!mod)
254	return ENOENT;
255
256    if (TAILQ_NEXT(mod, flink))
257	p->p_retval[0] = TAILQ_NEXT(mod, flink)->id;
258    else
259	p->p_retval[0] = 0;
260    return 0;
261}
262
263struct module_stat_v1 {
264    int		version;	/* set to sizeof(struct module_stat) */
265    char	name[MAXMODNAME];
266    int		refs;
267    int		id;
268};
269
270int
271modstat(struct proc* p, struct modstat_args* uap)
272{
273    module_t mod;
274    int error = 0;
275    int namelen;
276    int version;
277    struct module_stat* stat;
278
279    mod = module_lookupbyid(SCARG(uap, modid));
280    if (!mod)
281	return ENOENT;
282
283    stat = SCARG(uap, stat);
284
285    /*
286     * Check the version of the user's structure.
287     */
288    if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
289	goto out;
290    if (version != sizeof(struct module_stat_v1)
291	&& version != sizeof(struct module_stat)) {
292	error = EINVAL;
293	goto out;
294    }
295
296    namelen = strlen(mod->name) + 1;
297    if (namelen > MAXMODNAME)
298	namelen = MAXMODNAME;
299    if ((error = copyout(mod->name, &stat->name[0], namelen)) != 0)
300	goto out;
301
302    if ((error = copyout(&mod->refs, &stat->refs, sizeof(int))) != 0)
303	goto out;
304    if ((error = copyout(&mod->id, &stat->id, sizeof(int))) != 0)
305	goto out;
306
307    /*
308     * >v1 stat includes module data.
309     */
310    if (version == sizeof(struct module_stat)) {
311	if ((error = copyout(&mod->data, &stat->data, sizeof(mod->data))) != 0)
312	    goto out;
313    }
314
315    p->p_retval[0] = 0;
316
317out:
318    return error;
319}
320
321int
322modfind(struct proc* p, struct modfind_args* uap)
323{
324    int error = 0;
325    char name[MAXMODNAME];
326    module_t mod;
327
328    if ((error = copyinstr(SCARG(uap, name), name, sizeof name, 0)) != 0)
329	goto out;
330
331    mod = module_lookupbyname(name);
332    if (!mod)
333	error = ENOENT;
334    else
335	p->p_retval[0] = mod->id;
336
337out:
338    return error;
339}
340