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