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