summaryrefslogtreecommitdiffstats
path: root/sys/boot/common/module.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/boot/common/module.c')
-rw-r--r--sys/boot/common/module.c414
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;
+ }
+}
OpenPOWER on IntegriCloud