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.13 1999/01/09 14:59:50 dfr 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 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 modspecific_t data; /* module specific data */ 52 }; 53 54 #define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg) 55 56 static modulelist_t modules; 57 static int nextid = 1; 58 59 static void module_shutdown(int, void*); 60 61 static void 62 module_init(void* arg) 63 { 64 TAILQ_INIT(&modules); 65 at_shutdown(module_shutdown, 0, SHUTDOWN_POST_SYNC); 66 } 67 68 SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0); 69 70 static void 71 module_shutdown(int arg1, void* arg2) 72 { 73 module_t mod; 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_init(void *arg) 81 { 82 moduledata_t* data = (moduledata_t*) arg; 83 int error; 84 85 error = module_register(data->name, data->evhand, data->priv, data->_file); 86 if (error) 87 printf("module_register_init: module_register(%s, %lx, %p) error %d\n", 88 data->name, (u_long)(uintfptr_t)data->evhand, data->priv, error); 89 } 90 91 int 92 module_register(const char* name, modeventhand_t handler, void* arg, void *file) 93 { 94 size_t namelen; 95 module_t newmod; 96 int error; 97 linker_file_t container = file; 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 bzero(&newmod->data, sizeof(newmod->data)); 112 TAILQ_INSERT_TAIL(&modules, newmod, link); 113 114 if (container == NULL) 115 container = linker_current_file; 116 if (container) { 117 TAILQ_INSERT_TAIL(&container->modules, newmod, flink); 118 newmod->file = container; 119 } else 120 newmod->file = 0; 121 122 if (error = MOD_EVENT(newmod, MOD_LOAD)) { 123 MOD_EVENT(newmod, MOD_UNLOAD); 124 module_release(newmod); 125 return error; 126 } 127 128 return 0; 129 } 130 131 void 132 module_reference(module_t mod) 133 { 134 MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs)); 135 136 mod->refs++; 137 } 138 139 void 140 module_release(module_t mod) 141 { 142 if (mod->refs <= 0) 143 panic("module_release: bad reference count"); 144 145 MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs)); 146 147 mod->refs--; 148 if (mod->refs == 0) { 149 TAILQ_REMOVE(&modules, mod, link); 150 if (mod->file) { 151 TAILQ_REMOVE(&mod->file->modules, mod, flink); 152 } 153 free(mod, M_MODULE); 154 } 155 } 156 157 module_t 158 module_lookupbyname(const char* name) 159 { 160 module_t mod; 161 162 for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) { 163 if (!strcmp(mod->name, name)) 164 return mod; 165 } 166 167 return 0; 168 } 169 170 module_t 171 module_lookupbyid(int modid) 172 { 173 module_t mod; 174 175 for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) { 176 if (mod->id == modid) 177 return mod; 178 } 179 180 return 0; 181 } 182 183 int 184 module_unload(module_t mod) 185 { 186 return MOD_EVENT(mod, MOD_UNLOAD); 187 } 188 189 int 190 module_getid(module_t mod) 191 { 192 return mod->id; 193 } 194 195 module_t 196 module_getfnext(module_t mod) 197 { 198 return TAILQ_NEXT(mod, flink); 199 } 200 201 void 202 module_setspecific(module_t mod, modspecific_t *datap) 203 { 204 mod->data = *datap; 205 } 206 207 /* 208 * Syscalls. 209 */ 210 int 211 modnext(struct proc* p, struct modnext_args* uap) 212 { 213 module_t mod; 214 215 p->p_retval[0] = -1; 216 if (SCARG(uap, modid) == 0) { 217 mod = TAILQ_FIRST(&modules); 218 if (mod) { 219 p->p_retval[0] = mod->id; 220 return 0; 221 } else 222 return ENOENT; 223 } 224 225 mod = module_lookupbyid(SCARG(uap, modid)); 226 if (!mod) 227 return ENOENT; 228 229 if (TAILQ_NEXT(mod, link)) 230 p->p_retval[0] = TAILQ_NEXT(mod, link)->id; 231 else 232 p->p_retval[0] = 0; 233 return 0; 234 } 235 236 int 237 modfnext(struct proc* p, struct modfnext_args* uap) 238 { 239 module_t mod; 240 241 p->p_retval[0] = -1; 242 243 mod = module_lookupbyid(SCARG(uap, modid)); 244 if (!mod) 245 return ENOENT; 246 247 if (TAILQ_NEXT(mod, flink)) 248 p->p_retval[0] = TAILQ_NEXT(mod, flink)->id; 249 else 250 p->p_retval[0] = 0; 251 return 0; 252 } 253 254 struct module_stat_v1 { 255 int version; /* set to sizeof(struct module_stat) */ 256 char name[MAXMODNAME]; 257 int refs; 258 int id; 259 }; 260 261 int 262 modstat(struct proc* p, struct modstat_args* uap) 263 { 264 module_t mod; 265 int error = 0; 266 int namelen; 267 int version; 268 struct module_stat* stat; 269 270 mod = module_lookupbyid(SCARG(uap, modid)); 271 if (!mod) 272 return ENOENT; 273 274 stat = SCARG(uap, stat); 275 276 /* 277 * Check the version of the user's structure. 278 */ 279 if (error = copyin(&stat->version, &version, sizeof(version))) 280 goto out; 281 if (version != sizeof(struct module_stat_v1) 282 && version != sizeof(struct module_stat)) { 283 error = EINVAL; 284 goto out; 285 } 286 287 namelen = strlen(mod->name) + 1; 288 if (namelen > MAXMODNAME) 289 namelen = MAXMODNAME; 290 if (error = copyout(mod->name, &stat->name[0], namelen)) 291 goto out; 292 293 if (error = copyout(&mod->refs, &stat->refs, sizeof(int))) 294 goto out; 295 if (error = copyout(&mod->id, &stat->id, sizeof(int))) 296 goto out; 297 298 /* 299 * >v1 stat includes module data. 300 */ 301 if (version == sizeof(struct module_stat)) { 302 if (error = copyout(&mod->data, &stat->data, sizeof(mod->data))) 303 goto out; 304 } 305 306 p->p_retval[0] = 0; 307 308 out: 309 return error; 310 } 311 312 int 313 modfind(struct proc* p, struct modfind_args* uap) 314 { 315 int error = 0; 316 char name[MAXMODNAME]; 317 module_t mod; 318 319 if (error = copyinstr(SCARG(uap, name), name, sizeof name, 0)) 320 goto out; 321 322 mod = module_lookupbyname(name); 323 if (!mod) 324 error = ENOENT; 325 else 326 p->p_retval[0] = mod->id; 327 328 out: 329 return error; 330 } 331