diff --git a/include/kernel/module.h b/include/kernel/module.h index 535b82d38806909ff8ea054368e71c234378a336..944b26dfac2f3b7300bec0847757fe305533c40f 100644 --- a/include/kernel/module.h +++ b/include/kernel/module.h @@ -17,6 +17,12 @@ struct elf_module { unsigned long pa; unsigned long va; + void *base; + + int (*init)(void); + int (*exit)(void); + + int refcnt; unsigned int align; @@ -48,5 +54,6 @@ struct module_section *find_mod_sec(const struct elf_module *m, const char *name); int module_load(struct elf_module *m, void *p); +void modules_list_loaded(void); #endif /* _KERNEL_MODULE_H_ */ diff --git a/kernel/module.c b/kernel/module.c index 6915cf59ab7739720c048b825a4a97f6c47e9c92..671e9b0a2c8c00f80a793fd5d31abec61a591ff2 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -1,3 +1,14 @@ +/** + * @file kernel/module.c + * + * + * TODO 1. module chainloading, reference counting and dependency + * tracking for automatic unloading of unused modules + * 2. code cleanup + * 3. ??? + * 4. profit + */ + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -6,13 +17,23 @@ #include <kernel/err.h> #include <kernel/module.h> #include <kernel/ksym.h> +#include <kernel/kmem.h> +#include <kernel/kernel.h> -/* XXX quick and dirty kmalloc() standin */ -#include <page.h> -static void *kmalloc(size_t size) { - return page_alloc(); -} + +#define MOD "MODULE: " + + +/* if we need more space, this is how many entries we will add */ +#define MODULE_REALLOC 10 +/* this is where we keep track of loaded modules */ +static struct { + struct elf_module **m; + int sz; + int cnt; +} _kmod; + /** @@ -72,6 +93,7 @@ static unsigned int get_num_dyn_entries(const struct elf_module *m) return m->dyn_size / sizeof(Elf_Dyn); } + /** * @brief find a dynamic entry by tag * @@ -137,7 +159,6 @@ static unsigned int find_sec_type(const struct elf_module *m, } - /** * @brief find an elf section by name * @@ -157,6 +178,7 @@ static unsigned int find_sec(const struct elf_module *m, const char *name) return 0; } + /** * @brief get an entry in the .shstrtab * @@ -171,6 +193,7 @@ static char *get_shstrtab_str(const struct elf_module *m, unsigned int idx) return NULL; } + /** * @brief get an entry in the .strtab * @@ -211,7 +234,6 @@ static char *get_symbol_str(const struct elf_module *m, unsigned int idx) } - /** * @brief find module section by name * @@ -244,14 +266,15 @@ void dump_sections(const struct elf_module *m) size_t i; - printk("\nSECTIONS:\n" - "============================\n" - "\t[NUM]\t[NAME]\t\t\t[TYPE]\t\t[SIZE]\t[ENTSZ]\t[FLAGS]\n"); + printk(MOD "SECTIONS:\n" + MOD "============================\n" + MOD "\t[NUM]\t[NAME]\t\t\t[TYPE]\t\t[SIZE]\t[ENTSZ]\t[FLAGS]\n" + ); for (i = 0; i < m->ehdr->e_shnum; i++) { - printk("\t%d\t%-20s", i, m->sh_str + m->shdr[i].sh_name); + printk(MOD "\t%d\t%-20s", i, m->sh_str + m->shdr[i].sh_name); switch (m->shdr[i].sh_type) { case SHT_NULL: @@ -298,7 +321,7 @@ void dump_sections(const struct elf_module *m) if (m->shdr[i].sh_flags & SHF_MASKPROC) printk("MASKPROC "); - printk("\n"); + printk(MOD "\n"); } @@ -326,14 +349,14 @@ static unsigned long get_symbol_type(const struct elf_module *m, idx = find_sec(m, ".symtab"); if (!idx) { - printk("WARN: no .symtab section found\n"); + pr_debug(MOD "WARN: no .symtab section found\n"); return -1; } symtab = &m->shdr[idx]; if (symtab->sh_entsize != sizeof(Elf_Sym)) { - printk("Error %d != %ld\n", sizeof(Elf_Sym), symtab->sh_entsize); + pr_debug("Error %d != %ld\n", sizeof(Elf_Sym), symtab->sh_entsize); return -1; } @@ -373,14 +396,14 @@ static unsigned long get_symbol_value(const struct elf_module *m, idx = find_sec(m, ".symtab"); if (!idx) { - printk("WARN: no .symtab section found\n"); + pr_debug(MOD "WARN: no .symtab section found\n"); return -1; } symtab = &m->shdr[idx]; if (symtab->sh_entsize != sizeof(Elf_Sym)) { - printk("Error %d != %ld\n", sizeof(Elf_Sym), symtab->sh_entsize); + pr_debug(MOD "Error %d != %ld\n", sizeof(Elf_Sym), symtab->sh_entsize); return -1; } @@ -416,14 +439,14 @@ static int dump_symtab(struct elf_module *m) idx = find_sec(m, ".symtab"); if (!idx) { - printk("WARN: no .symtab section found\n"); + printk(MOD "WARN: no .symtab section found\n"); return -1; } symtab = &m->shdr[idx]; if (symtab->sh_entsize != sizeof(Elf_Sym)) { - printk("Error %d != %ld\n", sizeof(Elf_Sym), symtab->sh_entsize); + printk(MOD "Error %d != %ld\n", sizeof(Elf_Sym), symtab->sh_entsize); return -1; } @@ -432,14 +455,15 @@ static int dump_symtab(struct elf_module *m) sym_cnt = symtab->sh_size / symtab->sh_entsize; - printk("\n.symtab contains %d entries\n" - "============================\n" - "\t[NUM]\t[VALUE]\t\t\t[SIZE]\t[TYPE]\t[NAME]\n", sym_cnt); + printk(MOD "\n" + MOD ".symtab contains %d entries\n" + MOD "============================\n" + MOD "\t[NUM]\t[VALUE]\t\t\t[SIZE]\t[TYPE]\t[NAME]\n", sym_cnt); for (i = 0; i < sym_cnt; i++) { - printk("\t%d\t%016lx\t%4ld", + printk(MOD "\t%d\t%016lx\t%4ld", i, symbols[i].st_value, symbols[i].st_size); @@ -472,7 +496,6 @@ static int dump_symtab(struct elf_module *m) - /** * @brief dump the contents of strtab */ @@ -487,16 +510,16 @@ static void dump_strtab(const struct elf_module *m) return; - printk("\n.strtab:\n" + printk(MOD "\n.strtab:\n" "============================\n" "\t[OFF]\t[STR]\n"); while(i < m->sh_size) { - printk("\t[%d]\t%s\n", i, m->str + i); + printk(MOD "\t[%d]\t%s\n", i, m->str + i); i += strlen(m->str + i) + 1; } - printk("\n\n"); + printk(MOD "\n\n"); } @@ -597,23 +620,28 @@ static int set_strtab(struct elf_module *m) static int setup_module(struct elf_module *m) { + int i; + + /* initialise module configuration */ m->pa = 0; m->va = 0; - // XXX - //m->size = 0; + m->size = 0; + m->refcnt = 0; m->align = sizeof(void *); m->dyn = NULL; m->dyn_size = 0; - m->sec = NULL; + m->base = NULL; + m->init = NULL; + m->exit = NULL; /* set section headers */ if (m->ehdr->e_shoff) { m->shdr = (Elf_Shdr *) (((char *) m->ehdr) + m->ehdr->e_shoff); } else { m->shdr = NULL; - printk("ERR: no section header found\n"); + pr_debug(MOD "ERR: no section header found\n"); return -1; } @@ -623,7 +651,7 @@ static int setup_module(struct elf_module *m) /* locate and set dynamic string table */ if (!set_dynstr(m)) { - printk("WARN: no dynamic string table found\n"); + pr_debug(MOD "WARN: no dynamic string table found\n"); } /* locate and set string table */ @@ -632,29 +660,24 @@ static int setup_module(struct elf_module *m) /* set up for relocatable object */ if (m->ehdr->e_type == ET_REL) { - printk("TODO\n"); - - m->align = 0x200000; /* PC */ -#if 0 - int i; - m->size = 0; for (i = 0; i < m->ehdr->e_shnum; i++) { if ((m->shdr[i].sh_flags & SHF_ALLOC)) { - printk("Alloc section: %s, size %ld\n", - m->sh_str + m->shdr[i].sh_name, - m->shdr[i].sh_size); + pr_debug(MOD "Alloc section: %s, size %ld\n", + m->sh_str + m->shdr[i].sh_name, + m->shdr[i].sh_size); m->size += m->shdr[i].sh_size; - if (m->shdr[idx].sh_addralign > m->align) - - m->align = m->shdr[idx].sh_addralign; + if (m->shdr[i].sh_addralign > m->align) { + m->align = m->shdr[i].sh_addralign; + pr_debug(MOD "align: %d\n", m->align); + } } } -#endif } + return 0; } @@ -672,30 +695,28 @@ static int module_load_mem(struct elf_module *m) struct module_section *s; - void *mem; - - mem = kmalloc(m->size); + m->base = kmalloc(m->size + m->align); - if (!mem) - return -ENOMEM; + if (!m->base) + goto error; /* exec info */ - m->va = (unsigned long) mem; - m->pa = (unsigned long) mem; + m->va = (unsigned long) ALIGN_PTR(m->base, m->align); + m->pa = (unsigned long) ALIGN_PTR(m->base, m->align); - - printk("\n\nLoading module run-time sections\n"); + pr_debug(MOD "\n" MOD "\n" + MOD "Loading module run-time sections\n"); va_load = m->va; pa_load = m->pa; m->num_sec = get_num_alloc_sections(m); m->sec = (struct module_section *) - kmalloc(sizeof(struct module_section) * m->num_sec); + kcalloc(sizeof(struct module_section), m->num_sec); if (!m->sec) - return -1; + goto error; s = m->sec; @@ -718,19 +739,19 @@ static int module_load_mem(struct elf_module *m) s->name = kmalloc(strlen(src)); if (!s->name) - return -1; + goto error; strcpy(s->name, src); if (sec->sh_type & SHT_NOBITS) { - printk("\tZero segment %10s at %p size %ld\n", + pr_debug(MOD "\tZero segment %10s at %p size %ld\n", s->name, (char *) va_load, sec->sh_size); bzero((void *) va_load, s->size); } else { - printk("\tCopy segment %10s from %p to %p size %ld\n", + pr_debug(MOD "\tCopy segment %10s from %p to %p size %ld\n", s->name, (char *) m->ehdr + sec->sh_offset, (char *) va_load, @@ -747,12 +768,22 @@ static int module_load_mem(struct elf_module *m) s++; if (s > &m->sec[m->num_sec]) { - printk("Error out of section memory\n"); - return -1; + pr_debug(MOD "Error out of section memory\n"); + goto error; } } return 0; + +error: + if (m->sec) + for (idx = 0; idx < m->num_sec; idx++) + kfree(m->sec[idx].name); + + kfree(m->sec); + kfree(m->base); + + return -ENOMEM; } @@ -786,7 +817,8 @@ static int module_relocate(struct elf_module *m) sec = get_sec(m, idx); - printk("\nSection Header info: %ld\n", sec->sh_info); + pr_debug(MOD "\n" + MOD "Section Header info: %ld\n", sec->sh_info); if (sec) { @@ -794,7 +826,7 @@ static int module_relocate(struct elf_module *m) rel_cnt = sec->sh_size / sec->sh_entsize; - printk("Found %d RELA entries\n", rel_cnt); + pr_debug(MOD "Found %d RELA entries\n", rel_cnt); /* relocation table in memory */ relatab = (Elf_Rela *) ((long)m->ehdr + sec->sh_offset); @@ -806,7 +838,7 @@ static int module_relocate(struct elf_module *m) struct module_section *s; struct module_section *text = find_mod_sec(m, ".text"); - printk("OFF: %08lx INF: %8lx ADD: %3ld LNK: %ld SEC: %d NAME: %s\n\n", + pr_debug(MOD "OFF: %08lx INF: %8lx ADD: %3ld LNK: %ld SEC: %d NAME: %s\n", relatab[i].r_offset, relatab[i].r_info, relatab[i].r_addend, @@ -822,15 +854,16 @@ static int module_relocate(struct elf_module *m) if (!sym) { unsigned long symval; - printk("\tNot found in library, resolving in module\n"); + pr_info(MOD "\tSymbol %s not found in library, trying to resolving in module\n", + symstr); if (!(get_symbol_type(m, symstr) & STT_FUNC)) { - printk("\tERROR, unresolved symbol %s\n", symstr); + pr_err(MOD "\tERROR, unresolved symbol %s\n", symstr); return -1; } if (!get_symbol_value(m, symstr, &symval)) { - printk("\tERROR, unresolved symbol %s\n", symstr); + pr_err(MOD "\tERROR, unresolved symbol %s\n", symstr); return -1; } @@ -838,7 +871,7 @@ static int module_relocate(struct elf_module *m) } - printk("\tSymbol %s at %lx\n", symstr, sym); + pr_info(MOD "\tSymbol %s at %lx\n", symstr, sym); apply_relocate_add(m, &relatab[i], sym); @@ -849,21 +882,21 @@ static int module_relocate(struct elf_module *m) s = find_mod_sec(m, secstr); if (!s) { - printk("Error cannot locate section %s for symbol\n", secstr); + pr_debug(MOD "Error cannot locate section %s for symbol\n", secstr); continue; } /* target address to insert at location */ reladdr = (long) s->addr; - printk("\tRelative symbol address: %x, entry at %08lx\n", reladdr, s->addr); + pr_debug(MOD "\tRelative symbol address: %x, entry at %08lx\n", reladdr, s->addr); apply_relocate_add(m, &relatab[i], reladdr); } - printk("\n"); + pr_debug(MOD "\n"); } - printk("\n"); + pr_debug(MOD "\n"); } } @@ -872,63 +905,110 @@ static int module_relocate(struct elf_module *m) } +void module_unload(struct elf_module *m) +{ + int i; + if (m->exit) { + if (m->exit()) + pr_err(MOD "Module exit call failed.\n"); + } -typedef void (*entrypoint_t)(void); -void go(entrypoint_t ep) -{ - ep(); - printk("done\n"); + if (m->sec) { + for (i = 0; i < m->num_sec; i++) + kfree(m->sec[i].name); + } + + kfree(m->sec); + kfree(m->base); } + int module_load(struct elf_module *m, void *p) { unsigned long symval; - entrypoint_t ep; /* the ELF binary starts with the ELF header */ m->ehdr = (Elf_Ehdr *) p; - printk("Checking ELF header\n"); + pr_debug(MOD "Checking ELF header\n"); if (elf_header_check(m->ehdr)) - return -1; + goto error; - printk("Setting up module configuration\n"); + pr_debug(MOD "Setting up module configuration\n"); if (setup_module(m)) - return -1; - - - dump_sections(m); + goto error; if (module_load_mem(m)) - return -1; - - dump_symtab(m); + goto cleanup; if (module_relocate(m)) - return -1; + goto cleanup; -#if 1 - if (!get_symbol_value(m, "_module_init", &symval)) { - printk("module init not found\n"); - return -1; + if (_kmod.cnt == _kmod.sz) { + _kmod.m = krealloc(_kmod.m, (_kmod.sz + MODULE_REALLOC) * + sizeof(struct elf_module **)); + + bzero(&_kmod.m[_kmod.sz], sizeof(struct elf_module **) * + MODULE_REALLOC); + _kmod.sz += MODULE_REALLOC; } - ep = (entrypoint_t) (m->va + symval); + _kmod.m[_kmod.cnt++] = m; - printk("Binary entrypoint is %lx; invoking %p\n", m->ehdr->e_entry, ep); + if (get_symbol_value(m, "_module_init", &symval)) + m->init = (void *) (m->va + symval); + else + pr_warn(MOD "_module_init() not found\n"); + + + if (get_symbol_value(m, "_module_exit", &symval)) + m->exit = (void *) (m->va + symval); + else + pr_warn(MOD "_module_exit() not found\n"); + + + pr_debug(MOD "Binary entrypoint is %lx; invoking _module_init() at %p\n", + m->ehdr->e_entry, m->init); + + if (m->init) { + if (m->init()) { + pr_err(MOD "Module initialisation failed.\n"); + goto cleanup; + } + } - go(ep); -#endif return 0; + +cleanup: + module_unload(m); +error: + return -1; } +void modules_list_loaded(void) +{ + struct elf_module **m; + + + m = _kmod.m; + + while((*m)) { + printk(MOD "Contents of module %p loaded at base %p\n" + MOD "\n", + (*m), (*m)->base); + dump_sections((*m)); + dump_symtab((*m)); + + m++; + } +}