summaryrefslogtreecommitdiffstats
path: root/kernel/module.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/module.c')
-rw-r--r--kernel/module.c201
1 files changed, 189 insertions, 12 deletions
diff --git a/kernel/module.c b/kernel/module.c
index eb3ca2417..e29a48ba5 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -23,6 +23,17 @@
* - Supports redefines of all symbols, for streams-like behaviour.
* - Compatible with older versions of insmod.
*
+ * New addition in December 1994: (Bjorn Ekwall, idea from Jacques Gelinas)
+ * - Externally callable function:
+ *
+ * "int register_symtab(struct symbol_table *)"
+ *
+ * This function can be called from within the kernel,
+ * and ALSO from loadable modules.
+ * The goal is to assist in modularizing the kernel even more,
+ * and finally: reducing the number of entries in ksyms.c
+ * since every subsystem should now be able to decide and
+ * control exactly what symbols it wants to export, locally!
*/
#ifdef DEBUG_MODULE
@@ -40,6 +51,7 @@ static struct module *find_module( const char *name);
static int get_mod_name( char *user_name, char *buf);
static int free_modules( void);
+static int module_init_flag = 0; /* Hmm... */
/*
* Called at boot time
@@ -117,7 +129,7 @@ rename_module_symbol(char *old_name, char *new_name)
/*
* Allocate space for a module.
*/
-asmlinkage int
+asmlinkage unsigned long
sys_create_module(char *module_name, unsigned long size)
{
struct module *mp;
@@ -162,7 +174,7 @@ sys_create_module(char *module_name, unsigned long size)
PRINTK(("module `%s' (%lu pages @ 0x%08lx) created\n",
mp->name, (unsigned long) mp->size, (unsigned long) mp->addr));
- return (int) addr;
+ return (unsigned long) addr;
}
/*
@@ -248,7 +260,7 @@ sys_init_module(char *module_name, char *code, unsigned codesize,
/* relocate name pointers, index referred from start of table */
for (sym = &(newtab->symbol[0]), i = 0;
i < newtab->n_symbols; ++sym, ++i) {
- if ((int)sym->name < legal_start || size <= (int)sym->name) {
+ if ((unsigned long)sym->name < legal_start || size <= (unsigned long)sym->name) {
printk("Illegal symbol table! Rejected!\n");
kfree_s(newtab, size);
return -EINVAL;
@@ -285,8 +297,12 @@ sys_init_module(char *module_name, char *code, unsigned codesize,
}
}
- if ((*rt.init)() != 0)
+ module_init_flag = 1; /* Hmm... */
+ if ((*rt.init)() != 0) {
+ module_init_flag = 0; /* Hmm... */
return -EBUSY;
+ }
+ module_init_flag = 0; /* Hmm... */
mp->state = MOD_RUNNING;
return 0;
@@ -354,6 +370,9 @@ sys_get_kernel_syms(struct kernel_sym *table)
/* include the count for the module name! */
nmodsyms += mp->symtab->n_symbols + 1;
}
+ else
+ /* include the count for the module name! */
+ nmodsyms += 1; /* return modules without symbols too */
}
if (table != NULL) {
@@ -364,21 +383,22 @@ sys_get_kernel_syms(struct kernel_sym *table)
/* copy all module symbols first (always LIFO order) */
for (mp = module_list; mp; mp = mp->next) {
- if ((mp->state == MOD_RUNNING) &&
- (mp->symtab != NULL) && (mp->symtab->n_symbols > 0)) {
+ if (mp->state == MOD_RUNNING) {
/* magic: write module info as a pseudo symbol */
isym.value = (unsigned long)mp;
sprintf(isym.name, "#%s", mp->name);
memcpy_tofs(to, &isym, sizeof isym);
++to;
- for (i = mp->symtab->n_symbols,
- from = mp->symtab->symbol;
- i > 0; --i, ++from, ++to) {
+ if (mp->symtab != NULL) {
+ for (i = mp->symtab->n_symbols,
+ from = mp->symtab->symbol;
+ i > 0; --i, ++from, ++to) {
- isym.value = (unsigned long)from->addr;
- strncpy(isym.name, from->name, sizeof isym.name);
- memcpy_tofs(to, &isym, sizeof isym);
+ isym.value = (unsigned long)from->addr;
+ strncpy(isym.name, from->name, sizeof isym.name);
+ memcpy_tofs(to, &isym, sizeof isym);
+ }
}
}
}
@@ -582,3 +602,160 @@ int get_ksyms_list(char *buf)
return p - buf;
}
+
+/*
+ * Rules:
+ * - The new symbol table should be statically allocated, or else you _have_
+ * to set the "size" field of the struct to the number of bytes allocated.
+ *
+ * - The strings that name the symbols will not be copied, maybe the pointers
+ *
+ * - For a loadable module, the function should only be called in the
+ * context of init_module
+ *
+ * Those are the only restrictions! (apart from not being reenterable...)
+ *
+ * If you want to remove a symbol table for a loadable module,
+ * the call looks like: "register_symtab(0)".
+ *
+ * The look of the code is mostly dictated by the format of
+ * the frozen struct symbol_table, due to compatibility demands.
+ */
+#define INTSIZ sizeof(struct internal_symbol)
+#define REFSIZ sizeof(struct module_ref)
+#define SYMSIZ sizeof(struct symbol_table)
+#define MODSIZ sizeof(struct module)
+static struct symbol_table nulltab;
+
+int
+register_symtab(struct symbol_table *intab)
+{
+ struct module *mp;
+ struct module *link;
+ struct symbol_table *oldtab;
+ struct symbol_table *newtab;
+ struct module_ref *newref;
+ int size;
+
+ if (intab && (intab->n_symbols == 0)) {
+ struct internal_symbol *sym;
+ /* How many symbols, really? */
+
+ for (sym = intab->symbol; sym->name; ++sym)
+ intab->n_symbols +=1;
+ }
+
+#if 1
+ if (module_init_flag == 0) { /* Hmm... */
+#else
+ if (module_list == &kernel_module) {
+#endif
+ /* Aha! Called from an "internal" module */
+ if (!intab)
+ return 0; /* or -ESILLY_PROGRAMMER :-) */
+
+ /* create a pseudo module! */
+ if (!(mp = (struct module*) kmalloc(MODSIZ, GFP_KERNEL))) {
+ /* panic time! */
+ printk("Out of memory for new symbol table!\n");
+ return -ENOMEM;
+ }
+ /* else OK */
+ memset(mp, 0, MODSIZ);
+ mp->state = MOD_RUNNING; /* Since it is resident... */
+ mp->name = ""; /* This is still the "kernel" symbol table! */
+ mp->symtab = intab;
+
+ /* link it in _after_ the resident symbol table */
+ mp->next = kernel_module.next;
+ kernel_module.next = mp;
+
+ return 0;
+ }
+
+ /* else ******** Called from a loadable module **********/
+
+ /*
+ * This call should _only_ be done in the context of the
+ * call to init_module i.e. when loading the module!!
+ * Or else...
+ */
+ mp = module_list; /* true when doing init_module! */
+
+ /* Any table there before? */
+ if ((oldtab = mp->symtab) == (struct symbol_table*)0) {
+ /* No, just insert it! */
+ mp->symtab = intab;
+ return 0;
+ }
+
+ /* else ****** we have to replace the module symbol table ******/
+#if 0
+ if (oldtab->n_symbols > 0) {
+ /* Oh dear, I have to drop the old ones... */
+ printk("Warning, dropping old symbols\n");
+ }
+#endif
+
+ if (oldtab->n_refs == 0) { /* no problems! */
+ mp->symtab = intab;
+ /* if the old table was kmalloc-ed, drop it */
+ if (oldtab->size > 0)
+ kfree_s(oldtab, oldtab->size);
+
+ return 0;
+ }
+
+ /* else */
+ /***** The module references other modules... insmod said so! *****/
+ /* We have to allocate a new symbol table, or we lose them! */
+ if (intab == (struct symbol_table*)0)
+ intab = &nulltab; /* easier code with zeroes in place */
+
+ /* the input symbol table space does not include the string table */
+ /* (it does for symbol tables that insmod creates) */
+
+ if (!(newtab = (struct symbol_table*)kmalloc(
+ size = SYMSIZ + intab->n_symbols * INTSIZ +
+ oldtab->n_refs * REFSIZ,
+ GFP_KERNEL))) {
+ /* panic time! */
+ printk("Out of memory for new symbol table!\n");
+ return -ENOMEM;
+ }
+
+ /* copy up to, and including, the new symbols */
+ memcpy(newtab, intab, SYMSIZ + intab->n_symbols * INTSIZ);
+
+ newtab->size = size;
+ newtab->n_refs = oldtab->n_refs;
+
+ /* copy references */
+ memcpy( ((char *)newtab) + SYMSIZ + intab->n_symbols * INTSIZ,
+ ((char *)oldtab) + SYMSIZ + oldtab->n_symbols * INTSIZ,
+ oldtab->n_refs * REFSIZ);
+
+ /* relink references from the old table to the new one */
+
+ /* pointer to the first reference entry in newtab! Really! */
+ newref = (struct module_ref*) &(newtab->symbol[newtab->n_symbols]);
+
+ /* check for reference links from previous modules */
+ for ( link = module_list;
+ link && (link != &kernel_module);
+ link = link->next) {
+
+ if (link->ref && (link->ref->module == mp))
+ link->ref = newref++;
+ }
+
+ mp->symtab = newtab;
+
+ /* all references (if any) have been handled */
+
+ /* if the old table was kmalloc-ed, drop it */
+ if (oldtab->size > 0)
+ kfree_s(oldtab, oldtab->size);
+
+ return 0;
+}