kern_module.c revision 37629
10Sstevel@tonic-gate/*-
20Sstevel@tonic-gate * Copyright (c) 1997 Doug Rabson
30Sstevel@tonic-gate * All rights reserved.
40Sstevel@tonic-gate *
56073Sacruz * Redistribution and use in source and binary forms, with or without
66073Sacruz * modification, are permitted provided that the following conditions
70Sstevel@tonic-gate * are met:
80Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright
90Sstevel@tonic-gate *    notice, this list of conditions and the following disclaimer.
100Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright
110Sstevel@tonic-gate *    notice, this list of conditions and the following disclaimer in the
120Sstevel@tonic-gate *    documentation and/or other materials provided with the distribution.
130Sstevel@tonic-gate *
140Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
150Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
160Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
170Sstevel@tonic-gate * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
180Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
190Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
200Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
210Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
226073Sacruz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
230Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
240Sstevel@tonic-gate * SUCH DAMAGE.
250Sstevel@tonic-gate *
260Sstevel@tonic-gate *	$Id: kern_module.c,v 1.7 1998/07/11 07:45:40 bde Exp $
270Sstevel@tonic-gate */
280Sstevel@tonic-gate
290Sstevel@tonic-gate#include <sys/param.h>
300Sstevel@tonic-gate#include <sys/kernel.h>
310Sstevel@tonic-gate#include <sys/systm.h>
320Sstevel@tonic-gate#include <sys/malloc.h>
330Sstevel@tonic-gate#include <sys/sysproto.h>
340Sstevel@tonic-gate#include <sys/sysent.h>
350Sstevel@tonic-gate#include <sys/module.h>
360Sstevel@tonic-gate#include <sys/linker.h>
370Sstevel@tonic-gate#include <sys/proc.h>
380Sstevel@tonic-gate
390Sstevel@tonic-gate#define M_MODULE	M_TEMP		/* XXX */
400Sstevel@tonic-gate
410Sstevel@tonic-gatetypedef TAILQ_HEAD(, module) modulelist_t;
420Sstevel@tonic-gatestruct module {
430Sstevel@tonic-gate    TAILQ_ENTRY(module)	link;		/* chain together all modules */
440Sstevel@tonic-gate    TAILQ_ENTRY(module)	flink;		/* all modules in a file */
450Sstevel@tonic-gate    struct linker_file*	file;		/* file which contains this module */
460Sstevel@tonic-gate    int			refs;		/* reference count */
470Sstevel@tonic-gate    int			id;		/* unique id number */
480Sstevel@tonic-gate    char		*name;		/* module name */
490Sstevel@tonic-gate    modeventhand_t	handler;	/* event handler */
500Sstevel@tonic-gate    void		*arg;		/* argument for handler */
510Sstevel@tonic-gate};
520Sstevel@tonic-gate
530Sstevel@tonic-gate#define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg)
540Sstevel@tonic-gate
550Sstevel@tonic-gatestatic modulelist_t modules;
560Sstevel@tonic-gatestatic int nextid = 1;
570Sstevel@tonic-gate
580Sstevel@tonic-gatestatic void module_shutdown(int, void*);
590Sstevel@tonic-gate
600Sstevel@tonic-gatestatic void
610Sstevel@tonic-gatemodule_init(void* arg)
620Sstevel@tonic-gate{
630Sstevel@tonic-gate    TAILQ_INIT(&modules);
640Sstevel@tonic-gate    at_shutdown(module_shutdown, 0, SHUTDOWN_POST_SYNC);
650Sstevel@tonic-gate}
660Sstevel@tonic-gate
670Sstevel@tonic-gateSYSINIT(module, SI_SUB_KMEM, SI_ORDER_ANY, module_init, 0);
680Sstevel@tonic-gate
690Sstevel@tonic-gatestatic void
700Sstevel@tonic-gatemodule_shutdown(int arg1, void* arg2)
710Sstevel@tonic-gate{
720Sstevel@tonic-gate    module_t mod;
730Sstevel@tonic-gate
740Sstevel@tonic-gate    for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link))
750Sstevel@tonic-gate	MOD_EVENT(mod, MOD_SHUTDOWN);
760Sstevel@tonic-gate}
770Sstevel@tonic-gate
780Sstevel@tonic-gatevoid
790Sstevel@tonic-gatemodule_register_init(void *arg)
800Sstevel@tonic-gate{
810Sstevel@tonic-gate    moduledata_t* data = (moduledata_t*) arg;
820Sstevel@tonic-gate    int error;
830Sstevel@tonic-gate
840Sstevel@tonic-gate    if (error = module_register(data->name, data->evhand, data->priv))
850Sstevel@tonic-gate	printf("module_register_init: module_register(%s, %lx, %p) returned %d",
860Sstevel@tonic-gate	       data->name, (u_long)(uintfptr_t)data->evhand, data->priv, error);
870Sstevel@tonic-gate}
880Sstevel@tonic-gate
890Sstevel@tonic-gateint
900Sstevel@tonic-gatemodule_register(const char* name, modeventhand_t handler, void* arg)
910Sstevel@tonic-gate{
920Sstevel@tonic-gate    size_t namelen;
930Sstevel@tonic-gate    module_t newmod;
940Sstevel@tonic-gate    int error;
950Sstevel@tonic-gate
960Sstevel@tonic-gate    namelen = strlen(name) + 1;
970Sstevel@tonic-gate    newmod = (module_t) malloc(sizeof(struct module) + namelen,
980Sstevel@tonic-gate			       M_MODULE, M_WAITOK);
990Sstevel@tonic-gate    if (newmod == 0)
1000Sstevel@tonic-gate	return ENOMEM;
1010Sstevel@tonic-gate
1020Sstevel@tonic-gate    newmod->refs = 1;
1030Sstevel@tonic-gate    newmod->id = nextid++;
1040Sstevel@tonic-gate    newmod->name = (char *) (newmod + 1);
1050Sstevel@tonic-gate    strcpy(newmod->name, name);
1060Sstevel@tonic-gate    newmod->handler = handler;
1070Sstevel@tonic-gate    newmod->arg = arg;
1080Sstevel@tonic-gate    TAILQ_INSERT_TAIL(&modules, newmod, link);
1090Sstevel@tonic-gate
1100Sstevel@tonic-gate    if (linker_current_file) {
1110Sstevel@tonic-gate	TAILQ_INSERT_TAIL(&linker_current_file->modules, newmod, flink);
1120Sstevel@tonic-gate	newmod->file = linker_current_file;
1130Sstevel@tonic-gate    } else
1146073Sacruz	newmod->file = 0;
1150Sstevel@tonic-gate
1160Sstevel@tonic-gate    if (error = MOD_EVENT(newmod, MOD_LOAD)) {
1170Sstevel@tonic-gate	module_release(newmod);
1186073Sacruz	return error;
1196073Sacruz    }
1206073Sacruz
1216073Sacruz    return 0;
1226073Sacruz}
1236073Sacruz
1246073Sacruzvoid
1256073Sacruzmodule_reference(module_t mod)
1266073Sacruz{
1276073Sacruz    MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
1286073Sacruz
1296073Sacruz    mod->refs++;
1300Sstevel@tonic-gate}
1310Sstevel@tonic-gate
1320Sstevel@tonic-gatevoid
1330Sstevel@tonic-gatemodule_release(module_t mod)
1340Sstevel@tonic-gate{
1350Sstevel@tonic-gate    if (mod->refs <= 0)
1360Sstevel@tonic-gate	panic("module_release: bad reference count");
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate    MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
1390Sstevel@tonic-gate
1400Sstevel@tonic-gate    mod->refs--;
1410Sstevel@tonic-gate    if (mod->refs == 0) {
1420Sstevel@tonic-gate	TAILQ_REMOVE(&modules, mod, link);
1430Sstevel@tonic-gate	if (mod->file) {
1440Sstevel@tonic-gate	    TAILQ_REMOVE(&mod->file->modules, mod, flink);
1450Sstevel@tonic-gate	}
1460Sstevel@tonic-gate	free(mod, M_MODULE);
1470Sstevel@tonic-gate    }
1480Sstevel@tonic-gate}
1490Sstevel@tonic-gate
1500Sstevel@tonic-gatemodule_t
1510Sstevel@tonic-gatemodule_lookupbyname(const char* name)
1520Sstevel@tonic-gate{
1530Sstevel@tonic-gate    module_t mod;
1540Sstevel@tonic-gate
1550Sstevel@tonic-gate    for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) {
1560Sstevel@tonic-gate	if (!strcmp(mod->name, name))
1570Sstevel@tonic-gate	    return mod;
1580Sstevel@tonic-gate    }
1590Sstevel@tonic-gate
1600Sstevel@tonic-gate    return 0;
1610Sstevel@tonic-gate}
1620Sstevel@tonic-gate
1630Sstevel@tonic-gatemodule_t
1640Sstevel@tonic-gatemodule_lookupbyid(int modid)
1650Sstevel@tonic-gate{
1660Sstevel@tonic-gate    module_t mod;
1670Sstevel@tonic-gate
1680Sstevel@tonic-gate    for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) {
1690Sstevel@tonic-gate	if (mod->id == modid)
1700Sstevel@tonic-gate	    return mod;
1710Sstevel@tonic-gate    }
1720Sstevel@tonic-gate
1730Sstevel@tonic-gate    return 0;
1740Sstevel@tonic-gate}
1750Sstevel@tonic-gate
1760Sstevel@tonic-gateint
1770Sstevel@tonic-gatemodule_unload(module_t mod)
1780Sstevel@tonic-gate{
1790Sstevel@tonic-gate    return MOD_EVENT(mod, MOD_UNLOAD);
1800Sstevel@tonic-gate}
1810Sstevel@tonic-gate
1820Sstevel@tonic-gateint
1830Sstevel@tonic-gatemodule_getid(module_t mod)
1840Sstevel@tonic-gate{
1850Sstevel@tonic-gate    return mod->id;
1860Sstevel@tonic-gate}
1870Sstevel@tonic-gate
1880Sstevel@tonic-gatemodule_t
1890Sstevel@tonic-gatemodule_getfnext(module_t mod)
1900Sstevel@tonic-gate{
1910Sstevel@tonic-gate    return TAILQ_NEXT(mod, flink);
1920Sstevel@tonic-gate}
1930Sstevel@tonic-gate
1940Sstevel@tonic-gate/*
1950Sstevel@tonic-gate * Syscalls.
1960Sstevel@tonic-gate */
1970Sstevel@tonic-gateint
1980Sstevel@tonic-gatemodnext(struct proc* p, struct modnext_args* uap)
1990Sstevel@tonic-gate{
2000Sstevel@tonic-gate    module_t mod;
2010Sstevel@tonic-gate
2020Sstevel@tonic-gate    p->p_retval[0] = -1;
2030Sstevel@tonic-gate    if (SCARG(uap, modid) == 0) {
2040Sstevel@tonic-gate	mod = TAILQ_FIRST(&modules);
2050Sstevel@tonic-gate	if (mod) {
2060Sstevel@tonic-gate	    p->p_retval[0] = mod->id;
2070Sstevel@tonic-gate	    return 0;
2080Sstevel@tonic-gate	} else
2090Sstevel@tonic-gate	    return ENOENT;
2100Sstevel@tonic-gate    }
2110Sstevel@tonic-gate
2120Sstevel@tonic-gate    mod = module_lookupbyid(SCARG(uap, modid));
2130Sstevel@tonic-gate    if (!mod)
2140Sstevel@tonic-gate	return ENOENT;
2150Sstevel@tonic-gate
2160Sstevel@tonic-gate    if (TAILQ_NEXT(mod, link))
2170Sstevel@tonic-gate	p->p_retval[0] = TAILQ_NEXT(mod, link)->id;
2180Sstevel@tonic-gate    else
2190Sstevel@tonic-gate	p->p_retval[0] = 0;
2200Sstevel@tonic-gate    return 0;
2210Sstevel@tonic-gate}
2220Sstevel@tonic-gate
2230Sstevel@tonic-gateint
2240Sstevel@tonic-gatemodfnext(struct proc* p, struct modfnext_args* uap)
2250Sstevel@tonic-gate{
2260Sstevel@tonic-gate    module_t mod;
2270Sstevel@tonic-gate
2280Sstevel@tonic-gate    p->p_retval[0] = -1;
2290Sstevel@tonic-gate
2300Sstevel@tonic-gate    mod = module_lookupbyid(SCARG(uap, modid));
2310Sstevel@tonic-gate    if (!mod)
2320Sstevel@tonic-gate	return ENOENT;
2330Sstevel@tonic-gate
2340Sstevel@tonic-gate    if (TAILQ_NEXT(mod, flink))
2350Sstevel@tonic-gate	p->p_retval[0] = TAILQ_NEXT(mod, flink)->id;
2360Sstevel@tonic-gate    else
2370Sstevel@tonic-gate	p->p_retval[0] = 0;
2380Sstevel@tonic-gate    return 0;
2390Sstevel@tonic-gate}
2400Sstevel@tonic-gate
2410Sstevel@tonic-gateint
2420Sstevel@tonic-gatemodstat(struct proc* p, struct modstat_args* uap)
2430Sstevel@tonic-gate{
2440Sstevel@tonic-gate    module_t mod;
245    int error = 0;
246    int namelen;
247    int version;
248    struct module_stat* stat;
249
250    mod = module_lookupbyid(SCARG(uap, modid));
251    if (!mod)
252	return ENOENT;
253
254    stat = SCARG(uap, stat);
255
256    /*
257     * Check the version of the user's structure.
258     */
259    if (error = copyin(&stat->version, &version, sizeof(version)))
260	goto out;
261    if (version != sizeof(struct module_stat)) {
262	error = EINVAL;
263	goto out;
264    }
265
266    namelen = strlen(mod->name) + 1;
267    if (namelen > MAXMODNAME)
268	namelen = MAXMODNAME;
269    if (error = copyout(mod->name, &stat->name[0], namelen))
270	goto out;
271
272    if (error = copyout(&mod->refs, &stat->refs, sizeof(int)))
273	goto out;
274    if (error = copyout(&mod->id, &stat->id, sizeof(int)))
275	goto out;
276
277    p->p_retval[0] = 0;
278
279out:
280    return error;
281}
282
283int
284modfind(struct proc* p, struct modfind_args* uap)
285{
286    int error = 0;
287    char name[MAXMODNAME];
288    module_t mod;
289
290    if (error = copyinstr(SCARG(uap, name), name, sizeof name, 0))
291	goto out;
292
293    mod = module_lookupbyname(name);
294    if (!mod)
295	error = ENOENT;
296    else
297	p->p_retval[0] = mod->id;
298
299out:
300    return error;
301}
302