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