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 27 #include "opt_compat.h" 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/kernel.h> 34 #include <sys/systm.h> 35 #include <sys/eventhandler.h> 36 #include <sys/malloc.h> 37 #include <sys/sysproto.h> 38 #include <sys/sysent.h> 39 #include <sys/proc.h> 40 #include <sys/lock.h> 41 #include <sys/mutex.h> 42 #include <sys/reboot.h> 43 #include <sys/sx.h> 44 #include <sys/module.h> 45 #include <sys/linker.h> 46 47 static MALLOC_DEFINE(M_MODULE, "module", "module data structures"); 48 49 typedef TAILQ_HEAD(, module) modulelist_t; 50 struct module { 51 TAILQ_ENTRY(module) link; /* chain together all modules */ 52 TAILQ_ENTRY(module) flink; /* all modules in a file */ 53 struct linker_file *file; /* file which contains this module */ 54 int refs; /* reference count */ 55 int id; /* unique id number */ 56 char *name; /* module name */ 57 modeventhand_t handler; /* event handler */ 58 void *arg; /* argument for handler */ 59 modspecific_t data; /* module specific data */ 60 }; 61 62 #define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg) 63 64 static modulelist_t modules; 65 struct sx modules_sx; 66 static int nextid = 1; 67 static void module_shutdown(void *, int); 68 69 static int 70 modevent_nop(module_t mod, int what, void *arg) 71 { 72 73 switch(what) { 74 case MOD_LOAD: 75 return (0); 76 case MOD_UNLOAD: 77 return (EBUSY); 78 default: 79 return (EOPNOTSUPP); 80 } 81 } 82 83 static void 84 module_init(void *arg) 85 { 86 87 sx_init(&modules_sx, "module subsystem sx lock"); 88 TAILQ_INIT(&modules); 89 EVENTHANDLER_REGISTER(shutdown_final, module_shutdown, NULL, 90 SHUTDOWN_PRI_DEFAULT); 91 } 92 93 SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0); 94 95 static void 96 module_shutdown(void *arg1, int arg2) 97 { 98 module_t mod; 99 100 if (arg2 & RB_NOSYNC) 101 return; 102 mtx_lock(&Giant); 103 MOD_SLOCK; 104 TAILQ_FOREACH(mod, &modules, link) 105 MOD_EVENT(mod, MOD_SHUTDOWN); 106 MOD_SUNLOCK; 107 mtx_unlock(&Giant); 108 } 109 110 void 111 module_register_init(const void *arg) 112 { 113 const moduledata_t *data = (const moduledata_t *)arg; 114 int error; 115 module_t mod; 116 117 mtx_lock(&Giant); 118 MOD_SLOCK; 119 mod = module_lookupbyname(data->name); 120 if (mod == NULL) 121 panic("module_register_init: module named %s not found\n", 122 data->name); 123 MOD_SUNLOCK; 124 error = MOD_EVENT(mod, MOD_LOAD); 125 if (error) { 126 MOD_EVENT(mod, MOD_UNLOAD); 127 MOD_XLOCK; 128 module_release(mod); 129 MOD_XUNLOCK; 130 printf("module_register_init: MOD_LOAD (%s, %p, %p) error" 131 " %d\n", data->name, (void *)data->evhand, data->priv, 132 error); 133 } else { 134 MOD_XLOCK; 135 if (mod->file) { 136 /* 137 * Once a module is succesfully loaded, move 138 * it to the head of the module list for this 139 * linker file. This resorts the list so that 140 * when the kernel linker iterates over the 141 * modules to unload them, it will unload them 142 * in the reverse order they were loaded. 143 */ 144 TAILQ_REMOVE(&mod->file->modules, mod, flink); 145 TAILQ_INSERT_HEAD(&mod->file->modules, mod, flink); 146 } 147 MOD_XUNLOCK; 148 } 149 mtx_unlock(&Giant); 150 } 151 152 int 153 module_register(const moduledata_t *data, linker_file_t container) 154 { 155 size_t namelen; 156 module_t newmod; 157 158 MOD_XLOCK; 159 newmod = module_lookupbyname(data->name); 160 if (newmod != NULL) { 161 MOD_XUNLOCK; 162 printf("module_register: module %s already exists!\n", 163 data->name); 164 return (EEXIST); 165 } 166 namelen = strlen(data->name) + 1; 167 newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK); 168 if (newmod == NULL) { 169 MOD_XUNLOCK; 170 return (ENOMEM); 171 } 172 newmod->refs = 1; 173 newmod->id = nextid++; 174 newmod->name = (char *)(newmod + 1); 175 strcpy(newmod->name, data->name); 176 newmod->handler = data->evhand ? data->evhand : modevent_nop; 177 newmod->arg = data->priv; 178 bzero(&newmod->data, sizeof(newmod->data)); 179 TAILQ_INSERT_TAIL(&modules, newmod, link); 180 181 if (container) 182 TAILQ_INSERT_TAIL(&container->modules, newmod, flink); 183 newmod->file = container; 184 MOD_XUNLOCK; 185 return (0); 186 } 187 188 void 189 module_reference(module_t mod) 190 { 191 192 MOD_XLOCK_ASSERT; 193 194 MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs)); 195 mod->refs++; 196 } 197 198 void 199 module_release(module_t mod) 200 { 201 202 MOD_XLOCK_ASSERT; 203 204 if (mod->refs <= 0) 205 panic("module_release: bad reference count"); 206 207 MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs)); 208 209 mod->refs--; 210 if (mod->refs == 0) { 211 TAILQ_REMOVE(&modules, mod, link); 212 if (mod->file) 213 TAILQ_REMOVE(&mod->file->modules, mod, flink); 214 free(mod, M_MODULE); 215 } 216 } 217 218 module_t 219 module_lookupbyname(const char *name) 220 { 221 module_t mod; 222 int err; 223 224 MOD_LOCK_ASSERT; 225 226 TAILQ_FOREACH(mod, &modules, link) { 227 err = strcmp(mod->name, name); 228 if (err == 0) 229 return (mod); 230 } 231 return (NULL); 232 } 233 234 module_t 235 module_lookupbyid(int modid) 236 { 237 module_t mod; 238 239 MOD_LOCK_ASSERT; 240 241 TAILQ_FOREACH(mod, &modules, link) 242 if (mod->id == modid) 243 return(mod); 244 return (NULL); 245 } 246 247 int 248 module_quiesce(module_t mod) 249 { 250 int error; 251 252 mtx_lock(&Giant); 253 error = MOD_EVENT(mod, MOD_QUIESCE); 254 mtx_unlock(&Giant); 255 if (error == EOPNOTSUPP || error == EINVAL) 256 error = 0; 257 return (error); 258 } 259 260 int 261 module_unload(module_t mod) 262 { 263 int error; 264 265 mtx_lock(&Giant); 266 error = MOD_EVENT(mod, MOD_UNLOAD); 267 mtx_unlock(&Giant); 268 return (error); 269 } 270 271 int 272 module_getid(module_t mod) 273 { 274 275 MOD_LOCK_ASSERT; 276 return (mod->id); 277 } 278 279 module_t 280 module_getfnext(module_t mod) 281 { 282 283 MOD_LOCK_ASSERT; 284 return (TAILQ_NEXT(mod, flink)); 285 } 286 287 const char * 288 module_getname(module_t mod) 289 { 290 291 MOD_LOCK_ASSERT; 292 return (mod->name); 293 } 294 295 void 296 module_setspecific(module_t mod, modspecific_t *datap) 297 { 298 299 MOD_XLOCK_ASSERT; 300 mod->data = *datap; 301 } 302 303 linker_file_t 304 module_file(module_t mod) 305 { 306 307 return (mod->file); 308 } 309 310 /* 311 * Syscalls. 312 */ 313 int 314 modnext(struct thread *td, struct modnext_args *uap) 315 { 316 module_t mod; 317 int error = 0; 318 319 td->td_retval[0] = -1; 320 321 MOD_SLOCK; 322 if (uap->modid == 0) { 323 mod = TAILQ_FIRST(&modules); 324 if (mod) 325 td->td_retval[0] = mod->id; 326 else 327 error = ENOENT; 328 goto done2; 329 } 330 mod = module_lookupbyid(uap->modid); 331 if (mod == NULL) { 332 error = ENOENT; 333 goto done2; 334 } 335 if (TAILQ_NEXT(mod, link)) 336 td->td_retval[0] = TAILQ_NEXT(mod, link)->id; 337 else 338 td->td_retval[0] = 0; 339 done2: 340 MOD_SUNLOCK; 341 return (error); 342 } 343 344 int 345 modfnext(struct thread *td, struct modfnext_args *uap) 346 { 347 module_t mod; 348 int error; 349 350 td->td_retval[0] = -1; 351 352 MOD_SLOCK; 353 mod = module_lookupbyid(uap->modid); 354 if (mod == NULL) { 355 error = ENOENT; 356 } else { 357 error = 0; 358 if (TAILQ_NEXT(mod, flink)) 359 td->td_retval[0] = TAILQ_NEXT(mod, flink)->id; 360 else 361 td->td_retval[0] = 0; 362 } 363 MOD_SUNLOCK; 364 return (error); 365 } 366 367 struct module_stat_v1 { 368 int version; /* set to sizeof(struct module_stat) */ 369 char name[MAXMODNAME]; 370 int refs; 371 int id; 372 }; 373 374 int 375 modstat(struct thread *td, struct modstat_args *uap) 376 { 377 module_t mod; 378 modspecific_t data; 379 int error = 0; 380 int id, namelen, refs, version; 381 struct module_stat *stat; 382 char *name; 383 384 MOD_SLOCK; 385 mod = module_lookupbyid(uap->modid); 386 if (mod == NULL) { 387 MOD_SUNLOCK; 388 return (ENOENT); 389 } 390 id = mod->id; 391 refs = mod->refs; 392 name = mod->name; 393 data = mod->data; 394 MOD_SUNLOCK; 395 stat = uap->stat; 396 397 /* 398 * Check the version of the user's structure. 399 */ 400 if ((error = copyin(&stat->version, &version, sizeof(version))) != 0) 401 return (error); 402 if (version != sizeof(struct module_stat_v1) 403 && version != sizeof(struct module_stat)) 404 return (EINVAL); 405 namelen = strlen(mod->name) + 1; 406 if (namelen > MAXMODNAME) 407 namelen = MAXMODNAME; 408 if ((error = copyout(name, &stat->name[0], namelen)) != 0) 409 return (error); 410 411 if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0) 412 return (error); 413 if ((error = copyout(&id, &stat->id, sizeof(int))) != 0) 414 return (error); 415 416 /* 417 * >v1 stat includes module data. 418 */ 419 if (version == sizeof(struct module_stat)) 420 if ((error = copyout(&data, &stat->data, 421 sizeof(data))) != 0) 422 return (error); 423 td->td_retval[0] = 0; 424 return (error); 425 } 426 427 int 428 modfind(struct thread *td, struct modfind_args *uap) 429 { 430 int error = 0; 431 char name[MAXMODNAME]; 432 module_t mod; 433 434 if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0) 435 return (error); 436 437 MOD_SLOCK; 438 mod = module_lookupbyname(name); 439 if (mod == NULL) 440 error = ENOENT; 441 else 442 td->td_retval[0] = module_getid(mod); 443 MOD_SUNLOCK; 444 return (error); 445 } 446 447 MODULE_VERSION(kernel, __FreeBSD_version); 448 449 #ifdef COMPAT_FREEBSD32 450 #include <sys/mount.h> 451 #include <sys/socket.h> 452 #include <compat/freebsd32/freebsd32_util.h> 453 #include <compat/freebsd32/freebsd32.h> 454 #include <compat/freebsd32/freebsd32_proto.h> 455 456 typedef union modspecific32 { 457 int intval; 458 uint32_t uintval; 459 int longval; 460 uint32_t ulongval; 461 } modspecific32_t; 462 463 struct module_stat32 { 464 int version; 465 char name[MAXMODNAME]; 466 int refs; 467 int id; 468 modspecific32_t data; 469 }; 470 471 int 472 freebsd32_modstat(struct thread *td, struct freebsd32_modstat_args *uap) 473 { 474 module_t mod; 475 modspecific32_t data32; 476 int error = 0; 477 int id, namelen, refs, version; 478 struct module_stat32 *stat32; 479 char *name; 480 481 MOD_SLOCK; 482 mod = module_lookupbyid(uap->modid); 483 if (mod == NULL) { 484 MOD_SUNLOCK; 485 return (ENOENT); 486 } 487 488 id = mod->id; 489 refs = mod->refs; 490 name = mod->name; 491 CP(mod->data, data32, intval); 492 CP(mod->data, data32, uintval); 493 CP(mod->data, data32, longval); 494 CP(mod->data, data32, ulongval); 495 MOD_SUNLOCK; 496 stat32 = uap->stat; 497 498 if ((error = copyin(&stat32->version, &version, sizeof(version))) != 0) 499 return (error); 500 if (version != sizeof(struct module_stat_v1) 501 && version != sizeof(struct module_stat32)) 502 return (EINVAL); 503 namelen = strlen(mod->name) + 1; 504 if (namelen > MAXMODNAME) 505 namelen = MAXMODNAME; 506 if ((error = copyout(name, &stat32->name[0], namelen)) != 0) 507 return (error); 508 509 if ((error = copyout(&refs, &stat32->refs, sizeof(int))) != 0) 510 return (error); 511 if ((error = copyout(&id, &stat32->id, sizeof(int))) != 0) 512 return (error); 513 514 /* 515 * >v1 stat includes module data. 516 */ 517 if (version == sizeof(struct module_stat32)) 518 if ((error = copyout(&data32, &stat32->data, 519 sizeof(data32))) != 0) 520 return (error); 521 td->td_retval[0] = 0; 522 return (error); 523 } 524 #endif 525