kern_module.c revision 60833
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 * $FreeBSD: head/sys/kern/kern_module.c 60833 2000-05-23 20:41:01Z jake $ 27 */ 28 29#include <sys/param.h> 30#include <sys/kernel.h> 31#include <sys/systm.h> 32#include <sys/eventhandler.h> 33#include <sys/malloc.h> 34#include <sys/sysproto.h> 35#include <sys/sysent.h> 36#include <sys/module.h> 37#include <sys/linker.h> 38#include <sys/proc.h> 39 40MALLOC_DEFINE(M_MODULE, "module", "module data structures"); 41 42typedef TAILQ_HEAD(, struct module) modulelist_t; 43struct module { 44 TAILQ_ENTRY(struct module) link; /* chain together all modules */ 45 TAILQ_ENTRY(struct module) flink; /* all modules in a file */ 46 struct linker_file* file; /* file which contains this module */ 47 int refs; /* reference count */ 48 int id; /* unique id number */ 49 char *name; /* module name */ 50 modeventhand_t handler; /* event handler */ 51 void *arg; /* argument for handler */ 52 modspecific_t data; /* module specific data */ 53}; 54 55#define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg) 56 57static modulelist_t modules; 58static int nextid = 1; 59 60static void module_shutdown(void*, int); 61 62static int 63modevent_nop(module_t mod, int what, void* arg) 64{ 65 return 0; 66} 67 68 69static void 70module_init(void* arg) 71{ 72 TAILQ_INIT(&modules); 73 EVENTHANDLER_REGISTER(shutdown_post_sync, module_shutdown, NULL, 74 SHUTDOWN_PRI_DEFAULT); 75} 76 77SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0); 78 79static void 80module_shutdown(void* arg1, int arg2) 81{ 82 module_t mod; 83 84 for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) 85 MOD_EVENT(mod, MOD_SHUTDOWN); 86} 87 88void 89module_register_init(const void *arg) 90{ 91 const moduledata_t* data = (const moduledata_t*) arg; 92 int error; 93 module_t mod; 94 95 mod = module_lookupbyname(data->name); 96 if (mod == NULL) 97 panic("module_register_init: module named %s not found\n", data->name); 98 error = MOD_EVENT(mod, MOD_LOAD); 99 if (error) { 100 MOD_EVENT(mod, MOD_UNLOAD); 101 module_release(mod); 102 printf("module_register_init: MOD_LOAD (%s, %lx, %p) error %d\n", 103 data->name, (u_long)(uintfptr_t)data->evhand, data->priv, error); 104 } 105} 106 107int 108module_register(const moduledata_t *data, linker_file_t container) 109{ 110 size_t namelen; 111 module_t newmod; 112 113 newmod = module_lookupbyname(data->name); 114 if (newmod != NULL) { 115 printf("module_register: module %s already exists!\n", data->name); 116 return EEXIST; 117 } 118 namelen = strlen(data->name) + 1; 119 newmod = (module_t) malloc(sizeof(struct module) + namelen, 120 M_MODULE, M_WAITOK); 121 if (newmod == 0) 122 return ENOMEM; 123 124 newmod->refs = 1; 125 newmod->id = nextid++; 126 newmod->name = (char *) (newmod + 1); 127 strcpy(newmod->name, data->name); 128 newmod->handler = data->evhand ? data->evhand : modevent_nop; 129 newmod->arg = data->priv; 130 bzero(&newmod->data, sizeof(newmod->data)); 131 TAILQ_INSERT_TAIL(&modules, newmod, link); 132 133 if (container) 134 TAILQ_INSERT_TAIL(&container->modules, newmod, flink); 135 newmod->file = container; 136 137 return 0; 138} 139 140void 141module_reference(module_t mod) 142{ 143 MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs)); 144 145 mod->refs++; 146} 147 148void 149module_release(module_t mod) 150{ 151 if (mod->refs <= 0) 152 panic("module_release: bad reference count"); 153 154 MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs)); 155 156 mod->refs--; 157 if (mod->refs == 0) { 158 TAILQ_REMOVE(&modules, mod, link); 159 if (mod->file) { 160 TAILQ_REMOVE(&mod->file->modules, mod, flink); 161 } 162 free(mod, M_MODULE); 163 } 164} 165 166module_t 167module_lookupbyname(const char* name) 168{ 169 module_t mod; 170 171 for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) { 172 if (!strcmp(mod->name, name)) 173 return mod; 174 } 175 176 return 0; 177} 178 179module_t 180module_lookupbyid(int modid) 181{ 182 module_t mod; 183 184 for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) { 185 if (mod->id == modid) 186 return mod; 187 } 188 189 return 0; 190} 191 192int 193module_unload(module_t mod) 194{ 195 return MOD_EVENT(mod, MOD_UNLOAD); 196} 197 198int 199module_getid(module_t mod) 200{ 201 return mod->id; 202} 203 204module_t 205module_getfnext(module_t mod) 206{ 207 return TAILQ_NEXT(mod, flink); 208} 209 210void 211module_setspecific(module_t mod, modspecific_t *datap) 212{ 213 mod->data = *datap; 214} 215 216/* 217 * Syscalls. 218 */ 219int 220modnext(struct proc* p, struct modnext_args* uap) 221{ 222 module_t mod; 223 224 p->p_retval[0] = -1; 225 if (SCARG(uap, modid) == 0) { 226 mod = TAILQ_FIRST(&modules); 227 if (mod) { 228 p->p_retval[0] = mod->id; 229 return 0; 230 } else 231 return ENOENT; 232 } 233 234 mod = module_lookupbyid(SCARG(uap, modid)); 235 if (!mod) 236 return ENOENT; 237 238 if (TAILQ_NEXT(mod, link)) 239 p->p_retval[0] = TAILQ_NEXT(mod, link)->id; 240 else 241 p->p_retval[0] = 0; 242 return 0; 243} 244 245int 246modfnext(struct proc* p, struct modfnext_args* uap) 247{ 248 module_t mod; 249 250 p->p_retval[0] = -1; 251 252 mod = module_lookupbyid(SCARG(uap, modid)); 253 if (!mod) 254 return ENOENT; 255 256 if (TAILQ_NEXT(mod, flink)) 257 p->p_retval[0] = TAILQ_NEXT(mod, flink)->id; 258 else 259 p->p_retval[0] = 0; 260 return 0; 261} 262 263struct module_stat_v1 { 264 int version; /* set to sizeof(struct module_stat) */ 265 char name[MAXMODNAME]; 266 int refs; 267 int id; 268}; 269 270int 271modstat(struct proc* p, struct modstat_args* uap) 272{ 273 module_t mod; 274 int error = 0; 275 int namelen; 276 int version; 277 struct module_stat* stat; 278 279 mod = module_lookupbyid(SCARG(uap, modid)); 280 if (!mod) 281 return ENOENT; 282 283 stat = SCARG(uap, stat); 284 285 /* 286 * Check the version of the user's structure. 287 */ 288 if ((error = copyin(&stat->version, &version, sizeof(version))) != 0) 289 goto out; 290 if (version != sizeof(struct module_stat_v1) 291 && version != sizeof(struct module_stat)) { 292 error = EINVAL; 293 goto out; 294 } 295 296 namelen = strlen(mod->name) + 1; 297 if (namelen > MAXMODNAME) 298 namelen = MAXMODNAME; 299 if ((error = copyout(mod->name, &stat->name[0], namelen)) != 0) 300 goto out; 301 302 if ((error = copyout(&mod->refs, &stat->refs, sizeof(int))) != 0) 303 goto out; 304 if ((error = copyout(&mod->id, &stat->id, sizeof(int))) != 0) 305 goto out; 306 307 /* 308 * >v1 stat includes module data. 309 */ 310 if (version == sizeof(struct module_stat)) { 311 if ((error = copyout(&mod->data, &stat->data, sizeof(mod->data))) != 0) 312 goto out; 313 } 314 315 p->p_retval[0] = 0; 316 317out: 318 return error; 319} 320 321int 322modfind(struct proc* p, struct modfind_args* uap) 323{ 324 int error = 0; 325 char name[MAXMODNAME]; 326 module_t mod; 327 328 if ((error = copyinstr(SCARG(uap, name), name, sizeof name, 0)) != 0) 329 goto out; 330 331 mod = module_lookupbyname(name); 332 if (!mod) 333 error = ENOENT; 334 else 335 p->p_retval[0] = mod->id; 336 337out: 338 return error; 339} 340