1cea6c86cSDoug Rabson /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
38a36da99SPedro F. Giffuni *
4cea6c86cSDoug Rabson * Copyright (c) 1997 Doug Rabson
5cea6c86cSDoug Rabson * All rights reserved.
6cea6c86cSDoug Rabson *
7cea6c86cSDoug Rabson * Redistribution and use in source and binary forms, with or without
8cea6c86cSDoug Rabson * modification, are permitted provided that the following conditions
9cea6c86cSDoug Rabson * are met:
10cea6c86cSDoug Rabson * 1. Redistributions of source code must retain the above copyright
11cea6c86cSDoug Rabson * notice, this list of conditions and the following disclaimer.
12cea6c86cSDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright
13cea6c86cSDoug Rabson * notice, this list of conditions and the following disclaimer in the
14cea6c86cSDoug Rabson * documentation and/or other materials provided with the distribution.
15cea6c86cSDoug Rabson *
16cea6c86cSDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17cea6c86cSDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18cea6c86cSDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19cea6c86cSDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20cea6c86cSDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21cea6c86cSDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22cea6c86cSDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23cea6c86cSDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24cea6c86cSDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25cea6c86cSDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26cea6c86cSDoug Rabson * SUCH DAMAGE.
27cea6c86cSDoug Rabson */
28cea6c86cSDoug Rabson
29cea6c86cSDoug Rabson #include <sys/param.h>
30cea6c86cSDoug Rabson #include <sys/kernel.h>
31cea6c86cSDoug Rabson #include <sys/systm.h>
32fcb893a8SMike Smith #include <sys/eventhandler.h>
33cea6c86cSDoug Rabson #include <sys/malloc.h>
34cea6c86cSDoug Rabson #include <sys/sysproto.h>
35cea6c86cSDoug Rabson #include <sys/sysent.h>
36cb226aaaSPoul-Henning Kamp #include <sys/proc.h>
37835a82eeSMatthew Dillon #include <sys/lock.h>
38835a82eeSMatthew Dillon #include <sys/mutex.h>
391a1c04b6SDon Lewis #include <sys/reboot.h>
409b3851e9SAndrew R. Reiter #include <sys/sx.h>
419b3851e9SAndrew R. Reiter #include <sys/module.h>
429b3851e9SAndrew R. Reiter #include <sys/linker.h>
43cea6c86cSDoug Rabson
44959b7375SPoul-Henning Kamp static MALLOC_DEFINE(M_MODULE, "module", "module data structures");
45cea6c86cSDoug Rabson
46cea6c86cSDoug Rabson struct module {
47e3975643SJake Burkholder TAILQ_ENTRY(module) link; /* chain together all modules */
48e3975643SJake Burkholder TAILQ_ENTRY(module) flink; /* all modules in a file */
49cea6c86cSDoug Rabson struct linker_file *file; /* file which contains this module */
50cea6c86cSDoug Rabson int refs; /* reference count */
51cea6c86cSDoug Rabson int id; /* unique id number */
52cea6c86cSDoug Rabson char *name; /* module name */
53cea6c86cSDoug Rabson modeventhand_t handler; /* event handler */
54cea6c86cSDoug Rabson void *arg; /* argument for handler */
55a35261efSDoug Rabson modspecific_t data; /* module specific data */
56cea6c86cSDoug Rabson };
57cea6c86cSDoug Rabson
58cea6c86cSDoug Rabson #define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg)
59cea6c86cSDoug Rabson
6057c15380SAttilio Rao static TAILQ_HEAD(modulelist, module) modules;
619b3851e9SAndrew R. Reiter struct sx modules_sx;
62cea6c86cSDoug Rabson static int nextid = 1;
63fcb893a8SMike Smith static void module_shutdown(void *, int);
64cea6c86cSDoug Rabson
65845ccef4SPeter Wemm static int
modevent_nop(module_t mod,int what,void * arg)66845ccef4SPeter Wemm modevent_nop(module_t mod, int what, void *arg)
67845ccef4SPeter Wemm {
68e2ad640eSPoul-Henning Kamp
69e2ad640eSPoul-Henning Kamp switch(what) {
70e2ad640eSPoul-Henning Kamp case MOD_LOAD:
71b65420f9SAndrew R. Reiter return (0);
72e2ad640eSPoul-Henning Kamp case MOD_UNLOAD:
73e2ad640eSPoul-Henning Kamp return (EBUSY);
74e2ad640eSPoul-Henning Kamp default:
75e2ad640eSPoul-Henning Kamp return (EOPNOTSUPP);
76e2ad640eSPoul-Henning Kamp }
77845ccef4SPeter Wemm }
78845ccef4SPeter Wemm
79cea6c86cSDoug Rabson static void
module_init(void * arg)80cea6c86cSDoug Rabson module_init(void *arg)
81cea6c86cSDoug Rabson {
82287698b4SAndrew R. Reiter
839b3851e9SAndrew R. Reiter sx_init(&modules_sx, "module subsystem sx lock");
84cea6c86cSDoug Rabson TAILQ_INIT(&modules);
852488f309SPeter Wemm EVENTHANDLER_REGISTER(shutdown_final, module_shutdown, NULL,
86fcb893a8SMike Smith SHUTDOWN_PRI_DEFAULT);
87cea6c86cSDoug Rabson }
88cea6c86cSDoug Rabson
89891cf3edSEd Maste SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, NULL);
90cea6c86cSDoug Rabson
91cea6c86cSDoug Rabson static void
module_shutdown(void * arg1,int arg2)92fcb893a8SMike Smith module_shutdown(void *arg1, int arg2)
93cea6c86cSDoug Rabson {
94cea6c86cSDoug Rabson module_t mod;
95cea6c86cSDoug Rabson
961a1c04b6SDon Lewis if (arg2 & RB_NOSYNC)
971a1c04b6SDon Lewis return;
98c94ce032SJohn Baldwin mtx_lock(&Giant);
999b3851e9SAndrew R. Reiter MOD_SLOCK;
10057c15380SAttilio Rao TAILQ_FOREACH_REVERSE(mod, &modules, modulelist, link)
101cea6c86cSDoug Rabson MOD_EVENT(mod, MOD_SHUTDOWN);
1029b3851e9SAndrew R. Reiter MOD_SUNLOCK;
103c94ce032SJohn Baldwin mtx_unlock(&Giant);
104cea6c86cSDoug Rabson }
105cea6c86cSDoug Rabson
106cea6c86cSDoug Rabson void
module_register_init(const void * arg)1073cfc69e6SMatthew Dillon module_register_init(const void *arg)
108cea6c86cSDoug Rabson {
1093cfc69e6SMatthew Dillon const moduledata_t *data = (const moduledata_t *)arg;
110cea6c86cSDoug Rabson int error;
111b5b15c3fSPeter Wemm module_t mod;
112cea6c86cSDoug Rabson
113c94ce032SJohn Baldwin mtx_lock(&Giant);
1149b3851e9SAndrew R. Reiter MOD_SLOCK;
115b5b15c3fSPeter Wemm mod = module_lookupbyname(data->name);
116b5b15c3fSPeter Wemm if (mod == NULL)
117287698b4SAndrew R. Reiter panic("module_register_init: module named %s not found\n",
118287698b4SAndrew R. Reiter data->name);
1199b3851e9SAndrew R. Reiter MOD_SUNLOCK;
120b5b15c3fSPeter Wemm error = MOD_EVENT(mod, MOD_LOAD);
121b5b15c3fSPeter Wemm if (error) {
122b5b15c3fSPeter Wemm MOD_EVENT(mod, MOD_UNLOAD);
1239b3851e9SAndrew R. Reiter MOD_XLOCK;
124b5b15c3fSPeter Wemm module_release(mod);
1259b3851e9SAndrew R. Reiter MOD_XUNLOCK;
126bd47bef5SPeter Wemm printf("module_register_init: MOD_LOAD (%s, %p, %p) error"
127bd47bef5SPeter Wemm " %d\n", data->name, (void *)data->evhand, data->priv,
128287698b4SAndrew R. Reiter error);
12975444a85SJohn Baldwin } else {
13075444a85SJohn Baldwin MOD_XLOCK;
13175444a85SJohn Baldwin if (mod->file) {
13275444a85SJohn Baldwin /*
133dda66918SJohn Baldwin * Once a module is successfully loaded, move
13475444a85SJohn Baldwin * it to the head of the module list for this
13575444a85SJohn Baldwin * linker file. This resorts the list so that
13675444a85SJohn Baldwin * when the kernel linker iterates over the
13775444a85SJohn Baldwin * modules to unload them, it will unload them
13875444a85SJohn Baldwin * in the reverse order they were loaded.
13975444a85SJohn Baldwin */
14075444a85SJohn Baldwin TAILQ_REMOVE(&mod->file->modules, mod, flink);
14175444a85SJohn Baldwin TAILQ_INSERT_HEAD(&mod->file->modules, mod, flink);
14275444a85SJohn Baldwin }
14375444a85SJohn Baldwin MOD_XUNLOCK;
144cea6c86cSDoug Rabson }
145c94ce032SJohn Baldwin mtx_unlock(&Giant);
146b5b15c3fSPeter Wemm }
147cea6c86cSDoug Rabson
148cea6c86cSDoug Rabson int
module_register(const moduledata_t * data,linker_file_t container)149b5b15c3fSPeter Wemm module_register(const moduledata_t *data, linker_file_t container)
150cea6c86cSDoug Rabson {
151cea6c86cSDoug Rabson size_t namelen;
152cea6c86cSDoug Rabson module_t newmod;
153cea6c86cSDoug Rabson
154059d68deSMaxim Konovalov MOD_XLOCK;
155b5b15c3fSPeter Wemm newmod = module_lookupbyname(data->name);
156b5b15c3fSPeter Wemm if (newmod != NULL) {
157059d68deSMaxim Konovalov MOD_XUNLOCK;
158b9a5c7b5SEdward Tomasz Napierala printf("%s: cannot register %s from %s; already loaded from %s\n",
159b9a5c7b5SEdward Tomasz Napierala __func__, data->name, container->filename, newmod->file->filename);
160b65420f9SAndrew R. Reiter return (EEXIST);
161b5b15c3fSPeter Wemm }
162b5b15c3fSPeter Wemm namelen = strlen(data->name) + 1;
163a163d034SWarner Losh newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK);
164cea6c86cSDoug Rabson newmod->refs = 1;
165cea6c86cSDoug Rabson newmod->id = nextid++;
166cea6c86cSDoug Rabson newmod->name = (char *)(newmod + 1);
167b5b15c3fSPeter Wemm strcpy(newmod->name, data->name);
168845ccef4SPeter Wemm newmod->handler = data->evhand ? data->evhand : modevent_nop;
169b5b15c3fSPeter Wemm newmod->arg = data->priv;
170a35261efSDoug Rabson bzero(&newmod->data, sizeof(newmod->data));
171cea6c86cSDoug Rabson TAILQ_INSERT_TAIL(&modules, newmod, link);
172cea6c86cSDoug Rabson
173b5b15c3fSPeter Wemm if (container)
174f3b0d442SPeter Wemm TAILQ_INSERT_TAIL(&container->modules, newmod, flink);
1751d23cba9SPeter Wemm newmod->file = container;
1769b3851e9SAndrew R. Reiter MOD_XUNLOCK;
177b65420f9SAndrew R. Reiter return (0);
178cea6c86cSDoug Rabson }
179cea6c86cSDoug Rabson
180cea6c86cSDoug Rabson void
module_reference(module_t mod)181cea6c86cSDoug Rabson module_reference(module_t mod)
182cea6c86cSDoug Rabson {
183cea6c86cSDoug Rabson
1849b3851e9SAndrew R. Reiter MOD_XLOCK_ASSERT;
1859b3851e9SAndrew R. Reiter
186287698b4SAndrew R. Reiter MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs));
187cea6c86cSDoug Rabson mod->refs++;
188cea6c86cSDoug Rabson }
189cea6c86cSDoug Rabson
190cea6c86cSDoug Rabson void
module_release(module_t mod)191cea6c86cSDoug Rabson module_release(module_t mod)
192cea6c86cSDoug Rabson {
193287698b4SAndrew R. Reiter
1949b3851e9SAndrew R. Reiter MOD_XLOCK_ASSERT;
1959b3851e9SAndrew R. Reiter
196cea6c86cSDoug Rabson if (mod->refs <= 0)
197cea6c86cSDoug Rabson panic("module_release: bad reference count");
198cea6c86cSDoug Rabson
199cea6c86cSDoug Rabson MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs));
200cea6c86cSDoug Rabson
201cea6c86cSDoug Rabson mod->refs--;
202cea6c86cSDoug Rabson if (mod->refs == 0) {
203cea6c86cSDoug Rabson TAILQ_REMOVE(&modules, mod, link);
204287698b4SAndrew R. Reiter if (mod->file)
205cea6c86cSDoug Rabson TAILQ_REMOVE(&mod->file->modules, mod, flink);
206cea6c86cSDoug Rabson free(mod, M_MODULE);
207cea6c86cSDoug Rabson }
208cea6c86cSDoug Rabson }
209cea6c86cSDoug Rabson
210cea6c86cSDoug Rabson module_t
module_lookupbyname(const char * name)211cea6c86cSDoug Rabson module_lookupbyname(const char *name)
212cea6c86cSDoug Rabson {
213cea6c86cSDoug Rabson module_t mod;
214287698b4SAndrew R. Reiter int err;
215cea6c86cSDoug Rabson
2169b3851e9SAndrew R. Reiter MOD_LOCK_ASSERT;
2179b3851e9SAndrew R. Reiter
218fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(mod, &modules, link) {
219287698b4SAndrew R. Reiter err = strcmp(mod->name, name);
220287698b4SAndrew R. Reiter if (err == 0)
221b65420f9SAndrew R. Reiter return (mod);
222cea6c86cSDoug Rabson }
223b65420f9SAndrew R. Reiter return (NULL);
224cea6c86cSDoug Rabson }
225cea6c86cSDoug Rabson
226cea6c86cSDoug Rabson module_t
module_lookupbyid(int modid)227cea6c86cSDoug Rabson module_lookupbyid(int modid)
228cea6c86cSDoug Rabson {
229cea6c86cSDoug Rabson module_t mod;
230cea6c86cSDoug Rabson
2319b3851e9SAndrew R. Reiter MOD_LOCK_ASSERT;
2329b3851e9SAndrew R. Reiter
2339b3851e9SAndrew R. Reiter TAILQ_FOREACH(mod, &modules, link)
234cea6c86cSDoug Rabson if (mod->id == modid)
235b65420f9SAndrew R. Reiter return(mod);
236b65420f9SAndrew R. Reiter return (NULL);
237cea6c86cSDoug Rabson }
238cea6c86cSDoug Rabson
239cea6c86cSDoug Rabson int
module_quiesce(module_t mod)240b4824b48SJohn Baldwin module_quiesce(module_t mod)
241cea6c86cSDoug Rabson {
24265a311fcSPoul-Henning Kamp int error;
243287698b4SAndrew R. Reiter
244c94ce032SJohn Baldwin mtx_lock(&Giant);
24565a311fcSPoul-Henning Kamp error = MOD_EVENT(mod, MOD_QUIESCE);
246b4824b48SJohn Baldwin mtx_unlock(&Giant);
2473e019deaSPoul-Henning Kamp if (error == EOPNOTSUPP || error == EINVAL)
24865a311fcSPoul-Henning Kamp error = 0;
249b4824b48SJohn Baldwin return (error);
250b4824b48SJohn Baldwin }
251b4824b48SJohn Baldwin
252b4824b48SJohn Baldwin int
module_unload(module_t mod)253b4824b48SJohn Baldwin module_unload(module_t mod)
254b4824b48SJohn Baldwin {
255b4824b48SJohn Baldwin int error;
256b4824b48SJohn Baldwin
257b4824b48SJohn Baldwin mtx_lock(&Giant);
258c94ce032SJohn Baldwin error = MOD_EVENT(mod, MOD_UNLOAD);
259c94ce032SJohn Baldwin mtx_unlock(&Giant);
26065a311fcSPoul-Henning Kamp return (error);
261cea6c86cSDoug Rabson }
262cea6c86cSDoug Rabson
263cea6c86cSDoug Rabson int
module_getid(module_t mod)264cea6c86cSDoug Rabson module_getid(module_t mod)
265cea6c86cSDoug Rabson {
266287698b4SAndrew R. Reiter
2679b3851e9SAndrew R. Reiter MOD_LOCK_ASSERT;
268b65420f9SAndrew R. Reiter return (mod->id);
269cea6c86cSDoug Rabson }
270cea6c86cSDoug Rabson
271cea6c86cSDoug Rabson module_t
module_getfnext(module_t mod)272cea6c86cSDoug Rabson module_getfnext(module_t mod)
273cea6c86cSDoug Rabson {
274287698b4SAndrew R. Reiter
2759b3851e9SAndrew R. Reiter MOD_LOCK_ASSERT;
276b65420f9SAndrew R. Reiter return (TAILQ_NEXT(mod, flink));
277cea6c86cSDoug Rabson }
278cea6c86cSDoug Rabson
279b4824b48SJohn Baldwin const char *
module_getname(module_t mod)280b4824b48SJohn Baldwin module_getname(module_t mod)
281b4824b48SJohn Baldwin {
282b4824b48SJohn Baldwin
283b4824b48SJohn Baldwin MOD_LOCK_ASSERT;
284b4824b48SJohn Baldwin return (mod->name);
285b4824b48SJohn Baldwin }
286b4824b48SJohn Baldwin
287a35261efSDoug Rabson void
module_setspecific(module_t mod,modspecific_t * datap)288a35261efSDoug Rabson module_setspecific(module_t mod, modspecific_t *datap)
289a35261efSDoug Rabson {
290287698b4SAndrew R. Reiter
2919b3851e9SAndrew R. Reiter MOD_XLOCK_ASSERT;
292a35261efSDoug Rabson mod->data = *datap;
293a35261efSDoug Rabson }
294a35261efSDoug Rabson
2952971c361SJohn Baldwin linker_file_t
module_file(module_t mod)2962971c361SJohn Baldwin module_file(module_t mod)
2972971c361SJohn Baldwin {
2982971c361SJohn Baldwin
2992971c361SJohn Baldwin return (mod->file);
3002971c361SJohn Baldwin }
3012971c361SJohn Baldwin
302cea6c86cSDoug Rabson /*
303cea6c86cSDoug Rabson * Syscalls.
304cea6c86cSDoug Rabson */
305cea6c86cSDoug Rabson int
sys_modnext(struct thread * td,struct modnext_args * uap)3068451d0ddSKip Macy sys_modnext(struct thread *td, struct modnext_args *uap)
307cea6c86cSDoug Rabson {
308cea6c86cSDoug Rabson module_t mod;
309835a82eeSMatthew Dillon int error = 0;
310835a82eeSMatthew Dillon
311b40ce416SJulian Elischer td->td_retval[0] = -1;
312e024f583SAndrew R. Reiter
3139b3851e9SAndrew R. Reiter MOD_SLOCK;
314d1e405c5SAlfred Perlstein if (uap->modid == 0) {
315cea6c86cSDoug Rabson mod = TAILQ_FIRST(&modules);
316835a82eeSMatthew Dillon if (mod)
317b40ce416SJulian Elischer td->td_retval[0] = mod->id;
318835a82eeSMatthew Dillon else
319835a82eeSMatthew Dillon error = ENOENT;
320835a82eeSMatthew Dillon goto done2;
321cea6c86cSDoug Rabson }
322d1e405c5SAlfred Perlstein mod = module_lookupbyid(uap->modid);
323835a82eeSMatthew Dillon if (mod == NULL) {
324835a82eeSMatthew Dillon error = ENOENT;
325835a82eeSMatthew Dillon goto done2;
326835a82eeSMatthew Dillon }
327cea6c86cSDoug Rabson if (TAILQ_NEXT(mod, link))
328b40ce416SJulian Elischer td->td_retval[0] = TAILQ_NEXT(mod, link)->id;
329cea6c86cSDoug Rabson else
330b40ce416SJulian Elischer td->td_retval[0] = 0;
331835a82eeSMatthew Dillon done2:
3329b3851e9SAndrew R. Reiter MOD_SUNLOCK;
333835a82eeSMatthew Dillon return (error);
334cea6c86cSDoug Rabson }
335cea6c86cSDoug Rabson
336cea6c86cSDoug Rabson int
sys_modfnext(struct thread * td,struct modfnext_args * uap)3378451d0ddSKip Macy sys_modfnext(struct thread *td, struct modfnext_args *uap)
338cea6c86cSDoug Rabson {
339cea6c86cSDoug Rabson module_t mod;
340835a82eeSMatthew Dillon int error;
341cea6c86cSDoug Rabson
342b40ce416SJulian Elischer td->td_retval[0] = -1;
343cea6c86cSDoug Rabson
3449b3851e9SAndrew R. Reiter MOD_SLOCK;
345d1e405c5SAlfred Perlstein mod = module_lookupbyid(uap->modid);
346835a82eeSMatthew Dillon if (mod == NULL) {
347835a82eeSMatthew Dillon error = ENOENT;
348835a82eeSMatthew Dillon } else {
349835a82eeSMatthew Dillon error = 0;
350cea6c86cSDoug Rabson if (TAILQ_NEXT(mod, flink))
351b40ce416SJulian Elischer td->td_retval[0] = TAILQ_NEXT(mod, flink)->id;
352cea6c86cSDoug Rabson else
353b40ce416SJulian Elischer td->td_retval[0] = 0;
354835a82eeSMatthew Dillon }
3559b3851e9SAndrew R. Reiter MOD_SUNLOCK;
356835a82eeSMatthew Dillon return (error);
357cea6c86cSDoug Rabson }
358cea6c86cSDoug Rabson
359a35261efSDoug Rabson struct module_stat_v1 {
360a35261efSDoug Rabson int version; /* set to sizeof(struct module_stat) */
361df38ada2SBjoern A. Zeeb char name[MAXMODNAMEV1V2];
362a35261efSDoug Rabson int refs;
363a35261efSDoug Rabson int id;
364a35261efSDoug Rabson };
365a35261efSDoug Rabson
366df38ada2SBjoern A. Zeeb struct module_stat_v2 {
367df38ada2SBjoern A. Zeeb int version; /* set to sizeof(struct module_stat) */
368df38ada2SBjoern A. Zeeb char name[MAXMODNAMEV1V2];
369df38ada2SBjoern A. Zeeb int refs;
370df38ada2SBjoern A. Zeeb int id;
371df38ada2SBjoern A. Zeeb modspecific_t data;
372df38ada2SBjoern A. Zeeb };
373df38ada2SBjoern A. Zeeb
374cea6c86cSDoug Rabson int
sys_modstat(struct thread * td,struct modstat_args * uap)3758451d0ddSKip Macy sys_modstat(struct thread *td, struct modstat_args *uap)
376cea6c86cSDoug Rabson {
377cea6c86cSDoug Rabson module_t mod;
3789b3851e9SAndrew R. Reiter modspecific_t data;
379cea6c86cSDoug Rabson int error = 0;
3809b3851e9SAndrew R. Reiter int id, namelen, refs, version;
381cea6c86cSDoug Rabson struct module_stat *stat;
382df38ada2SBjoern A. Zeeb struct module_stat_v2 *stat_v2;
3839b3851e9SAndrew R. Reiter char *name;
384df38ada2SBjoern A. Zeeb bool is_v1v2;
385cea6c86cSDoug Rabson
3869b3851e9SAndrew R. Reiter MOD_SLOCK;
387d1e405c5SAlfred Perlstein mod = module_lookupbyid(uap->modid);
388835a82eeSMatthew Dillon if (mod == NULL) {
3899b3851e9SAndrew R. Reiter MOD_SUNLOCK;
390e024f583SAndrew R. Reiter return (ENOENT);
391835a82eeSMatthew Dillon }
3929b3851e9SAndrew R. Reiter id = mod->id;
3939b3851e9SAndrew R. Reiter refs = mod->refs;
3949b3851e9SAndrew R. Reiter name = mod->name;
3959b3851e9SAndrew R. Reiter data = mod->data;
3969b3851e9SAndrew R. Reiter MOD_SUNLOCK;
397d1e405c5SAlfred Perlstein stat = uap->stat;
398cea6c86cSDoug Rabson
399cea6c86cSDoug Rabson /*
400cea6c86cSDoug Rabson * Check the version of the user's structure.
401cea6c86cSDoug Rabson */
402d254af07SMatthew Dillon if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
403e024f583SAndrew R. Reiter return (error);
404df38ada2SBjoern A. Zeeb is_v1v2 = (version == sizeof(struct module_stat_v1) ||
405df38ada2SBjoern A. Zeeb version == sizeof(struct module_stat_v2));
406df38ada2SBjoern A. Zeeb if (!is_v1v2 && version != sizeof(struct module_stat))
407e024f583SAndrew R. Reiter return (EINVAL);
408cea6c86cSDoug Rabson namelen = strlen(mod->name) + 1;
409df38ada2SBjoern A. Zeeb if (is_v1v2 && namelen > MAXMODNAMEV1V2)
410df38ada2SBjoern A. Zeeb namelen = MAXMODNAMEV1V2;
411df38ada2SBjoern A. Zeeb else if (namelen > MAXMODNAMEV3)
412df38ada2SBjoern A. Zeeb namelen = MAXMODNAMEV3;
4139b3851e9SAndrew R. Reiter if ((error = copyout(name, &stat->name[0], namelen)) != 0)
414e024f583SAndrew R. Reiter return (error);
415cea6c86cSDoug Rabson
416df38ada2SBjoern A. Zeeb /* Extending MAXMODNAME gives an offset change for v3. */
417df38ada2SBjoern A. Zeeb if (is_v1v2) {
418df38ada2SBjoern A. Zeeb stat_v2 = (struct module_stat_v2 *)stat;
419df38ada2SBjoern A. Zeeb if ((error = copyout(&refs, &stat_v2->refs, sizeof(int))) != 0)
420df38ada2SBjoern A. Zeeb return (error);
421df38ada2SBjoern A. Zeeb if ((error = copyout(&id, &stat_v2->id, sizeof(int))) != 0)
422df38ada2SBjoern A. Zeeb return (error);
423df38ada2SBjoern A. Zeeb } else {
4249b3851e9SAndrew R. Reiter if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0)
425e024f583SAndrew R. Reiter return (error);
4269b3851e9SAndrew R. Reiter if ((error = copyout(&id, &stat->id, sizeof(int))) != 0)
427e024f583SAndrew R. Reiter return (error);
428df38ada2SBjoern A. Zeeb }
429cea6c86cSDoug Rabson
430a35261efSDoug Rabson /*
431a35261efSDoug Rabson * >v1 stat includes module data.
432a35261efSDoug Rabson */
433df38ada2SBjoern A. Zeeb if (version == sizeof(struct module_stat_v2)) {
434df38ada2SBjoern A. Zeeb if ((error = copyout(&data, &stat_v2->data,
435df38ada2SBjoern A. Zeeb sizeof(data))) != 0)
436df38ada2SBjoern A. Zeeb return (error);
437df38ada2SBjoern A. Zeeb } else if (version == sizeof(struct module_stat)) {
4389b3851e9SAndrew R. Reiter if ((error = copyout(&data, &stat->data,
4399b3851e9SAndrew R. Reiter sizeof(data))) != 0)
440e024f583SAndrew R. Reiter return (error);
441df38ada2SBjoern A. Zeeb }
442b40ce416SJulian Elischer td->td_retval[0] = 0;
443b65420f9SAndrew R. Reiter return (error);
444cea6c86cSDoug Rabson }
445cea6c86cSDoug Rabson
446cea6c86cSDoug Rabson int
sys_modfind(struct thread * td,struct modfind_args * uap)4478451d0ddSKip Macy sys_modfind(struct thread *td, struct modfind_args *uap)
448cea6c86cSDoug Rabson {
449cea6c86cSDoug Rabson int error = 0;
450df38ada2SBjoern A. Zeeb char name[MAXMODNAMEV3];
451cea6c86cSDoug Rabson module_t mod;
452cea6c86cSDoug Rabson
453d1e405c5SAlfred Perlstein if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0)
454e024f583SAndrew R. Reiter return (error);
455cea6c86cSDoug Rabson
4569b3851e9SAndrew R. Reiter MOD_SLOCK;
457cea6c86cSDoug Rabson mod = module_lookupbyname(name);
458835a82eeSMatthew Dillon if (mod == NULL)
459cea6c86cSDoug Rabson error = ENOENT;
460cea6c86cSDoug Rabson else
4619b3851e9SAndrew R. Reiter td->td_retval[0] = module_getid(mod);
4629b3851e9SAndrew R. Reiter MOD_SUNLOCK;
463b65420f9SAndrew R. Reiter return (error);
464cea6c86cSDoug Rabson }
4650e214fadSPaul Saab
46674712770SJohn Baldwin MODULE_VERSION(kernel, __FreeBSD_version);
46774712770SJohn Baldwin
468841c0c7eSNathan Whitehorn #ifdef COMPAT_FREEBSD32
4690e214fadSPaul Saab #include <sys/mount.h>
47074427aa4SJohn Baldwin #include <sys/socket.h>
4710e214fadSPaul Saab #include <compat/freebsd32/freebsd32_util.h>
4720e214fadSPaul Saab #include <compat/freebsd32/freebsd32.h>
4730e214fadSPaul Saab #include <compat/freebsd32/freebsd32_proto.h>
4740e214fadSPaul Saab
4750e214fadSPaul Saab typedef union modspecific32 {
4760e214fadSPaul Saab int intval;
47760ae52f7SEd Schouten uint32_t uintval;
4780e214fadSPaul Saab int longval;
47960ae52f7SEd Schouten uint32_t ulongval;
4800e214fadSPaul Saab } modspecific32_t;
4810e214fadSPaul Saab
482df38ada2SBjoern A. Zeeb struct module_stat32_v2 {
483df38ada2SBjoern A. Zeeb int version;
484df38ada2SBjoern A. Zeeb char name[MAXMODNAMEV1V2];
485df38ada2SBjoern A. Zeeb int refs;
486df38ada2SBjoern A. Zeeb int id;
487df38ada2SBjoern A. Zeeb modspecific32_t data;
488df38ada2SBjoern A. Zeeb };
489df38ada2SBjoern A. Zeeb
4900e214fadSPaul Saab struct module_stat32 {
4910e214fadSPaul Saab int version;
4920e214fadSPaul Saab char name[MAXMODNAME];
4930e214fadSPaul Saab int refs;
4940e214fadSPaul Saab int id;
4950e214fadSPaul Saab modspecific32_t data;
4960e214fadSPaul Saab };
4970e214fadSPaul Saab
4980e214fadSPaul Saab int
freebsd32_modstat(struct thread * td,struct freebsd32_modstat_args * uap)4990e214fadSPaul Saab freebsd32_modstat(struct thread *td, struct freebsd32_modstat_args *uap)
5000e214fadSPaul Saab {
5010e214fadSPaul Saab module_t mod;
5020e214fadSPaul Saab modspecific32_t data32;
5030e214fadSPaul Saab int error = 0;
5040e214fadSPaul Saab int id, namelen, refs, version;
5050e214fadSPaul Saab struct module_stat32 *stat32;
506df38ada2SBjoern A. Zeeb struct module_stat32_v2 *stat32_v2;
5070e214fadSPaul Saab char *name;
508df38ada2SBjoern A. Zeeb bool is_v1v2;
5090e214fadSPaul Saab
5100e214fadSPaul Saab MOD_SLOCK;
5110e214fadSPaul Saab mod = module_lookupbyid(uap->modid);
5120e214fadSPaul Saab if (mod == NULL) {
5130e214fadSPaul Saab MOD_SUNLOCK;
5140e214fadSPaul Saab return (ENOENT);
5150e214fadSPaul Saab }
5160e214fadSPaul Saab
5170e214fadSPaul Saab id = mod->id;
5180e214fadSPaul Saab refs = mod->refs;
5190e214fadSPaul Saab name = mod->name;
520*034c0856SKa Ho Ng _Static_assert(sizeof(data32) == sizeof(data32.uintval),
521*034c0856SKa Ho Ng "bad modspecific32_t size");
522b7820945SPaul Saab CP(mod->data, data32, uintval);
5230e214fadSPaul Saab MOD_SUNLOCK;
5240e214fadSPaul Saab stat32 = uap->stat;
5250e214fadSPaul Saab
5260e214fadSPaul Saab if ((error = copyin(&stat32->version, &version, sizeof(version))) != 0)
5270e214fadSPaul Saab return (error);
528df38ada2SBjoern A. Zeeb is_v1v2 = (version == sizeof(struct module_stat_v1) ||
529df38ada2SBjoern A. Zeeb version == sizeof(struct module_stat32_v2));
530df38ada2SBjoern A. Zeeb if (!is_v1v2 && version != sizeof(struct module_stat32))
5310e214fadSPaul Saab return (EINVAL);
5320e214fadSPaul Saab namelen = strlen(mod->name) + 1;
533df38ada2SBjoern A. Zeeb if (is_v1v2 && namelen > MAXMODNAMEV1V2)
534df38ada2SBjoern A. Zeeb namelen = MAXMODNAMEV1V2;
535df38ada2SBjoern A. Zeeb else if (namelen > MAXMODNAMEV3)
536df38ada2SBjoern A. Zeeb namelen = MAXMODNAMEV3;
5370e214fadSPaul Saab if ((error = copyout(name, &stat32->name[0], namelen)) != 0)
5380e214fadSPaul Saab return (error);
5390e214fadSPaul Saab
540df38ada2SBjoern A. Zeeb /* Extending MAXMODNAME gives an offset change for v3. */
541df38ada2SBjoern A. Zeeb if (is_v1v2) {
542df38ada2SBjoern A. Zeeb stat32_v2 = (struct module_stat32_v2 *)stat32;
543df38ada2SBjoern A. Zeeb if ((error = copyout(&refs, &stat32_v2->refs, sizeof(int))) != 0)
544df38ada2SBjoern A. Zeeb return (error);
545df38ada2SBjoern A. Zeeb if ((error = copyout(&id, &stat32_v2->id, sizeof(int))) != 0)
546df38ada2SBjoern A. Zeeb return (error);
547df38ada2SBjoern A. Zeeb } else {
5480e214fadSPaul Saab if ((error = copyout(&refs, &stat32->refs, sizeof(int))) != 0)
5490e214fadSPaul Saab return (error);
5500e214fadSPaul Saab if ((error = copyout(&id, &stat32->id, sizeof(int))) != 0)
5510e214fadSPaul Saab return (error);
552df38ada2SBjoern A. Zeeb }
5530e214fadSPaul Saab
5540e214fadSPaul Saab /*
5550e214fadSPaul Saab * >v1 stat includes module data.
5560e214fadSPaul Saab */
557df38ada2SBjoern A. Zeeb if (version == sizeof(struct module_stat32_v2)) {
558df38ada2SBjoern A. Zeeb if ((error = copyout(&data32, &stat32_v2->data,
559df38ada2SBjoern A. Zeeb sizeof(data32))) != 0)
560df38ada2SBjoern A. Zeeb return (error);
561df38ada2SBjoern A. Zeeb } else if (version == sizeof(struct module_stat32)) {
5620e214fadSPaul Saab if ((error = copyout(&data32, &stat32->data,
5630e214fadSPaul Saab sizeof(data32))) != 0)
5640e214fadSPaul Saab return (error);
565df38ada2SBjoern A. Zeeb }
5660e214fadSPaul Saab td->td_retval[0] = 0;
5670e214fadSPaul Saab return (error);
5680e214fadSPaul Saab }
5690e214fadSPaul Saab #endif
570