kern_module.c revision 91067
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 91067 2002-02-22 13:33:10Z arr $
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>
3982749Sdillon#include <sys/lock.h>
4082749Sdillon#include <sys/mutex.h>
4125537Sdfr
4269774Sphkstatic MALLOC_DEFINE(M_MODULE, "module", "module data structures");
4325537Sdfr
4460938Sjaketypedef TAILQ_HEAD(, module) modulelist_t;
4525537Sdfrstruct module {
4690963Sarr	TAILQ_ENTRY(module)	link;	/* chain together all modules */
4790963Sarr	TAILQ_ENTRY(module)	flink;	/* all modules in a file */
4890963Sarr	struct linker_file	*file;	/* file which contains this module */
4990963Sarr	int			refs;	/* reference count */
5090963Sarr	int 			id;	/* unique id number */
5190963Sarr	char 			*name;	/* module name */
5290963Sarr	modeventhand_t 		handler;	/* event handler */
5390963Sarr	void 			*arg;	/* argument for handler */
5490963Sarr	modspecific_t 		data;	/* module specific data */
5525537Sdfr};
5625537Sdfr
5790963Sarr#define MOD_EVENT(mod, type)	(mod)->handler((mod), (type), (mod)->arg)
5825537Sdfr
5925537Sdfrstatic modulelist_t modules;
6025537Sdfrstatic int nextid = 1;
6190963Sarrstatic void module_shutdown(void *, int);
6225537Sdfr
6352991Speterstatic int
6490963Sarrmodevent_nop(module_t mod, int what, void *arg)
6552991Speter{
6690980Sarr	return (0);
6752991Speter}
6852991Speter
6952991Speter
7025537Sdfrstatic void
7190963Sarrmodule_init(void *arg)
7225537Sdfr{
7390963Sarr
7490963Sarr	TAILQ_INIT(&modules);
7590963Sarr	EVENTHANDLER_REGISTER(shutdown_post_sync, module_shutdown, NULL,
7690963Sarr	    SHUTDOWN_PRI_DEFAULT);
7725537Sdfr}
7825537Sdfr
7990963SarrSYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0)
8025537Sdfr
8125537Sdfrstatic void
8290963Sarrmodule_shutdown(void *arg1, int arg2)
8325537Sdfr{
8490963Sarr	module_t mod;
8525537Sdfr
8690963Sarr	TAILQ_FOREACH(mod, &modules, link)
8790963Sarr		MOD_EVENT(mod, MOD_SHUTDOWN);
8825537Sdfr}
8925537Sdfr
9025537Sdfrvoid
9143387Sdillonmodule_register_init(const void *arg)
9225537Sdfr{
9390963Sarr	const moduledata_t *data = (const moduledata_t *)arg;
9490963Sarr	int error;
9590963Sarr	module_t mod;
9625537Sdfr
9790963Sarr	mod = module_lookupbyname(data->name);
9890963Sarr	if (mod == NULL)
9991067Sarr		panic("module_register_init: module named %s not found\n",
10090963Sarr		    data->name);
10190963Sarr	error = MOD_EVENT(mod, MOD_LOAD);
10290963Sarr	if (error) {
10390963Sarr		MOD_EVENT(mod, MOD_UNLOAD);
10490963Sarr		module_release(mod);
10591067Sarr		printf("module_register_init: MOD_LOAD (%s, %lx, %p) error"
10691067Sarr		    " %d\n", data->name, data->evhand, data->priv,
10791067Sarr		    error);
10890963Sarr	}
10925537Sdfr}
11025537Sdfr
11125537Sdfrint
11246693Spetermodule_register(const moduledata_t *data, linker_file_t container)
11325537Sdfr{
11490963Sarr	size_t namelen;
11590963Sarr	module_t newmod;
11625537Sdfr
11790963Sarr	newmod = module_lookupbyname(data->name);
11890963Sarr	if (newmod != NULL) {
11991067Sarr		printf("module_register: module %s already exists!\n",
12090963Sarr		    data->name);
12190980Sarr		return (EEXIST);
12290963Sarr	}
12390963Sarr	namelen = strlen(data->name) + 1;
12490963Sarr	newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK);
12590963Sarr	if (newmod == NULL)
12690980Sarr		return (ENOMEM);
12790963Sarr	newmod->refs = 1;
12890963Sarr	newmod->id = nextid++;
12990963Sarr	newmod->name = (char *)(newmod + 1);
13090963Sarr	strcpy(newmod->name, data->name);
13190963Sarr	newmod->handler = data->evhand ? data->evhand : modevent_nop;
13290963Sarr	newmod->arg = data->priv;
13390963Sarr	bzero(&newmod->data, sizeof(newmod->data));
13490963Sarr	TAILQ_INSERT_TAIL(&modules, newmod, link);
13525537Sdfr
13690963Sarr	if (container)
13790963Sarr		TAILQ_INSERT_TAIL(&container->modules, newmod, flink);
13890963Sarr	newmod->file = container;
13990980Sarr	return (0);
14025537Sdfr}
14125537Sdfr
14225537Sdfrvoid
14325537Sdfrmodule_reference(module_t mod)
14425537Sdfr{
14525537Sdfr
14690963Sarr	MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
14790963Sarr	mod->refs++;
14825537Sdfr}
14925537Sdfr
15025537Sdfrvoid
15125537Sdfrmodule_release(module_t mod)
15225537Sdfr{
15325537Sdfr
15490963Sarr	if (mod->refs <= 0)
15590963Sarr		panic("module_release: bad reference count");
15625537Sdfr
15790963Sarr	MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
15890963Sarr
15990963Sarr	mod->refs--;
16090963Sarr	if (mod->refs == 0) {
16190963Sarr		TAILQ_REMOVE(&modules, mod, link);
16290963Sarr		if (mod->file)
16390963Sarr			TAILQ_REMOVE(&mod->file->modules, mod, flink);
16490963Sarr		free(mod, M_MODULE);
16525537Sdfr	}
16625537Sdfr}
16725537Sdfr
16825537Sdfrmodule_t
16990963Sarrmodule_lookupbyname(const char *name)
17025537Sdfr{
17190963Sarr	module_t mod;
17290963Sarr	int err;
17325537Sdfr
17490963Sarr	TAILQ_FOREACH(mod, &modules, link) {
17590963Sarr		err = strcmp(mod->name, name);
17690963Sarr		if (err == 0)
17790980Sarr			return (mod);
17890963Sarr	}
17990980Sarr	return (NULL);
18025537Sdfr}
18125537Sdfr
18225537Sdfrmodule_t
18325537Sdfrmodule_lookupbyid(int modid)
18425537Sdfr{
18590980Sarr	module_t mod;
18625537Sdfr
18790963Sarr	TAILQ_FOREACH(mod, &modules, link) {
18890963Sarr		if (mod->id == modid)
18990980Sarr			return (mod);
19090963Sarr	}
19190980Sarr	return (NULL);
19225537Sdfr}
19325537Sdfr
19425537Sdfrint
19525537Sdfrmodule_unload(module_t mod)
19625537Sdfr{
19790963Sarr
19890980Sarr	return (MOD_EVENT(mod, MOD_UNLOAD));
19925537Sdfr}
20025537Sdfr
20125537Sdfrint
20225537Sdfrmodule_getid(module_t mod)
20325537Sdfr{
20490963Sarr
20590980Sarr	return (mod->id);
20625537Sdfr}
20725537Sdfr
20825537Sdfrmodule_t
20925537Sdfrmodule_getfnext(module_t mod)
21025537Sdfr{
21190963Sarr
21290980Sarr	return (TAILQ_NEXT(mod, flink));
21325537Sdfr}
21425537Sdfr
21542435Sdfrvoid
21642435Sdfrmodule_setspecific(module_t mod, modspecific_t *datap)
21742435Sdfr{
21890963Sarr
21990963Sarr	mod->data = *datap;
22042435Sdfr}
22142435Sdfr
22225537Sdfr/*
22325537Sdfr * Syscalls.
22425537Sdfr */
22582749Sdillon/*
22682749Sdillon * MPSAFE
22782749Sdillon */
22825537Sdfrint
22983366Sjulianmodnext(struct thread *td, struct modnext_args *uap)
23025537Sdfr{
23190963Sarr	module_t mod;
23290963Sarr	int error = 0;
23325537Sdfr
23490963Sarr	mtx_lock(&Giant);
23582749Sdillon
23690963Sarr	td->td_retval[0] = -1;
23790963Sarr	if (SCARG(uap, modid) == 0) {
23890963Sarr		mod = TAILQ_FIRST(&modules);
23990963Sarr		if (mod)
24090963Sarr			td->td_retval[0] = mod->id;
24190963Sarr		else
24290963Sarr			error = ENOENT;
24390963Sarr		goto done2;
24490963Sarr	}
24590963Sarr	mod = module_lookupbyid(SCARG(uap, modid));
24690963Sarr	if (mod == NULL) {
24790963Sarr		error = ENOENT;
24890963Sarr		goto done2;
24990963Sarr	}
25090963Sarr	if (TAILQ_NEXT(mod, link))
25190963Sarr		td->td_retval[0] = TAILQ_NEXT(mod, link)->id;
25282749Sdillon	else
25390963Sarr		td->td_retval[0] = 0;
25482749Sdillondone2:
25590963Sarr	mtx_unlock(&Giant);
25690963Sarr	return (error);
25725537Sdfr}
25825537Sdfr
25982749Sdillon/*
26082749Sdillon * MPSAFE
26182749Sdillon */
26225537Sdfrint
26383366Sjulianmodfnext(struct thread *td, struct modfnext_args *uap)
26425537Sdfr{
26590963Sarr	module_t mod;
26690963Sarr	int error;
26725537Sdfr
26890963Sarr	td->td_retval[0] = -1;
26925537Sdfr
27090963Sarr	mtx_lock(&Giant);
27182749Sdillon
27290963Sarr	mod = module_lookupbyid(SCARG(uap, modid));
27390963Sarr	if (mod == NULL) {
27490963Sarr		error = ENOENT;
27590963Sarr	} else {
27690963Sarr		error = 0;
27790963Sarr		if (TAILQ_NEXT(mod, flink))
27890963Sarr			td->td_retval[0] = TAILQ_NEXT(mod, flink)->id;
27990963Sarr		else
28090963Sarr			td->td_retval[0] = 0;
28190963Sarr	}
28290963Sarr	mtx_unlock(&Giant);
28390963Sarr	return (error);
28425537Sdfr}
28525537Sdfr
28642435Sdfrstruct module_stat_v1 {
28791067Sarr	int	version;		/* set to sizeof(struct module_stat) */
28891067Sarr	char	name[MAXMODNAME];
28991067Sarr	int	refs;
29091067Sarr	int	id;
29142435Sdfr};
29242435Sdfr
29382749Sdillon/*
29482749Sdillon * MPSAFE
29582749Sdillon */
29625537Sdfrint
29783366Sjulianmodstat(struct thread *td, struct modstat_args *uap)
29825537Sdfr{
29990963Sarr	module_t mod;
30090963Sarr	int error = 0;
30190963Sarr	int namelen;
30290963Sarr	int version;
30390963Sarr	struct module_stat *stat;
30425537Sdfr
30590963Sarr	mtx_lock(&Giant);
30682749Sdillon
30790963Sarr	mod = module_lookupbyid(SCARG(uap, modid));
30890963Sarr	if (mod == NULL) {
30990963Sarr		error = ENOENT;
31090963Sarr		goto out;
31190963Sarr	}
31290963Sarr	stat = SCARG(uap, stat);
31325537Sdfr
31490963Sarr	/*
31590963Sarr	 * Check the version of the user's structure.
31690963Sarr	 */
31790963Sarr	if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
31890963Sarr		goto out;
31990963Sarr	if (version != sizeof(struct module_stat_v1)
32090963Sarr	    && version != sizeof(struct module_stat)) {
32190963Sarr		error = EINVAL;
32290963Sarr		goto out;
32390963Sarr	}
32490963Sarr	namelen = strlen(mod->name) + 1;
32590963Sarr	if (namelen > MAXMODNAME)
32690963Sarr		namelen = MAXMODNAME;
32790963Sarr	if ((error = copyout(mod->name, &stat->name[0], namelen)) != 0)
32890963Sarr		goto out;
32925537Sdfr
33090963Sarr	if ((error = copyout(&mod->refs, &stat->refs, sizeof(int))) != 0)
33190963Sarr		goto out;
33290963Sarr	if ((error = copyout(&mod->id, &stat->id, sizeof(int))) != 0)
33390963Sarr		goto out;
33425537Sdfr
33590963Sarr	/*
33690963Sarr	 * >v1 stat includes module data.
33790963Sarr	 */
33890963Sarr	if (version == sizeof(struct module_stat)) {
33990963Sarr		if ((error = copyout(&mod->data, &stat->data,
34090963Sarr		    sizeof(mod->data))) != 0)
34190963Sarr			goto out;
34290963Sarr	}
34390963Sarr	td->td_retval[0] = 0;
34425537Sdfrout:
34590963Sarr	mtx_unlock(&Giant);
34690980Sarr	return (error);
34725537Sdfr}
34825537Sdfr
34982749Sdillon/*
35082749Sdillon * MPSAFE
35182749Sdillon */
35225537Sdfrint
35383366Sjulianmodfind(struct thread *td, struct modfind_args *uap)
35425537Sdfr{
35590963Sarr	int error = 0;
35690963Sarr	char name[MAXMODNAME];
35790963Sarr	module_t mod;
35825537Sdfr
35990963Sarr	if ((error = copyinstr(SCARG(uap, name), name, sizeof name, 0)) != 0)
36090963Sarr		goto out;
36125537Sdfr
36290963Sarr	mtx_lock(&Giant);
36390963Sarr	mod = module_lookupbyname(name);
36490963Sarr	if (mod == NULL)
36590963Sarr		error = ENOENT;
36690963Sarr	else
36790963Sarr		td->td_retval[0] = mod->id;
36890963Sarr	mtx_unlock(&Giant);
36925537Sdfrout:
37090980Sarr	return (error);
37125537Sdfr}
372