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