2 * Copyright (c) 1997 Doug Rabson
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include "opt_compat.h"
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
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>
41 #include <sys/mutex.h>
42 #include <sys/reboot.h>
44 #include <sys/module.h>
45 #include <sys/linker.h>
47 static MALLOC_DEFINE(M_MODULE
, "module", "module data structures");
49 typedef TAILQ_HEAD(, module
) modulelist_t
;
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 */
62 #define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg)
64 static modulelist_t modules
;
66 static int nextid
= 1;
67 static void module_shutdown(void *, int);
70 modevent_nop(module_t mod
, int what
, void *arg
)
84 module_init(void *arg
)
87 sx_init(&modules_sx
, "module subsystem sx lock");
89 EVENTHANDLER_REGISTER(shutdown_final
, module_shutdown
, NULL
,
90 SHUTDOWN_PRI_DEFAULT
);
93 SYSINIT(module
, SI_SUB_KLD
, SI_ORDER_FIRST
, module_init
, 0);
96 module_shutdown(void *arg1
, int arg2
)
100 if (arg2
& RB_NOSYNC
)
104 TAILQ_FOREACH(mod
, &modules
, link
)
105 MOD_EVENT(mod
, MOD_SHUTDOWN
);
111 module_register_init(const void *arg
)
113 const moduledata_t
*data
= (const moduledata_t
*)arg
;
119 mod
= module_lookupbyname(data
->name
);
121 panic("module_register_init: module named %s not found\n",
124 error
= MOD_EVENT(mod
, MOD_LOAD
);
126 MOD_EVENT(mod
, MOD_UNLOAD
);
130 printf("module_register_init: MOD_LOAD (%s, %p, %p) error"
131 " %d\n", data
->name
, (void *)data
->evhand
, data
->priv
,
138 module_register(const moduledata_t
*data
, linker_file_t container
)
144 newmod
= module_lookupbyname(data
->name
);
145 if (newmod
!= NULL
) {
147 printf("module_register: module %s already exists!\n",
151 namelen
= strlen(data
->name
) + 1;
152 newmod
= malloc(sizeof(struct module
) + namelen
, M_MODULE
, M_WAITOK
);
153 if (newmod
== NULL
) {
158 newmod
->id
= nextid
++;
159 newmod
->name
= (char *)(newmod
+ 1);
160 strcpy(newmod
->name
, data
->name
);
161 newmod
->handler
= data
->evhand
? data
->evhand
: modevent_nop
;
162 newmod
->arg
= data
->priv
;
163 bzero(&newmod
->data
, sizeof(newmod
->data
));
164 TAILQ_INSERT_TAIL(&modules
, newmod
, link
);
167 TAILQ_INSERT_TAIL(&container
->modules
, newmod
, flink
);
168 newmod
->file
= container
;
174 module_reference(module_t mod
)
179 MOD_DPF(REFS
, ("module_reference: before, refs=%d\n", mod
->refs
));
184 module_release(module_t mod
)
190 panic("module_release: bad reference count");
192 MOD_DPF(REFS
, ("module_release: before, refs=%d\n", mod
->refs
));
195 if (mod
->refs
== 0) {
196 TAILQ_REMOVE(&modules
, mod
, link
);
198 TAILQ_REMOVE(&mod
->file
->modules
, mod
, flink
);
206 module_lookupbyname(const char *name
)
213 TAILQ_FOREACH(mod
, &modules
, link
) {
214 err
= strcmp(mod
->name
, name
);
222 module_lookupbyid(int modid
)
228 TAILQ_FOREACH(mod
, &modules
, link
)
229 if (mod
->id
== modid
)
235 module_unload(module_t mod
, int flags
)
240 error
= MOD_EVENT(mod
, MOD_QUIESCE
);
241 if (error
== EOPNOTSUPP
|| error
== EINVAL
)
243 if (error
== 0 || flags
== LINKER_UNLOAD_FORCE
)
244 error
= MOD_EVENT(mod
, MOD_UNLOAD
);
250 module_getid(module_t mod
)
258 module_getfnext(module_t mod
)
262 return (TAILQ_NEXT(mod
, flink
));
266 module_setspecific(module_t mod
, modspecific_t
*datap
)
274 module_file(module_t mod
)
284 modnext(struct thread
*td
, struct modnext_args
*uap
)
289 td
->td_retval
[0] = -1;
292 if (uap
->modid
== 0) {
293 mod
= TAILQ_FIRST(&modules
);
295 td
->td_retval
[0] = mod
->id
;
300 mod
= module_lookupbyid(uap
->modid
);
305 if (TAILQ_NEXT(mod
, link
))
306 td
->td_retval
[0] = TAILQ_NEXT(mod
, link
)->id
;
308 td
->td_retval
[0] = 0;
315 modfnext(struct thread
*td
, struct modfnext_args
*uap
)
320 td
->td_retval
[0] = -1;
323 mod
= module_lookupbyid(uap
->modid
);
328 if (TAILQ_NEXT(mod
, flink
))
329 td
->td_retval
[0] = TAILQ_NEXT(mod
, flink
)->id
;
331 td
->td_retval
[0] = 0;
337 struct module_stat_v1
{
338 int version
; /* set to sizeof(struct module_stat) */
339 char name
[MAXMODNAME
];
345 modstat(struct thread
*td
, struct modstat_args
*uap
)
350 int id
, namelen
, refs
, version
;
351 struct module_stat
*stat
;
355 mod
= module_lookupbyid(uap
->modid
);
368 * Check the version of the user's structure.
370 if ((error
= copyin(&stat
->version
, &version
, sizeof(version
))) != 0)
372 if (version
!= sizeof(struct module_stat_v1
)
373 && version
!= sizeof(struct module_stat
))
375 namelen
= strlen(mod
->name
) + 1;
376 if (namelen
> MAXMODNAME
)
377 namelen
= MAXMODNAME
;
378 if ((error
= copyout(name
, &stat
->name
[0], namelen
)) != 0)
381 if ((error
= copyout(&refs
, &stat
->refs
, sizeof(int))) != 0)
383 if ((error
= copyout(&id
, &stat
->id
, sizeof(int))) != 0)
387 * >v1 stat includes module data.
389 if (version
== sizeof(struct module_stat
))
390 if ((error
= copyout(&data
, &stat
->data
,
393 td
->td_retval
[0] = 0;
398 modfind(struct thread
*td
, struct modfind_args
*uap
)
401 char name
[MAXMODNAME
];
404 if ((error
= copyinstr(uap
->name
, name
, sizeof name
, 0)) != 0)
408 mod
= module_lookupbyname(name
);
412 td
->td_retval
[0] = module_getid(mod
);
417 MODULE_VERSION(kernel
, __FreeBSD_version
);
420 #include <sys/mount.h>
421 #include <sys/socket.h>
422 #include <compat/freebsd32/freebsd32_util.h>
423 #include <compat/freebsd32/freebsd32.h>
424 #include <compat/freebsd32/freebsd32_proto.h>
426 typedef union modspecific32
{
433 struct module_stat32
{
435 char name
[MAXMODNAME
];
438 modspecific32_t data
;
442 freebsd32_modstat(struct thread
*td
, struct freebsd32_modstat_args
*uap
)
445 modspecific32_t data32
;
447 int id
, namelen
, refs
, version
;
448 struct module_stat32
*stat32
;
452 mod
= module_lookupbyid(uap
->modid
);
461 CP(mod
->data
, data32
, intval
);
462 CP(mod
->data
, data32
, uintval
);
463 CP(mod
->data
, data32
, longval
);
464 CP(mod
->data
, data32
, ulongval
);
468 if ((error
= copyin(&stat32
->version
, &version
, sizeof(version
))) != 0)
470 if (version
!= sizeof(struct module_stat_v1
)
471 && version
!= sizeof(struct module_stat32
))
473 namelen
= strlen(mod
->name
) + 1;
474 if (namelen
> MAXMODNAME
)
475 namelen
= MAXMODNAME
;
476 if ((error
= copyout(name
, &stat32
->name
[0], namelen
)) != 0)
479 if ((error
= copyout(&refs
, &stat32
->refs
, sizeof(int))) != 0)
481 if ((error
= copyout(&id
, &stat32
->id
, sizeof(int))) != 0)
485 * >v1 stat includes module data.
487 if (version
== sizeof(struct module_stat32
))
488 if ((error
= copyout(&data32
, &stat32
->data
,
489 sizeof(data32
))) != 0)
491 td
->td_retval
[0] = 0;