module.c revision 199767f8919635c4928607450d9e0abb932109ce
/*-
* Copyright (c) 1998 Michael Smith <msmith@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
__FBSDID("$FreeBSD$");
/*
*/
#include <stand.h>
#include <string.h>
#include "bootstrap.h"
#define MDIR_REMOVED 0x0001
#define MDIR_NOHINTS 0x0002
struct moduledir {
char *d_path; /* path of modules directory */
int d_hintsz; /* size of hints data */
int d_flags;
};
static struct kernel_module * file_findmodule(struct preloaded_file *fp, char *modname, struct mod_depend *verinfo);
static int file_havepath(const char *name);
static void moduledir_rebuild(void);
/* load address should be tweaked by first module loaded (kernel) */
static vm_offset_t loadaddr = 0;
#if defined(LOADER_FDT_SUPPORT)
static const char *default_searchpath =
#else
static const char *default_searchpath ="/platform/i86pc";
#endif
static const char *kld_ext_list[] = {
".ko",
"",
".debug",
};
/*
* 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>
*/
static int
{
char *typestr;
optind = 1;
optreset = 1;
if (argc == 1) {
command_errmsg = "no filename specified";
return (CMD_CRIT);
}
switch(ch) {
case 'k':
dokld = 1;
break;
case 't':
dofile = 1;
break;
case '?':
default:
/* getopt has already reported an error */
return (CMD_OK);
}
}
/*
* Request to load a raw file?
*/
if (dofile) {
command_errmsg = "invalid load type";
return (CMD_CRIT);
}
return (CMD_WARN);
}
return (CMD_OK);
/* Failing to load mfs_root is never going to end well! */
return (CMD_FATAL);
return (CMD_ERROR);
}
/*
* Do we have explicit KLD load ?
*/
return (CMD_WARN);
}
}
/*
* Looks like a request for a module.
*/
return (CMD_WARN);
}
}
#ifdef __FreeBSD__
static int
{
char typestr[80];
char *cp;
if (argc < 3) {
command_errmsg = "usage is [-n key#] <prov> <file>";
return(CMD_ERROR);
}
num = 0;
optind = 1;
optreset = 1;
switch(ch) {
case 'n':
"bad key index '%s'", optarg);
return(CMD_ERROR);
}
break;
case '?':
default:
/* getopt has already reported an error */
return(CMD_OK);
}
}
}
#endif /* __FreeBSD__ */
void
unload(void)
{
struct preloaded_file *fp;
while (preloaded_files != NULL) {
}
loadaddr = 0;
unsetenv("kernelname");
}
static int
{
unload();
return(CMD_OK);
}
static int
{
struct preloaded_file *fp;
struct kernel_module *mp;
struct file_metadata *md;
char lbuf[80];
verbose = 0;
optind = 1;
optreset = 1;
switch(ch) {
case 'v':
verbose = 1;
break;
case '?':
default:
/* getopt has already reported an error */
return(CMD_OK);
}
}
pager_open();
if (pager_output(lbuf))
break;
pager_output(" args: ");
if (pager_output("\n"))
break;
}
pager_output(" modules: ");
}
if (pager_output("\n"))
break;
}
if (verbose) {
/* XXX could add some formatting smarts here to display some better */
break;
}
}
if (ret)
break;
}
pager_close();
return(CMD_OK);
}
/*
* File level interface, functions file_*
*/
int
{
static int last_file_format = 0;
struct preloaded_file *fp;
int error;
int i;
if (error == 0) {
break;
} else if (last_file_format == i && i != 0) {
/* Restart from the beginning */
i = -1;
last_file_format = 0;
continue;
}
continue; /* Unknown to this handler? */
if (error) {
break;
}
}
return (error);
}
static int
{
struct file_metadata *md;
struct preloaded_file *fp;
struct mod_depend *verinfo;
struct kernel_module *mp;
char *dmodname;
int error;
return (0);
error = 0;
do {
if (error)
break;
/*
* If module loaded via kld name which isn't listed
* in the linker.hints file, we should check if it have
* required version.
*/
"module '%s' exists but with wrong version", dmodname);
break;
}
}
} while (md);
if (!error)
return (0);
/* Load failed; discard everything */
}
return (error);
}
/*
* We've been asked to load (fname) as (type), so just suck it in,
* no arguments or anything.
*/
struct preloaded_file *
{
struct preloaded_file *fp;
char *name;
/* We can't load first */
command_errmsg = "can't load file before kernel";
return(NULL);
}
/* locate the file on the load path */
"can't find '%s'", fname);
return(NULL);
}
return(NULL);
}
for (;;) {
/* read in 4k chunks; size is not really important */
if (got == 0) /* end of file */
break;
if (got < 0) { /* error */
return(NULL);
}
}
/* Looks OK so far; create & populate control structure */
fp = file_alloc();
/* recognise space consumption */
/* Add to the list of loaded files */
if (insert != 0)
return(fp);
}
/*
* Load the module (name), pass it (argc),(argv), add container file
* to the list of loaded files.
*/
int
{
struct kernel_module *mp;
int err;
char *filename;
if (file_havepath(modname)) {
}
/* see if module is already loaded */
if (mp) {
return (0);
}
/* locate file with the module on the search path */
"can't find '%s'", modname);
return (ENOENT);
}
return (err);
}
/*
* Load specified KLD. If path is omitted, then try to locate it via
* search path.
*/
int
{
int err;
char *filename;
/*
* Get fully qualified KLD name
*/
"can't find '%s'", kldname);
return (ENOENT);
}
/*
* Check if KLD already loaded
*/
if (fp) {
"warning: KLD '%s' already loaded", filename);
return (0);
}
for (last_file = preloaded_files;
;
do {
if (err)
break;
if (file_load_dependencies(fp) != 0) {
break;
}
} while(0);
"don't know how to load module '%s'", filename);
}
return (err);
}
/*
* Find a file matching (name) and (type).
* NULL may be passed as a wildcard to either.
*/
struct preloaded_file *
{
struct preloaded_file *fp;
break;
}
return (fp);
}
/*
* Find a module matching (name) inside of given file.
* NULL may be passed as a wildcard.
*/
struct kernel_module *
struct mod_depend *verinfo)
{
if (mp)
return (mp);
}
return (NULL);
}
bestver = 0;
return (mp);
return (mp);
}
}
}
return (best);
}
/*
* Make a copy of (size) bytes of data from (p), and associate them as
* metadata of (type) to the module (mp).
*/
void
{
struct file_metadata *md;
}
/*
* Find a metadata object of (type) associated with the file (fp)
*/
struct file_metadata *
{
struct file_metadata *md;
break;
return(md);
}
struct file_metadata *
{
return (NULL);
break;
return (md);
}
/*
* Check if the given file is in place and return full path to it.
*/
static char *
{
const char **cpp;
extlen = 0;
}
return (NULL);
return result;
}
return NULL;
}
/*
* Check if file name have any qualifiers
*/
static int
file_havepath(const char *name)
{
const char *cp;
}
/*
* Attempt to find the file (name) on the module searchpath.
* 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 *
{
char *result;
int namelen;
/* Don't look for nothing */
return(NULL);
if (*name == 0)
if (file_havepath(name)) {
/* Qualified, so just see if it exists */
return(NULL);
}
if (result)
break;
}
return(result);
}
static char *
struct mod_depend *verinfo)
{
char *result;
found = 0;
bestver = 0;
goto bad;
switch (ival) {
case MDT_VERSION:
break;
cp += sizeof(int);
found = 1;
break;
}
}
break;
default:
break;
}
}
/*
* Finally check if KLD is in the place
*/
if (found)
else if (best)
bad:
/*
* If nothing found or hints is absent - fallback to the old way
* by using "kldname[.ko]" as module name.
*/
return result;
}
/*
* Attempt to locate the file containing the module (name)
*/
static char *
{
char *result;
/*
* Now we ready to lookup module in the given directories
*/
if (result)
break;
}
return(result);
}
int
struct kernel_module **newmp)
{
struct kernel_module *mp;
struct mod_depend mdepend;
if (mp)
return (EEXIST);
return (ENOMEM);
if (newmp)
return (0);
}
/*
* Throw a file away
*/
void
{
return;
while (md) {
}
while (mp) {
}
}
/*
* Allocate a new file; must be used instead of malloc()
* to ensure safe initialisation.
*/
struct preloaded_file *
file_alloc(void)
{
struct preloaded_file *fp;
}
return (fp);
}
/*
* Add a module to the chain
*/
static void
{
struct preloaded_file *cm;
/* Append to list of loaded file */
if (preloaded_files == NULL) {
} else {
;
}
}
static char *
{
char *cp;
return NULL;
return (cp);
}
/*
* Read linker.hints file into memory performing some sanity checks.
*/
static void
{
char *path;
return;
return;
}
goto bad;
goto bad;
goto bad;
return;
bad:
}
return;
}
/*
* Extract directories from the ';' separated list, remove duplicates.
*/
static void
moduledir_rebuild(void)
{
/*
* Rebuild list of module directories if it changed
*/
;
/*
* Ignore trailing slashes
*/
;
continue;
break;
}
return;
}
if (*ep == 0)
break;
}
/*
* Delete unused directories if any
*/
while (mdp) {
} else {
}
}
return;
}