From a9153ec3040f54fa52b68e14dafed2aba7b780ae Mon Sep 17 00:00:00 2001 From: Joel Sherrill Date: Wed, 7 Mar 2012 09:52:04 -0600 Subject: Initial import Code is based on FreeBSD 8.2 with USB support from Sebastian Huber and Thomas Doerfler. Initial TCP/IP stack work is from Kevel Kirspel. --- rtems/freebsd/kern/kern_module.c | 551 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 551 insertions(+) create mode 100644 rtems/freebsd/kern/kern_module.c (limited to 'rtems/freebsd/kern/kern_module.c') diff --git a/rtems/freebsd/kern/kern_module.c b/rtems/freebsd/kern/kern_module.c new file mode 100644 index 00000000..3dfc761c --- /dev/null +++ b/rtems/freebsd/kern/kern_module.c @@ -0,0 +1,551 @@ +#include + +/*- + * Copyright (c) 1997 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static MALLOC_DEFINE(M_MODULE, "module", "module data structures"); + +struct module { + TAILQ_ENTRY(module) link; /* chain together all modules */ +#ifndef __rtems__ + TAILQ_ENTRY(module) flink; /* all modules in a file */ + struct linker_file *file; /* file which contains this module */ + int refs; /* reference count */ +#endif /* __rtems__ */ + int id; /* unique id number */ + char *name; /* module name */ + modeventhand_t handler; /* event handler */ + void *arg; /* argument for handler */ + modspecific_t data; /* module specific data */ +}; + +#define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg) + +static TAILQ_HEAD(modulelist, module) modules; +struct sx modules_sx; +static int nextid = 1; +#ifndef __rtems__ +static void module_shutdown(void *, int); +#endif /* __rtems__ */ + +static int +modevent_nop(module_t mod, int what, void *arg) +{ + + switch(what) { + case MOD_LOAD: + return (0); + case MOD_UNLOAD: + return (EBUSY); + default: + return (EOPNOTSUPP); + } +} + +static void +module_init(void *arg) +{ + + sx_init(&modules_sx, "module subsystem sx lock"); + TAILQ_INIT(&modules); +#ifndef __rtems__ + EVENTHANDLER_REGISTER(shutdown_final, module_shutdown, NULL, + SHUTDOWN_PRI_DEFAULT); +#endif /* __rtems__ */ +} + +SYSINIT(module, SI_SUB_KLD, SI_ORDER_FIRST, module_init, 0); + +#ifndef __rtems__ +static void +module_shutdown(void *arg1, int arg2) +{ + module_t mod; + + if (arg2 & RB_NOSYNC) + return; + mtx_lock(&Giant); + MOD_SLOCK; + TAILQ_FOREACH_REVERSE(mod, &modules, modulelist, link) + MOD_EVENT(mod, MOD_SHUTDOWN); + MOD_SUNLOCK; + mtx_unlock(&Giant); +} +#endif /* __rtems__ */ + +void +module_register_init(const void *arg) +{ + const moduledata_t *data = (const moduledata_t *)arg; + int error; + module_t mod; + + mtx_lock(&Giant); + MOD_SLOCK; + mod = module_lookupbyname(data->name); + if (mod == NULL) + panic("module_register_init: module named %s not found\n", + data->name); + MOD_SUNLOCK; + error = MOD_EVENT(mod, MOD_LOAD); + if (error) { + MOD_EVENT(mod, MOD_UNLOAD); + MOD_XLOCK; + module_release(mod); + MOD_XUNLOCK; + printf("module_register_init: MOD_LOAD (%s, %p, %p) error" + " %d\n", data->name, (void *)data->evhand, data->priv, + error); + } else { +#ifndef __rtems__ + MOD_XLOCK; + if (mod->file) { + /* + * Once a module is succesfully loaded, move + * it to the head of the module list for this + * linker file. This resorts the list so that + * when the kernel linker iterates over the + * modules to unload them, it will unload them + * in the reverse order they were loaded. + */ + TAILQ_REMOVE(&mod->file->modules, mod, flink); + TAILQ_INSERT_HEAD(&mod->file->modules, mod, flink); + } + MOD_XUNLOCK; +#endif /* __rtems__ */ + } + mtx_unlock(&Giant); +} + +int +module_register(const moduledata_t *data, linker_file_t container) +{ + size_t namelen; + module_t newmod; + + MOD_XLOCK; + newmod = module_lookupbyname(data->name); + if (newmod != NULL) { + MOD_XUNLOCK; + printf("module_register: module %s already exists!\n", + data->name); + return (EEXIST); + } + namelen = strlen(data->name) + 1; + newmod = malloc(sizeof(struct module) + namelen, M_MODULE, M_WAITOK); + if (newmod == NULL) { + MOD_XUNLOCK; + return (ENOMEM); + } +#ifndef __rtems__ + newmod->refs = 1; +#endif /* __rtems__ */ + newmod->id = nextid++; + newmod->name = (char *)(newmod + 1); + strcpy(newmod->name, data->name); + newmod->handler = data->evhand ? data->evhand : modevent_nop; + newmod->arg = data->priv; + bzero(&newmod->data, sizeof(newmod->data)); + TAILQ_INSERT_TAIL(&modules, newmod, link); + + if (container) +#ifndef __rtems__ + TAILQ_INSERT_TAIL(&container->modules, newmod, flink); + newmod->file = container; +#else /* __rtems__ */ + BSD_PANIC("not supported"); +#endif /* __rtems__ */ + MOD_XUNLOCK; + return (0); +} + +#ifndef __rtems__ +void +module_reference(module_t mod) +{ + + MOD_XLOCK_ASSERT; + + MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs)); + mod->refs++; +} +#endif /* __rtems__ */ + +void +module_release(module_t mod) +{ + + MOD_XLOCK_ASSERT; + +#ifndef __rtems__ + if (mod->refs <= 0) + panic("module_release: bad reference count"); + + MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs)); + + mod->refs--; + if (mod->refs == 0) { +#endif /* __rtems__ */ + TAILQ_REMOVE(&modules, mod, link); +#ifndef __rtems__ + if (mod->file) + TAILQ_REMOVE(&mod->file->modules, mod, flink); +#endif /* __rtems__ */ + free(mod, M_MODULE); +#ifndef __rtems__ + } +#endif /* __rtems__ */ +} + +module_t +module_lookupbyname(const char *name) +{ + module_t mod; + int err; + + MOD_LOCK_ASSERT; + + TAILQ_FOREACH(mod, &modules, link) { + err = strcmp(mod->name, name); + if (err == 0) + return (mod); + } + return (NULL); +} + +#ifndef __rtems__ +module_t +module_lookupbyid(int modid) +{ + module_t mod; + + MOD_LOCK_ASSERT; + + TAILQ_FOREACH(mod, &modules, link) + if (mod->id == modid) + return(mod); + return (NULL); +} + +int +module_quiesce(module_t mod) +{ + int error; + + mtx_lock(&Giant); + error = MOD_EVENT(mod, MOD_QUIESCE); + mtx_unlock(&Giant); + if (error == EOPNOTSUPP || error == EINVAL) + error = 0; + return (error); +} + +int +module_unload(module_t mod) +{ + int error; + + mtx_lock(&Giant); + error = MOD_EVENT(mod, MOD_UNLOAD); + mtx_unlock(&Giant); + return (error); +} + +int +module_getid(module_t mod) +{ + + MOD_LOCK_ASSERT; + return (mod->id); +} + +module_t +module_getfnext(module_t mod) +{ + + MOD_LOCK_ASSERT; + return (TAILQ_NEXT(mod, flink)); +} + +const char * +module_getname(module_t mod) +{ + + MOD_LOCK_ASSERT; + return (mod->name); +} + +void +module_setspecific(module_t mod, modspecific_t *datap) +{ + + MOD_XLOCK_ASSERT; + mod->data = *datap; +} + +linker_file_t +module_file(module_t mod) +{ + + return (mod->file); +} + +/* + * Syscalls. + */ +int +modnext(struct thread *td, struct modnext_args *uap) +{ + module_t mod; + int error = 0; + + td->td_retval[0] = -1; + + MOD_SLOCK; + if (uap->modid == 0) { + mod = TAILQ_FIRST(&modules); + if (mod) + td->td_retval[0] = mod->id; + else + error = ENOENT; + goto done2; + } + mod = module_lookupbyid(uap->modid); + if (mod == NULL) { + error = ENOENT; + goto done2; + } + if (TAILQ_NEXT(mod, link)) + td->td_retval[0] = TAILQ_NEXT(mod, link)->id; + else + td->td_retval[0] = 0; +done2: + MOD_SUNLOCK; + return (error); +} + +int +modfnext(struct thread *td, struct modfnext_args *uap) +{ + module_t mod; + int error; + + td->td_retval[0] = -1; + + MOD_SLOCK; + mod = module_lookupbyid(uap->modid); + if (mod == NULL) { + error = ENOENT; + } else { + error = 0; + if (TAILQ_NEXT(mod, flink)) + td->td_retval[0] = TAILQ_NEXT(mod, flink)->id; + else + td->td_retval[0] = 0; + } + MOD_SUNLOCK; + return (error); +} + +struct module_stat_v1 { + int version; /* set to sizeof(struct module_stat) */ + char name[MAXMODNAME]; + int refs; + int id; +}; + +int +modstat(struct thread *td, struct modstat_args *uap) +{ + module_t mod; + modspecific_t data; + int error = 0; + int id, namelen, refs, version; + struct module_stat *stat; + char *name; + + MOD_SLOCK; + mod = module_lookupbyid(uap->modid); + if (mod == NULL) { + MOD_SUNLOCK; + return (ENOENT); + } + id = mod->id; + refs = mod->refs; + name = mod->name; + data = mod->data; + MOD_SUNLOCK; + stat = uap->stat; + + /* + * Check the version of the user's structure. + */ + if ((error = copyin(&stat->version, &version, sizeof(version))) != 0) + return (error); + if (version != sizeof(struct module_stat_v1) + && version != sizeof(struct module_stat)) + return (EINVAL); + namelen = strlen(mod->name) + 1; + if (namelen > MAXMODNAME) + namelen = MAXMODNAME; + if ((error = copyout(name, &stat->name[0], namelen)) != 0) + return (error); + + if ((error = copyout(&refs, &stat->refs, sizeof(int))) != 0) + return (error); + if ((error = copyout(&id, &stat->id, sizeof(int))) != 0) + return (error); + + /* + * >v1 stat includes module data. + */ + if (version == sizeof(struct module_stat)) + if ((error = copyout(&data, &stat->data, + sizeof(data))) != 0) + return (error); + td->td_retval[0] = 0; + return (error); +} + +int +modfind(struct thread *td, struct modfind_args *uap) +{ + int error = 0; + char name[MAXMODNAME]; + module_t mod; + + if ((error = copyinstr(uap->name, name, sizeof name, 0)) != 0) + return (error); + + MOD_SLOCK; + mod = module_lookupbyname(name); + if (mod == NULL) + error = ENOENT; + else + td->td_retval[0] = module_getid(mod); + MOD_SUNLOCK; + return (error); +} +#endif /* __rtems__ */ + +MODULE_VERSION(kernel, __FreeBSD_version); + +#ifdef COMPAT_FREEBSD32 +#include +#include +#include +#include +#include + +typedef union modspecific32 { + int intval; + u_int32_t uintval; + int longval; + u_int32_t ulongval; +} modspecific32_t; + +struct module_stat32 { + int version; + char name[MAXMODNAME]; + int refs; + int id; + modspecific32_t data; +}; + +int +freebsd32_modstat(struct thread *td, struct freebsd32_modstat_args *uap) +{ + module_t mod; + modspecific32_t data32; + int error = 0; + int id, namelen, refs, version; + struct module_stat32 *stat32; + char *name; + + MOD_SLOCK; + mod = module_lookupbyid(uap->modid); + if (mod == NULL) { + MOD_SUNLOCK; + return (ENOENT); + } + + id = mod->id; + refs = mod->refs; + name = mod->name; + CP(mod->data, data32, intval); + CP(mod->data, data32, uintval); + CP(mod->data, data32, longval); + CP(mod->data, data32, ulongval); + MOD_SUNLOCK; + stat32 = uap->stat; + + if ((error = copyin(&stat32->version, &version, sizeof(version))) != 0) + return (error); + if (version != sizeof(struct module_stat_v1) + && version != sizeof(struct module_stat32)) + return (EINVAL); + namelen = strlen(mod->name) + 1; + if (namelen > MAXMODNAME) + namelen = MAXMODNAME; + if ((error = copyout(name, &stat32->name[0], namelen)) != 0) + return (error); + + if ((error = copyout(&refs, &stat32->refs, sizeof(int))) != 0) + return (error); + if ((error = copyout(&id, &stat32->id, sizeof(int))) != 0) + return (error); + + /* + * >v1 stat includes module data. + */ + if (version == sizeof(struct module_stat32)) + if ((error = copyout(&data32, &stat32->data, + sizeof(data32))) != 0) + return (error); + td->td_retval[0] = 0; + return (error); +} +#endif -- cgit v1.2.3