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