diff options
Diffstat (limited to 'kernel/module.c')
-rw-r--r-- | kernel/module.c | 201 |
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; +} |