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