kern_module.c revision 31016
1/*- 2 * Copyright (c) 1997 Doug Rabson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $Id: kern_module.c,v 1.5 1997/11/06 19:29:11 phk Exp $ 27 */ 28 29#include <sys/param.h> 30#include <sys/kernel.h> 31#include <sys/systm.h> 32#include <sys/malloc.h> 33#include <sys/sysproto.h> 34#include <sys/sysent.h> 35#include <sys/module.h> 36#include <sys/linker.h> 37#include <sys/proc.h> 38 39#define M_MODULE M_TEMP /* XXX */ 40 41typedef TAILQ_HEAD(, module) modulelist_t; 42struct module { 43 TAILQ_ENTRY(module) link; /* chain together all modules */ 44 TAILQ_ENTRY(module) flink; /* all modules in a file */ 45 struct linker_file* file; /* file which contains this module */ 46 int refs; /* reference count */ 47 int id; /* unique id number */ 48 char *name; /* module name */ 49 modeventhand_t handler; /* event handler */ 50 void *arg; /* argument for handler */ 51}; 52 53#define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg) 54 55static modulelist_t modules; 56static int nextid = 1; 57 58static void module_shutdown(int, void*); 59 60static void 61module_init(void* arg) 62{ 63 TAILQ_INIT(&modules); 64 at_shutdown(module_shutdown, 0, SHUTDOWN_POST_SYNC); 65} 66 67SYSINIT(module, SI_SUB_KMEM, SI_ORDER_ANY, module_init, 0); 68 69static void 70module_shutdown(int arg1, void* arg2) 71{ 72 module_t mod; 73 74 for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) 75 MOD_EVENT(mod, MOD_SHUTDOWN); 76} 77 78void 79module_register_init(void *arg) 80{ 81 moduledata_t* data = (moduledata_t*) arg; 82 int error; 83 84 if (error = module_register(data->name, data->evhand, data->priv)) 85 printf("module_register_init: module_register(%s, %x, %x) returned %d", 86 data->name, data->evhand, data->priv, error); 87} 88 89int 90module_register(const char* name, modeventhand_t handler, void* arg) 91{ 92 size_t namelen; 93 module_t newmod; 94 int error; 95 96 namelen = strlen(name) + 1; 97 newmod = (module_t) malloc(sizeof(struct module) + namelen, 98 M_MODULE, M_WAITOK); 99 if (newmod == 0) 100 return ENOMEM; 101 102 newmod->refs = 1; 103 newmod->id = nextid++; 104 newmod->name = (char *) (newmod + 1); 105 strcpy(newmod->name, name); 106 newmod->handler = handler; 107 newmod->arg = arg; 108 TAILQ_INSERT_TAIL(&modules, newmod, link); 109 110 if (linker_current_file) { 111 TAILQ_INSERT_TAIL(&linker_current_file->modules, newmod, flink); 112 newmod->file = linker_current_file; 113 } else 114 newmod->file = 0; 115 116 if (error = MOD_EVENT(newmod, MOD_LOAD)) { 117 module_release(newmod); 118 return error; 119 } 120 121 return 0; 122} 123 124void 125module_reference(module_t mod) 126{ 127 MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs)); 128 129 mod->refs++; 130} 131 132void 133module_release(module_t mod) 134{ 135 if (mod->refs <= 0) 136 panic("module_release: bad reference count"); 137 138 MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs)); 139 140 mod->refs--; 141 if (mod->refs == 0) { 142 TAILQ_REMOVE(&modules, mod, link); 143 if (mod->file) { 144 TAILQ_REMOVE(&mod->file->modules, mod, flink); 145 } 146 free(mod, M_MODULE); 147 } 148} 149 150module_t 151module_lookupbyname(const char* name) 152{ 153 module_t mod; 154 155 for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) { 156 if (!strcmp(mod->name, name)) 157 return mod; 158 } 159 160 return 0; 161} 162 163module_t 164module_lookupbyid(int modid) 165{ 166 module_t mod; 167 168 for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) { 169 if (mod->id == modid) 170 return mod; 171 } 172 173 return 0; 174} 175 176int 177module_unload(module_t mod) 178{ 179 return MOD_EVENT(mod, MOD_UNLOAD); 180} 181 182int 183module_getid(module_t mod) 184{ 185 return mod->id; 186} 187 188module_t 189module_getfnext(module_t mod) 190{ 191 return TAILQ_NEXT(mod, flink); 192} 193 194/* 195 * Syscalls. 196 */ 197int 198modnext(struct proc* p, struct modnext_args* uap) 199{ 200 module_t mod; 201 202 p->p_retval[0] = -1; 203 if (SCARG(uap, modid) == 0) { 204 mod = TAILQ_FIRST(&modules); 205 if (mod) { 206 p->p_retval[0] = mod->id; 207 return 0; 208 } else 209 return ENOENT; 210 } 211 212 mod = module_lookupbyid(SCARG(uap, modid)); 213 if (!mod) 214 return ENOENT; 215 216 if (TAILQ_NEXT(mod, link)) 217 p->p_retval[0] = TAILQ_NEXT(mod, link)->id; 218 else 219 p->p_retval[0] = 0; 220 return 0; 221} 222 223int 224modfnext(struct proc* p, struct modfnext_args* uap) 225{ 226 module_t mod; 227 228 p->p_retval[0] = -1; 229 230 mod = module_lookupbyid(SCARG(uap, modid)); 231 if (!mod) 232 return ENOENT; 233 234 if (TAILQ_NEXT(mod, flink)) 235 p->p_retval[0] = TAILQ_NEXT(mod, flink)->id; 236 else 237 p->p_retval[0] = 0; 238 return 0; 239} 240 241int 242modstat(struct proc* p, struct modstat_args* uap) 243{ 244 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