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