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