kern_module.c revision 47330
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.17 1999/05/08 13:01:57 peter 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(const void *arg)
81{
82    const moduledata_t* data = (const moduledata_t*) arg;
83    int error;
84    module_t mod;
85
86    mod = module_lookupbyname(data->name);
87    if (mod == NULL) {
88#if 0
89	panic("module_register_init: module named %s not found\n", data->name);
90#else
91	/* temporary kludge until kernel `file' attachment registers modules */
92	error = module_register(data, linker_kernel_file);
93	if (error)
94	    panic("module_register_init: register of module failed! %d", error);
95	mod = module_lookupbyname(data->name);
96	if (mod == NULL)
97	    panic("module_register_init: module STILL not found!");
98#endif
99    }
100    error = MOD_EVENT(mod, MOD_LOAD);
101    if (error) {
102	MOD_EVENT(mod, MOD_UNLOAD);
103	module_release(mod);
104	printf("module_register_init: MOD_LOAD (%s, %lx, %p) error %d\n",
105	       data->name, (u_long)(uintfptr_t)data->evhand, data->priv, error);
106    }
107}
108
109int
110module_register(const moduledata_t *data, linker_file_t container)
111{
112    size_t namelen;
113    module_t newmod;
114
115    newmod = module_lookupbyname(data->name);
116    if (newmod != NULL) {
117	printf("module_register: module %s already exists!\n", data->name);
118	return EEXIST;
119    }
120    namelen = strlen(data->name) + 1;
121    newmod = (module_t) malloc(sizeof(struct module) + namelen,
122			       M_MODULE, M_WAITOK);
123    if (newmod == 0)
124	return ENOMEM;
125
126    newmod->refs = 1;
127    newmod->id = nextid++;
128    newmod->name = (char *) (newmod + 1);
129    strcpy(newmod->name, data->name);
130    newmod->handler = data->evhand;
131    newmod->arg = data->priv;
132    bzero(&newmod->data, sizeof(newmod->data));
133    TAILQ_INSERT_TAIL(&modules, newmod, link);
134
135    if (container == NULL)
136	container = linker_current_file;
137    if (container)
138	TAILQ_INSERT_TAIL(&container->modules, newmod, flink);
139    newmod->file = container;
140
141    return 0;
142}
143
144void
145module_reference(module_t mod)
146{
147    MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
148
149    mod->refs++;
150}
151
152void
153module_release(module_t mod)
154{
155    if (mod->refs <= 0)
156	panic("module_release: bad reference count");
157
158    MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
159
160    mod->refs--;
161    if (mod->refs == 0) {
162	TAILQ_REMOVE(&modules, mod, link);
163	if (mod->file) {
164	    TAILQ_REMOVE(&mod->file->modules, mod, flink);
165	}
166	free(mod, M_MODULE);
167    }
168}
169
170module_t
171module_lookupbyname(const char* name)
172{
173    module_t mod;
174
175    for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) {
176	if (!strcmp(mod->name, name))
177	    return mod;
178    }
179
180    return 0;
181}
182
183module_t
184module_lookupbyid(int modid)
185{
186    module_t mod;
187
188    for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) {
189	if (mod->id == modid)
190	    return mod;
191    }
192
193    return 0;
194}
195
196int
197module_unload(module_t mod)
198{
199    return MOD_EVENT(mod, MOD_UNLOAD);
200}
201
202int
203module_getid(module_t mod)
204{
205    return mod->id;
206}
207
208module_t
209module_getfnext(module_t mod)
210{
211    return TAILQ_NEXT(mod, flink);
212}
213
214void
215module_setspecific(module_t mod, modspecific_t *datap)
216{
217    mod->data = *datap;
218}
219
220/*
221 * Syscalls.
222 */
223int
224modnext(struct proc* p, struct modnext_args* uap)
225{
226    module_t mod;
227
228    p->p_retval[0] = -1;
229    if (SCARG(uap, modid) == 0) {
230	mod = TAILQ_FIRST(&modules);
231	if (mod) {
232	    p->p_retval[0] = mod->id;
233	    return 0;
234	} else
235	    return ENOENT;
236    }
237
238    mod = module_lookupbyid(SCARG(uap, modid));
239    if (!mod)
240	return ENOENT;
241
242    if (TAILQ_NEXT(mod, link))
243	p->p_retval[0] = TAILQ_NEXT(mod, link)->id;
244    else
245	p->p_retval[0] = 0;
246    return 0;
247}
248
249int
250modfnext(struct proc* p, struct modfnext_args* uap)
251{
252    module_t mod;
253
254    p->p_retval[0] = -1;
255
256    mod = module_lookupbyid(SCARG(uap, modid));
257    if (!mod)
258	return ENOENT;
259
260    if (TAILQ_NEXT(mod, flink))
261	p->p_retval[0] = TAILQ_NEXT(mod, flink)->id;
262    else
263	p->p_retval[0] = 0;
264    return 0;
265}
266
267struct module_stat_v1 {
268    int		version;	/* set to sizeof(struct module_stat) */
269    char	name[MAXMODNAME];
270    int		refs;
271    int		id;
272};
273
274int
275modstat(struct proc* p, struct modstat_args* uap)
276{
277    module_t mod;
278    int error = 0;
279    int namelen;
280    int version;
281    struct module_stat* stat;
282
283    mod = module_lookupbyid(SCARG(uap, modid));
284    if (!mod)
285	return ENOENT;
286
287    stat = SCARG(uap, stat);
288
289    /*
290     * Check the version of the user's structure.
291     */
292    if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
293	goto out;
294    if (version != sizeof(struct module_stat_v1)
295	&& version != sizeof(struct module_stat)) {
296	error = EINVAL;
297	goto out;
298    }
299
300    namelen = strlen(mod->name) + 1;
301    if (namelen > MAXMODNAME)
302	namelen = MAXMODNAME;
303    if ((error = copyout(mod->name, &stat->name[0], namelen)) != 0)
304	goto out;
305
306    if ((error = copyout(&mod->refs, &stat->refs, sizeof(int))) != 0)
307	goto out;
308    if ((error = copyout(&mod->id, &stat->id, sizeof(int))) != 0)
309	goto out;
310
311    /*
312     * >v1 stat includes module data.
313     */
314    if (version == sizeof(struct module_stat)) {
315	if ((error = copyout(&mod->data, &stat->data, sizeof(mod->data))) != 0)
316	    goto out;
317    }
318
319    p->p_retval[0] = 0;
320
321out:
322    return error;
323}
324
325int
326modfind(struct proc* p, struct modfind_args* uap)
327{
328    int error = 0;
329    char name[MAXMODNAME];
330    module_t mod;
331
332    if ((error = copyinstr(SCARG(uap, name), name, sizeof name, 0)) != 0)
333	goto out;
334
335    mod = module_lookupbyname(name);
336    if (!mod)
337	error = ENOENT;
338    else
339	p->p_retval[0] = mod->id;
340
341out:
342    return error;
343}
344