source: rtems-libbsd/freebsd/sys/kern/kern_module.c @ 150d4d6

4.1155-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since 150d4d6 was 150d4d6, checked in by Sebastian Huber <sebastian.huber@…>, on 10/24/13 at 09:11:32

Move content to new <machine/rtems-bsd-support.h>

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