kern_linker.c revision 43301
125537Sdfr/*-
225537Sdfr * Copyright (c) 1997 Doug Rabson
325537Sdfr * All rights reserved.
425537Sdfr *
525537Sdfr * Redistribution and use in source and binary forms, with or without
625537Sdfr * modification, are permitted provided that the following conditions
725537Sdfr * are met:
825537Sdfr * 1. Redistributions of source code must retain the above copyright
925537Sdfr *    notice, this list of conditions and the following disclaimer.
1025537Sdfr * 2. Redistributions in binary form must reproduce the above copyright
1125537Sdfr *    notice, this list of conditions and the following disclaimer in the
1225537Sdfr *    documentation and/or other materials provided with the distribution.
1325537Sdfr *
1425537Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1525537Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1625537Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1725537Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1825537Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1925537Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2025537Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2125537Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2225537Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2325537Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2425537Sdfr * SUCH DAMAGE.
2525537Sdfr *
2643301Sdillon *	$Id: kern_linker.c,v 1.23 1999/01/25 08:42:24 dfr Exp $
2725537Sdfr */
2825537Sdfr
2940159Speter#include "opt_ddb.h"
3040159Speter
3125537Sdfr#include <sys/param.h>
3225537Sdfr#include <sys/kernel.h>
3325537Sdfr#include <sys/systm.h>
3425537Sdfr#include <sys/malloc.h>
3525537Sdfr#include <sys/sysproto.h>
3625537Sdfr#include <sys/sysent.h>
3725537Sdfr#include <sys/proc.h>
3825537Sdfr#include <sys/lock.h>
3925537Sdfr#include <machine/cpu.h>
4040159Speter#include <machine/bootinfo.h>
4125537Sdfr#include <sys/module.h>
4225537Sdfr#include <sys/linker.h>
4331675Sdyson#include <sys/unistd.h>
4440159Speter#include <sys/fcntl.h>
4540159Speter#include <sys/libkern.h>
4640159Speter#include <sys/namei.h>
4740159Speter#include <sys/vnode.h>
4840159Speter#include <sys/sysctl.h>
4925537Sdfr
5040961Speter#ifdef KLD_DEBUG
5140961Speterint kld_debug = 0;
5240961Speter#endif
5340961Speter
5432153SbdeMALLOC_DEFINE(M_LINKER, "kld", "kernel linker");
5531324Sbdelinker_file_t linker_current_file;
5640906Speterlinker_file_t linker_kernel_file;
5731324Sbde
5825537Sdfrstatic struct lock lock;	/* lock for the file list */
5925537Sdfrstatic linker_class_list_t classes;
6025537Sdfrstatic linker_file_list_t files;
6125537Sdfrstatic int next_file_id = 1;
6225537Sdfr
6325537Sdfrstatic void
6425537Sdfrlinker_init(void* arg)
6525537Sdfr{
6625537Sdfr    lockinit(&lock, PVM, "klink", 0, 0);
6725537Sdfr    TAILQ_INIT(&classes);
6825537Sdfr    TAILQ_INIT(&files);
6925537Sdfr}
7025537Sdfr
7140159SpeterSYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0);
7225537Sdfr
7325537Sdfrint
7425537Sdfrlinker_add_class(const char* desc, void* priv,
7525537Sdfr		 struct linker_class_ops* ops)
7625537Sdfr{
7725537Sdfr    linker_class_t lc;
7825537Sdfr
7925537Sdfr    lc = malloc(sizeof(struct linker_class), M_LINKER, M_NOWAIT);
8025537Sdfr    if (!lc)
8125537Sdfr	return ENOMEM;
8240395Speter    bzero(lc, sizeof(*lc));
8325537Sdfr
8425537Sdfr    lc->desc = desc;
8525537Sdfr    lc->priv = priv;
8625537Sdfr    lc->ops = ops;
8725537Sdfr    TAILQ_INSERT_HEAD(&classes, lc, link);
8825537Sdfr
8925537Sdfr    return 0;
9025537Sdfr}
9125537Sdfr
9225537Sdfrstatic void
9325537Sdfrlinker_file_sysinit(linker_file_t lf)
9425537Sdfr{
9525537Sdfr    struct linker_set* sysinits;
9625537Sdfr    struct sysinit** sipp;
9725537Sdfr    struct sysinit** xipp;
9825537Sdfr    struct sysinit* save;
9940159Speter    moduledata_t *moddata;
10025537Sdfr
10125537Sdfr    KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n",
10225537Sdfr		   lf->filename));
10325537Sdfr
10425537Sdfr    sysinits = (struct linker_set*)
10525537Sdfr	linker_file_lookup_symbol(lf, "sysinit_set", 0);
10640159Speter
10740159Speter    KLD_DPF(FILE, ("linker_file_sysinit: SYSINITs %p\n", sysinits));
10825537Sdfr    if (!sysinits)
10925537Sdfr	return;
11025537Sdfr
11140159Speter    /* HACK ALERT! */
11240159Speter    for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) {
11340159Speter	if ((*sipp)->func == module_register_init) {
11440159Speter	    moddata = (*sipp)->udata;
11540159Speter	    moddata->_file = lf;
11640159Speter	}
11740159Speter    }
11840159Speter
11925537Sdfr    /*
12025537Sdfr     * Perform a bubble sort of the system initialization objects by
12125537Sdfr     * their subsystem (primary key) and order (secondary key).
12225537Sdfr     *
12325537Sdfr     * Since some things care about execution order, this is the
12425537Sdfr     * operation which ensures continued function.
12525537Sdfr     */
12641055Speter    for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) {
12741055Speter	for (xipp = sipp + 1; *xipp; xipp++) {
12841055Speter	    if ((*sipp)->subsystem <= (*xipp)->subsystem ||
12941055Speter		 ((*sipp)->subsystem == (*xipp)->subsystem &&
13041055Speter		  (*sipp)->order <= (*xipp)->order))
13125537Sdfr		continue;	/* skip*/
13225537Sdfr	    save = *sipp;
13325537Sdfr	    *sipp = *xipp;
13425537Sdfr	    *xipp = save;
13525537Sdfr	}
13625537Sdfr    }
13725537Sdfr
13825537Sdfr
13925537Sdfr    /*
14025537Sdfr     * Traverse the (now) ordered list of system initialization tasks.
14125537Sdfr     * Perform each task, and continue on to the next task.
14225537Sdfr     */
14341055Speter    for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) {
14441055Speter	if ((*sipp)->subsystem == SI_SUB_DUMMY)
14525537Sdfr	    continue;	/* skip dummy task(s)*/
14625537Sdfr
14741055Speter	switch ((*sipp)->type) {
14825537Sdfr	case SI_TYPE_DEFAULT:
14925537Sdfr	    /* no special processing*/
15041055Speter	    (*((*sipp)->func))((*sipp)->udata);
15125537Sdfr	    break;
15225537Sdfr
15325537Sdfr	case SI_TYPE_KTHREAD:
15431675Sdyson#if !defined(SMP)
15525537Sdfr	    /* kernel thread*/
15631675Sdyson	    if (fork1(&proc0, RFFDG|RFPROC|RFMEM))
15731675Sdyson		panic("fork kernel thread");
15831675Sdyson	    cpu_set_fork_handler(pfind(proc0.p_retval[0]),
15931675Sdyson		(*sipp)->func, (*sipp)->udata);
16031675Sdyson	    break;
16131675Sdyson#endif
16231675Sdyson
16331675Sdyson	case SI_TYPE_KPROCESS:
16431675Sdyson	    /* kernel thread*/
16531675Sdyson	    if (fork1(&proc0, RFFDG|RFPROC))
16625537Sdfr		panic("fork kernel process");
16730994Sphk	    cpu_set_fork_handler(pfind(proc0.p_retval[0]),
16830994Sphk		(*sipp)->func, (*sipp)->udata);
16925537Sdfr	    break;
17025537Sdfr
17125537Sdfr	default:
17241055Speter	    panic ("linker_file_sysinit: unrecognized init type");
17325537Sdfr	}
17425537Sdfr    }
17525537Sdfr}
17625537Sdfr
17741055Speterstatic void
17841055Speterlinker_file_sysuninit(linker_file_t lf)
17941055Speter{
18041055Speter    struct linker_set* sysuninits;
18141055Speter    struct sysinit** sipp;
18241055Speter    struct sysinit** xipp;
18341055Speter    struct sysinit* save;
18441055Speter
18541055Speter    KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n",
18641055Speter		   lf->filename));
18741055Speter
18841055Speter    sysuninits = (struct linker_set*)
18941055Speter	linker_file_lookup_symbol(lf, "sysuninit_set", 0);
19041055Speter
19141055Speter    KLD_DPF(FILE, ("linker_file_sysuninit: SYSUNINITs %p\n", sysuninits));
19241055Speter    if (!sysuninits)
19341055Speter	return;
19441055Speter
19541055Speter    /*
19641055Speter     * Perform a reverse bubble sort of the system initialization objects
19741055Speter     * by their subsystem (primary key) and order (secondary key).
19841055Speter     *
19941055Speter     * Since some things care about execution order, this is the
20041055Speter     * operation which ensures continued function.
20141055Speter     */
20241055Speter    for (sipp = (struct sysinit **)sysuninits->ls_items; *sipp; sipp++) {
20341055Speter	for (xipp = sipp + 1; *xipp; xipp++) {
20441055Speter	    if ((*sipp)->subsystem >= (*xipp)->subsystem ||
20541055Speter		 ((*sipp)->subsystem == (*xipp)->subsystem &&
20641055Speter		  (*sipp)->order >= (*xipp)->order))
20741055Speter		continue;	/* skip*/
20841055Speter	    save = *sipp;
20941055Speter	    *sipp = *xipp;
21041055Speter	    *xipp = save;
21141055Speter	}
21241055Speter    }
21341055Speter
21441055Speter
21541055Speter    /*
21641055Speter     * Traverse the (now) ordered list of system initialization tasks.
21741055Speter     * Perform each task, and continue on to the next task.
21841055Speter     */
21941055Speter    for (sipp = (struct sysinit **)sysuninits->ls_items; *sipp; sipp++) {
22041055Speter	if ((*sipp)->subsystem == SI_SUB_DUMMY)
22141055Speter	    continue;	/* skip dummy task(s)*/
22241055Speter
22341055Speter	switch ((*sipp)->type) {
22441055Speter	case SI_TYPE_DEFAULT:
22541055Speter	    /* no special processing*/
22641055Speter	    (*((*sipp)->func))((*sipp)->udata);
22741055Speter	    break;
22841055Speter
22941055Speter	default:
23041055Speter	    panic("linker_file_sysuninit: unrecognized uninit type");
23141055Speter	}
23241055Speter    }
23341055Speter}
23441055Speter
23525537Sdfrint
23625537Sdfrlinker_load_file(const char* filename, linker_file_t* result)
23725537Sdfr{
23825537Sdfr    linker_class_t lc;
23925537Sdfr    linker_file_t lf;
24042755Speter    int foundfile, error = 0;
24140861Speter    char *koname = NULL;
24225537Sdfr
24325537Sdfr    lf = linker_find_file_by_name(filename);
24425537Sdfr    if (lf) {
24525537Sdfr	KLD_DPF(FILE, ("linker_load_file: file %s is already loaded, incrementing refs\n", filename));
24625537Sdfr	*result = lf;
24725537Sdfr	lf->refs++;
24825537Sdfr	goto out;
24925537Sdfr    }
25025537Sdfr
25140861Speter    koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK);
25240861Speter    if (koname == NULL) {
25340861Speter	error = ENOMEM;
25440861Speter	goto out;
25540861Speter    }
25640861Speter    sprintf(koname, "%s.ko", filename);
25725537Sdfr    lf = NULL;
25842755Speter    foundfile = 0;
25925537Sdfr    for (lc = TAILQ_FIRST(&classes); lc; lc = TAILQ_NEXT(lc, link)) {
26025537Sdfr	KLD_DPF(FILE, ("linker_load_file: trying to load %s as %s\n",
26125537Sdfr		       filename, lc->desc));
26242755Speter
26342755Speter	error = lc->ops->load_file(koname, &lf);	/* First with .ko */
26442755Speter	if (lf == NULL && error == ENOENT)
26542755Speter	    error = lc->ops->load_file(filename, &lf);	/* Then try without */
26642755Speter	/*
26742755Speter	 * If we got something other than ENOENT, then it exists but we cannot
26842755Speter	 * load it for some other reason.
26942755Speter	 */
27042755Speter	if (error != ENOENT)
27142755Speter	    foundfile = 1;
27225537Sdfr	if (lf) {
27325537Sdfr	    linker_file_sysinit(lf);
27425537Sdfr
27525537Sdfr	    *result = lf;
27640861Speter	    error = 0;
27725537Sdfr	    goto out;
27825537Sdfr	}
27925537Sdfr    }
28042755Speter    /*
28142755Speter     * Less than ideal, but tells the user whether it failed to load or
28242755Speter     * the module was not found.
28342755Speter     */
28442755Speter    if (foundfile)
28542755Speter	error = ENOEXEC;	/* Format not recognised (or unloadable) */
28642755Speter    else
28742755Speter	error = ENOENT;		/* Nothing found */
28825537Sdfr
28925537Sdfrout:
29040861Speter    if (koname)
29140861Speter	free(koname, M_LINKER);
29225537Sdfr    return error;
29325537Sdfr}
29425537Sdfr
29525537Sdfrlinker_file_t
29625537Sdfrlinker_find_file_by_name(const char* filename)
29725537Sdfr{
29825537Sdfr    linker_file_t lf = 0;
29940861Speter    char *koname;
30025537Sdfr
30140861Speter    koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK);
30240861Speter    if (koname == NULL)
30340861Speter	goto out;
30440861Speter    sprintf(koname, "%s.ko", filename);
30540861Speter
30625537Sdfr    lockmgr(&lock, LK_SHARED, 0, curproc);
30740861Speter    for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) {
30840861Speter	if (!strcmp(lf->filename, koname))
30940861Speter	    break;
31025537Sdfr	if (!strcmp(lf->filename, filename))
31125537Sdfr	    break;
31240861Speter    }
31325537Sdfr    lockmgr(&lock, LK_RELEASE, 0, curproc);
31425537Sdfr
31540861Speterout:
31640861Speter    if (koname)
31740861Speter	free(koname, M_LINKER);
31825537Sdfr    return lf;
31925537Sdfr}
32025537Sdfr
32125537Sdfrlinker_file_t
32225537Sdfrlinker_find_file_by_id(int fileid)
32325537Sdfr{
32425537Sdfr    linker_file_t lf = 0;
32525537Sdfr
32625537Sdfr    lockmgr(&lock, LK_SHARED, 0, curproc);
32725537Sdfr    for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link))
32825537Sdfr	if (lf->id == fileid)
32925537Sdfr	    break;
33025537Sdfr    lockmgr(&lock, LK_RELEASE, 0, curproc);
33125537Sdfr
33225537Sdfr    return lf;
33325537Sdfr}
33425537Sdfr
33525537Sdfrlinker_file_t
33640159Speterlinker_make_file(const char* pathname, void* priv, struct linker_file_ops* ops)
33725537Sdfr{
33825537Sdfr    linker_file_t lf = 0;
33925537Sdfr    int namelen;
34040159Speter    const char *filename;
34125537Sdfr
34240159Speter    filename = rindex(pathname, '/');
34340159Speter    if (filename && filename[1])
34440159Speter	filename++;
34540159Speter    else
34640159Speter	filename = pathname;
34740159Speter
34825537Sdfr    KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename));
34925537Sdfr    lockmgr(&lock, LK_EXCLUSIVE|LK_RETRY, 0, curproc);
35025537Sdfr    namelen = strlen(filename) + 1;
35125537Sdfr    lf = malloc(sizeof(struct linker_file) + namelen, M_LINKER, M_WAITOK);
35225537Sdfr    if (!lf)
35325537Sdfr	goto out;
35440395Speter    bzero(lf, sizeof(*lf));
35525537Sdfr
35625537Sdfr    lf->refs = 1;
35725537Sdfr    lf->userrefs = 0;
35843185Sdfr    lf->flags = 0;
35925537Sdfr    lf->filename = (char*) (lf + 1);
36025537Sdfr    strcpy(lf->filename, filename);
36125537Sdfr    lf->id = next_file_id++;
36225537Sdfr    lf->ndeps = 0;
36325537Sdfr    lf->deps = NULL;
36425537Sdfr    STAILQ_INIT(&lf->common);
36525537Sdfr    TAILQ_INIT(&lf->modules);
36625537Sdfr
36725537Sdfr    lf->priv = priv;
36825537Sdfr    lf->ops = ops;
36925537Sdfr    TAILQ_INSERT_TAIL(&files, lf, link);
37025537Sdfr
37125537Sdfrout:
37225537Sdfr    lockmgr(&lock, LK_RELEASE, 0, curproc);
37325537Sdfr    return lf;
37425537Sdfr}
37525537Sdfr
37625537Sdfrint
37725537Sdfrlinker_file_unload(linker_file_t file)
37825537Sdfr{
37925537Sdfr    module_t mod, next;
38025537Sdfr    struct common_symbol* cp;
38125537Sdfr    int error = 0;
38225537Sdfr    int i;
38325537Sdfr
38440159Speter    KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs));
38525537Sdfr    lockmgr(&lock, LK_EXCLUSIVE|LK_RETRY, 0, curproc);
38625537Sdfr    if (file->refs == 1) {
38725537Sdfr	KLD_DPF(FILE, ("linker_file_unload: file is unloading, informing modules\n"));
38825537Sdfr	/*
38925537Sdfr	 * Inform any modules associated with this file.
39025537Sdfr	 */
39125537Sdfr	for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) {
39225537Sdfr	    next = module_getfnext(mod);
39325537Sdfr
39425537Sdfr	    /*
39525537Sdfr	     * Give the module a chance to veto the unload.
39625537Sdfr	     */
39743301Sdillon	    if ((error = module_unload(mod)) != 0) {
39825537Sdfr		KLD_DPF(FILE, ("linker_file_unload: module %x vetoes unload\n",
39925537Sdfr			       mod));
40025537Sdfr		lockmgr(&lock, LK_RELEASE, 0, curproc);
40125537Sdfr		goto out;
40225537Sdfr	    }
40325537Sdfr
40425537Sdfr	    module_release(mod);
40525537Sdfr	}
40625537Sdfr    }
40725537Sdfr
40825537Sdfr    file->refs--;
40925537Sdfr    if (file->refs > 0) {
41025537Sdfr	lockmgr(&lock, LK_RELEASE, 0, curproc);
41125537Sdfr	goto out;
41225537Sdfr    }
41325537Sdfr
41443185Sdfr    /* Don't try to run SYSUNINITs if we are unloaded due to a link error */
41543185Sdfr    if (file->flags & LINKER_FILE_LINKED)
41643185Sdfr	linker_file_sysuninit(file);
41741055Speter
41825537Sdfr    TAILQ_REMOVE(&files, file, link);
41925537Sdfr    lockmgr(&lock, LK_RELEASE, 0, curproc);
42040159Speter
42125537Sdfr    for (i = 0; i < file->ndeps; i++)
42225537Sdfr	linker_file_unload(file->deps[i]);
42325537Sdfr    free(file->deps, M_LINKER);
42425537Sdfr
42525537Sdfr    for (cp = STAILQ_FIRST(&file->common); cp;
42625537Sdfr	 cp = STAILQ_FIRST(&file->common)) {
42725537Sdfr	STAILQ_REMOVE(&file->common, cp, common_symbol, link);
42825537Sdfr	free(cp, M_LINKER);
42925537Sdfr    }
43025537Sdfr
43125537Sdfr    file->ops->unload(file);
43225537Sdfr    free(file, M_LINKER);
43325537Sdfr
43425537Sdfrout:
43525537Sdfr    return error;
43625537Sdfr}
43725537Sdfr
43825537Sdfrint
43925537Sdfrlinker_file_add_dependancy(linker_file_t file, linker_file_t dep)
44025537Sdfr{
44125537Sdfr    linker_file_t* newdeps;
44225537Sdfr
44325537Sdfr    newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t*),
44425537Sdfr		     M_LINKER, M_WAITOK);
44525537Sdfr    if (newdeps == NULL)
44625537Sdfr	return ENOMEM;
44740395Speter    bzero(newdeps, (file->ndeps + 1) * sizeof(linker_file_t*));
44825537Sdfr
44925537Sdfr    if (file->deps) {
45025537Sdfr	bcopy(file->deps, newdeps, file->ndeps * sizeof(linker_file_t*));
45125537Sdfr	free(file->deps, M_LINKER);
45225537Sdfr    }
45325537Sdfr    file->deps = newdeps;
45425537Sdfr    file->deps[file->ndeps] = dep;
45525537Sdfr    file->ndeps++;
45625537Sdfr
45725537Sdfr    return 0;
45825537Sdfr}
45925537Sdfr
46025537Sdfrcaddr_t
46125537Sdfrlinker_file_lookup_symbol(linker_file_t file, const char* name, int deps)
46225537Sdfr{
46338275Sdfr    linker_sym_t sym;
46438275Sdfr    linker_symval_t symval;
46542849Speter    linker_file_t lf;
46625537Sdfr    caddr_t address;
46725537Sdfr    size_t common_size = 0;
46825537Sdfr    int i;
46925537Sdfr
47040159Speter    KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d\n",
47125537Sdfr		  file, name, deps));
47225537Sdfr
47338275Sdfr    if (file->ops->lookup_symbol(file, name, &sym) == 0) {
47438275Sdfr	file->ops->symbol_values(file, sym, &symval);
47538275Sdfr	if (symval.value == 0)
47625537Sdfr	    /*
47725537Sdfr	     * For commons, first look them up in the dependancies and
47825537Sdfr	     * only allocate space if not found there.
47925537Sdfr	     */
48038275Sdfr	    common_size = symval.size;
48140159Speter	else {
48240159Speter	    KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol.value=%x\n", symval.value));
48338275Sdfr	    return symval.value;
48440159Speter	}
48538275Sdfr    }
48625537Sdfr
48742849Speter    if (deps) {
48825537Sdfr	for (i = 0; i < file->ndeps; i++) {
48925537Sdfr	    address = linker_file_lookup_symbol(file->deps[i], name, 0);
49040159Speter	    if (address) {
49140159Speter		KLD_DPF(SYM, ("linker_file_lookup_symbol: deps value=%x\n", address));
49225537Sdfr		return address;
49340159Speter	    }
49425537Sdfr	}
49525537Sdfr
49642849Speter	/* If we have not found it in the dependencies, search globally */
49742849Speter	for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) {
49842849Speter	    /* But skip the current file if it's on the list */
49942849Speter	    if (lf == file)
50042849Speter		continue;
50142849Speter	    /* And skip the files we searched above */
50242849Speter	    for (i = 0; i < file->ndeps; i++)
50342849Speter		if (lf == file->deps[i])
50442849Speter		    break;
50542849Speter	    if (i < file->ndeps)
50642849Speter		continue;
50742849Speter	    address = linker_file_lookup_symbol(lf, name, 0);
50842849Speter	    if (address) {
50942849Speter		KLD_DPF(SYM, ("linker_file_lookup_symbol: global value=%x\n", address));
51042849Speter		return address;
51142849Speter	    }
51242849Speter	}
51342849Speter    }
51442849Speter
51525537Sdfr    if (common_size > 0) {
51625537Sdfr	/*
51725537Sdfr	 * This is a common symbol which was not found in the
51825537Sdfr	 * dependancies.  We maintain a simple common symbol table in
51925537Sdfr	 * the file object.
52025537Sdfr	 */
52125537Sdfr	struct common_symbol* cp;
52225537Sdfr
52325537Sdfr	for (cp = STAILQ_FIRST(&file->common); cp;
52425537Sdfr	     cp = STAILQ_NEXT(cp, link))
52540159Speter	    if (!strcmp(cp->name, name)) {
52640159Speter		KLD_DPF(SYM, ("linker_file_lookup_symbol: old common value=%x\n", cp->address));
52725537Sdfr		return cp->address;
52840159Speter	    }
52925537Sdfr
53025537Sdfr	/*
53125537Sdfr	 * Round the symbol size up to align.
53225537Sdfr	 */
53325537Sdfr	common_size = (common_size + sizeof(int) - 1) & -sizeof(int);
53425537Sdfr	cp = malloc(sizeof(struct common_symbol)
53525537Sdfr		    + common_size
53625537Sdfr		    + strlen(name) + 1,
53725537Sdfr		    M_LINKER, M_WAITOK);
53840159Speter	if (!cp) {
53940159Speter	    KLD_DPF(SYM, ("linker_file_lookup_symbol: nomem\n"));
54025537Sdfr	    return 0;
54140159Speter	}
54240395Speter	bzero(cp, sizeof(struct common_symbol) + common_size + strlen(name)+ 1);
54325537Sdfr
54425537Sdfr	cp->address = (caddr_t) (cp + 1);
54525537Sdfr	cp->name = cp->address + common_size;
54625537Sdfr	strcpy(cp->name, name);
54725537Sdfr	bzero(cp->address, common_size);
54825537Sdfr	STAILQ_INSERT_TAIL(&file->common, cp, link);
54925537Sdfr
55040159Speter	KLD_DPF(SYM, ("linker_file_lookup_symbol: new common value=%x\n", cp->address));
55125537Sdfr	return cp->address;
55225537Sdfr    }
55325537Sdfr
55440159Speter    KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n"));
55525537Sdfr    return 0;
55625537Sdfr}
55725537Sdfr
55840159Speter#ifdef DDB
55925537Sdfr/*
56040159Speter * DDB Helpers.  DDB has to look across multiple files with their own
56140159Speter * symbol tables and string tables.
56240159Speter *
56340159Speter * Note that we do not obey list locking protocols here.  We really don't
56440159Speter * need DDB to hang because somebody's got the lock held.  We'll take the
56540159Speter * chance that the files list is inconsistant instead.
56640159Speter */
56740159Speter
56840159Speterint
56940159Speterlinker_ddb_lookup(char *symstr, linker_sym_t *sym)
57040159Speter{
57140159Speter    linker_file_t lf;
57240159Speter
57340159Speter    for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) {
57440159Speter	if (lf->ops->lookup_symbol(lf, symstr, sym) == 0)
57540159Speter	    return 0;
57640159Speter    }
57740159Speter    return ENOENT;
57840159Speter}
57940159Speter
58040159Speterint
58140159Speterlinker_ddb_search_symbol(caddr_t value, linker_sym_t *sym, long *diffp)
58240159Speter{
58340159Speter    linker_file_t lf;
58440159Speter    u_long off = (u_long)value;
58540159Speter    u_long diff, bestdiff;
58640159Speter    linker_sym_t best;
58740159Speter    linker_sym_t es;
58840159Speter
58940159Speter    best = 0;
59040159Speter    bestdiff = off;
59140159Speter    for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) {
59240159Speter	if (lf->ops->search_symbol(lf, value, &es, &diff) != 0)
59340159Speter	    continue;
59440159Speter	if (es != 0 && diff < bestdiff) {
59540159Speter	    best = es;
59640159Speter	    bestdiff = diff;
59740159Speter	}
59840159Speter	if (bestdiff == 0)
59940159Speter	    break;
60040159Speter    }
60140159Speter    if (best) {
60240159Speter	*sym = best;
60340159Speter	*diffp = bestdiff;
60440159Speter	return 0;
60540159Speter    } else {
60640159Speter	*sym = 0;
60740159Speter	*diffp = off;
60840159Speter	return ENOENT;
60940159Speter    }
61040159Speter}
61140159Speter
61240159Speterint
61340159Speterlinker_ddb_symbol_values(linker_sym_t sym, linker_symval_t *symval)
61440159Speter{
61540159Speter    linker_file_t lf;
61640159Speter
61740159Speter    for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) {
61840159Speter	if (lf->ops->symbol_values(lf, sym, symval) == 0)
61940159Speter	    return 0;
62040159Speter    }
62140159Speter    return ENOENT;
62240159Speter}
62340159Speter
62440159Speter#endif
62540159Speter
62640159Speter/*
62725537Sdfr * Syscalls.
62825537Sdfr */
62925537Sdfr
63025537Sdfrint
63130994Sphkkldload(struct proc* p, struct kldload_args* uap)
63225537Sdfr{
63342316Smsmith    char* filename = NULL, *modulename;
63425537Sdfr    linker_file_t lf;
63525537Sdfr    int error = 0;
63625537Sdfr
63730994Sphk    p->p_retval[0] = -1;
63825537Sdfr
63925537Sdfr    if (securelevel > 0)
64025537Sdfr	return EPERM;
64125537Sdfr
64243301Sdillon    if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
64325537Sdfr	return error;
64425537Sdfr
64525537Sdfr    filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
64643301Sdillon    if ((error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL)) != 0)
64725537Sdfr	goto out;
64825537Sdfr
64942316Smsmith    /* Can't load more than one module with the same name */
65042316Smsmith    modulename = rindex(filename, '/');
65142316Smsmith    if (modulename == NULL)
65242316Smsmith	modulename = filename;
65342316Smsmith    if (linker_find_file_by_name(modulename)) {
65442316Smsmith	error = EEXIST;
65542316Smsmith	goto out;
65642316Smsmith    }
65742316Smsmith
65843301Sdillon    if ((error = linker_load_file(filename, &lf)) != 0)
65925537Sdfr	goto out;
66025537Sdfr
66125537Sdfr    lf->userrefs++;
66230994Sphk    p->p_retval[0] = lf->id;
66340159Speter
66425537Sdfrout:
66525537Sdfr    if (filename)
66625537Sdfr	free(filename, M_TEMP);
66725537Sdfr    return error;
66825537Sdfr}
66925537Sdfr
67025537Sdfrint
67130994Sphkkldunload(struct proc* p, struct kldunload_args* uap)
67225537Sdfr{
67325537Sdfr    linker_file_t lf;
67425537Sdfr    int error = 0;
67525537Sdfr
67625537Sdfr    if (securelevel > 0)
67725537Sdfr	return EPERM;
67825537Sdfr
67943301Sdillon    if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
68025537Sdfr	return error;
68125537Sdfr
68225537Sdfr    lf = linker_find_file_by_id(SCARG(uap, fileid));
68325537Sdfr    if (lf) {
68425537Sdfr	KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs));
68525537Sdfr	if (lf->userrefs == 0) {
68643084Speter	    printf("linkerunload: attempt to unload file that was loaded by the kernel\n");
68725537Sdfr	    error = EBUSY;
68825537Sdfr	    goto out;
68925537Sdfr	}
69043084Speter	lf->userrefs--;
69142837Speter	error = linker_file_unload(lf);
69242837Speter	if (error)
69343084Speter	    lf->userrefs++;
69425537Sdfr    } else
69525537Sdfr	error = ENOENT;
69625537Sdfr
69725537Sdfrout:
69825537Sdfr    return error;
69925537Sdfr}
70025537Sdfr
70125537Sdfrint
70230994Sphkkldfind(struct proc* p, struct kldfind_args* uap)
70325537Sdfr{
70442316Smsmith    char* filename = NULL, *modulename;
70525537Sdfr    linker_file_t lf;
70625537Sdfr    int error = 0;
70725537Sdfr
70830994Sphk    p->p_retval[0] = -1;
70925537Sdfr
71025537Sdfr    filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
71143301Sdillon    if ((error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL)) != 0)
71225537Sdfr	goto out;
71325537Sdfr
71442316Smsmith    modulename = rindex(filename, '/');
71542316Smsmith    if (modulename == NULL)
71642316Smsmith	modulename = filename;
71742316Smsmith
71842316Smsmith    lf = linker_find_file_by_name(modulename);
71925537Sdfr    if (lf)
72030994Sphk	p->p_retval[0] = lf->id;
72125537Sdfr    else
72225537Sdfr	error = ENOENT;
72340159Speter
72425537Sdfrout:
72525537Sdfr    if (filename)
72625537Sdfr	free(filename, M_TEMP);
72725537Sdfr    return error;
72825537Sdfr}
72925537Sdfr
73025537Sdfrint
73130994Sphkkldnext(struct proc* p, struct kldnext_args* uap)
73225537Sdfr{
73325537Sdfr    linker_file_t lf;
73425537Sdfr    int error = 0;
73525537Sdfr
73625537Sdfr    if (SCARG(uap, fileid) == 0) {
73725537Sdfr	if (TAILQ_FIRST(&files))
73830994Sphk	    p->p_retval[0] = TAILQ_FIRST(&files)->id;
73925537Sdfr	else
74030994Sphk	    p->p_retval[0] = 0;
74125537Sdfr	return 0;
74225537Sdfr    }
74340159Speter
74425537Sdfr    lf = linker_find_file_by_id(SCARG(uap, fileid));
74525537Sdfr    if (lf) {
74625537Sdfr	if (TAILQ_NEXT(lf, link))
74730994Sphk	    p->p_retval[0] = TAILQ_NEXT(lf, link)->id;
74825537Sdfr	else
74930994Sphk	    p->p_retval[0] = 0;
75025537Sdfr    } else
75125537Sdfr	error = ENOENT;
75225537Sdfr
75325537Sdfr    return error;
75425537Sdfr}
75525537Sdfr
75625537Sdfrint
75730994Sphkkldstat(struct proc* p, struct kldstat_args* uap)
75825537Sdfr{
75925537Sdfr    linker_file_t lf;
76025537Sdfr    int error = 0;
76125537Sdfr    int version;
76225537Sdfr    struct kld_file_stat* stat;
76325537Sdfr    int namelen;
76425537Sdfr
76525537Sdfr    lf = linker_find_file_by_id(SCARG(uap, fileid));
76625537Sdfr    if (!lf) {
76725537Sdfr	error = ENOENT;
76825537Sdfr	goto out;
76925537Sdfr    }
77025537Sdfr
77125537Sdfr    stat = SCARG(uap, stat);
77225537Sdfr
77325537Sdfr    /*
77425537Sdfr     * Check the version of the user's structure.
77525537Sdfr     */
77643301Sdillon    if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
77725537Sdfr	goto out;
77825537Sdfr    if (version != sizeof(struct kld_file_stat)) {
77925537Sdfr	error = EINVAL;
78025537Sdfr	goto out;
78125537Sdfr    }
78225537Sdfr
78325537Sdfr    namelen = strlen(lf->filename) + 1;
78425537Sdfr    if (namelen > MAXPATHLEN)
78525537Sdfr	namelen = MAXPATHLEN;
78643301Sdillon    if ((error = copyout(lf->filename, &stat->name[0], namelen)) != 0)
78725537Sdfr	goto out;
78843301Sdillon    if ((error = copyout(&lf->refs, &stat->refs, sizeof(int))) != 0)
78925537Sdfr	goto out;
79043301Sdillon    if ((error = copyout(&lf->id, &stat->id, sizeof(int))) != 0)
79125537Sdfr	goto out;
79243301Sdillon    if ((error = copyout(&lf->address, &stat->address, sizeof(caddr_t))) != 0)
79325537Sdfr	goto out;
79443301Sdillon    if ((error = copyout(&lf->size, &stat->size, sizeof(size_t))) != 0)
79525537Sdfr	goto out;
79625537Sdfr
79730994Sphk    p->p_retval[0] = 0;
79825537Sdfr
79925537Sdfrout:
80025537Sdfr    return error;
80125537Sdfr}
80225537Sdfr
80325537Sdfrint
80430994Sphkkldfirstmod(struct proc* p, struct kldfirstmod_args* uap)
80525537Sdfr{
80625537Sdfr    linker_file_t lf;
80725537Sdfr    int error = 0;
80825537Sdfr
80925537Sdfr    lf = linker_find_file_by_id(SCARG(uap, fileid));
81025537Sdfr    if (lf) {
81125537Sdfr	if (TAILQ_FIRST(&lf->modules))
81230994Sphk	    p->p_retval[0] = module_getid(TAILQ_FIRST(&lf->modules));
81325537Sdfr	else
81430994Sphk	    p->p_retval[0] = 0;
81525537Sdfr    } else
81625537Sdfr	error = ENOENT;
81725537Sdfr
81825537Sdfr    return error;
81925537Sdfr}
82040159Speter
82141090Speterint
82241090Speterkldsym(struct proc *p, struct kldsym_args *uap)
82341090Speter{
82441090Speter    char *symstr = NULL;
82541090Speter    linker_sym_t sym;
82641090Speter    linker_symval_t symval;
82741090Speter    linker_file_t lf;
82841090Speter    struct kld_sym_lookup lookup;
82941090Speter    int error = 0;
83041090Speter
83143301Sdillon    if ((error = copyin(SCARG(uap, data), &lookup, sizeof(lookup))) != 0)
83241090Speter	goto out;
83341090Speter    if (lookup.version != sizeof(lookup) || SCARG(uap, cmd) != KLDSYM_LOOKUP) {
83441090Speter	error = EINVAL;
83541090Speter	goto out;
83641090Speter    }
83741090Speter
83841090Speter    symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
83943301Sdillon    if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0)
84041090Speter	goto out;
84141090Speter
84241090Speter    if (SCARG(uap, fileid) != 0) {
84341090Speter	lf = linker_find_file_by_id(SCARG(uap, fileid));
84441090Speter	if (lf == NULL) {
84541090Speter	    error = ENOENT;
84641090Speter	    goto out;
84741090Speter	}
84841090Speter	if (lf->ops->lookup_symbol(lf, symstr, &sym) == 0 &&
84941090Speter	    lf->ops->symbol_values(lf, sym, &symval) == 0) {
85041090Speter	    lookup.symvalue = (u_long)symval.value;
85141090Speter	    lookup.symsize = symval.size;
85241090Speter	    error = copyout(&lookup, SCARG(uap, data), sizeof(lookup));
85341090Speter	} else
85441090Speter	    error = ENOENT;
85541090Speter    } else {
85641090Speter	for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) {
85741090Speter	    if (lf->ops->lookup_symbol(lf, symstr, &sym) == 0 &&
85841090Speter		lf->ops->symbol_values(lf, sym, &symval) == 0) {
85941090Speter		lookup.symvalue = (u_long)symval.value;
86041090Speter		lookup.symsize = symval.size;
86141090Speter		error = copyout(&lookup, SCARG(uap, data), sizeof(lookup));
86241090Speter		break;
86341090Speter	    }
86441090Speter	}
86541090Speter	if (!lf)
86641090Speter	    error = ENOENT;
86741090Speter    }
86841090Speterout:
86941090Speter    if (symstr)
87041090Speter	free(symstr, M_TEMP);
87141090Speter    return error;
87241090Speter}
87341090Speter
87440159Speter/*
87540159Speter * Preloaded module support
87640159Speter */
87740159Speter
87840159Speterstatic void
87940159Speterlinker_preload(void* arg)
88040159Speter{
88140159Speter    caddr_t		modptr;
88240159Speter    char		*modname;
88340162Speter    char		*modtype;
88440159Speter    linker_file_t	lf;
88540159Speter    linker_class_t	lc;
88640159Speter    int			error;
88740159Speter    struct linker_set	*sysinits;
88840159Speter    struct sysinit	**sipp;
88940159Speter    moduledata_t	*moddata;
89040159Speter
89140159Speter    modptr = NULL;
89240159Speter    while ((modptr = preload_search_next_name(modptr)) != NULL) {
89340159Speter	modname = (char *)preload_search_info(modptr, MODINFO_NAME);
89440162Speter	modtype = (char *)preload_search_info(modptr, MODINFO_TYPE);
89540159Speter	if (modname == NULL) {
89640625Smsmith	    printf("Preloaded module at %p does not have a name!\n", modptr);
89740159Speter	    continue;
89840159Speter	}
89940162Speter	if (modtype == NULL) {
90040625Smsmith	    printf("Preloaded module at %p does not have a type!\n", modptr);
90140162Speter	    continue;
90240162Speter	}
90340625Smsmith	printf("Preloaded %s \"%s\" at %p.\n", modtype, modname, modptr);
90440159Speter	lf = linker_find_file_by_name(modname);
90540159Speter	if (lf) {
90640159Speter	    lf->userrefs++;
90740159Speter	    continue;
90840159Speter	}
90940159Speter	lf = NULL;
91040159Speter	for (lc = TAILQ_FIRST(&classes); lc; lc = TAILQ_NEXT(lc, link)) {
91140159Speter	    error = lc->ops->load_file(modname, &lf);
91240159Speter	    if (error) {
91340159Speter		lf = NULL;
91440159Speter		break;
91540159Speter	    }
91640159Speter	}
91740159Speter	if (lf) {
91840159Speter	    lf->userrefs++;
91940159Speter
92040159Speter	    sysinits = (struct linker_set*)
92140159Speter		linker_file_lookup_symbol(lf, "sysinit_set", 0);
92240159Speter	    if (sysinits) {
92340159Speter		/* HACK ALERT!
92440159Speter		 * This is to set the sysinit moduledata so that the module
92540159Speter		 * can attach itself to the correct containing file.
92640159Speter		 * The sysinit could be run at *any* time.
92740159Speter		 */
92840159Speter		for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) {
92940159Speter		    if ((*sipp)->func == module_register_init) {
93040159Speter			moddata = (*sipp)->udata;
93140159Speter			moddata->_file = lf;
93240159Speter		    }
93340159Speter		}
93440159Speter		sysinit_add((struct sysinit **)sysinits->ls_items);
93540159Speter	    }
93640159Speter	}
93740159Speter    }
93840159Speter}
93940159Speter
94040159SpeterSYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0);
94140159Speter
94240159Speter/*
94340159Speter * Search for a not-loaded module by name.
94440159Speter *
94540159Speter * Modules may be found in the following locations:
94640159Speter *
94740159Speter * - preloaded (result is just the module name)
94840159Speter * - on disk (result is full path to module)
94940159Speter *
95040159Speter * If the module name is qualified in any way (contains path, etc.)
95140159Speter * the we simply return a copy of it.
95240159Speter *
95340159Speter * The search path can be manipulated via sysctl.  Note that we use the ';'
95440159Speter * character as a separator to be consistent with the bootloader.
95540159Speter */
95640159Speter
95740159Speterstatic char linker_path[MAXPATHLEN + 1] = "/;/boot/;/modules/";
95840159Speter
95940159SpeterSYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path,
96040159Speter	      sizeof(linker_path), "module load search path");
96140159Speter
96240159Speterstatic char *
96340159Speterlinker_strdup(const char *str)
96440159Speter{
96540159Speter    char	*result;
96640159Speter
96740159Speter    if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL)
96840159Speter	strcpy(result, str);
96940159Speter    return(result);
97040159Speter}
97140159Speter
97240159Speterchar *
97340159Speterlinker_search_path(const char *name)
97440159Speter{
97540159Speter    struct nameidata	nd;
97640159Speter    struct proc		*p = curproc;	/* XXX */
97740159Speter    char		*cp, *ep, *result;
97840159Speter    int			error;
97940159Speter    enum vtype		type;
98040159Speter
98140159Speter    /* qualified at all? */
98240159Speter    if (index(name, '/'))
98340159Speter	return(linker_strdup(name));
98440159Speter
98540159Speter    /* traverse the linker path */
98640159Speter    cp = linker_path;
98740159Speter    for (;;) {
98840159Speter
98940159Speter	/* find the end of this component */
99040159Speter	for (ep = cp; (*ep != 0) && (*ep != ';'); ep++)
99140159Speter	    ;
99240159Speter	result = malloc((strlen(name) + (ep - cp) + 1), M_LINKER, M_WAITOK);
99340159Speter	if (result == NULL)	/* actually ENOMEM */
99440159Speter	    return(NULL);
99540159Speter
99640159Speter	strncpy(result, cp, ep - cp);
99740159Speter	strcpy(result + (ep - cp), name);
99840159Speter
99940159Speter	/*
100040159Speter	 * Attempt to open the file, and return the path if we succeed and it's
100140159Speter	 * a regular file.
100240159Speter	 */
100340159Speter	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, p);
100440159Speter	error = vn_open(&nd, FREAD, 0);
100540159Speter	if (error == 0) {
100640159Speter	    type = nd.ni_vp->v_type;
100740159Speter	    VOP_UNLOCK(nd.ni_vp, 0, p);
100840159Speter	    vn_close(nd.ni_vp, FREAD, p->p_ucred, p);
100940159Speter	    if (type == VREG)
101040159Speter		return(result);
101140159Speter	}
101240159Speter	free(result, M_LINKER);
101340159Speter
101440159Speter	if (*ep == 0)
101540159Speter	    break;
101640159Speter	cp = ep + 1;
101740159Speter    }
101840159Speter    return(NULL);
101940159Speter}
1020