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