kern_module.c revision 40158
125537Sdfr/*-
225537Sdfr * Copyright (c) 1997 Doug Rabson
325537Sdfr * All rights reserved.
425537Sdfr *
525537Sdfr * Redistribution and use in source and binary forms, with or without
625537Sdfr * modification, are permitted provided that the following conditions
725537Sdfr * are met:
825537Sdfr * 1. Redistributions of source code must retain the above copyright
925537Sdfr *    notice, this list of conditions and the following disclaimer.
1025537Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1125537Sdfr *    notice, this list of conditions and the following disclaimer in the
1225537Sdfr *    documentation and/or other materials provided with the distribution.
1325537Sdfr *
1425537Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1525537Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1625537Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1725537Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1825537Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1925537Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2025537Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2125537Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2225537Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2325537Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2425537Sdfr * SUCH DAMAGE.
2525537Sdfr *
2640158Speter *	$Id: kern_module.c,v 1.9 1998/10/03 11:05:45 dfr Exp $
2725537Sdfr */
2825537Sdfr
2925537Sdfr#include <sys/param.h>
3025537Sdfr#include <sys/kernel.h>
3125537Sdfr#include <sys/systm.h>
3225537Sdfr#include <sys/malloc.h>
3325537Sdfr#include <sys/sysproto.h>
3425537Sdfr#include <sys/sysent.h>
3525537Sdfr#include <sys/module.h>
3625537Sdfr#include <sys/linker.h>
3730994Sphk#include <sys/proc.h>
3825537Sdfr
3925537Sdfr#define M_MODULE	M_TEMP		/* XXX */
4025537Sdfr
4125537Sdfrtypedef TAILQ_HEAD(, module) modulelist_t;
4225537Sdfrstruct module {
4325537Sdfr    TAILQ_ENTRY(module)	link;		/* chain together all modules */
4425537Sdfr    TAILQ_ENTRY(module)	flink;		/* all modules in a file */
4525537Sdfr    struct linker_file*	file;		/* file which contains this module */
4625537Sdfr    int			refs;		/* reference count */
4725537Sdfr    int			id;		/* unique id number */
4825537Sdfr    char		*name;		/* module name */
4925537Sdfr    modeventhand_t	handler;	/* event handler */
5025537Sdfr    void		*arg;		/* argument for handler */
5125537Sdfr};
5225537Sdfr
5325537Sdfr#define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg)
5425537Sdfr
5525537Sdfrstatic modulelist_t modules;
5625537Sdfrstatic int nextid = 1;
5725537Sdfr
5825537Sdfrstatic void module_shutdown(int, void*);
5925537Sdfr
6025537Sdfrstatic void
6125537Sdfrmodule_init(void* arg)
6225537Sdfr{
6325537Sdfr    TAILQ_INIT(&modules);
6425537Sdfr    at_shutdown(module_shutdown, 0, SHUTDOWN_POST_SYNC);
6525537Sdfr}
6625537Sdfr
6740158SpeterSYSINIT(module, SI_SUB_KLD, SI_ORDER_ANY, module_init, 0);
6825537Sdfr
6925537Sdfrstatic void
7025537Sdfrmodule_shutdown(int arg1, void* arg2)
7125537Sdfr{
7225537Sdfr    module_t mod;
7325537Sdfr
7425537Sdfr    for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link))
7525537Sdfr	MOD_EVENT(mod, MOD_SHUTDOWN);
7625537Sdfr}
7725537Sdfr
7825537Sdfrvoid
7930683Sjmgmodule_register_init(void *arg)
8025537Sdfr{
8125537Sdfr    moduledata_t* data = (moduledata_t*) arg;
8225537Sdfr    int error;
8325537Sdfr
8440158Speter    error = module_register(data->name, data->evhand, data->priv, data->_file);
8540158Speter    if (error)
8637555Sbde	printf("module_register_init: module_register(%s, %lx, %p) returned %d",
8737629Sbde	       data->name, (u_long)(uintfptr_t)data->evhand, data->priv, error);
8825537Sdfr}
8925537Sdfr
9025537Sdfrint
9140158Spetermodule_register(const char* name, modeventhand_t handler, void* arg, void *file)
9225537Sdfr{
9325537Sdfr    size_t namelen;
9425537Sdfr    module_t newmod;
9525537Sdfr    int error;
9640158Speter    linker_file_t container = file;
9725537Sdfr
9825537Sdfr    namelen = strlen(name) + 1;
9925537Sdfr    newmod = (module_t) malloc(sizeof(struct module) + namelen,
10025537Sdfr			       M_MODULE, M_WAITOK);
10125537Sdfr    if (newmod == 0)
10225537Sdfr	return ENOMEM;
10325537Sdfr
10425537Sdfr    newmod->refs = 1;
10525537Sdfr    newmod->id = nextid++;
10625537Sdfr    newmod->name = (char *) (newmod + 1);
10725537Sdfr    strcpy(newmod->name, name);
10825537Sdfr    newmod->handler = handler;
10925537Sdfr    newmod->arg = arg;
11025537Sdfr    TAILQ_INSERT_TAIL(&modules, newmod, link);
11125537Sdfr
11240158Speter    if (container == NULL)
11340158Speter	container = linker_current_file;
11440158Speter    if (container) {
11540158Speter	TAILQ_INSERT_TAIL(&container->modules, newmod, flink);
11640158Speter	newmod->file = container;
11725537Sdfr    } else
11825537Sdfr	newmod->file = 0;
11925537Sdfr
12025537Sdfr    if (error = MOD_EVENT(newmod, MOD_LOAD)) {
12139916Sdfr	MOD_EVENT(newmod, MOD_UNLOAD);
12225537Sdfr	module_release(newmod);
12325537Sdfr	return error;
12425537Sdfr    }
12525537Sdfr
12625537Sdfr    return 0;
12725537Sdfr}
12825537Sdfr
12925537Sdfrvoid
13025537Sdfrmodule_reference(module_t mod)
13125537Sdfr{
13225537Sdfr    MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
13325537Sdfr
13425537Sdfr    mod->refs++;
13525537Sdfr}
13625537Sdfr
13725537Sdfrvoid
13825537Sdfrmodule_release(module_t mod)
13925537Sdfr{
14025537Sdfr    if (mod->refs <= 0)
14125537Sdfr	panic("module_release: bad reference count");
14225537Sdfr
14325537Sdfr    MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
14425537Sdfr
14525537Sdfr    mod->refs--;
14625537Sdfr    if (mod->refs == 0) {
14725537Sdfr	TAILQ_REMOVE(&modules, mod, link);
14825537Sdfr	if (mod->file) {
14925537Sdfr	    TAILQ_REMOVE(&mod->file->modules, mod, flink);
15025537Sdfr	}
15125537Sdfr	free(mod, M_MODULE);
15225537Sdfr    }
15325537Sdfr}
15425537Sdfr
15525537Sdfrmodule_t
15625537Sdfrmodule_lookupbyname(const char* name)
15725537Sdfr{
15825537Sdfr    module_t mod;
15925537Sdfr
16025537Sdfr    for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) {
16125537Sdfr	if (!strcmp(mod->name, name))
16225537Sdfr	    return mod;
16325537Sdfr    }
16425537Sdfr
16525537Sdfr    return 0;
16625537Sdfr}
16725537Sdfr
16825537Sdfrmodule_t
16925537Sdfrmodule_lookupbyid(int modid)
17025537Sdfr{
17125537Sdfr    module_t mod;
17225537Sdfr
17325537Sdfr    for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) {
17425537Sdfr	if (mod->id == modid)
17525537Sdfr	    return mod;
17625537Sdfr    }
17725537Sdfr
17825537Sdfr    return 0;
17925537Sdfr}
18025537Sdfr
18125537Sdfrint
18225537Sdfrmodule_unload(module_t mod)
18325537Sdfr{
18425537Sdfr    return MOD_EVENT(mod, MOD_UNLOAD);
18525537Sdfr}
18625537Sdfr
18725537Sdfrint
18825537Sdfrmodule_getid(module_t mod)
18925537Sdfr{
19025537Sdfr    return mod->id;
19125537Sdfr}
19225537Sdfr
19325537Sdfrmodule_t
19425537Sdfrmodule_getfnext(module_t mod)
19525537Sdfr{
19625537Sdfr    return TAILQ_NEXT(mod, flink);
19725537Sdfr}
19825537Sdfr
19925537Sdfr/*
20025537Sdfr * Syscalls.
20125537Sdfr */
20225537Sdfrint
20330994Sphkmodnext(struct proc* p, struct modnext_args* uap)
20425537Sdfr{
20525537Sdfr    module_t mod;
20625537Sdfr
20730994Sphk    p->p_retval[0] = -1;
20825537Sdfr    if (SCARG(uap, modid) == 0) {
20925537Sdfr	mod = TAILQ_FIRST(&modules);
21025537Sdfr	if (mod) {
21130994Sphk	    p->p_retval[0] = mod->id;
21225537Sdfr	    return 0;
21325537Sdfr	} else
21425537Sdfr	    return ENOENT;
21525537Sdfr    }
21625537Sdfr
21725537Sdfr    mod = module_lookupbyid(SCARG(uap, modid));
21825537Sdfr    if (!mod)
21925537Sdfr	return ENOENT;
22025537Sdfr
22125537Sdfr    if (TAILQ_NEXT(mod, link))
22230994Sphk	p->p_retval[0] = TAILQ_NEXT(mod, link)->id;
22325537Sdfr    else
22430994Sphk	p->p_retval[0] = 0;
22525537Sdfr    return 0;
22625537Sdfr}
22725537Sdfr
22825537Sdfrint
22930994Sphkmodfnext(struct proc* p, struct modfnext_args* uap)
23025537Sdfr{
23125537Sdfr    module_t mod;
23225537Sdfr
23330994Sphk    p->p_retval[0] = -1;
23425537Sdfr
23525537Sdfr    mod = module_lookupbyid(SCARG(uap, modid));
23625537Sdfr    if (!mod)
23725537Sdfr	return ENOENT;
23825537Sdfr
23925537Sdfr    if (TAILQ_NEXT(mod, flink))
24030994Sphk	p->p_retval[0] = TAILQ_NEXT(mod, flink)->id;
24125537Sdfr    else
24230994Sphk	p->p_retval[0] = 0;
24325537Sdfr    return 0;
24425537Sdfr}
24525537Sdfr
24625537Sdfrint
24730994Sphkmodstat(struct proc* p, struct modstat_args* uap)
24825537Sdfr{
24925537Sdfr    module_t mod;
25025537Sdfr    int error = 0;
25125537Sdfr    int namelen;
25225537Sdfr    int version;
25325537Sdfr    struct module_stat* stat;
25425537Sdfr
25525537Sdfr    mod = module_lookupbyid(SCARG(uap, modid));
25625537Sdfr    if (!mod)
25725537Sdfr	return ENOENT;
25825537Sdfr
25925537Sdfr    stat = SCARG(uap, stat);
26025537Sdfr
26125537Sdfr    /*
26225537Sdfr     * Check the version of the user's structure.
26325537Sdfr     */
26425537Sdfr    if (error = copyin(&stat->version, &version, sizeof(version)))
26525537Sdfr	goto out;
26625537Sdfr    if (version != sizeof(struct module_stat)) {
26725537Sdfr	error = EINVAL;
26825537Sdfr	goto out;
26925537Sdfr    }
27025537Sdfr
27125537Sdfr    namelen = strlen(mod->name) + 1;
27225537Sdfr    if (namelen > MAXMODNAME)
27325537Sdfr	namelen = MAXMODNAME;
27425537Sdfr    if (error = copyout(mod->name, &stat->name[0], namelen))
27525537Sdfr	goto out;
27625537Sdfr
27725537Sdfr    if (error = copyout(&mod->refs, &stat->refs, sizeof(int)))
27825537Sdfr	goto out;
27925537Sdfr    if (error = copyout(&mod->id, &stat->id, sizeof(int)))
28025537Sdfr	goto out;
28125537Sdfr
28230994Sphk    p->p_retval[0] = 0;
28325537Sdfr
28425537Sdfrout:
28525537Sdfr    return error;
28625537Sdfr}
28725537Sdfr
28825537Sdfrint
28930994Sphkmodfind(struct proc* p, struct modfind_args* uap)
29025537Sdfr{
29125537Sdfr    int error = 0;
29225537Sdfr    char name[MAXMODNAME];
29325537Sdfr    module_t mod;
29425537Sdfr
29525537Sdfr    if (error = copyinstr(SCARG(uap, name), name, sizeof name, 0))
29625537Sdfr	goto out;
29725537Sdfr
29825537Sdfr    mod = module_lookupbyname(name);
29925537Sdfr    if (!mod)
30025537Sdfr	error = ENOENT;
30125537Sdfr    else
30230994Sphk	p->p_retval[0] = mod->id;
30325537Sdfr
30425537Sdfrout:
30525537Sdfr    return error;
30625537Sdfr}
307