125537Sdfr/*- 225537Sdfr * Copyright (c) 1997 Doug Rabson 325537Sdfr * All rights reserved. 425537Sdfr * 525537Sdfr * Redistribution and use in source and binary forms, with or without 625537Sdfr * modification, are permitted provided that the following conditions 725537Sdfr * are met: 825537Sdfr * 1. Redistributions of source code must retain the above copyright 925537Sdfr * notice, this list of conditions and the following disclaimer. 1025537Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1125537Sdfr * notice, this list of conditions and the following disclaimer in the 1225537Sdfr * documentation and/or other materials provided with the distribution. 1325537Sdfr * 1425537Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1525537Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1625537Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1725537Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1825537Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1925537Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2025537Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2125537Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2225537Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2325537Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2425537Sdfr * SUCH DAMAGE. 2525537Sdfr */ 2625537Sdfr 27140482Sps#include "opt_compat.h" 28140482Sps 29116182Sobrien#include <sys/cdefs.h> 30116182Sobrien__FBSDID("$FreeBSD: stable/11/sys/kern/kern_module.c 359652 2020-04-06 07:16:31Z hselasky $"); 31116182Sobrien 3225537Sdfr#include <sys/param.h> 3325537Sdfr#include <sys/kernel.h> 3425537Sdfr#include <sys/systm.h> 3550107Smsmith#include <sys/eventhandler.h> 3625537Sdfr#include <sys/malloc.h> 3725537Sdfr#include <sys/sysproto.h> 3825537Sdfr#include <sys/sysent.h> 3930994Sphk#include <sys/proc.h> 4082749Sdillon#include <sys/lock.h> 4182749Sdillon#include <sys/mutex.h> 42134092Struckman#include <sys/reboot.h> 4392547Sarr#include <sys/sx.h> 4492547Sarr#include <sys/module.h> 4592547Sarr#include <sys/linker.h> 4625537Sdfr 4769774Sphkstatic MALLOC_DEFINE(M_MODULE, "module", "module data structures"); 4825537Sdfr 4925537Sdfrstruct module { 5090963Sarr TAILQ_ENTRY(module) link; /* chain together all modules */ 5190963Sarr TAILQ_ENTRY(module) flink; /* all modules in a file */ 5290963Sarr struct linker_file *file; /* file which contains this module */ 5390963Sarr int refs; /* reference count */ 5490963Sarr int id; /* unique id number */ 5590963Sarr char *name; /* module name */ 5690963Sarr modeventhand_t handler; /* event handler */ 5790963Sarr void *arg; /* argument for handler */ 5890963Sarr modspecific_t data; /* module specific data */ 5925537Sdfr}; 6025537Sdfr 6190963Sarr#define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg) 6225537Sdfr 63215683Sattiliostatic TAILQ_HEAD(modulelist, module) modules; 6492547Sarrstruct sx modules_sx; 6525537Sdfrstatic int nextid = 1; 6690963Sarrstatic void module_shutdown(void *, int); 6725537Sdfr 6852991Speterstatic int 6990963Sarrmodevent_nop(module_t mod, int what, void *arg) 7052991Speter{ 71132167Sphk 72132167Sphk switch(what) { 73132167Sphk case MOD_LOAD: 74132167Sphk return (0); 75132167Sphk case MOD_UNLOAD: 76132167Sphk return (EBUSY); 77132167Sphk default: 78132167Sphk return (EOPNOTSUPP); 79132167Sphk } 8052991Speter} 8152991Speter 8225537Sdfrstatic void 8390963Sarrmodule_init(void *arg) 8425537Sdfr{ 8590963Sarr 8692547Sarr sx_init(&modules_sx, "module subsystem sx lock"); 8790963Sarr TAILQ_INIT(&modules); 88108905Speter EVENTHANDLER_REGISTER(shutdown_final, module_shutdown, NULL, 8990963Sarr SHUTDOWN_PRI_DEFAULT); 9025537Sdfr} 9125537Sdfr 92359652ShselaskySYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, NULL); 9325537Sdfr 9425537Sdfrstatic void 9590963Sarrmodule_shutdown(void *arg1, int arg2) 9625537Sdfr{ 9790963Sarr module_t mod; 9825537Sdfr 99134092Struckman if (arg2 & RB_NOSYNC) 100134092Struckman return; 101159957Sjhb mtx_lock(&Giant); 10292547Sarr MOD_SLOCK; 103215683Sattilio TAILQ_FOREACH_REVERSE(mod, &modules, modulelist, link) 10490963Sarr MOD_EVENT(mod, MOD_SHUTDOWN); 10592547Sarr MOD_SUNLOCK; 106159957Sjhb mtx_unlock(&Giant); 10725537Sdfr} 10825537Sdfr 10925537Sdfrvoid 11043387Sdillonmodule_register_init(const void *arg) 11125537Sdfr{ 11290963Sarr const moduledata_t *data = (const moduledata_t *)arg; 11390963Sarr int error; 11490963Sarr module_t mod; 11525537Sdfr 116159957Sjhb mtx_lock(&Giant); 11792547Sarr MOD_SLOCK; 11890963Sarr mod = module_lookupbyname(data->name); 11990963Sarr if (mod == NULL) 12091067Sarr panic("module_register_init: module named %s not found\n", 12190963Sarr data->name); 12292547Sarr MOD_SUNLOCK; 12390963Sarr error = MOD_EVENT(mod, MOD_LOAD); 12490963Sarr if (error) { 12590963Sarr MOD_EVENT(mod, MOD_UNLOAD); 12692547Sarr MOD_XLOCK; 12790963Sarr module_release(mod); 12892547Sarr MOD_XUNLOCK; 12991261Speter printf("module_register_init: MOD_LOAD (%s, %p, %p) error" 13091261Speter " %d\n", data->name, (void *)data->evhand, data->priv, 13191067Sarr error); 132185642Sjhb } else { 133185642Sjhb MOD_XLOCK; 134185642Sjhb if (mod->file) { 135185642Sjhb /* 136239586Sjhb * Once a module is successfully loaded, move 137185642Sjhb * it to the head of the module list for this 138185642Sjhb * linker file. This resorts the list so that 139185642Sjhb * when the kernel linker iterates over the 140185642Sjhb * modules to unload them, it will unload them 141185642Sjhb * in the reverse order they were loaded. 142185642Sjhb */ 143185642Sjhb TAILQ_REMOVE(&mod->file->modules, mod, flink); 144185642Sjhb TAILQ_INSERT_HEAD(&mod->file->modules, mod, flink); 145185642Sjhb } 146185642Sjhb MOD_XUNLOCK; 14790963Sarr } 148159957Sjhb mtx_unlock(&Giant); 14925537Sdfr} 15025537Sdfr 15125537Sdfrint 15246693Spetermodule_register(const moduledata_t *data, linker_file_t container) 15325537Sdfr{ 15490963Sarr size_t namelen; 15590963Sarr module_t newmod; 15625537Sdfr 157159634Smaxim MOD_XLOCK; 15890963Sarr newmod = module_lookupbyname(data->name); 15990963Sarr if (newmod != NULL) { 160159634Smaxim MOD_XUNLOCK; 161289111Strasz printf("%s: cannot register %s from %s; already loaded from %s\n", 162289111Strasz __func__, data->name, container->filename, newmod->file->filename); 16390980Sarr return (EEXIST); 16490963Sarr } 16590963Sarr namelen = strlen(data->name) + 1; 166111119Simp newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK); 16790963Sarr newmod->refs = 1; 16890963Sarr newmod->id = nextid++; 16990963Sarr newmod->name = (char *)(newmod + 1); 17090963Sarr strcpy(newmod->name, data->name); 17190963Sarr newmod->handler = data->evhand ? data->evhand : modevent_nop; 17290963Sarr newmod->arg = data->priv; 17390963Sarr bzero(&newmod->data, sizeof(newmod->data)); 17490963Sarr TAILQ_INSERT_TAIL(&modules, newmod, link); 17525537Sdfr 17690963Sarr if (container) 17790963Sarr TAILQ_INSERT_TAIL(&container->modules, newmod, flink); 17890963Sarr newmod->file = container; 17992547Sarr MOD_XUNLOCK; 18090980Sarr return (0); 18125537Sdfr} 18225537Sdfr 18325537Sdfrvoid 18425537Sdfrmodule_reference(module_t mod) 18525537Sdfr{ 18625537Sdfr 18792547Sarr MOD_XLOCK_ASSERT; 18892547Sarr 18990963Sarr MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs)); 19090963Sarr mod->refs++; 19125537Sdfr} 19225537Sdfr 19325537Sdfrvoid 19425537Sdfrmodule_release(module_t mod) 19525537Sdfr{ 19625537Sdfr 19792547Sarr MOD_XLOCK_ASSERT; 19892547Sarr 19990963Sarr if (mod->refs <= 0) 20090963Sarr panic("module_release: bad reference count"); 20125537Sdfr 20290963Sarr MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs)); 20392547Sarr 20490963Sarr mod->refs--; 20590963Sarr if (mod->refs == 0) { 20690963Sarr TAILQ_REMOVE(&modules, mod, link); 20790963Sarr if (mod->file) 20890963Sarr TAILQ_REMOVE(&mod->file->modules, mod, flink); 20990963Sarr free(mod, M_MODULE); 21025537Sdfr } 21125537Sdfr} 21225537Sdfr 21325537Sdfrmodule_t 21490963Sarrmodule_lookupbyname(const char *name) 21525537Sdfr{ 21690963Sarr module_t mod; 21790963Sarr int err; 21825537Sdfr 21992547Sarr MOD_LOCK_ASSERT; 22092547Sarr 22190963Sarr TAILQ_FOREACH(mod, &modules, link) { 22290963Sarr err = strcmp(mod->name, name); 22390963Sarr if (err == 0) 22490980Sarr return (mod); 22590963Sarr } 22690980Sarr return (NULL); 22725537Sdfr} 22825537Sdfr 22925537Sdfrmodule_t 23025537Sdfrmodule_lookupbyid(int modid) 23125537Sdfr{ 23292547Sarr module_t mod; 23325537Sdfr 23492547Sarr MOD_LOCK_ASSERT; 23592547Sarr 23692547Sarr TAILQ_FOREACH(mod, &modules, link) 23792547Sarr if (mod->id == modid) 23892547Sarr return(mod); 23992547Sarr return (NULL); 24025537Sdfr} 24125537Sdfr 24225537Sdfrint 243185635Sjhbmodule_quiesce(module_t mod) 24425537Sdfr{ 245132117Sphk int error; 24690963Sarr 247159957Sjhb mtx_lock(&Giant); 248132117Sphk error = MOD_EVENT(mod, MOD_QUIESCE); 249185635Sjhb mtx_unlock(&Giant); 250132199Sphk if (error == EOPNOTSUPP || error == EINVAL) 251132117Sphk error = 0; 252185635Sjhb return (error); 253185635Sjhb} 254185635Sjhb 255185635Sjhbint 256185635Sjhbmodule_unload(module_t mod) 257185635Sjhb{ 258185635Sjhb int error; 259185635Sjhb 260185635Sjhb mtx_lock(&Giant); 261185635Sjhb error = MOD_EVENT(mod, MOD_UNLOAD); 262159957Sjhb mtx_unlock(&Giant); 263159957Sjhb return (error); 26425537Sdfr} 26525537Sdfr 26625537Sdfrint 26725537Sdfrmodule_getid(module_t mod) 26825537Sdfr{ 26990963Sarr 27092547Sarr MOD_LOCK_ASSERT; 27190980Sarr return (mod->id); 27225537Sdfr} 27325537Sdfr 27425537Sdfrmodule_t 27525537Sdfrmodule_getfnext(module_t mod) 27625537Sdfr{ 27790963Sarr 27892547Sarr MOD_LOCK_ASSERT; 27990980Sarr return (TAILQ_NEXT(mod, flink)); 28025537Sdfr} 28125537Sdfr 282185635Sjhbconst char * 283185635Sjhbmodule_getname(module_t mod) 284185635Sjhb{ 285185635Sjhb 286185635Sjhb MOD_LOCK_ASSERT; 287185635Sjhb return (mod->name); 288185635Sjhb} 289185635Sjhb 29042435Sdfrvoid 29142435Sdfrmodule_setspecific(module_t mod, modspecific_t *datap) 29242435Sdfr{ 29390963Sarr 29492547Sarr MOD_XLOCK_ASSERT; 29590963Sarr mod->data = *datap; 29642435Sdfr} 29742435Sdfr 298157818Sjhblinker_file_t 299157818Sjhbmodule_file(module_t mod) 300157818Sjhb{ 301157818Sjhb 302157818Sjhb return (mod->file); 303157818Sjhb} 304157818Sjhb 30525537Sdfr/* 30625537Sdfr * Syscalls. 30725537Sdfr */ 30825537Sdfrint 309225617Skmacysys_modnext(struct thread *td, struct modnext_args *uap) 31025537Sdfr{ 31190963Sarr module_t mod; 31290963Sarr int error = 0; 31325537Sdfr 31498835Sarr td->td_retval[0] = -1; 31582749Sdillon 31692547Sarr MOD_SLOCK; 317107849Salfred if (uap->modid == 0) { 31890963Sarr mod = TAILQ_FIRST(&modules); 31990963Sarr if (mod) 32090963Sarr td->td_retval[0] = mod->id; 32190963Sarr else 32290963Sarr error = ENOENT; 32390963Sarr goto done2; 32490963Sarr } 325107849Salfred mod = module_lookupbyid(uap->modid); 32690963Sarr if (mod == NULL) { 32790963Sarr error = ENOENT; 32890963Sarr goto done2; 32990963Sarr } 33090963Sarr if (TAILQ_NEXT(mod, link)) 33190963Sarr td->td_retval[0] = TAILQ_NEXT(mod, link)->id; 33282749Sdillon else 33390963Sarr td->td_retval[0] = 0; 33482749Sdillondone2: 33592547Sarr MOD_SUNLOCK; 33690963Sarr return (error); 33725537Sdfr} 33825537Sdfr 33925537Sdfrint 340225617Skmacysys_modfnext(struct thread *td, struct modfnext_args *uap) 34125537Sdfr{ 34290963Sarr module_t mod; 34390963Sarr int error; 34425537Sdfr 34590963Sarr td->td_retval[0] = -1; 34625537Sdfr 34792547Sarr MOD_SLOCK; 348107849Salfred mod = module_lookupbyid(uap->modid); 34990963Sarr if (mod == NULL) { 35090963Sarr error = ENOENT; 35190963Sarr } else { 35290963Sarr error = 0; 35390963Sarr if (TAILQ_NEXT(mod, flink)) 35490963Sarr td->td_retval[0] = TAILQ_NEXT(mod, flink)->id; 35590963Sarr else 35690963Sarr td->td_retval[0] = 0; 35790963Sarr } 35892547Sarr MOD_SUNLOCK; 35990963Sarr return (error); 36025537Sdfr} 36125537Sdfr 36242435Sdfrstruct module_stat_v1 { 36391067Sarr int version; /* set to sizeof(struct module_stat) */ 36491067Sarr char name[MAXMODNAME]; 36591067Sarr int refs; 36691067Sarr int id; 36742435Sdfr}; 36842435Sdfr 36925537Sdfrint 370225617Skmacysys_modstat(struct thread *td, struct modstat_args *uap) 37125537Sdfr{ 37290963Sarr module_t mod; 37392547Sarr modspecific_t data; 37490963Sarr int error = 0; 37592547Sarr int id, namelen, refs, version; 37690963Sarr struct module_stat *stat; 37792547Sarr char *name; 37825537Sdfr 37992547Sarr MOD_SLOCK; 380107849Salfred mod = module_lookupbyid(uap->modid); 38190963Sarr if (mod == NULL) { 38292547Sarr MOD_SUNLOCK; 38398835Sarr return (ENOENT); 38490963Sarr } 38592547Sarr id = mod->id; 38692547Sarr refs = mod->refs; 38792547Sarr name = mod->name; 38892547Sarr data = mod->data; 38992547Sarr MOD_SUNLOCK; 390107849Salfred stat = uap->stat; 39125537Sdfr 39290963Sarr /* 39390963Sarr * Check the version of the user's structure. 39490963Sarr */ 39590963Sarr if ((error = copyin(&stat->version, &version, sizeof(version))) != 0) 39698835Sarr return (error); 39790963Sarr if (version != sizeof(struct module_stat_v1) 39898835Sarr && version != sizeof(struct module_stat)) 39998835Sarr return (EINVAL); 40090963Sarr namelen = strlen(mod->name) + 1; 40190963Sarr if (namelen > MAXMODNAME) 40290963Sarr namelen = MAXMODNAME; 40392547Sarr if ((error = copyout(name, &stat->name[0], namelen)) != 0) 40498835Sarr return (error); 40525537Sdfr 40692547Sarr if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0) 40798835Sarr return (error); 40892547Sarr if ((error = copyout(&id, &stat->id, sizeof(int))) != 0) 40998835Sarr return (error); 41025537Sdfr 41190963Sarr /* 41290963Sarr * >v1 stat includes module data. 41390963Sarr */ 41498835Sarr if (version == sizeof(struct module_stat)) 41592547Sarr if ((error = copyout(&data, &stat->data, 41692547Sarr sizeof(data))) != 0) 41798835Sarr return (error); 41890963Sarr td->td_retval[0] = 0; 41990980Sarr return (error); 42025537Sdfr} 42125537Sdfr 42225537Sdfrint 423225617Skmacysys_modfind(struct thread *td, struct modfind_args *uap) 42425537Sdfr{ 42590963Sarr int error = 0; 42690963Sarr char name[MAXMODNAME]; 42790963Sarr module_t mod; 42825537Sdfr 429107849Salfred if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0) 43098835Sarr return (error); 43125537Sdfr 43292547Sarr MOD_SLOCK; 43390963Sarr mod = module_lookupbyname(name); 43490963Sarr if (mod == NULL) 43590963Sarr error = ENOENT; 43690963Sarr else 43792547Sarr td->td_retval[0] = module_getid(mod); 43892547Sarr MOD_SUNLOCK; 43990980Sarr return (error); 44025537Sdfr} 441140482Sps 442176252SjhbMODULE_VERSION(kernel, __FreeBSD_version); 443176252Sjhb 444205014Snwhitehorn#ifdef COMPAT_FREEBSD32 445140482Sps#include <sys/mount.h> 446174377Sjhb#include <sys/socket.h> 447140482Sps#include <compat/freebsd32/freebsd32_util.h> 448140482Sps#include <compat/freebsd32/freebsd32.h> 449140482Sps#include <compat/freebsd32/freebsd32_proto.h> 450140482Sps 451140482Spstypedef union modspecific32 { 452140482Sps int intval; 453209390Sed uint32_t uintval; 454140482Sps int longval; 455209390Sed uint32_t ulongval; 456140482Sps} modspecific32_t; 457140482Sps 458140482Spsstruct module_stat32 { 459140482Sps int version; 460140482Sps char name[MAXMODNAME]; 461140482Sps int refs; 462140482Sps int id; 463140482Sps modspecific32_t data; 464140482Sps}; 465140482Sps 466140482Spsint 467140482Spsfreebsd32_modstat(struct thread *td, struct freebsd32_modstat_args *uap) 468140482Sps{ 469140482Sps module_t mod; 470140482Sps modspecific32_t data32; 471140482Sps int error = 0; 472140482Sps int id, namelen, refs, version; 473140482Sps struct module_stat32 *stat32; 474140482Sps char *name; 475140482Sps 476140482Sps MOD_SLOCK; 477140482Sps mod = module_lookupbyid(uap->modid); 478140482Sps if (mod == NULL) { 479140482Sps MOD_SUNLOCK; 480140482Sps return (ENOENT); 481140482Sps } 482140482Sps 483140482Sps id = mod->id; 484140482Sps refs = mod->refs; 485140482Sps name = mod->name; 486142067Sps CP(mod->data, data32, intval); 487142067Sps CP(mod->data, data32, uintval); 488142067Sps CP(mod->data, data32, longval); 489142067Sps CP(mod->data, data32, ulongval); 490140482Sps MOD_SUNLOCK; 491140482Sps stat32 = uap->stat; 492140482Sps 493140482Sps if ((error = copyin(&stat32->version, &version, sizeof(version))) != 0) 494140482Sps return (error); 495140482Sps if (version != sizeof(struct module_stat_v1) 496140482Sps && version != sizeof(struct module_stat32)) 497140482Sps return (EINVAL); 498140482Sps namelen = strlen(mod->name) + 1; 499140482Sps if (namelen > MAXMODNAME) 500140482Sps namelen = MAXMODNAME; 501140482Sps if ((error = copyout(name, &stat32->name[0], namelen)) != 0) 502140482Sps return (error); 503140482Sps 504140482Sps if ((error = copyout(&refs, &stat32->refs, sizeof(int))) != 0) 505140482Sps return (error); 506140482Sps if ((error = copyout(&id, &stat32->id, sizeof(int))) != 0) 507140482Sps return (error); 508140482Sps 509140482Sps /* 510140482Sps * >v1 stat includes module data. 511140482Sps */ 512140482Sps if (version == sizeof(struct module_stat32)) 513140482Sps if ((error = copyout(&data32, &stat32->data, 514140482Sps sizeof(data32))) != 0) 515140482Sps return (error); 516140482Sps td->td_retval[0] = 0; 517140482Sps return (error); 518140482Sps} 519140482Sps#endif 520