1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 1997 Doug Rabson 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 #include <sys/param.h> 31 #include <sys/kernel.h> 32 #include <sys/systm.h> 33 #include <sys/eventhandler.h> 34 #include <sys/malloc.h> 35 #include <sys/sysproto.h> 36 #include <sys/sysent.h> 37 #include <sys/proc.h> 38 #include <sys/lock.h> 39 #include <sys/mutex.h> 40 #include <sys/reboot.h> 41 #include <sys/sx.h> 42 #include <sys/module.h> 43 #include <sys/linker.h> 44 45 static MALLOC_DEFINE(M_MODULE, "module", "module data structures"); 46 47 struct module { 48 TAILQ_ENTRY(module) link; /* chain together all modules */ 49 TAILQ_ENTRY(module) flink; /* all modules in a file */ 50 struct linker_file *file; /* file which contains this module */ 51 int refs; /* reference count */ 52 int id; /* unique id number */ 53 char *name; /* module name */ 54 modeventhand_t handler; /* event handler */ 55 void *arg; /* argument for handler */ 56 modspecific_t data; /* module specific data */ 57 }; 58 59 #define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg) 60 61 static TAILQ_HEAD(modulelist, module) modules; 62 struct sx modules_sx; 63 static int nextid = 1; 64 static void module_shutdown(void *, int); 65 66 static int 67 modevent_nop(module_t mod, int what, void *arg) 68 { 69 70 switch(what) { 71 case MOD_LOAD: 72 return (0); 73 case MOD_UNLOAD: 74 return (EBUSY); 75 default: 76 return (EOPNOTSUPP); 77 } 78 } 79 80 static void 81 module_init(void *arg) 82 { 83 84 sx_init(&modules_sx, "module subsystem sx lock"); 85 TAILQ_INIT(&modules); 86 EVENTHANDLER_REGISTER(shutdown_final, module_shutdown, NULL, 87 SHUTDOWN_PRI_DEFAULT); 88 } 89 90 SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, NULL); 91 92 static void 93 module_shutdown(void *arg1, int arg2) 94 { 95 module_t mod; 96 97 if (arg2 & RB_NOSYNC) 98 return; 99 mtx_lock(&Giant); 100 MOD_SLOCK; 101 TAILQ_FOREACH_REVERSE(mod, &modules, modulelist, link) 102 MOD_EVENT(mod, MOD_SHUTDOWN); 103 MOD_SUNLOCK; 104 mtx_unlock(&Giant); 105 } 106 107 void 108 module_register_init(const void *arg) 109 { 110 const moduledata_t *data = (const moduledata_t *)arg; 111 int error; 112 module_t mod; 113 114 mtx_lock(&Giant); 115 MOD_SLOCK; 116 mod = module_lookupbyname(data->name); 117 if (mod == NULL) 118 panic("module_register_init: module named %s not found\n", 119 data->name); 120 MOD_SUNLOCK; 121 error = MOD_EVENT(mod, MOD_LOAD); 122 if (error) { 123 MOD_EVENT(mod, MOD_UNLOAD); 124 MOD_XLOCK; 125 module_release(mod); 126 MOD_XUNLOCK; 127 printf("module_register_init: MOD_LOAD (%s, %p, %p) error" 128 " %d\n", data->name, (void *)data->evhand, data->priv, 129 error); 130 } else { 131 MOD_XLOCK; 132 if (mod->file) { 133 /* 134 * Once a module is successfully loaded, move 135 * it to the head of the module list for this 136 * linker file. This resorts the list so that 137 * when the kernel linker iterates over the 138 * modules to unload them, it will unload them 139 * in the reverse order they were loaded. 140 */ 141 TAILQ_REMOVE(&mod->file->modules, mod, flink); 142 TAILQ_INSERT_HEAD(&mod->file->modules, mod, flink); 143 } 144 MOD_XUNLOCK; 145 } 146 mtx_unlock(&Giant); 147 } 148 149 int 150 module_register(const moduledata_t *data, linker_file_t container) 151 { 152 size_t namelen; 153 module_t newmod; 154 155 MOD_XLOCK; 156 newmod = module_lookupbyname(data->name); 157 if (newmod != NULL) { 158 MOD_XUNLOCK; 159 printf("%s: cannot register %s from %s; already loaded from %s\n", 160 __func__, data->name, container->filename, newmod->file->filename); 161 return (EEXIST); 162 } 163 namelen = strlen(data->name) + 1; 164 newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK); 165 newmod->refs = 1; 166 newmod->id = nextid++; 167 newmod->name = (char *)(newmod + 1); 168 strcpy(newmod->name, data->name); 169 newmod->handler = data->evhand ? data->evhand : modevent_nop; 170 newmod->arg = data->priv; 171 bzero(&newmod->data, sizeof(newmod->data)); 172 TAILQ_INSERT_TAIL(&modules, newmod, link); 173 174 if (container) 175 TAILQ_INSERT_TAIL(&container->modules, newmod, flink); 176 newmod->file = container; 177 MOD_XUNLOCK; 178 return (0); 179 } 180 181 void 182 module_reference(module_t mod) 183 { 184 185 MOD_XLOCK_ASSERT; 186 187 MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs)); 188 mod->refs++; 189 } 190 191 void 192 module_release(module_t mod) 193 { 194 195 MOD_XLOCK_ASSERT; 196 197 if (mod->refs <= 0) 198 panic("module_release: bad reference count"); 199 200 MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs)); 201 202 mod->refs--; 203 if (mod->refs == 0) { 204 TAILQ_REMOVE(&modules, mod, link); 205 if (mod->file) 206 TAILQ_REMOVE(&mod->file->modules, mod, flink); 207 free(mod, M_MODULE); 208 } 209 } 210 211 module_t 212 module_lookupbyname(const char *name) 213 { 214 module_t mod; 215 int err; 216 217 MOD_LOCK_ASSERT; 218 219 TAILQ_FOREACH(mod, &modules, link) { 220 err = strcmp(mod->name, name); 221 if (err == 0) 222 return (mod); 223 } 224 return (NULL); 225 } 226 227 module_t 228 module_lookupbyid(int modid) 229 { 230 module_t mod; 231 232 MOD_LOCK_ASSERT; 233 234 TAILQ_FOREACH(mod, &modules, link) 235 if (mod->id == modid) 236 return(mod); 237 return (NULL); 238 } 239 240 int 241 module_quiesce(module_t mod) 242 { 243 int error; 244 245 mtx_lock(&Giant); 246 error = MOD_EVENT(mod, MOD_QUIESCE); 247 mtx_unlock(&Giant); 248 if (error == EOPNOTSUPP || error == EINVAL) 249 error = 0; 250 return (error); 251 } 252 253 int 254 module_unload(module_t mod) 255 { 256 int error; 257 258 mtx_lock(&Giant); 259 error = MOD_EVENT(mod, MOD_UNLOAD); 260 mtx_unlock(&Giant); 261 return (error); 262 } 263 264 int 265 module_getid(module_t mod) 266 { 267 268 MOD_LOCK_ASSERT; 269 return (mod->id); 270 } 271 272 module_t 273 module_getfnext(module_t mod) 274 { 275 276 MOD_LOCK_ASSERT; 277 return (TAILQ_NEXT(mod, flink)); 278 } 279 280 const char * 281 module_getname(module_t mod) 282 { 283 284 MOD_LOCK_ASSERT; 285 return (mod->name); 286 } 287 288 void 289 module_setspecific(module_t mod, modspecific_t *datap) 290 { 291 292 MOD_XLOCK_ASSERT; 293 mod->data = *datap; 294 } 295 296 linker_file_t 297 module_file(module_t mod) 298 { 299 300 return (mod->file); 301 } 302 303 /* 304 * Syscalls. 305 */ 306 int 307 sys_modnext(struct thread *td, struct modnext_args *uap) 308 { 309 module_t mod; 310 int error = 0; 311 312 td->td_retval[0] = -1; 313 314 MOD_SLOCK; 315 if (uap->modid == 0) { 316 mod = TAILQ_FIRST(&modules); 317 if (mod) 318 td->td_retval[0] = mod->id; 319 else 320 error = ENOENT; 321 goto done2; 322 } 323 mod = module_lookupbyid(uap->modid); 324 if (mod == NULL) { 325 error = ENOENT; 326 goto done2; 327 } 328 if (TAILQ_NEXT(mod, link)) 329 td->td_retval[0] = TAILQ_NEXT(mod, link)->id; 330 else 331 td->td_retval[0] = 0; 332 done2: 333 MOD_SUNLOCK; 334 return (error); 335 } 336 337 int 338 sys_modfnext(struct thread *td, struct modfnext_args *uap) 339 { 340 module_t mod; 341 int error; 342 343 td->td_retval[0] = -1; 344 345 MOD_SLOCK; 346 mod = module_lookupbyid(uap->modid); 347 if (mod == NULL) { 348 error = ENOENT; 349 } else { 350 error = 0; 351 if (TAILQ_NEXT(mod, flink)) 352 td->td_retval[0] = TAILQ_NEXT(mod, flink)->id; 353 else 354 td->td_retval[0] = 0; 355 } 356 MOD_SUNLOCK; 357 return (error); 358 } 359 360 struct module_stat_v1 { 361 int version; /* set to sizeof(struct module_stat) */ 362 char name[MAXMODNAMEV1V2]; 363 int refs; 364 int id; 365 }; 366 367 struct module_stat_v2 { 368 int version; /* set to sizeof(struct module_stat) */ 369 char name[MAXMODNAMEV1V2]; 370 int refs; 371 int id; 372 modspecific_t data; 373 }; 374 375 int 376 sys_modstat(struct thread *td, struct modstat_args *uap) 377 { 378 module_t mod; 379 modspecific_t data; 380 int error = 0; 381 int id, namelen, refs, version; 382 struct module_stat *stat; 383 struct module_stat_v2 *stat_v2; 384 char *name; 385 bool is_v1v2; 386 387 MOD_SLOCK; 388 mod = module_lookupbyid(uap->modid); 389 if (mod == NULL) { 390 MOD_SUNLOCK; 391 return (ENOENT); 392 } 393 id = mod->id; 394 refs = mod->refs; 395 name = mod->name; 396 data = mod->data; 397 MOD_SUNLOCK; 398 stat = uap->stat; 399 400 /* 401 * Check the version of the user's structure. 402 */ 403 if ((error = copyin(&stat->version, &version, sizeof(version))) != 0) 404 return (error); 405 is_v1v2 = (version == sizeof(struct module_stat_v1) || 406 version == sizeof(struct module_stat_v2)); 407 if (!is_v1v2 && version != sizeof(struct module_stat)) 408 return (EINVAL); 409 namelen = strlen(mod->name) + 1; 410 if (is_v1v2 && namelen > MAXMODNAMEV1V2) 411 namelen = MAXMODNAMEV1V2; 412 else if (namelen > MAXMODNAMEV3) 413 namelen = MAXMODNAMEV3; 414 if ((error = copyout(name, &stat->name[0], namelen)) != 0) 415 return (error); 416 417 /* Extending MAXMODNAME gives an offset change for v3. */ 418 if (is_v1v2) { 419 stat_v2 = (struct module_stat_v2 *)stat; 420 if ((error = copyout(&refs, &stat_v2->refs, sizeof(int))) != 0) 421 return (error); 422 if ((error = copyout(&id, &stat_v2->id, sizeof(int))) != 0) 423 return (error); 424 } else { 425 if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0) 426 return (error); 427 if ((error = copyout(&id, &stat->id, sizeof(int))) != 0) 428 return (error); 429 } 430 431 /* 432 * >v1 stat includes module data. 433 */ 434 if (version == sizeof(struct module_stat_v2)) { 435 if ((error = copyout(&data, &stat_v2->data, 436 sizeof(data))) != 0) 437 return (error); 438 } else if (version == sizeof(struct module_stat)) { 439 if ((error = copyout(&data, &stat->data, 440 sizeof(data))) != 0) 441 return (error); 442 } 443 td->td_retval[0] = 0; 444 return (error); 445 } 446 447 int 448 sys_modfind(struct thread *td, struct modfind_args *uap) 449 { 450 int error = 0; 451 char name[MAXMODNAMEV3]; 452 module_t mod; 453 454 if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0) 455 return (error); 456 457 MOD_SLOCK; 458 mod = module_lookupbyname(name); 459 if (mod == NULL) 460 error = ENOENT; 461 else 462 td->td_retval[0] = module_getid(mod); 463 MOD_SUNLOCK; 464 return (error); 465 } 466 467 MODULE_VERSION(kernel, __FreeBSD_version); 468 469 #ifdef COMPAT_FREEBSD32 470 #include <sys/mount.h> 471 #include <sys/socket.h> 472 #include <compat/freebsd32/freebsd32_util.h> 473 #include <compat/freebsd32/freebsd32.h> 474 #include <compat/freebsd32/freebsd32_proto.h> 475 476 typedef union modspecific32 { 477 int intval; 478 uint32_t uintval; 479 int longval; 480 uint32_t ulongval; 481 } modspecific32_t; 482 483 struct module_stat32_v2 { 484 int version; 485 char name[MAXMODNAMEV1V2]; 486 int refs; 487 int id; 488 modspecific32_t data; 489 }; 490 491 struct module_stat32 { 492 int version; 493 char name[MAXMODNAME]; 494 int refs; 495 int id; 496 modspecific32_t data; 497 }; 498 499 int 500 freebsd32_modstat(struct thread *td, struct freebsd32_modstat_args *uap) 501 { 502 module_t mod; 503 modspecific32_t data32; 504 int error = 0; 505 int id, namelen, refs, version; 506 struct module_stat32 *stat32; 507 struct module_stat32_v2 *stat32_v2; 508 char *name; 509 bool is_v1v2; 510 511 MOD_SLOCK; 512 mod = module_lookupbyid(uap->modid); 513 if (mod == NULL) { 514 MOD_SUNLOCK; 515 return (ENOENT); 516 } 517 518 id = mod->id; 519 refs = mod->refs; 520 name = mod->name; 521 _Static_assert(sizeof(data32) == sizeof(data32.uintval), 522 "bad modspecific32_t size"); 523 CP(mod->data, data32, uintval); 524 MOD_SUNLOCK; 525 stat32 = uap->stat; 526 527 if ((error = copyin(&stat32->version, &version, sizeof(version))) != 0) 528 return (error); 529 is_v1v2 = (version == sizeof(struct module_stat_v1) || 530 version == sizeof(struct module_stat32_v2)); 531 if (!is_v1v2 && version != sizeof(struct module_stat32)) 532 return (EINVAL); 533 namelen = strlen(mod->name) + 1; 534 if (is_v1v2 && namelen > MAXMODNAMEV1V2) 535 namelen = MAXMODNAMEV1V2; 536 else if (namelen > MAXMODNAMEV3) 537 namelen = MAXMODNAMEV3; 538 if ((error = copyout(name, &stat32->name[0], namelen)) != 0) 539 return (error); 540 541 /* Extending MAXMODNAME gives an offset change for v3. */ 542 if (is_v1v2) { 543 stat32_v2 = (struct module_stat32_v2 *)stat32; 544 if ((error = copyout(&refs, &stat32_v2->refs, sizeof(int))) != 0) 545 return (error); 546 if ((error = copyout(&id, &stat32_v2->id, sizeof(int))) != 0) 547 return (error); 548 } else { 549 if ((error = copyout(&refs, &stat32->refs, sizeof(int))) != 0) 550 return (error); 551 if ((error = copyout(&id, &stat32->id, sizeof(int))) != 0) 552 return (error); 553 } 554 555 /* 556 * >v1 stat includes module data. 557 */ 558 if (version == sizeof(struct module_stat32_v2)) { 559 if ((error = copyout(&data32, &stat32_v2->data, 560 sizeof(data32))) != 0) 561 return (error); 562 } else if (version == sizeof(struct module_stat32)) { 563 if ((error = copyout(&data32, &stat32->data, 564 sizeof(data32))) != 0) 565 return (error); 566 } 567 td->td_retval[0] = 0; 568 return (error); 569 } 570 #endif 571