kern_module.c revision 43301
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 *
2643301Sdillon *	$Id: kern_module.c,v 1.14 1999/01/09 16:50:04 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 */
5142435Sdfr    modspecific_t	data;		/* module specific data */
5225537Sdfr};
5325537Sdfr
5425537Sdfr#define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg)
5525537Sdfr
5625537Sdfrstatic modulelist_t modules;
5725537Sdfrstatic int nextid = 1;
5825537Sdfr
5925537Sdfrstatic void module_shutdown(int, void*);
6025537Sdfr
6125537Sdfrstatic void
6225537Sdfrmodule_init(void* arg)
6325537Sdfr{
6425537Sdfr    TAILQ_INIT(&modules);
6525537Sdfr    at_shutdown(module_shutdown, 0, SHUTDOWN_POST_SYNC);
6625537Sdfr}
6725537Sdfr
6840435SpeterSYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0);
6925537Sdfr
7025537Sdfrstatic void
7125537Sdfrmodule_shutdown(int arg1, void* arg2)
7225537Sdfr{
7325537Sdfr    module_t mod;
7425537Sdfr
7525537Sdfr    for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link))
7625537Sdfr	MOD_EVENT(mod, MOD_SHUTDOWN);
7725537Sdfr}
7825537Sdfr
7925537Sdfrvoid
8030683Sjmgmodule_register_init(void *arg)
8125537Sdfr{
8225537Sdfr    moduledata_t* data = (moduledata_t*) arg;
8325537Sdfr    int error;
8425537Sdfr
8540158Speter    error = module_register(data->name, data->evhand, data->priv, data->_file);
8640158Speter    if (error)
8740945Speter	printf("module_register_init: module_register(%s, %lx, %p) error %d\n",
8837629Sbde	       data->name, (u_long)(uintfptr_t)data->evhand, data->priv, error);
8925537Sdfr}
9025537Sdfr
9125537Sdfrint
9240158Spetermodule_register(const char* name, modeventhand_t handler, void* arg, void *file)
9325537Sdfr{
9425537Sdfr    size_t namelen;
9525537Sdfr    module_t newmod;
9625537Sdfr    int error;
9740158Speter    linker_file_t container = file;
9825537Sdfr
9925537Sdfr    namelen = strlen(name) + 1;
10025537Sdfr    newmod = (module_t) malloc(sizeof(struct module) + namelen,
10125537Sdfr			       M_MODULE, M_WAITOK);
10225537Sdfr    if (newmod == 0)
10325537Sdfr	return ENOMEM;
10425537Sdfr
10525537Sdfr    newmod->refs = 1;
10625537Sdfr    newmod->id = nextid++;
10725537Sdfr    newmod->name = (char *) (newmod + 1);
10825537Sdfr    strcpy(newmod->name, name);
10925537Sdfr    newmod->handler = handler;
11025537Sdfr    newmod->arg = arg;
11142435Sdfr    bzero(&newmod->data, sizeof(newmod->data));
11225537Sdfr    TAILQ_INSERT_TAIL(&modules, newmod, link);
11325537Sdfr
11440158Speter    if (container == NULL)
11540158Speter	container = linker_current_file;
11640158Speter    if (container) {
11740158Speter	TAILQ_INSERT_TAIL(&container->modules, newmod, flink);
11840158Speter	newmod->file = container;
11925537Sdfr    } else
12025537Sdfr	newmod->file = 0;
12125537Sdfr
12243301Sdillon    if ((error = MOD_EVENT(newmod, MOD_LOAD)) != 0) {
12339916Sdfr	MOD_EVENT(newmod, MOD_UNLOAD);
12425537Sdfr	module_release(newmod);
12525537Sdfr	return error;
12625537Sdfr    }
12725537Sdfr
12825537Sdfr    return 0;
12925537Sdfr}
13025537Sdfr
13125537Sdfrvoid
13225537Sdfrmodule_reference(module_t mod)
13325537Sdfr{
13425537Sdfr    MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
13525537Sdfr
13625537Sdfr    mod->refs++;
13725537Sdfr}
13825537Sdfr
13925537Sdfrvoid
14025537Sdfrmodule_release(module_t mod)
14125537Sdfr{
14225537Sdfr    if (mod->refs <= 0)
14325537Sdfr	panic("module_release: bad reference count");
14425537Sdfr
14525537Sdfr    MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
14625537Sdfr
14725537Sdfr    mod->refs--;
14825537Sdfr    if (mod->refs == 0) {
14925537Sdfr	TAILQ_REMOVE(&modules, mod, link);
15025537Sdfr	if (mod->file) {
15125537Sdfr	    TAILQ_REMOVE(&mod->file->modules, mod, flink);
15225537Sdfr	}
15325537Sdfr	free(mod, M_MODULE);
15425537Sdfr    }
15525537Sdfr}
15625537Sdfr
15725537Sdfrmodule_t
15825537Sdfrmodule_lookupbyname(const char* name)
15925537Sdfr{
16025537Sdfr    module_t mod;
16125537Sdfr
16225537Sdfr    for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) {
16325537Sdfr	if (!strcmp(mod->name, name))
16425537Sdfr	    return mod;
16525537Sdfr    }
16625537Sdfr
16725537Sdfr    return 0;
16825537Sdfr}
16925537Sdfr
17025537Sdfrmodule_t
17125537Sdfrmodule_lookupbyid(int modid)
17225537Sdfr{
17325537Sdfr    module_t mod;
17425537Sdfr
17525537Sdfr    for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) {
17625537Sdfr	if (mod->id == modid)
17725537Sdfr	    return mod;
17825537Sdfr    }
17925537Sdfr
18025537Sdfr    return 0;
18125537Sdfr}
18225537Sdfr
18325537Sdfrint
18425537Sdfrmodule_unload(module_t mod)
18525537Sdfr{
18625537Sdfr    return MOD_EVENT(mod, MOD_UNLOAD);
18725537Sdfr}
18825537Sdfr
18925537Sdfrint
19025537Sdfrmodule_getid(module_t mod)
19125537Sdfr{
19225537Sdfr    return mod->id;
19325537Sdfr}
19425537Sdfr
19525537Sdfrmodule_t
19625537Sdfrmodule_getfnext(module_t mod)
19725537Sdfr{
19825537Sdfr    return TAILQ_NEXT(mod, flink);
19925537Sdfr}
20025537Sdfr
20142435Sdfrvoid
20242435Sdfrmodule_setspecific(module_t mod, modspecific_t *datap)
20342435Sdfr{
20442435Sdfr    mod->data = *datap;
20542435Sdfr}
20642435Sdfr
20725537Sdfr/*
20825537Sdfr * Syscalls.
20925537Sdfr */
21025537Sdfrint
21130994Sphkmodnext(struct proc* p, struct modnext_args* uap)
21225537Sdfr{
21325537Sdfr    module_t mod;
21425537Sdfr
21530994Sphk    p->p_retval[0] = -1;
21625537Sdfr    if (SCARG(uap, modid) == 0) {
21725537Sdfr	mod = TAILQ_FIRST(&modules);
21825537Sdfr	if (mod) {
21930994Sphk	    p->p_retval[0] = mod->id;
22025537Sdfr	    return 0;
22125537Sdfr	} else
22225537Sdfr	    return ENOENT;
22325537Sdfr    }
22425537Sdfr
22525537Sdfr    mod = module_lookupbyid(SCARG(uap, modid));
22625537Sdfr    if (!mod)
22725537Sdfr	return ENOENT;
22825537Sdfr
22925537Sdfr    if (TAILQ_NEXT(mod, link))
23030994Sphk	p->p_retval[0] = TAILQ_NEXT(mod, link)->id;
23125537Sdfr    else
23230994Sphk	p->p_retval[0] = 0;
23325537Sdfr    return 0;
23425537Sdfr}
23525537Sdfr
23625537Sdfrint
23730994Sphkmodfnext(struct proc* p, struct modfnext_args* uap)
23825537Sdfr{
23925537Sdfr    module_t mod;
24025537Sdfr
24130994Sphk    p->p_retval[0] = -1;
24225537Sdfr
24325537Sdfr    mod = module_lookupbyid(SCARG(uap, modid));
24425537Sdfr    if (!mod)
24525537Sdfr	return ENOENT;
24625537Sdfr
24725537Sdfr    if (TAILQ_NEXT(mod, flink))
24830994Sphk	p->p_retval[0] = TAILQ_NEXT(mod, flink)->id;
24925537Sdfr    else
25030994Sphk	p->p_retval[0] = 0;
25125537Sdfr    return 0;
25225537Sdfr}
25325537Sdfr
25442435Sdfrstruct module_stat_v1 {
25542435Sdfr    int		version;	/* set to sizeof(struct module_stat) */
25642435Sdfr    char	name[MAXMODNAME];
25742435Sdfr    int		refs;
25842435Sdfr    int		id;
25942435Sdfr};
26042435Sdfr
26125537Sdfrint
26230994Sphkmodstat(struct proc* p, struct modstat_args* uap)
26325537Sdfr{
26425537Sdfr    module_t mod;
26525537Sdfr    int error = 0;
26625537Sdfr    int namelen;
26725537Sdfr    int version;
26825537Sdfr    struct module_stat* stat;
26925537Sdfr
27025537Sdfr    mod = module_lookupbyid(SCARG(uap, modid));
27125537Sdfr    if (!mod)
27225537Sdfr	return ENOENT;
27325537Sdfr
27425537Sdfr    stat = SCARG(uap, stat);
27525537Sdfr
27625537Sdfr    /*
27725537Sdfr     * Check the version of the user's structure.
27825537Sdfr     */
27943301Sdillon    if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
28025537Sdfr	goto out;
28142435Sdfr    if (version != sizeof(struct module_stat_v1)
28242435Sdfr	&& version != sizeof(struct module_stat)) {
28325537Sdfr	error = EINVAL;
28425537Sdfr	goto out;
28525537Sdfr    }
28625537Sdfr
28725537Sdfr    namelen = strlen(mod->name) + 1;
28825537Sdfr    if (namelen > MAXMODNAME)
28925537Sdfr	namelen = MAXMODNAME;
29043301Sdillon    if ((error = copyout(mod->name, &stat->name[0], namelen)) != 0)
29125537Sdfr	goto out;
29225537Sdfr
29343301Sdillon    if ((error = copyout(&mod->refs, &stat->refs, sizeof(int))) != 0)
29425537Sdfr	goto out;
29543301Sdillon    if ((error = copyout(&mod->id, &stat->id, sizeof(int))) != 0)
29625537Sdfr	goto out;
29725537Sdfr
29842435Sdfr    /*
29942435Sdfr     * >v1 stat includes module data.
30042435Sdfr     */
30142435Sdfr    if (version == sizeof(struct module_stat)) {
30243301Sdillon	if ((error = copyout(&mod->data, &stat->data, sizeof(mod->data))) != 0)
30342435Sdfr	    goto out;
30442439Sdfr    }
30542435Sdfr
30630994Sphk    p->p_retval[0] = 0;
30725537Sdfr
30825537Sdfrout:
30925537Sdfr    return error;
31025537Sdfr}
31125537Sdfr
31225537Sdfrint
31330994Sphkmodfind(struct proc* p, struct modfind_args* uap)
31425537Sdfr{
31525537Sdfr    int error = 0;
31625537Sdfr    char name[MAXMODNAME];
31725537Sdfr    module_t mod;
31825537Sdfr
31943301Sdillon    if ((error = copyinstr(SCARG(uap, name), name, sizeof name, 0)) != 0)
32025537Sdfr	goto out;
32125537Sdfr
32225537Sdfr    mod = module_lookupbyname(name);
32325537Sdfr    if (!mod)
32425537Sdfr	error = ENOENT;
32525537Sdfr    else
32630994Sphk	p->p_retval[0] = mod->id;
32725537Sdfr
32825537Sdfrout:
32925537Sdfr    return error;
33025537Sdfr}
331