kern_module.c revision 83366
1178784Skmacy/*-
2178784Skmacy * Copyright (c) 1997 Doug Rabson
3178784Skmacy * All rights reserved.
4178784Skmacy *
5178784Skmacy * Redistribution and use in source and binary forms, with or without
6178784Skmacy * modification, are permitted provided that the following conditions
7178784Skmacy * are met:
8178784Skmacy * 1. Redistributions of source code must retain the above copyright
9178784Skmacy *    notice, this list of conditions and the following disclaimer.
10178784Skmacy * 2. Redistributions in binary form must reproduce the above copyright
11178784Skmacy *    notice, this list of conditions and the following disclaimer in the
12178784Skmacy *    documentation and/or other materials provided with the distribution.
13178784Skmacy *
14178784Skmacy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15178784Skmacy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16178784Skmacy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17178784Skmacy * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18178784Skmacy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19178784Skmacy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20178784Skmacy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21178784Skmacy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22178784Skmacy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23178784Skmacy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24178784Skmacy * SUCH DAMAGE.
25178784Skmacy *
26178784Skmacy * $FreeBSD: head/sys/kern/kern_module.c 83366 2001-09-12 08:38:13Z julian $
27178784Skmacy */
28178784Skmacy
29178784Skmacy#include <sys/param.h>
30178784Skmacy#include <sys/kernel.h>
31178784Skmacy#include <sys/systm.h>
32178784Skmacy#include <sys/eventhandler.h>
33178784Skmacy#include <sys/malloc.h>
34178784Skmacy#include <sys/sysproto.h>
35178784Skmacy#include <sys/sysent.h>
36178784Skmacy#include <sys/module.h>
37178784Skmacy#include <sys/linker.h>
38178784Skmacy#include <sys/proc.h>
39178784Skmacy#include <sys/lock.h>
40178784Skmacy#include <sys/mutex.h>
41178784Skmacy
42178784Skmacystatic MALLOC_DEFINE(M_MODULE, "module", "module data structures");
43178784Skmacy
44178784Skmacytypedef TAILQ_HEAD(, module) modulelist_t;
45230966Sdimstruct module {
46178784Skmacy    TAILQ_ENTRY(module)	link;		/* chain together all modules */
47178784Skmacy    TAILQ_ENTRY(module)	flink;		/* all modules in a file */
48178784Skmacy    struct linker_file*	file;		/* file which contains this module */
49178784Skmacy    int			refs;		/* reference count */
50178784Skmacy    int			id;		/* unique id number */
51178784Skmacy    char		*name;		/* module name */
52178784Skmacy    modeventhand_t	handler;	/* event handler */
53178784Skmacy    void		*arg;		/* argument for handler */
54178784Skmacy    modspecific_t	data;		/* module specific data */
55178784Skmacy};
56178784Skmacy
57178784Skmacy#define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg)
58178784Skmacy
59178784Skmacystatic modulelist_t modules;
60178784Skmacystatic int nextid = 1;
61178784Skmacy
62178784Skmacystatic void module_shutdown(void*, int);
63178784Skmacy
64178784Skmacystatic int
65178784Skmacymodevent_nop(module_t mod, int what, void* arg)
66178784Skmacy{
67178784Skmacy	return 0;
68178784Skmacy}
69178784Skmacy
70178784Skmacy
71178784Skmacystatic void
72178784Skmacymodule_init(void* arg)
73178784Skmacy{
74178784Skmacy    TAILQ_INIT(&modules);
75178784Skmacy    EVENTHANDLER_REGISTER(shutdown_post_sync, module_shutdown, NULL,
76178784Skmacy			  SHUTDOWN_PRI_DEFAULT);
77178784Skmacy}
78178784Skmacy
79178784SkmacySYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0);
80178784Skmacy
81178784Skmacystatic void
82178784Skmacymodule_shutdown(void* arg1, int arg2)
83178784Skmacy{
84178784Skmacy    module_t mod;
85178784Skmacy
86178784Skmacy    TAILQ_FOREACH(mod, &modules, link)
87178784Skmacy	MOD_EVENT(mod, MOD_SHUTDOWN);
88178784Skmacy}
89178784Skmacy
90178784Skmacyvoid
91178784Skmacymodule_register_init(const void *arg)
92178784Skmacy{
93178784Skmacy    const moduledata_t* data = (const moduledata_t*) arg;
94178784Skmacy    int error;
95178784Skmacy    module_t mod;
96178784Skmacy
97178784Skmacy    mod = module_lookupbyname(data->name);
98178784Skmacy    if (mod == NULL)
99178784Skmacy	panic("module_register_init: module named %s not found\n", data->name);
100178784Skmacy    error = MOD_EVENT(mod, MOD_LOAD);
101178784Skmacy    if (error) {
102178784Skmacy	MOD_EVENT(mod, MOD_UNLOAD);
103178784Skmacy	module_release(mod);
104178784Skmacy	printf("module_register_init: MOD_LOAD (%s, %lx, %p) error %d\n",
105178784Skmacy	       data->name, (u_long)(uintfptr_t)data->evhand, data->priv, error);
106178784Skmacy    }
107178784Skmacy}
108178784Skmacy
109178784Skmacyint
110178784Skmacymodule_register(const moduledata_t *data, linker_file_t container)
111178784Skmacy{
112178784Skmacy    size_t namelen;
113178784Skmacy    module_t newmod;
114178784Skmacy
115178784Skmacy    newmod = module_lookupbyname(data->name);
116178784Skmacy    if (newmod != NULL) {
117178784Skmacy	printf("module_register: module %s already exists!\n", data->name);
118178784Skmacy	return EEXIST;
119178784Skmacy    }
120178784Skmacy    namelen = strlen(data->name) + 1;
121178784Skmacy    newmod = (module_t) malloc(sizeof(struct module) + namelen,
122178784Skmacy			       M_MODULE, M_WAITOK);
123178784Skmacy    if (newmod == 0)
124178784Skmacy	return ENOMEM;
125178784Skmacy
126178784Skmacy    newmod->refs = 1;
127178784Skmacy    newmod->id = nextid++;
128178784Skmacy    newmod->name = (char *) (newmod + 1);
129178784Skmacy    strcpy(newmod->name, data->name);
130178784Skmacy    newmod->handler = data->evhand ? data->evhand : modevent_nop;
131178784Skmacy    newmod->arg = data->priv;
132178784Skmacy    bzero(&newmod->data, sizeof(newmod->data));
133178784Skmacy    TAILQ_INSERT_TAIL(&modules, newmod, link);
134178784Skmacy
135178784Skmacy    if (container)
136178784Skmacy	TAILQ_INSERT_TAIL(&container->modules, newmod, flink);
137178784Skmacy    newmod->file = container;
138178784Skmacy
139178784Skmacy    return 0;
140178784Skmacy}
141178784Skmacy
142178784Skmacyvoid
143178784Skmacymodule_reference(module_t mod)
144178784Skmacy{
145178784Skmacy    MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
146178784Skmacy
147178784Skmacy    mod->refs++;
148178784Skmacy}
149178784Skmacy
150178784Skmacyvoid
151178784Skmacymodule_release(module_t mod)
152178784Skmacy{
153178784Skmacy    if (mod->refs <= 0)
154178784Skmacy	panic("module_release: bad reference count");
155178784Skmacy
156178784Skmacy    MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
157178784Skmacy
158178784Skmacy    mod->refs--;
159178784Skmacy    if (mod->refs == 0) {
160178784Skmacy	TAILQ_REMOVE(&modules, mod, link);
161178784Skmacy	if (mod->file) {
162178784Skmacy	    TAILQ_REMOVE(&mod->file->modules, mod, flink);
163178784Skmacy	}
164178784Skmacy	free(mod, M_MODULE);
165    }
166}
167
168module_t
169module_lookupbyname(const char* name)
170{
171    module_t mod;
172
173    TAILQ_FOREACH(mod, &modules, link) {
174	if (!strcmp(mod->name, name))
175	    return mod;
176    }
177
178    return 0;
179}
180
181module_t
182module_lookupbyid(int modid)
183{
184    module_t mod;
185
186    TAILQ_FOREACH(mod, &modules, link) {
187	if (mod->id == modid)
188	    return mod;
189    }
190
191    return 0;
192}
193
194int
195module_unload(module_t mod)
196{
197    return MOD_EVENT(mod, MOD_UNLOAD);
198}
199
200int
201module_getid(module_t mod)
202{
203    return mod->id;
204}
205
206module_t
207module_getfnext(module_t mod)
208{
209    return TAILQ_NEXT(mod, flink);
210}
211
212void
213module_setspecific(module_t mod, modspecific_t *datap)
214{
215    mod->data = *datap;
216}
217
218/*
219 * Syscalls.
220 */
221/*
222 * MPSAFE
223 */
224int
225modnext(struct thread *td, struct modnext_args *uap)
226{
227    module_t mod;
228    int error = 0;
229
230    mtx_lock(&Giant);
231
232    td->td_retval[0] = -1;
233    if (SCARG(uap, modid) == 0) {
234	mod = TAILQ_FIRST(&modules);
235	if (mod)
236	    td->td_retval[0] = mod->id;
237	else
238	    error = ENOENT;
239	goto done2;
240    }
241
242    mod = module_lookupbyid(SCARG(uap, modid));
243    if (mod == NULL) {
244	error = ENOENT;
245	goto done2;
246    }
247
248    if (TAILQ_NEXT(mod, link))
249	td->td_retval[0] = TAILQ_NEXT(mod, link)->id;
250    else
251	td->td_retval[0] = 0;
252done2:
253    mtx_unlock(&Giant);
254    return (error);
255}
256
257/*
258 * MPSAFE
259 */
260int
261modfnext(struct thread *td, struct modfnext_args *uap)
262{
263    module_t mod;
264    int error;
265
266    td->td_retval[0] = -1;
267
268    mtx_lock(&Giant);
269
270    mod = module_lookupbyid(SCARG(uap, modid));
271    if (mod == NULL) {
272	error = ENOENT;
273    } else {
274	error = 0;
275	if (TAILQ_NEXT(mod, flink))
276	    td->td_retval[0] = TAILQ_NEXT(mod, flink)->id;
277	else
278	    td->td_retval[0] = 0;
279    }
280    mtx_unlock(&Giant);
281    return (error);
282}
283
284struct module_stat_v1 {
285    int		version;	/* set to sizeof(struct module_stat) */
286    char	name[MAXMODNAME];
287    int		refs;
288    int		id;
289};
290
291/*
292 * MPSAFE
293 */
294int
295modstat(struct thread *td, struct modstat_args *uap)
296{
297    module_t mod;
298    int error = 0;
299    int namelen;
300    int version;
301    struct module_stat* stat;
302
303    mtx_lock(&Giant);
304
305    mod = module_lookupbyid(SCARG(uap, modid));
306    if (mod == NULL) {
307	error = ENOENT;
308	goto out;
309    }
310
311    stat = SCARG(uap, stat);
312
313    /*
314     * Check the version of the user's structure.
315     */
316    if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
317	goto out;
318    if (version != sizeof(struct module_stat_v1)
319	&& version != sizeof(struct module_stat)) {
320	error = EINVAL;
321	goto out;
322    }
323
324    namelen = strlen(mod->name) + 1;
325    if (namelen > MAXMODNAME)
326	namelen = MAXMODNAME;
327    if ((error = copyout(mod->name, &stat->name[0], namelen)) != 0)
328	goto out;
329
330    if ((error = copyout(&mod->refs, &stat->refs, sizeof(int))) != 0)
331	goto out;
332    if ((error = copyout(&mod->id, &stat->id, sizeof(int))) != 0)
333	goto out;
334
335    /*
336     * >v1 stat includes module data.
337     */
338    if (version == sizeof(struct module_stat)) {
339	if ((error = copyout(&mod->data, &stat->data, sizeof(mod->data))) != 0)
340	    goto out;
341    }
342
343    td->td_retval[0] = 0;
344
345out:
346    mtx_unlock(&Giant);
347    return error;
348}
349
350/*
351 * MPSAFE
352 */
353int
354modfind(struct thread *td, struct modfind_args *uap)
355{
356    int error = 0;
357    char name[MAXMODNAME];
358    module_t mod;
359
360    if ((error = copyinstr(SCARG(uap, name), name, sizeof name, 0)) != 0)
361	goto out;
362
363    mtx_lock(&Giant);
364    mod = module_lookupbyname(name);
365    if (mod == NULL)
366	error = ENOENT;
367    else
368	td->td_retval[0] = mod->id;
369    mtx_unlock(&Giant);
370out:
371    return error;
372}
373