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.17 1999/05/08 13:01:57 peter 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(const void *arg) 81 { 82 const moduledata_t* data = (const moduledata_t*) arg; 83 int error; 84 module_t mod; 85 86 mod = module_lookupbyname(data->name); 87 if (mod == NULL) { 88 #if 0 89 panic("module_register_init: module named %s not found\n", data->name); 90 #else 91 /* temporary kludge until kernel `file' attachment registers modules */ 92 error = module_register(data, linker_kernel_file); 93 if (error) 94 panic("module_register_init: register of module failed! %d", error); 95 mod = module_lookupbyname(data->name); 96 if (mod == NULL) 97 panic("module_register_init: module STILL not found!"); 98 #endif 99 } 100 error = MOD_EVENT(mod, MOD_LOAD); 101 if (error) { 102 MOD_EVENT(mod, MOD_UNLOAD); 103 module_release(mod); 104 printf("module_register_init: MOD_LOAD (%s, %lx, %p) error %d\n", 105 data->name, (u_long)(uintfptr_t)data->evhand, data->priv, error); 106 } 107 } 108 109 int 110 module_register(const moduledata_t *data, linker_file_t container) 111 { 112 size_t namelen; 113 module_t newmod; 114 115 newmod = module_lookupbyname(data->name); 116 if (newmod != NULL) { 117 printf("module_register: module %s already exists!\n", data->name); 118 return EEXIST; 119 } 120 namelen = strlen(data->name) + 1; 121 newmod = (module_t) malloc(sizeof(struct module) + namelen, 122 M_MODULE, M_WAITOK); 123 if (newmod == 0) 124 return ENOMEM; 125 126 newmod->refs = 1; 127 newmod->id = nextid++; 128 newmod->name = (char *) (newmod + 1); 129 strcpy(newmod->name, data->name); 130 newmod->handler = data->evhand; 131 newmod->arg = data->priv; 132 bzero(&newmod->data, sizeof(newmod->data)); 133 TAILQ_INSERT_TAIL(&modules, newmod, link); 134 135 if (container == NULL) 136 container = linker_current_file; 137 if (container) 138 TAILQ_INSERT_TAIL(&container->modules, newmod, flink); 139 newmod->file = container; 140 141 return 0; 142 } 143 144 void 145 module_reference(module_t mod) 146 { 147 MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs)); 148 149 mod->refs++; 150 } 151 152 void 153 module_release(module_t mod) 154 { 155 if (mod->refs <= 0) 156 panic("module_release: bad reference count"); 157 158 MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs)); 159 160 mod->refs--; 161 if (mod->refs == 0) { 162 TAILQ_REMOVE(&modules, mod, link); 163 if (mod->file) { 164 TAILQ_REMOVE(&mod->file->modules, mod, flink); 165 } 166 free(mod, M_MODULE); 167 } 168 } 169 170 module_t 171 module_lookupbyname(const char* name) 172 { 173 module_t mod; 174 175 for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) { 176 if (!strcmp(mod->name, name)) 177 return mod; 178 } 179 180 return 0; 181 } 182 183 module_t 184 module_lookupbyid(int modid) 185 { 186 module_t mod; 187 188 for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) { 189 if (mod->id == modid) 190 return mod; 191 } 192 193 return 0; 194 } 195 196 int 197 module_unload(module_t mod) 198 { 199 return MOD_EVENT(mod, MOD_UNLOAD); 200 } 201 202 int 203 module_getid(module_t mod) 204 { 205 return mod->id; 206 } 207 208 module_t 209 module_getfnext(module_t mod) 210 { 211 return TAILQ_NEXT(mod, flink); 212 } 213 214 void 215 module_setspecific(module_t mod, modspecific_t *datap) 216 { 217 mod->data = *datap; 218 } 219 220 /* 221 * Syscalls. 222 */ 223 int 224 modnext(struct proc* p, struct modnext_args* uap) 225 { 226 module_t mod; 227 228 p->p_retval[0] = -1; 229 if (SCARG(uap, modid) == 0) { 230 mod = TAILQ_FIRST(&modules); 231 if (mod) { 232 p->p_retval[0] = mod->id; 233 return 0; 234 } else 235 return ENOENT; 236 } 237 238 mod = module_lookupbyid(SCARG(uap, modid)); 239 if (!mod) 240 return ENOENT; 241 242 if (TAILQ_NEXT(mod, link)) 243 p->p_retval[0] = TAILQ_NEXT(mod, link)->id; 244 else 245 p->p_retval[0] = 0; 246 return 0; 247 } 248 249 int 250 modfnext(struct proc* p, struct modfnext_args* uap) 251 { 252 module_t mod; 253 254 p->p_retval[0] = -1; 255 256 mod = module_lookupbyid(SCARG(uap, modid)); 257 if (!mod) 258 return ENOENT; 259 260 if (TAILQ_NEXT(mod, flink)) 261 p->p_retval[0] = TAILQ_NEXT(mod, flink)->id; 262 else 263 p->p_retval[0] = 0; 264 return 0; 265 } 266 267 struct module_stat_v1 { 268 int version; /* set to sizeof(struct module_stat) */ 269 char name[MAXMODNAME]; 270 int refs; 271 int id; 272 }; 273 274 int 275 modstat(struct proc* p, struct modstat_args* uap) 276 { 277 module_t mod; 278 int error = 0; 279 int namelen; 280 int version; 281 struct module_stat* stat; 282 283 mod = module_lookupbyid(SCARG(uap, modid)); 284 if (!mod) 285 return ENOENT; 286 287 stat = SCARG(uap, stat); 288 289 /* 290 * Check the version of the user's structure. 291 */ 292 if ((error = copyin(&stat->version, &version, sizeof(version))) != 0) 293 goto out; 294 if (version != sizeof(struct module_stat_v1) 295 && version != sizeof(struct module_stat)) { 296 error = EINVAL; 297 goto out; 298 } 299 300 namelen = strlen(mod->name) + 1; 301 if (namelen > MAXMODNAME) 302 namelen = MAXMODNAME; 303 if ((error = copyout(mod->name, &stat->name[0], namelen)) != 0) 304 goto out; 305 306 if ((error = copyout(&mod->refs, &stat->refs, sizeof(int))) != 0) 307 goto out; 308 if ((error = copyout(&mod->id, &stat->id, sizeof(int))) != 0) 309 goto out; 310 311 /* 312 * >v1 stat includes module data. 313 */ 314 if (version == sizeof(struct module_stat)) { 315 if ((error = copyout(&mod->data, &stat->data, sizeof(mod->data))) != 0) 316 goto out; 317 } 318 319 p->p_retval[0] = 0; 320 321 out: 322 return error; 323 } 324 325 int 326 modfind(struct proc* p, struct modfind_args* uap) 327 { 328 int error = 0; 329 char name[MAXMODNAME]; 330 module_t mod; 331 332 if ((error = copyinstr(SCARG(uap, name), name, sizeof name, 0)) != 0) 333 goto out; 334 335 mod = module_lookupbyname(name); 336 if (!mod) 337 error = ENOENT; 338 else 339 p->p_retval[0] = mod->id; 340 341 out: 342 return error; 343 } 344