diff options
Diffstat (limited to 'sys/boot/common/module.c')
-rw-r--r-- | sys/boot/common/module.c | 414 |
1 files changed, 376 insertions, 38 deletions
diff --git a/sys/boot/common/module.c b/sys/boot/common/module.c index 28c10dc..f10fe3b 100644 --- a/sys/boot/common/module.c +++ b/sys/boot/common/module.c @@ -23,7 +23,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: module.c,v 1.1.1.1 1998/08/21 03:17:41 msmith Exp $ + * $Id: module.c,v 1.2 1998/08/31 21:10:42 msmith Exp $ */ /* @@ -38,16 +38,68 @@ #include "bootstrap.h" +static struct loaded_module *mod_loadmodule(char *name, int argc, char *argv[]); +static char *mod_searchdep(struct loaded_module *mp); +static char *mod_searchmodule(char *name); +static void mod_append(struct loaded_module *mp); + /* XXX load address should be tweaked by first module loaded (kernel) */ static vm_offset_t loadaddr = 0; struct loaded_module *loaded_modules = NULL; +/* + * load an object, either a disk file or code module. + * + * To load a file, the syntax is: + * + * load -t <type> <path> + * + * code modules are loaded as: + * + * load <path> <options> + */ + COMMAND_SET(load, "load", "load a kernel or module", command_load); static int command_load(int argc, char *argv[]) { + char *typestr; + int dofile, ch; + + dofile = 0; + optind = 1; + typestr = NULL; + while ((ch = getopt(argc, argv, "t:")) != -1) { + switch(ch) { + case 't': + typestr = optarg; + dofile = 1; + break; + case '?': + default: + /* getopt has already reported an error */ + return(CMD_OK); + } + } + argv += (optind - 1); + argc -= (optind - 1); + + /* + * Request to load a raw file? + */ + if (dofile) { + if ((typestr == NULL) || (*typestr == 0)) { + command_errmsg = "invalid load type"; + return(CMD_ERROR); + } + return(mod_loadobj(typestr, argv[1])); + } + + /* + * Looks like a request for a module. + */ return(mod_load(argv[1], argc - 2, argv + 2)); } @@ -57,21 +109,11 @@ static int command_unload(int argc, char *argv[]) { struct loaded_module *mp; - struct module_metadata *md; while (loaded_modules != NULL) { mp = loaded_modules; loaded_modules = loaded_modules->m_next; - while (mp->m_metadata != NULL) { - md = mp->m_metadata; - mp->m_metadata = mp->m_metadata->md_next; - free(md); - } - free(mp->m_name); - free(mp->m_type); - if (mp->m_args != NULL) - free(mp->m_args); - free(mp); + mod_discard(mp); } loadaddr = 0; return(CMD_OK); @@ -83,8 +125,24 @@ static int command_lsmod(int argc, char *argv[]) { struct loaded_module *am; + struct module_metadata *md; char lbuf[80]; - + int ch, verbose; + + verbose = 0; + optind = 1; + while ((ch = getopt(argc, argv, "v")) != -1) { + switch(ch) { + case 'v': + verbose = 1; + break; + case '?': + default: + /* getopt has already reported an error */ + return(CMD_OK); + } + } + pager_open(); for (am = loaded_modules; (am != NULL); am = am->m_next) { sprintf(lbuf, " %x: %s (%s, 0x%x)\n", @@ -95,20 +153,141 @@ command_lsmod(int argc, char *argv[]) pager_output(am->m_args); pager_output("\n"); } + if (verbose) + /* XXX could add some formatting smarts here to display some better */ + for (md = am->m_metadata; md != NULL; md = md->md_next) { + sprintf(lbuf, " 0x%04x, 0x%x\n", md->md_type, md->md_size); + pager_output(lbuf); + } } pager_close(); return(CMD_OK); } +/* + * We've been asked to load (name) and give it (argc),(argv). + * Start by trying to load it, and then attempt to load all of its + * dependancies. If we fail at any point, throw them all away and + * fail the entire load. + * + * XXX if a depended-on module requires arguments, it must be loaded + * explicitly first. + */ int mod_load(char *name, int argc, char *argv[]) { - struct loaded_module *am, *cm; - int i, err; + struct loaded_module *last_mod, *base_mod, *mp; + char *dep_name; + + /* remember previous last module on chain */ + for (last_mod = loaded_modules; + (last_mod != NULL) && (last_mod->m_next != NULL); + last_mod = last_mod->m_next) + ; - for (i = 0, am = NULL; (module_formats[i] != NULL) && (am == NULL); i++) { - /* XXX call searchmodule() to search for module (name) */ - if ((err = (module_formats[i]->l_load)(name, loadaddr, &am)) != 0) { + /* + * Load the first module; note that it's the only one that gets + * arguments explicitly. + */ + if ((base_mod = mod_loadmodule(name, argc, argv)) == NULL) + return(CMD_ERROR); + + /* + * Look for dependancies. + */ + while ((dep_name = mod_searchdep(base_mod)) != NULL) { + printf("loading required module '%s'\n", dep_name); + if ((mp = mod_loadmodule(dep_name, 0, NULL)) == NULL) { + /* Load failed; discard everything */ + while (base_mod != NULL) { + mp = base_mod; + base_mod = base_mod->m_next; + mod_discard(mp); + } + last_mod->m_next = NULL; + loadaddr = last_mod->m_addr + last_mod->m_size; + /* error message already set by mod_loadmodule */ + return(CMD_ERROR); + } + } + return(CMD_OK); +} + +/* + * We've been asked to load (name) as (type), so just suck it in, + * no arguments or anything. + */ +int +mod_loadobj(char *type, char *name) +{ + struct loaded_module *mp; + char *cp; + int fd, got; + vm_offset_t laddr; + + /* We can't load first */ + if ((mod_findmodule(NULL, NULL)) == NULL) { + command_errmsg = "can't load file before kernel"; + return(CMD_ERROR); + } + + /* Try to come up with a fully-qualified name if we don't have one */ + if ((cp = mod_searchmodule(name)) != NULL) + name = cp; + + if ((fd = open(name, O_RDONLY)) < 0) { + sprintf(command_errbuf, "can't open '%s': %s", name, strerror(errno)); + return(CMD_ERROR); + } + + laddr = loadaddr; + for (;;) { + /* read in 4k chunks; size is not really important */ + got = archsw.arch_readin(fd, laddr, 4096); + if (got == 0) /* end of file */ + break; + if (got < 0) { /* error */ + sprintf(command_errbuf, "error reading '%s': %s", name, strerror(errno)); + return(CMD_ERROR); + } + laddr += got; + } + + /* Looks OK so far; create & populate control structure */ + mp = malloc(sizeof(struct loaded_module)); + mp->m_name = strdup(name); + mp->m_type = strdup(type); + mp->m_args = NULL; + mp->m_metadata = NULL; + mp->m_loader = -1; + mp->m_addr = loadaddr; + mp->m_size = laddr - loadaddr; + + /* recognise space consumption */ + loadaddr = laddr; + + /* Add to the list of loaded modules */ + mod_append(mp); + return(CMD_OK); +} + +/* + * Load the module (name), pass it (argc),(argv). + * Don't do any dependancy checking. + */ +static struct loaded_module * +mod_loadmodule(char *name, int argc, char *argv[]) +{ + struct loaded_module *mp; + int i, err; + char *cp; + + /* Try to come up with a fully-qualified name if we don't have one */ + if ((cp = mod_searchmodule(name)) != NULL) + name = cp; + err = 0; + for (i = 0, mp = NULL; (module_formats[i] != NULL) && (mp == NULL); i++) { + if ((err = (module_formats[i]->l_load)(name, loadaddr, &mp)) != 0) { /* Unknown to this handler? */ if (err == EFTYPE) @@ -116,34 +295,87 @@ mod_load(char *name, int argc, char *argv[]) /* Fatal error */ sprintf(command_errbuf, "can't load module '%s': %s", name, strerror(err)); - return(CMD_ERROR); + return(NULL); } else { + + /* Load was OK, set args */ + mp->m_args = unargv(argc, argv); + + /* where can we put the next one? */ + loadaddr = mp->m_addr + mp->m_size; + /* remember the loader */ - am->m_loader = i; + mp->m_loader = i; + + /* Add to the list of loaded modules */ + mod_append(mp); + + break; } } - if (am == NULL) { - sprintf(command_errbuf, "can't work out what to do with '%s'", name); - return(CMD_ERROR); - } - /* where can we put the next one? */ - loadaddr = am->m_addr + am->m_size; - - /* Load was OK, set args */ - am->m_args = unargv(argc, argv); + if (err == EFTYPE) + sprintf(command_errbuf, "don't know how to load module '%s'", name); + return(mp); +} - /* Append to list of loaded modules */ - am->m_next = NULL; - if (loaded_modules == NULL) { - loaded_modules = am; - } else { - for (cm = loaded_modules; cm->m_next != NULL; cm = cm->m_next) - ; - cm->m_next = am; +/* + * Search the modules from (mp) onwards, and return the name of the + * first unresolved dependancy, or NULL if none were found. + */ +static char * +mod_searchdep(struct loaded_module *mp) +{ + struct kld_module_identifier *ident, *dident; + struct kld_module_dependancy *deps, *dp; + struct module_metadata *md; + struct loaded_module *dmp; + int dindex; + + for (; mp != NULL; mp = mp->m_next) { + + /* + * Get KLD module data + */ + ident = NULL; + deps = NULL; + if ((md = mod_findmetadata(mp, MODINFOMD_KLDIDENT)) != NULL) + ident = (struct kld_module_identifier *)md->md_data; + if ((md = mod_findmetadata(mp, MODINFOMD_KLDDEP)) != NULL) + deps = (struct kld_module_dependancy *)md->md_data; + + /* + * Both must exist for this module to depend on anything + */ + if ((ident != NULL) && (deps != NULL)) { + + /* Iterate over dependancies */ + for (dindex = 0; dindex < ident->ki_ndeps; dindex++) { + dp = KLD_GETDEP(ident, deps, dindex); + + /* + * Look for a module matching the dependancy; if we don't have it, + * we need it. + */ + if ((dmp = mod_findmodule(dp->kd_name, NULL)) == NULL) + return(dp->kd_name); + + /* Version check */ + if ((md = mod_findmetadata(dmp, MODINFOMD_KLDIDENT)) != NULL) { + dident = (struct kld_module_identifier *)md->md_data; + if (dp->kd_version != dident->ki_version) + printf("module '%s' requires '%s' version %d, but version %d is loaded\n", + mp->m_name, dp->kd_name, dp->kd_version, dident->ki_version); + } + } + } } - return(CMD_OK); + return(NULL); } +/* + * Find a module matching (name) and (type). + * NULL may be passed as a wildcard to either. + */ struct loaded_module * mod_findmodule(char *name, char *type) { @@ -157,6 +389,10 @@ mod_findmodule(char *name, char *type) return(mp); } +/* + * Make a copy of (size) bytes of data from (p), and associate them as + * metadata of (type) to the module (mp). + */ void mod_addmetadata(struct loaded_module *mp, int type, size_t size, void *p) { @@ -170,6 +406,10 @@ mod_addmetadata(struct loaded_module *mp, int type, size_t size, void *p) mp->m_metadata = md; } +/* + * Find a metadata object of (type) associated with the module + * (mp) + */ struct module_metadata * mod_findmetadata(struct loaded_module *mp, int type) { @@ -180,3 +420,101 @@ mod_findmetadata(struct loaded_module *mp, int type) break; return(md); } + +/* + * Attempt to locate a kernel module file for the module (name). + * If (name) is qualified in any way, we simply check it and + * return it or NULL. If it is not qualified, then we attempt + * to construct a path using entries in the environment variable + * module_path. + * + * The path we return a pointer to need never be freed, as we manage + * it internally. + */ +static char * +mod_searchmodule(char *name) +{ + static char *result = NULL; + static char *defpath = "/boot", *path; + char *cp, *sp; + struct stat sb; + + /* Don't look for nothing */ + if ((name == NULL) || (*name == 0)) + return(name); + + /* + * See if there's a device on the front, or a directory name. + */ + archsw.arch_getdev(NULL, name, &cp); + if ((cp != name) || (strchr(name, '/') != NULL)) { + /* Qualified, so just see if it exists */ + if (stat(name, &sb) == 0) + return(name); + return(NULL); + } + + /* + * Get the module path + */ + if ((cp = getenv("module_path")) == NULL) + cp = defpath; + sp = path = strdup(cp); + + /* + * Traverse the path, splitting off ';'-delimited components. + */ + if (result != NULL) + free(result); + while((cp = strsep(&path, ";")) != NULL) { + result = malloc(strlen(cp) + strlen(name) + 2); + sprintf(result, "%s/%s", cp, name); + if (stat(result, &sb) == 0) + break; + free(result); + result = NULL; + } + free(sp); + return(result); +} + +/* + * Throw a module away + */ +void +mod_discard(struct loaded_module *mp) +{ + struct module_metadata *md; + + while (mp->m_metadata != NULL) { + md = mp->m_metadata; + mp->m_metadata = mp->m_metadata->md_next; + free(md); + } + if (mp->m_name != NULL) + free(mp->m_name); + if (mp->m_type != NULL) + free(mp->m_type); + if (mp->m_args != NULL) + free(mp->m_args); + free(mp); +} + +/* + * Add a module to the chain + */ +static void +mod_append(struct loaded_module *mp) +{ + struct loaded_module *cm; + + /* Append to list of loaded modules */ + mp->m_next = NULL; + if (loaded_modules == NULL) { + loaded_modules = mp; + } else { + for (cm = loaded_modules; cm->m_next != NULL; cm = cm->m_next) + ; + cm->m_next = mp; + } +} |