kern_module.c revision 60938
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 *
2650477Speter * $FreeBSD: head/sys/kern/kern_module.c 60938 2000-05-26 02:09:24Z jake $
2725537Sdfr */
2825537Sdfr
2925537Sdfr#include <sys/param.h>
3025537Sdfr#include <sys/kernel.h>
3125537Sdfr#include <sys/systm.h>
3250107Smsmith#include <sys/eventhandler.h>
3325537Sdfr#include <sys/malloc.h>
3425537Sdfr#include <sys/sysproto.h>
3525537Sdfr#include <sys/sysent.h>
3625537Sdfr#include <sys/module.h>
3725537Sdfr#include <sys/linker.h>
3830994Sphk#include <sys/proc.h>
3925537Sdfr
4059751SpeterMALLOC_DEFINE(M_MODULE, "module", "module data structures");
4125537Sdfr
4260938Sjaketypedef TAILQ_HEAD(, module) modulelist_t;
4325537Sdfrstruct module {
4460938Sjake    TAILQ_ENTRY(module)	link;		/* chain together all modules */
4560938Sjake    TAILQ_ENTRY(module)	flink;		/* all modules in a file */
4625537Sdfr    struct linker_file*	file;		/* file which contains this module */
4725537Sdfr    int			refs;		/* reference count */
4825537Sdfr    int			id;		/* unique id number */
4925537Sdfr    char		*name;		/* module name */
5025537Sdfr    modeventhand_t	handler;	/* event handler */
5125537Sdfr    void		*arg;		/* argument for handler */
5242435Sdfr    modspecific_t	data;		/* module specific data */
5325537Sdfr};
5425537Sdfr
5525537Sdfr#define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg)
5625537Sdfr
5725537Sdfrstatic modulelist_t modules;
5825537Sdfrstatic int nextid = 1;
5925537Sdfr
6050107Smsmithstatic void module_shutdown(void*, int);
6125537Sdfr
6252991Speterstatic int
6352991Spetermodevent_nop(module_t mod, int what, void* arg)
6452991Speter{
6552991Speter	return 0;
6652991Speter}
6752991Speter
6852991Speter
6925537Sdfrstatic void
7025537Sdfrmodule_init(void* arg)
7125537Sdfr{
7225537Sdfr    TAILQ_INIT(&modules);
7350107Smsmith    EVENTHANDLER_REGISTER(shutdown_post_sync, module_shutdown, NULL,
7450107Smsmith			  SHUTDOWN_PRI_DEFAULT);
7525537Sdfr}
7625537Sdfr
7740435SpeterSYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0);
7825537Sdfr
7925537Sdfrstatic void
8050107Smsmithmodule_shutdown(void* arg1, int arg2)
8125537Sdfr{
8225537Sdfr    module_t mod;
8325537Sdfr
8425537Sdfr    for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link))
8525537Sdfr	MOD_EVENT(mod, MOD_SHUTDOWN);
8625537Sdfr}
8725537Sdfr
8825537Sdfrvoid
8943387Sdillonmodule_register_init(const void *arg)
9025537Sdfr{
9143387Sdillon    const moduledata_t* data = (const moduledata_t*) arg;
9225537Sdfr    int error;
9346693Speter    module_t mod;
9425537Sdfr
9546693Speter    mod = module_lookupbyname(data->name);
9659751Speter    if (mod == NULL)
9746693Speter	panic("module_register_init: module named %s not found\n", data->name);
9846693Speter    error = MOD_EVENT(mod, MOD_LOAD);
9946693Speter    if (error) {
10046693Speter	MOD_EVENT(mod, MOD_UNLOAD);
10146693Speter	module_release(mod);
10246693Speter	printf("module_register_init: MOD_LOAD (%s, %lx, %p) error %d\n",
10337629Sbde	       data->name, (u_long)(uintfptr_t)data->evhand, data->priv, error);
10446693Speter    }
10525537Sdfr}
10625537Sdfr
10725537Sdfrint
10846693Spetermodule_register(const moduledata_t *data, linker_file_t container)
10925537Sdfr{
11025537Sdfr    size_t namelen;
11125537Sdfr    module_t newmod;
11225537Sdfr
11346693Speter    newmod = module_lookupbyname(data->name);
11446693Speter    if (newmod != NULL) {
11546693Speter	printf("module_register: module %s already exists!\n", data->name);
11646693Speter	return EEXIST;
11746693Speter    }
11846693Speter    namelen = strlen(data->name) + 1;
11925537Sdfr    newmod = (module_t) malloc(sizeof(struct module) + namelen,
12025537Sdfr			       M_MODULE, M_WAITOK);
12125537Sdfr    if (newmod == 0)
12225537Sdfr	return ENOMEM;
12325537Sdfr
12425537Sdfr    newmod->refs = 1;
12525537Sdfr    newmod->id = nextid++;
12625537Sdfr    newmod->name = (char *) (newmod + 1);
12746693Speter    strcpy(newmod->name, data->name);
12852991Speter    newmod->handler = data->evhand ? data->evhand : modevent_nop;
12946693Speter    newmod->arg = data->priv;
13042435Sdfr    bzero(&newmod->data, sizeof(newmod->data));
13125537Sdfr    TAILQ_INSERT_TAIL(&modules, newmod, link);
13225537Sdfr
13346693Speter    if (container)
13440158Speter	TAILQ_INSERT_TAIL(&container->modules, newmod, flink);
13547330Speter    newmod->file = container;
13625537Sdfr
13725537Sdfr    return 0;
13825537Sdfr}
13925537Sdfr
14025537Sdfrvoid
14125537Sdfrmodule_reference(module_t mod)
14225537Sdfr{
14325537Sdfr    MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
14425537Sdfr
14525537Sdfr    mod->refs++;
14625537Sdfr}
14725537Sdfr
14825537Sdfrvoid
14925537Sdfrmodule_release(module_t mod)
15025537Sdfr{
15125537Sdfr    if (mod->refs <= 0)
15225537Sdfr	panic("module_release: bad reference count");
15325537Sdfr
15425537Sdfr    MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
15525537Sdfr
15625537Sdfr    mod->refs--;
15725537Sdfr    if (mod->refs == 0) {
15825537Sdfr	TAILQ_REMOVE(&modules, mod, link);
15925537Sdfr	if (mod->file) {
16025537Sdfr	    TAILQ_REMOVE(&mod->file->modules, mod, flink);
16125537Sdfr	}
16225537Sdfr	free(mod, M_MODULE);
16325537Sdfr    }
16425537Sdfr}
16525537Sdfr
16625537Sdfrmodule_t
16725537Sdfrmodule_lookupbyname(const char* name)
16825537Sdfr{
16925537Sdfr    module_t mod;
17025537Sdfr
17125537Sdfr    for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) {
17225537Sdfr	if (!strcmp(mod->name, name))
17325537Sdfr	    return mod;
17425537Sdfr    }
17525537Sdfr
17625537Sdfr    return 0;
17725537Sdfr}
17825537Sdfr
17925537Sdfrmodule_t
18025537Sdfrmodule_lookupbyid(int modid)
18125537Sdfr{
18225537Sdfr    module_t mod;
18325537Sdfr
18425537Sdfr    for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) {
18525537Sdfr	if (mod->id == modid)
18625537Sdfr	    return mod;
18725537Sdfr    }
18825537Sdfr
18925537Sdfr    return 0;
19025537Sdfr}
19125537Sdfr
19225537Sdfrint
19325537Sdfrmodule_unload(module_t mod)
19425537Sdfr{
19525537Sdfr    return MOD_EVENT(mod, MOD_UNLOAD);
19625537Sdfr}
19725537Sdfr
19825537Sdfrint
19925537Sdfrmodule_getid(module_t mod)
20025537Sdfr{
20125537Sdfr    return mod->id;
20225537Sdfr}
20325537Sdfr
20425537Sdfrmodule_t
20525537Sdfrmodule_getfnext(module_t mod)
20625537Sdfr{
20725537Sdfr    return TAILQ_NEXT(mod, flink);
20825537Sdfr}
20925537Sdfr
21042435Sdfrvoid
21142435Sdfrmodule_setspecific(module_t mod, modspecific_t *datap)
21242435Sdfr{
21342435Sdfr    mod->data = *datap;
21442435Sdfr}
21542435Sdfr
21625537Sdfr/*
21725537Sdfr * Syscalls.
21825537Sdfr */
21925537Sdfrint
22030994Sphkmodnext(struct proc* p, struct modnext_args* uap)
22125537Sdfr{
22225537Sdfr    module_t mod;
22325537Sdfr
22430994Sphk    p->p_retval[0] = -1;
22525537Sdfr    if (SCARG(uap, modid) == 0) {
22625537Sdfr	mod = TAILQ_FIRST(&modules);
22725537Sdfr	if (mod) {
22830994Sphk	    p->p_retval[0] = mod->id;
22925537Sdfr	    return 0;
23025537Sdfr	} else
23125537Sdfr	    return ENOENT;
23225537Sdfr    }
23325537Sdfr
23425537Sdfr    mod = module_lookupbyid(SCARG(uap, modid));
23525537Sdfr    if (!mod)
23625537Sdfr	return ENOENT;
23725537Sdfr
23825537Sdfr    if (TAILQ_NEXT(mod, link))
23930994Sphk	p->p_retval[0] = TAILQ_NEXT(mod, link)->id;
24025537Sdfr    else
24130994Sphk	p->p_retval[0] = 0;
24225537Sdfr    return 0;
24325537Sdfr}
24425537Sdfr
24525537Sdfrint
24630994Sphkmodfnext(struct proc* p, struct modfnext_args* uap)
24725537Sdfr{
24825537Sdfr    module_t mod;
24925537Sdfr
25030994Sphk    p->p_retval[0] = -1;
25125537Sdfr
25225537Sdfr    mod = module_lookupbyid(SCARG(uap, modid));
25325537Sdfr    if (!mod)
25425537Sdfr	return ENOENT;
25525537Sdfr
25625537Sdfr    if (TAILQ_NEXT(mod, flink))
25730994Sphk	p->p_retval[0] = TAILQ_NEXT(mod, flink)->id;
25825537Sdfr    else
25930994Sphk	p->p_retval[0] = 0;
26025537Sdfr    return 0;
26125537Sdfr}
26225537Sdfr
26342435Sdfrstruct module_stat_v1 {
26442435Sdfr    int		version;	/* set to sizeof(struct module_stat) */
26542435Sdfr    char	name[MAXMODNAME];
26642435Sdfr    int		refs;
26742435Sdfr    int		id;
26842435Sdfr};
26942435Sdfr
27025537Sdfrint
27130994Sphkmodstat(struct proc* p, struct modstat_args* uap)
27225537Sdfr{
27325537Sdfr    module_t mod;
27425537Sdfr    int error = 0;
27525537Sdfr    int namelen;
27625537Sdfr    int version;
27725537Sdfr    struct module_stat* stat;
27825537Sdfr
27925537Sdfr    mod = module_lookupbyid(SCARG(uap, modid));
28025537Sdfr    if (!mod)
28125537Sdfr	return ENOENT;
28225537Sdfr
28325537Sdfr    stat = SCARG(uap, stat);
28425537Sdfr
28525537Sdfr    /*
28625537Sdfr     * Check the version of the user's structure.
28725537Sdfr     */
28843301Sdillon    if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
28925537Sdfr	goto out;
29042435Sdfr    if (version != sizeof(struct module_stat_v1)
29142435Sdfr	&& version != sizeof(struct module_stat)) {
29225537Sdfr	error = EINVAL;
29325537Sdfr	goto out;
29425537Sdfr    }
29525537Sdfr
29625537Sdfr    namelen = strlen(mod->name) + 1;
29725537Sdfr    if (namelen > MAXMODNAME)
29825537Sdfr	namelen = MAXMODNAME;
29943301Sdillon    if ((error = copyout(mod->name, &stat->name[0], namelen)) != 0)
30025537Sdfr	goto out;
30125537Sdfr
30243301Sdillon    if ((error = copyout(&mod->refs, &stat->refs, sizeof(int))) != 0)
30325537Sdfr	goto out;
30443301Sdillon    if ((error = copyout(&mod->id, &stat->id, sizeof(int))) != 0)
30525537Sdfr	goto out;
30625537Sdfr
30742435Sdfr    /*
30842435Sdfr     * >v1 stat includes module data.
30942435Sdfr     */
31042435Sdfr    if (version == sizeof(struct module_stat)) {
31143301Sdillon	if ((error = copyout(&mod->data, &stat->data, sizeof(mod->data))) != 0)
31242435Sdfr	    goto out;
31342439Sdfr    }
31442435Sdfr
31530994Sphk    p->p_retval[0] = 0;
31625537Sdfr
31725537Sdfrout:
31825537Sdfr    return error;
31925537Sdfr}
32025537Sdfr
32125537Sdfrint
32230994Sphkmodfind(struct proc* p, struct modfind_args* uap)
32325537Sdfr{
32425537Sdfr    int error = 0;
32525537Sdfr    char name[MAXMODNAME];
32625537Sdfr    module_t mod;
32725537Sdfr
32843301Sdillon    if ((error = copyinstr(SCARG(uap, name), name, sizeof name, 0)) != 0)
32925537Sdfr	goto out;
33025537Sdfr
33125537Sdfr    mod = module_lookupbyname(name);
33225537Sdfr    if (!mod)
33325537Sdfr	error = ENOENT;
33425537Sdfr    else
33530994Sphk	p->p_retval[0] = mod->id;
33625537Sdfr
33725537Sdfrout:
33825537Sdfr    return error;
33925537Sdfr}
340