kern_linker.c revision 74641
140516Swpaul/*-
2119868Swpaul * Copyright (c) 1997-2000 Doug Rabson
340516Swpaul * All rights reserved.
440516Swpaul *
540516Swpaul * Redistribution and use in source and binary forms, with or without
640516Swpaul * modification, are permitted provided that the following conditions
740516Swpaul * are met:
840516Swpaul * 1. Redistributions of source code must retain the above copyright
940516Swpaul *    notice, this list of conditions and the following disclaimer.
1040516Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1140516Swpaul *    notice, this list of conditions and the following disclaimer in the
1240516Swpaul *    documentation and/or other materials provided with the distribution.
1340516Swpaul *
1440516Swpaul * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1540516Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1640516Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1740516Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1840516Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1940516Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2040516Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2140516Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2240516Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2340516Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2440516Swpaul * SUCH DAMAGE.
2540516Swpaul *
2640516Swpaul * $FreeBSD: head/sys/kern/kern_linker.c 74641 2001-03-22 07:55:33Z bp $
2740516Swpaul */
2840516Swpaul
2940516Swpaul#include "opt_ddb.h"
3040516Swpaul
3140516Swpaul#include <sys/param.h>
3240516Swpaul#include <sys/kernel.h>
33122678Sobrien#include <sys/systm.h>
34122678Sobrien#include <sys/malloc.h>
35122678Sobrien#include <sys/sysproto.h>
3640516Swpaul#include <sys/sysent.h>
37119868Swpaul#include <sys/proc.h>
3840516Swpaul#include <sys/lock.h>
39119868Swpaul#include <sys/module.h>
40119868Swpaul#include <sys/linker.h>
4140516Swpaul#include <sys/fcntl.h>
4240516Swpaul#include <sys/libkern.h>
43119868Swpaul#include <sys/namei.h>
44119868Swpaul#include <sys/vnode.h>
45119868Swpaul#include <sys/sysctl.h>
4640516Swpaul
4740516Swpaul
4840516Swpaul#include "linker_if.h"
4940516Swpaul
5040516Swpaul#ifdef KLD_DEBUG
5140516Swpaulint kld_debug = 0;
5240516Swpaul#endif
5340516Swpaul
5440516Swpaulstatic char *linker_search_path(const char *name);
5540516Swpaulstatic const char *linker_basename(const char* path);
5641569Swpaul
5740516SwpaulMALLOC_DEFINE(M_LINKER, "linker", "kernel linker");
5840516Swpaul
5940516Swpaullinker_file_t linker_kernel_file;
6040516Swpaul
6140516Swpaulstatic struct lock lock;	/* lock for the file list */
6240516Swpaulstatic linker_class_list_t classes;
6340516Swpaulstatic linker_file_list_t linker_files;
6440516Swpaulstatic int next_file_id = 1;
6540516Swpaul
6640516Swpaul/* XXX wrong name; we're looking at version provision tags here, not modules */
6740516Swpaultypedef TAILQ_HEAD(, modlist) modlisthead_t;
6840516Swpaulstruct modlist {
6940516Swpaul    TAILQ_ENTRY(modlist) link;		/* chain together all modules */
7040516Swpaul    linker_file_t	container;
7140516Swpaul    const char		*name;
7240516Swpaul};
7340516Swpaultypedef struct modlist	*modlist_t;
7440516Swpaulstatic modlisthead_t	found_modules;
7540516Swpaul
7640516Swpaulstatic char *
7740516Swpaullinker_strdup(const char *str)
7840516Swpaul{
7940516Swpaul    char	*result;
8040516Swpaul
8140516Swpaul    if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL)
8240516Swpaul	strcpy(result, str);
8340516Swpaul    return(result);
8440516Swpaul}
8540516Swpaul
8640516Swpaulstatic void
87108729Sjakelinker_init(void* arg)
8840516Swpaul{
8940516Swpaul    lockinit(&lock, PVM, "klink", 0, 0);
9040516Swpaul    TAILQ_INIT(&classes);
9140516Swpaul    TAILQ_INIT(&linker_files);
9240516Swpaul}
9340516Swpaul
9440516SwpaulSYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0);
9540516Swpaul
9640516Swpaulint
9740516Swpaullinker_add_class(linker_class_t lc)
9840516Swpaul{
9940516Swpaul    kobj_class_compile((kobj_class_t) lc);
10040516Swpaul    TAILQ_INSERT_TAIL(&classes, lc, link);
10140516Swpaul    return 0;
10240516Swpaul}
10341569Swpaul
10441569Swpaulstatic void
10541569Swpaullinker_file_sysinit(linker_file_t lf)
10650703Swpaul{
10750703Swpaul    struct linker_set* sysinits;
10850703Swpaul    struct sysinit** sipp;
10940516Swpaul    struct sysinit** xipp;
11050703Swpaul    struct sysinit* save;
11150703Swpaul
11250703Swpaul    KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n",
113119871Swpaul		   lf->filename));
114119871Swpaul
11540516Swpaul    sysinits = (struct linker_set*)
116113506Smdodd	linker_file_lookup_symbol(lf, "sysinit_set", 0);
117113506Smdodd
11859758Speter    KLD_DPF(FILE, ("linker_file_sysinit: SYSINITs %p\n", sysinits));
11959758Speter    if (!sysinits)
12051089Speter	return;
12150703Swpaul    /*
12250703Swpaul     * Perform a bubble sort of the system initialization objects by
12340516Swpaul     * their subsystem (primary key) and order (secondary key).
12440516Swpaul     *
12540516Swpaul     * Since some things care about execution order, this is the
12640516Swpaul     * operation which ensures continued function.
12740516Swpaul     */
12840516Swpaul    for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) {
12940516Swpaul	for (xipp = sipp + 1; *xipp; xipp++) {
13040516Swpaul	    if ((*sipp)->subsystem < (*xipp)->subsystem ||
13140516Swpaul		 ((*sipp)->subsystem == (*xipp)->subsystem &&
13240516Swpaul		  (*sipp)->order <= (*xipp)->order))
13340516Swpaul		continue;	/* skip*/
13440516Swpaul	    save = *sipp;
13540516Swpaul	    *sipp = *xipp;
13640516Swpaul	    *xipp = save;
13740516Swpaul	}
13840516Swpaul    }
139117388Swpaul
14040516Swpaul
141117388Swpaul    /*
14240516Swpaul     * Traverse the (now) ordered list of system initialization tasks.
143117388Swpaul     * Perform each task, and continue on to the next task.
14467771Swpaul     */
145118978Swpaul    for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) {
146118978Swpaul	if ((*sipp)->subsystem == SI_SUB_DUMMY)
147117388Swpaul	    continue;	/* skip dummy task(s)*/
14841243Swpaul
149117388Swpaul	/* Call function */
15044238Swpaul	(*((*sipp)->func))((*sipp)->udata);
151117388Swpaul    }
15244238Swpaul}
153117388Swpaul
15472813Swpaulstatic void
155117388Swpaullinker_file_sysuninit(linker_file_t lf)
15696112Sjhb{
157117388Swpaul    struct linker_set* sysuninits;
15894400Swpaul    struct sysinit** sipp;
159117388Swpaul    struct sysinit** xipp;
160103020Siwasaki    struct sysinit* save;
161117388Swpaul
162109095Ssanpei    KLD_DPF(FILE, ("linker_file_sysuninit: calling SYSUNINITs for %s\n",
163117388Swpaul		   lf->filename));
164111381Sdan
165117388Swpaul    sysuninits = (struct linker_set*)
166112379Ssanpei	linker_file_lookup_symbol(lf, "sysuninit_set", 0);
167117388Swpaul
168117388Swpaul    KLD_DPF(FILE, ("linker_file_sysuninit: SYSUNINITs %p\n", sysuninits));
169117388Swpaul    if (!sysuninits)
170117388Swpaul	return;
171117388Swpaul
172117388Swpaul    /*
173123740Speter     * Perform a reverse bubble sort of the system initialization objects
17440516Swpaul     * by their subsystem (primary key) and order (secondary key).
17540516Swpaul     *
17692739Salfred     * Since some things care about execution order, this is the
17792739Salfred     * operation which ensures continued function.
17892739Salfred     */
17940516Swpaul    for (sipp = (struct sysinit **)sysuninits->ls_items; *sipp; sipp++) {
180119868Swpaul	for (xipp = sipp + 1; *xipp; xipp++) {
18140516Swpaul	    if ((*sipp)->subsystem > (*xipp)->subsystem ||
18292739Salfred		 ((*sipp)->subsystem == (*xipp)->subsystem &&
18392739Salfred		  (*sipp)->order >= (*xipp)->order))
18492739Salfred		continue;	/* skip*/
18592739Salfred	    save = *sipp;
18692739Salfred	    *sipp = *xipp;
18792739Salfred	    *xipp = save;
18892739Salfred	}
18992739Salfred    }
19092739Salfred
19192739Salfred    /*
19292739Salfred     * Traverse the (now) ordered list of system initialization tasks.
19392739Salfred     * Perform each task, and continue on to the next task.
19492739Salfred     */
19592739Salfred    for (sipp = (struct sysinit **)sysuninits->ls_items; *sipp; sipp++) {
19640516Swpaul	if ((*sipp)->subsystem == SI_SUB_DUMMY)
19792739Salfred	    continue;	/* skip dummy task(s)*/
19892739Salfred
19992739Salfred	/* Call function */
20092739Salfred	(*((*sipp)->func))((*sipp)->udata);
20192739Salfred    }
20292739Salfred}
20392739Salfred
20440516Swpaulstatic void
20592739Salfredlinker_file_register_sysctls(linker_file_t lf)
20692739Salfred{
20792739Salfred    struct linker_set* sysctls;
20840516Swpaul
209123289Sobrien    KLD_DPF(FILE, ("linker_file_register_sysctls: registering SYSCTLs for %s\n",
21092739Salfred		   lf->filename));
21192739Salfred
21292739Salfred    sysctls = (struct linker_set*)
21340516Swpaul	linker_file_lookup_symbol(lf, "sysctl_set", 0);
21492739Salfred
21592739Salfred    KLD_DPF(FILE, ("linker_file_register_sysctls: SYSCTLs %p\n", sysctls));
21681713Swpaul    if (!sysctls)
21750703Swpaul	return;
21850703Swpaul
21950703Swpaul    sysctl_register_set(sysctls);
22050703Swpaul}
22150703Swpaul
22250703Swpaulstatic void
22350703Swpaullinker_file_unregister_sysctls(linker_file_t lf)
22450703Swpaul{
22550703Swpaul    struct linker_set* sysctls;
22650703Swpaul
22750703Swpaul    KLD_DPF(FILE, ("linker_file_unregister_sysctls: registering SYSCTLs for %s\n",
22850703Swpaul		   lf->filename));
22950703Swpaul
23086822Siwasaki    sysctls = (struct linker_set*)
23186822Siwasaki	linker_file_lookup_symbol(lf, "sysctl_set", 0);
23250703Swpaul
23350703Swpaul    KLD_DPF(FILE, ("linker_file_unregister_sysctls: SYSCTLs %p\n", sysctls));
23450703Swpaul    if (!sysctls)
23550703Swpaul	return;
23650703Swpaul
23750703Swpaul    sysctl_unregister_set(sysctls);
23850703Swpaul}
23950703Swpaul
24050703Swpaulextern struct linker_set modmetadata_set;
24150703Swpaul
24250703Swpaulstatic int
24350703Swpaullinker_file_register_modules(linker_file_t lf)
24450703Swpaul{
24550703Swpaul    int error;
24650703Swpaul    struct linker_set *modules;
24751455Swpaul    struct mod_metadata **mdpp;
24850703Swpaul    const moduledata_t *moddata;
24950703Swpaul
25050703Swpaul    KLD_DPF(FILE, ("linker_file_register_modules: registering modules in %s\n",
25150703Swpaul		   lf->filename));
25250703Swpaul
25350703Swpaul    modules = (struct linker_set*)
254113506Smdodd	linker_file_lookup_symbol(lf, "modmetadata_set", 0);
255123019Simp
25651473Swpaul    if (!modules && lf == linker_kernel_file)
25750703Swpaul	modules = &modmetadata_set;
25840516Swpaul
25940516Swpaul    if (modules == NULL)
26040516Swpaul	return 0;
26140516Swpaul    for (mdpp = (struct mod_metadata**)modules->ls_items; *mdpp; mdpp++) {
26240516Swpaul	if ((*mdpp)->md_type != MDT_MODULE)
26340516Swpaul	    continue;
26440516Swpaul	moddata = (*mdpp)->md_data;
26540516Swpaul	KLD_DPF(FILE, ("Registering module %s in %s\n",
26681713Swpaul             moddata->name, lf->filename));
26781713Swpaul	if (module_lookupbyname(moddata->name) != NULL) {
26881713Swpaul	    printf("Warning: module %s already exists\n", moddata->name);
26981713Swpaul	    continue;	/* or return a error ? */
27081713Swpaul	}
27181713Swpaul	error = module_register(moddata, lf);
27281713Swpaul	if (error)
27381713Swpaul	    printf("Module %s failed to register: %d\n", moddata->name, error);
27481713Swpaul    }
27581713Swpaul    return 0;
27681713Swpaul}
27781713Swpaul
27881713Swpaulstatic void
27981713Swpaullinker_init_kernel_modules(void)
28081713Swpaul{
28181713Swpaul    linker_file_register_modules(linker_kernel_file);
28281713Swpaul}
28381713Swpaul
28481713SwpaulSYSINIT(linker_kernel, SI_SUB_KLD, SI_ORDER_ANY, linker_init_kernel_modules, 0);
28581713Swpaul
28681713Swpaulint
28781713Swpaullinker_load_file(const char* filename, linker_file_t* result)
28881713Swpaul{
28981713Swpaul    linker_class_t lc;
29081713Swpaul    linker_file_t lf;
29181713Swpaul    int foundfile, error = 0;
29281713Swpaul
29381713Swpaul    /* Refuse to load modules if securelevel raised */
29440516Swpaul    if (securelevel > 0)
29540516Swpaul	return EPERM;
29640516Swpaul
297102335Salfred    lf = linker_find_file_by_name(filename);
298102335Salfred    if (lf) {
29940516Swpaul	KLD_DPF(FILE, ("linker_load_file: file %s is already loaded, incrementing refs\n", filename));
30041656Swpaul	*result = lf;
30140516Swpaul	lf->refs++;
30240516Swpaul	goto out;
30340516Swpaul    }
30467931Swpaul
30540516Swpaul    lf = NULL;
30640516Swpaul    foundfile = 0;
30755170Sbillf    TAILQ_FOREACH(lc, &classes, link) {
30840516Swpaul	KLD_DPF(FILE, ("linker_load_file: trying to load %s as %s\n",
30940516Swpaul		       filename, lc->desc));
31040516Swpaul	error = LINKER_LOAD_FILE(lc, filename, &lf);
31140516Swpaul	/*
31240516Swpaul	 * If we got something other than ENOENT, then it exists but we cannot
31340516Swpaul	 * load it for some other reason.
31440516Swpaul	 */
31540516Swpaul	if (error != ENOENT)
31640516Swpaul	    foundfile = 1;
31740516Swpaul	if (lf) {
31840516Swpaul	    linker_file_register_modules(lf);
31940516Swpaul	    linker_file_register_sysctls(lf);
32040516Swpaul	    linker_file_sysinit(lf);
32140516Swpaul	    lf->flags |= LINKER_FILE_LINKED;
32240516Swpaul
32340516Swpaul	    *result = lf;
32440516Swpaul	    error = 0;
32540516Swpaul	    goto out;
32640516Swpaul	}
32740516Swpaul    }
328102335Salfred    /*
329102335Salfred     * Less than ideal, but tells the user whether it failed to load or
33040516Swpaul     * the module was not found.
33141656Swpaul     */
33240516Swpaul    if (foundfile)
33340516Swpaul	error = ENOEXEC;	/* Format not recognised (or unloadable) */
33440516Swpaul    else
33540516Swpaul	error = ENOENT;		/* Nothing found */
33640516Swpaul
33740516Swpaulout:
33840516Swpaul    return error;
33940516Swpaul}
34040516Swpaul
34140516Swpaullinker_file_t
34240516Swpaullinker_find_file_by_name(const char* filename)
34340516Swpaul{
34440516Swpaul    linker_file_t lf = 0;
34540516Swpaul    char *koname;
34640516Swpaul
34740516Swpaul    koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK);
34840516Swpaul    if (koname == NULL)
34940516Swpaul	goto out;
35040516Swpaul    sprintf(koname, "%s.ko", filename);
35140516Swpaul
35240516Swpaul    lockmgr(&lock, LK_SHARED, 0, curproc);
35340516Swpaul    TAILQ_FOREACH(lf, &linker_files, link) {
35440516Swpaul	if (!strcmp(lf->filename, koname))
35540516Swpaul	    break;
35640516Swpaul	if (!strcmp(lf->filename, filename))
35740516Swpaul	    break;
35840516Swpaul    }
35940516Swpaul    lockmgr(&lock, LK_RELEASE, 0, curproc);
36040516Swpaul
36140516Swpaulout:
36240516Swpaul    if (koname)
36340516Swpaul	free(koname, M_LINKER);
36440516Swpaul    return lf;
36540516Swpaul}
36640516Swpaul
36740516Swpaullinker_file_t
36840516Swpaullinker_find_file_by_id(int fileid)
36940516Swpaul{
370102335Salfred    linker_file_t lf = 0;
371102335Salfred
37240516Swpaul    lockmgr(&lock, LK_SHARED, 0, curproc);
37340516Swpaul    TAILQ_FOREACH(lf, &linker_files, link)
37440516Swpaul	if (lf->id == fileid)
37540516Swpaul	    break;
37640516Swpaul    lockmgr(&lock, LK_RELEASE, 0, curproc);
37740516Swpaul
37840516Swpaul    return lf;
37940516Swpaul}
38040516Swpaul
38140516Swpaullinker_file_t
38240516Swpaullinker_make_file(const char* pathname, linker_class_t lc)
38340516Swpaul{
38440516Swpaul    linker_file_t lf = 0;
38540516Swpaul    const char *filename;
38640516Swpaul
38740516Swpaul    filename = linker_basename(pathname);
38840516Swpaul
38940516Swpaul    KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename));
39040516Swpaul    lockmgr(&lock, LK_EXCLUSIVE, 0, curproc);
39140516Swpaul    lf = (linker_file_t) kobj_create((kobj_class_t) lc, M_LINKER, M_WAITOK);
39240516Swpaul    if (!lf)
39340516Swpaul	goto out;
39440516Swpaul
39540516Swpaul    lf->refs = 1;
39640516Swpaul    lf->userrefs = 0;
39740516Swpaul    lf->flags = 0;
39840516Swpaul    lf->filename = linker_strdup(filename);
39940516Swpaul    lf->id = next_file_id++;
40040516Swpaul    lf->ndeps = 0;
40140516Swpaul    lf->deps = NULL;
402105221Sphk    STAILQ_INIT(&lf->common);
40340516Swpaul    TAILQ_INIT(&lf->modules);
40440516Swpaul
40540516Swpaul    TAILQ_INSERT_TAIL(&linker_files, lf, link);
406105221Sphk
40740516Swpaulout:
40840516Swpaul    lockmgr(&lock, LK_RELEASE, 0, curproc);
40940516Swpaul    return lf;
41040516Swpaul}
411102335Salfred
412102335Salfredint
41340516Swpaullinker_file_unload(linker_file_t file)
41440516Swpaul{
41540516Swpaul    module_t mod, next;
41640516Swpaul    modlist_t ml, nextml;
41740516Swpaul    struct common_symbol* cp;
41840516Swpaul    int error = 0;
41940516Swpaul    int i;
42040516Swpaul
42140516Swpaul    /* Refuse to unload modules if securelevel raised */
42240516Swpaul    if (securelevel > 0)
42340516Swpaul	return EPERM;
42440516Swpaul
42540516Swpaul    KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs));
42640516Swpaul    lockmgr(&lock, LK_EXCLUSIVE, 0, curproc);
42740516Swpaul    if (file->refs == 1) {
42840516Swpaul	KLD_DPF(FILE, ("linker_file_unload: file is unloading, informing modules\n"));
42940516Swpaul	/*
43040516Swpaul	 * Inform any modules associated with this file.
43140516Swpaul	 */
432102335Salfred	for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) {
433102335Salfred	    next = module_getfnext(mod);
43440516Swpaul
43540516Swpaul	    /*
43640516Swpaul	     * Give the module a chance to veto the unload.
43740516Swpaul	     */
43840516Swpaul	    if ((error = module_unload(mod)) != 0) {
43940516Swpaul		KLD_DPF(FILE, ("linker_file_unload: module %x vetoes unload\n",
44040516Swpaul			       mod));
44140516Swpaul		lockmgr(&lock, LK_RELEASE, 0, curproc);
44240516Swpaul		goto out;
443109109Sdes	    }
44440516Swpaul
445109109Sdes	    module_release(mod);
44640516Swpaul	}
447109109Sdes    }
44840516Swpaul
44940516Swpaul    file->refs--;
45040516Swpaul    if (file->refs > 0) {
45140516Swpaul	lockmgr(&lock, LK_RELEASE, 0, curproc);
45240516Swpaul	goto out;
45340516Swpaul    }
45440516Swpaul
45540516Swpaul    for (ml = TAILQ_FIRST(&found_modules); ml; ml = nextml) {
45640516Swpaul	nextml = TAILQ_NEXT(ml, link);
45740516Swpaul	if (ml->container == file) {
458102335Salfred	    TAILQ_REMOVE(&found_modules, ml, link);
459102335Salfred	}
46040516Swpaul    }
46140516Swpaul
462109109Sdes    /* Don't try to run SYSUNINITs if we are unloaded due to a link error */
46340516Swpaul    if (file->flags & LINKER_FILE_LINKED) {
46467087Swpaul	linker_file_sysuninit(file);
46540516Swpaul	linker_file_unregister_sysctls(file);
46667087Swpaul    }
46740516Swpaul
46840516Swpaul    TAILQ_REMOVE(&linker_files, file, link);
46940516Swpaul    lockmgr(&lock, LK_RELEASE, 0, curproc);
47040516Swpaul
47140516Swpaul    if (file->deps) {
47240516Swpaul	for (i = 0; i < file->ndeps; i++)
47340516Swpaul	    linker_file_unload(file->deps[i]);
47440516Swpaul	free(file->deps, M_LINKER);
475109109Sdes	file->deps = NULL;
47640516Swpaul    }
47740516Swpaul
47840516Swpaul    for (cp = STAILQ_FIRST(&file->common); cp;
479109109Sdes	 cp = STAILQ_FIRST(&file->common)) {
48040516Swpaul	STAILQ_REMOVE(&file->common, cp, common_symbol, link);
48140516Swpaul	free(cp, M_LINKER);
48240516Swpaul    }
48340516Swpaul
48440516Swpaul    LINKER_UNLOAD(file);
48540516Swpaul    if (file->filename) {
48640516Swpaul	free(file->filename, M_LINKER);
48740516Swpaul	file->filename = NULL;
48840516Swpaul    }
48940516Swpaul    kobj_delete((kobj_t) file, M_LINKER);
49040516Swpaul
49140516Swpaulout:
49240516Swpaul    return error;
49340516Swpaul}
49440516Swpaul
49540516Swpaulint
49640516Swpaullinker_file_add_dependancy(linker_file_t file, linker_file_t dep)
49740516Swpaul{
49840516Swpaul    linker_file_t* newdeps;
49940516Swpaul
50040516Swpaul    newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t*),
50140516Swpaul		     M_LINKER, M_WAITOK | M_ZERO);
50240516Swpaul    if (newdeps == NULL)
50340516Swpaul	return ENOMEM;
50440516Swpaul
505109058Smbr    if (file->deps) {
50640516Swpaul	bcopy(file->deps, newdeps, file->ndeps * sizeof(linker_file_t*));
50740516Swpaul	free(file->deps, M_LINKER);
50840516Swpaul    }
50940516Swpaul    file->deps = newdeps;
51040516Swpaul    file->deps[file->ndeps] = dep;
51140516Swpaul    file->ndeps++;
51240516Swpaul
51340516Swpaul    return 0;
51440516Swpaul}
51540516Swpaul
51640516Swpaulcaddr_t
51740516Swpaullinker_file_lookup_symbol(linker_file_t file, const char* name, int deps)
51840516Swpaul{
51940516Swpaul    c_linker_sym_t sym;
52040516Swpaul    linker_symval_t symval;
52140516Swpaul    caddr_t address;
52240516Swpaul    size_t common_size = 0;
52340516Swpaul    int i;
52440516Swpaul
52540516Swpaul    KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d\n",
52640516Swpaul		  file, name, deps));
52740516Swpaul
52840516Swpaul    if (LINKER_LOOKUP_SYMBOL(file, name, &sym) == 0) {
52940516Swpaul	LINKER_SYMBOL_VALUES(file, sym, &symval);
53040516Swpaul	if (symval.value == 0)
53140516Swpaul	    /*
53240516Swpaul	     * For commons, first look them up in the dependancies and
53340516Swpaul	     * only allocate space if not found there.
53440516Swpaul	     */
53540516Swpaul	    common_size = symval.size;
53640516Swpaul	else {
53740516Swpaul	    KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol.value=%x\n", symval.value));
53840516Swpaul	    return symval.value;
53940516Swpaul	}
54040516Swpaul    }
54140516Swpaul
54267087Swpaul    if (deps) {
54340516Swpaul	for (i = 0; i < file->ndeps; i++) {
54440516Swpaul	    address = linker_file_lookup_symbol(file->deps[i], name, 0);
54540516Swpaul	    if (address) {
54640516Swpaul		KLD_DPF(SYM, ("linker_file_lookup_symbol: deps value=%x\n", address));
54740516Swpaul		return address;
54840516Swpaul	    }
54940516Swpaul	}
55040516Swpaul    }
55140516Swpaul
552102335Salfred    if (common_size > 0) {
553102335Salfred	/*
55440516Swpaul	 * This is a common symbol which was not found in the
55540516Swpaul	 * dependancies.  We maintain a simple common symbol table in
556109109Sdes	 * the file object.
55740516Swpaul	 */
55867087Swpaul	struct common_symbol* cp;
55940516Swpaul
56040516Swpaul	STAILQ_FOREACH(cp, &file->common, link)
56140516Swpaul	    if (!strcmp(cp->name, name)) {
56240516Swpaul		KLD_DPF(SYM, ("linker_file_lookup_symbol: old common value=%x\n", cp->address));
56340516Swpaul		return cp->address;
56440516Swpaul	    }
56540516Swpaul
56640516Swpaul	/*
567109109Sdes	 * Round the symbol size up to align.
56840516Swpaul	 */
569109109Sdes	common_size = (common_size + sizeof(int) - 1) & -sizeof(int);
57040516Swpaul	cp = malloc(sizeof(struct common_symbol)
57140516Swpaul		    + common_size
57240516Swpaul		    + strlen(name) + 1,
57340516Swpaul		    M_LINKER, M_WAITOK | M_ZERO);
57440516Swpaul	if (!cp) {
57540516Swpaul	    KLD_DPF(SYM, ("linker_file_lookup_symbol: nomem\n"));
57640516Swpaul	    return 0;
57740516Swpaul	}
57840516Swpaul
57940516Swpaul	cp->address = (caddr_t) (cp + 1);
58040516Swpaul	cp->name = cp->address + common_size;
58140516Swpaul	strcpy(cp->name, name);
58240516Swpaul	bzero(cp->address, common_size);
58340516Swpaul	STAILQ_INSERT_TAIL(&file->common, cp, link);
58440516Swpaul
58540516Swpaul	KLD_DPF(SYM, ("linker_file_lookup_symbol: new common value=%x\n", cp->address));
58640516Swpaul	return cp->address;
58740516Swpaul    }
58840516Swpaul
58940516Swpaul    KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n"));
59040516Swpaul    return 0;
59140516Swpaul}
59240516Swpaul
59367087Swpaul#ifdef DDB
59440516Swpaul/*
59540516Swpaul * DDB Helpers.  DDB has to look across multiple files with their own
59640516Swpaul * symbol tables and string tables.
59740516Swpaul *
598102335Salfred * Note that we do not obey list locking protocols here.  We really don't
599102335Salfred * need DDB to hang because somebody's got the lock held.  We'll take the
60050703Swpaul * chance that the files list is inconsistant instead.
60150703Swpaul */
60250703Swpaul
60340516Swpaulint
60440516Swpaullinker_ddb_lookup(const char *symstr, c_linker_sym_t *sym)
60540516Swpaul{
60640516Swpaul    linker_file_t lf;
60740516Swpaul
60850703Swpaul    TAILQ_FOREACH(lf, &linker_files, link) {
60967087Swpaul	if (LINKER_LOOKUP_SYMBOL(lf, symstr, sym) == 0)
61050703Swpaul	    return 0;
611119868Swpaul    }
61250703Swpaul    return ENOENT;
61367087Swpaul}
61467087Swpaul
61550703Swpaulint
61667087Swpaullinker_ddb_search_symbol(caddr_t value, c_linker_sym_t *sym, long *diffp)
61740516Swpaul{
61850703Swpaul    linker_file_t lf;
61940516Swpaul    u_long off = (uintptr_t)value;
62040516Swpaul    u_long diff, bestdiff;
62150703Swpaul    c_linker_sym_t best;
62240516Swpaul    c_linker_sym_t es;
62340516Swpaul
62450703Swpaul    best = 0;
62540516Swpaul    bestdiff = off;
62640516Swpaul    TAILQ_FOREACH(lf, &linker_files, link) {
62750703Swpaul	if (LINKER_SEARCH_SYMBOL(lf, value, &es, &diff) != 0)
62850703Swpaul	    continue;
62950703Swpaul	if (es != 0 && diff < bestdiff) {
63050703Swpaul	    best = es;
63140516Swpaul	    bestdiff = diff;
63240516Swpaul	}
63350703Swpaul	if (bestdiff == 0)
63450703Swpaul	    break;
63567087Swpaul    }
63650703Swpaul    if (best) {
63794149Swpaul	*sym = best;
63894149Swpaul	*diffp = bestdiff;
63994149Swpaul	return 0;
64094149Swpaul    } else {
64194149Swpaul	*sym = 0;
64294149Swpaul	*diffp = off;
64394149Swpaul	return ENOENT;
64494149Swpaul    }
64594149Swpaul}
64694149Swpaul
64740516Swpaulint
64840516Swpaullinker_ddb_symbol_values(c_linker_sym_t sym, linker_symval_t *symval)
64967087Swpaul{
65040516Swpaul    linker_file_t lf;
65140516Swpaul
65240516Swpaul    TAILQ_FOREACH(lf, &linker_files, link) {
65367087Swpaul	if (LINKER_SYMBOL_VALUES(lf, sym, symval) == 0)
65440516Swpaul	    return 0;
65540516Swpaul    }
65640516Swpaul    return ENOENT;
65740516Swpaul}
65840516Swpaul
65950703Swpaul#endif
66040516Swpaul
66140516Swpaul/*
66267087Swpaul * Syscalls.
66340516Swpaul */
66440516Swpaul
66540516Swpaulint
66640516Swpaulkldload(struct proc* p, struct kldload_args* uap)
667102335Salfred{
668102335Salfred    char* pathname, *realpath;
66950703Swpaul    const char *filename;
67050703Swpaul    linker_file_t lf;
67150703Swpaul    int error = 0;
67240516Swpaul
67340516Swpaul    p->p_retval[0] = -1;
67440516Swpaul
67540516Swpaul    if (securelevel > 0)	/* redundant, but that's OK */
67650703Swpaul	return EPERM;
67767087Swpaul
67850703Swpaul    if ((error = suser(p)) != 0)
679119868Swpaul	return error;
68050703Swpaul
68167087Swpaul    realpath = NULL;
68267087Swpaul    pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
68350703Swpaul    if ((error = copyinstr(SCARG(uap, file), pathname, MAXPATHLEN, NULL)) != 0)
68467087Swpaul	goto out;
68540516Swpaul
68650703Swpaul    realpath = linker_search_path(pathname);
68740516Swpaul    if (realpath == NULL) {
68840516Swpaul	error = ENOENT;
68950703Swpaul	goto out;
69040516Swpaul    }
69140516Swpaul    /* Can't load more than one file with the same name */
69250703Swpaul    filename = linker_basename(realpath);
69340516Swpaul    if (linker_find_file_by_name(filename)) {
69440516Swpaul	error = EEXIST;
69550703Swpaul	goto out;
69650703Swpaul    }
69750703Swpaul
69850703Swpaul    if ((error = linker_load_file(realpath, &lf)) != 0)
69940516Swpaul	goto out;
70040516Swpaul
70150703Swpaul    lf->userrefs++;
70250703Swpaul    p->p_retval[0] = lf->id;
70367087Swpaul
70450703Swpaulout:
70550703Swpaul    if (pathname)
70640516Swpaul	free(pathname, M_TEMP);
70740516Swpaul    if (realpath)
70867087Swpaul	free(realpath, M_LINKER);
70950703Swpaul    return error;
71040516Swpaul}
71140516Swpaul
71267087Swpaulint
71350703Swpaulkldunload(struct proc* p, struct kldunload_args* uap)
71440516Swpaul{
71540516Swpaul    linker_file_t lf;
71640516Swpaul    int error = 0;
71740516Swpaul
71850703Swpaul    if (securelevel > 0)	/* redundant, but that's OK */
71940516Swpaul	return EPERM;
72040516Swpaul
72140516Swpaul    if ((error = suser(p)) != 0)
72240516Swpaul	return error;
72340516Swpaul
72467087Swpaul    lf = linker_find_file_by_id(SCARG(uap, fileid));
72550703Swpaul    if (lf) {
72650703Swpaul	KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs));
72750703Swpaul	if (lf->userrefs == 0) {
728102335Salfred	    printf("kldunload: attempt to unload file that was loaded by the kernel\n");
729102335Salfred	    error = EBUSY;
73050703Swpaul	    goto out;
73150703Swpaul	}
73240516Swpaul	lf->userrefs--;
73340516Swpaul	error = linker_file_unload(lf);
73440516Swpaul	if (error)
73540516Swpaul	    lf->userrefs++;
73643062Swpaul    } else
73740516Swpaul	error = ENOENT;
738122625Sobrien
739122625Sobrienout:
740123289Sobrien    return error;
74140516Swpaul}
742123289Sobrien
743123289Sobrienint
744123289Sobrienkldfind(struct proc* p, struct kldfind_args* uap)
74540516Swpaul{
74640516Swpaul    char* pathname;
74740516Swpaul    const char *filename;
74840516Swpaul    linker_file_t lf;
749122625Sobrien    int error = 0;
750122625Sobrien
751122625Sobrien    p->p_retval[0] = -1;
75240516Swpaul
75340516Swpaul    pathname = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
75440516Swpaul    if ((error = copyinstr(SCARG(uap, file), pathname, MAXPATHLEN, NULL)) != 0)
75540516Swpaul	goto out;
75640516Swpaul
75740516Swpaul    filename = linker_basename(pathname);
75840516Swpaul
75943062Swpaul    lf = linker_find_file_by_name(filename);
76040516Swpaul    if (lf)
76140516Swpaul	p->p_retval[0] = lf->id;
76240516Swpaul    else
76340516Swpaul	error = ENOENT;
76440516Swpaul
765102335Salfredout:
766102335Salfred    if (pathname)
76740516Swpaul	free(pathname, M_TEMP);
76840516Swpaul    return error;
76940516Swpaul}
77040516Swpaul
77140516Swpaulint
77240516Swpaulkldnext(struct proc* p, struct kldnext_args* uap)
77340516Swpaul{
77440516Swpaul    linker_file_t lf;
77540516Swpaul    int error = 0;
77640516Swpaul
77740516Swpaul    if (SCARG(uap, fileid) == 0) {
77840516Swpaul	if (TAILQ_FIRST(&linker_files))
77940516Swpaul	    p->p_retval[0] = TAILQ_FIRST(&linker_files)->id;
78043062Swpaul	else
78140516Swpaul	    p->p_retval[0] = 0;
78240516Swpaul	return 0;
78340516Swpaul    }
78440516Swpaul
78540516Swpaul    lf = linker_find_file_by_id(SCARG(uap, fileid));
78640516Swpaul    if (lf) {
78740516Swpaul	if (TAILQ_NEXT(lf, link))
78840516Swpaul	    p->p_retval[0] = TAILQ_NEXT(lf, link)->id;
78940516Swpaul	else
79040516Swpaul	    p->p_retval[0] = 0;
79140516Swpaul    } else
79240516Swpaul	error = ENOENT;
79372084Sphk
79440516Swpaul    return error;
79540516Swpaul}
796122625Sobrien
79740516Swpaulint
79840516Swpaulkldstat(struct proc* p, struct kldstat_args* uap)
79940516Swpaul{
80040516Swpaul    linker_file_t lf;
80140516Swpaul    int error = 0;
80240516Swpaul    int version;
80340516Swpaul    struct kld_file_stat* stat;
80440516Swpaul    int namelen;
80540516Swpaul
80640516Swpaul    lf = linker_find_file_by_id(SCARG(uap, fileid));
80740516Swpaul    if (!lf) {
80840516Swpaul	error = ENOENT;
80940516Swpaul	goto out;
81040516Swpaul    }
81140516Swpaul
81240516Swpaul    stat = SCARG(uap, stat);
81340516Swpaul
81440516Swpaul    /*
81540516Swpaul     * Check the version of the user's structure.
816102335Salfred     */
817102335Salfred    if ((error = copyin(&stat->version, &version, sizeof(version))) != 0)
81840516Swpaul	goto out;
81940516Swpaul    if (version != sizeof(struct kld_file_stat)) {
82040516Swpaul	error = EINVAL;
82140516Swpaul	goto out;
82240516Swpaul    }
82340516Swpaul
82440516Swpaul    namelen = strlen(lf->filename) + 1;
82540516Swpaul    if (namelen > MAXPATHLEN)
82640516Swpaul	namelen = MAXPATHLEN;
82740516Swpaul    if ((error = copyout(lf->filename, &stat->name[0], namelen)) != 0)
82840516Swpaul	goto out;
82940516Swpaul    if ((error = copyout(&lf->refs, &stat->refs, sizeof(int))) != 0)
83040516Swpaul	goto out;
83140516Swpaul    if ((error = copyout(&lf->id, &stat->id, sizeof(int))) != 0)
832109109Sdes	goto out;
83340516Swpaul    if ((error = copyout(&lf->address, &stat->address, sizeof(caddr_t))) != 0)
83440516Swpaul	goto out;
83540516Swpaul    if ((error = copyout(&lf->size, &stat->size, sizeof(size_t))) != 0)
83640516Swpaul	goto out;
83740516Swpaul
83840516Swpaul    p->p_retval[0] = 0;
839102335Salfred
840102335Salfredout:
84150703Swpaul    return error;
84240516Swpaul}
84340516Swpaul
844119868Swpaulint
845117388Swpaulkldfirstmod(struct proc* p, struct kldfirstmod_args* uap)
846117388Swpaul{
84740516Swpaul    linker_file_t lf;
84840516Swpaul    int error = 0;
849117388Swpaul
85040516Swpaul    lf = linker_find_file_by_id(SCARG(uap, fileid));
85140516Swpaul    if (lf) {
85250703Swpaul	if (TAILQ_FIRST(&lf->modules))
85350703Swpaul	    p->p_retval[0] = module_getid(TAILQ_FIRST(&lf->modules));
854117388Swpaul	else
855117388Swpaul	    p->p_retval[0] = 0;
856117388Swpaul    } else
857117388Swpaul	error = ENOENT;
858117388Swpaul
859117388Swpaul    return error;
860117388Swpaul}
861117388Swpaul
862117388Swpaulint
863117388Swpaulkldsym(struct proc *p, struct kldsym_args *uap)
864117388Swpaul{
865117388Swpaul    char *symstr = NULL;
866117388Swpaul    c_linker_sym_t sym;
867117388Swpaul    linker_symval_t symval;
868117388Swpaul    linker_file_t lf;
869117388Swpaul    struct kld_sym_lookup lookup;
870117388Swpaul    int error = 0;
871117388Swpaul
872119868Swpaul    if ((error = copyin(SCARG(uap, data), &lookup, sizeof(lookup))) != 0)
873119868Swpaul	goto out;
874119868Swpaul    if (lookup.version != sizeof(lookup) || SCARG(uap, cmd) != KLDSYM_LOOKUP) {
875117388Swpaul	error = EINVAL;
876117388Swpaul	goto out;
877119868Swpaul    }
878119868Swpaul
879119868Swpaul    symstr = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
880124076Swpaul    if ((error = copyinstr(lookup.symname, symstr, MAXPATHLEN, NULL)) != 0)
881124076Swpaul	goto out;
882119954Swpaul
883119954Swpaul    if (SCARG(uap, fileid) != 0) {
884119868Swpaul	lf = linker_find_file_by_id(SCARG(uap, fileid));
885119868Swpaul	if (lf == NULL) {
886119868Swpaul	    error = ENOENT;
887119868Swpaul	    goto out;
888119868Swpaul	}
88950703Swpaul	if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 &&
89040516Swpaul	    LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) {
89140516Swpaul	    lookup.symvalue = (uintptr_t)symval.value;
89240516Swpaul	    lookup.symsize = symval.size;
89340516Swpaul	    error = copyout(&lookup, SCARG(uap, data), sizeof(lookup));
89450703Swpaul	} else
89540516Swpaul	    error = ENOENT;
89640516Swpaul    } else {
89740516Swpaul	TAILQ_FOREACH(lf, &linker_files, link) {
89840516Swpaul	    if (LINKER_LOOKUP_SYMBOL(lf, symstr, &sym) == 0 &&
89940516Swpaul		LINKER_SYMBOL_VALUES(lf, sym, &symval) == 0) {
90040516Swpaul		lookup.symvalue = (uintptr_t)symval.value;
901102335Salfred		lookup.symsize = symval.size;
902102335Salfred		error = copyout(&lookup, SCARG(uap, data), sizeof(lookup));
90350703Swpaul		break;
90440516Swpaul	    }
90540516Swpaul	}
906108729Sjake	if (!lf)
90740516Swpaul	    error = ENOENT;
90840516Swpaul    }
909119868Swpaulout:
910117388Swpaul    if (symstr)
911108729Sjake	free(symstr, M_TEMP);
91240516Swpaul    return error;
91350703Swpaul}
91450703Swpaul
91540516Swpaul/*
91693818Sjhb * Preloaded module support
91793818Sjhb */
918117208Simp
91940516Swpaulstatic modlist_t
92040516Swpaulmodlist_lookup(const char *name)
92140516Swpaul{
92240516Swpaul    modlist_t mod;
92370167Swpaul
92470167Swpaul    TAILQ_FOREACH(mod, &found_modules, link) {
92540516Swpaul	if (!strcmp(mod->name, name))
92670167Swpaul	    return mod;
92770167Swpaul    }
92870167Swpaul    return NULL;
92970167Swpaul}
93040516Swpaul
93170167Swpaul/*
93270167Swpaul * This routine is cheap and nasty but will work for data pointers.
93370167Swpaul */
93470167Swpaulstatic void *
93540516Swpaullinker_reloc_ptr(linker_file_t lf, void *offset)
93670167Swpaul{
93740516Swpaul	return lf->address + (uintptr_t)offset;
93870167Swpaul}
93970167Swpaul
94070167Swpaulstatic void
94170167Swpaullinker_preload(void* arg)
94240516Swpaul{
943117208Simp    caddr_t		modptr;
94440516Swpaul    char		*modname, *nmodname;
94540516Swpaul    char		*modtype;
94640516Swpaul    linker_file_t	lf;
94772813Swpaul    linker_class_t	lc;
94840516Swpaul    int			error;
949109109Sdes    struct linker_set	*sysinits;
95050703Swpaul    linker_file_list_t	loaded_files;
95150703Swpaul    linker_file_list_t	depended_files;
95250703Swpaul    struct linker_set	*deps;
95350703Swpaul    struct mod_metadata	*mp, *nmp;
95450703Swpaul    int			i, j;
95550703Swpaul    int			resolves;
95640516Swpaul    modlist_t		mod;
95740516Swpaul
95840516Swpaul    TAILQ_INIT(&loaded_files);
959117388Swpaul    TAILQ_INIT(&depended_files);
96069127Sroger    TAILQ_INIT(&found_modules);
96169127Sroger    error = 0;
96269127Sroger
96369127Sroger    modptr = NULL;
96469127Sroger    while ((modptr = preload_search_next_name(modptr)) != NULL) {
96569127Sroger	modname = (char *)preload_search_info(modptr, MODINFO_NAME);
96669127Sroger	modtype = (char *)preload_search_info(modptr, MODINFO_TYPE);
967119868Swpaul	if (modname == NULL) {
968119868Swpaul	    printf("Preloaded module at %p does not have a name!\n", modptr);
96969127Sroger	    continue;
970117388Swpaul	}
97169127Sroger	if (modtype == NULL) {
97250703Swpaul	    printf("Preloaded module at %p does not have a type!\n", modptr);
97350703Swpaul	    continue;
97450703Swpaul	}
975112872Snjl	printf("Preloaded %s \"%s\" at %p.\n", modtype, modname, modptr);
97650703Swpaul	lf = NULL;
97750703Swpaul	TAILQ_FOREACH(lc, &classes, link) {
97850703Swpaul	    error = LINKER_LINK_PRELOAD(lc, modname, &lf);
97950703Swpaul	    if (error) {
98050703Swpaul		lf = NULL;
98140516Swpaul		break;
98250703Swpaul	    }
98340516Swpaul	}
98440516Swpaul	if (lf)
98540516Swpaul	    TAILQ_INSERT_TAIL(&loaded_files, lf, loaded);
98640516Swpaul    }
98740516Swpaul
98867931Swpaul    /*
98967931Swpaul     * First get a list of stuff in the kernel.
99068215Swpaul     */
99167931Swpaul    deps = (struct linker_set*)
99240516Swpaul	linker_file_lookup_symbol(linker_kernel_file, MDT_SETNAME, 0);
99340516Swpaul    if (deps) {
99440516Swpaul	for (i = 0; i < deps->ls_length; i++) {
99540516Swpaul	    mp = deps->ls_items[i];
996108729Sjake	    if (mp->md_type != MDT_VERSION)
997108729Sjake		continue;
998108729Sjake	    modname = mp->md_cval;
999108729Sjake	    if (modlist_lookup(modname) != NULL) {
1000108729Sjake		printf("module %s already present!\n", modname);
100140516Swpaul		/* XXX what can we do? this is a build error. :-( */
100240516Swpaul		continue;
100340516Swpaul	    }
100440516Swpaul	    mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT|M_ZERO);
100540516Swpaul	    if (mod == NULL)
100640516Swpaul		panic("no memory for module list");
100740516Swpaul	    mod->container = linker_kernel_file;
100840516Swpaul	    mod->name = modname;
100940516Swpaul	    TAILQ_INSERT_TAIL(&found_modules, mod, link);
101040516Swpaul	}
101140516Swpaul    }
101240516Swpaul
101340516Swpaul    /*
101440516Swpaul     * this is a once-off kinky bubble sort
101540516Swpaul     * resolve relocation dependency requirements
1016117388Swpaul     */
1017119868Swpaulrestart:
1018117388Swpaul    TAILQ_FOREACH(lf, &loaded_files, loaded) {
1019117388Swpaul	deps = (struct linker_set*)
1020117388Swpaul	    linker_file_lookup_symbol(lf, MDT_SETNAME, 0);
1021117388Swpaul	/*
1022117388Swpaul	 * First, look to see if we would successfully link with this stuff.
1023117388Swpaul	 */
1024117388Swpaul	resolves = 1;	/* unless we know otherwise */
1025119868Swpaul	if (deps) {
1026119868Swpaul	    for (i = 0; i < deps->ls_length; i++) {
102740516Swpaul		mp = linker_reloc_ptr(lf, deps->ls_items[i]);
102850703Swpaul		if (mp->md_type != MDT_DEPEND)
102940516Swpaul		    continue;
103040516Swpaul		modname = linker_reloc_ptr(lf, mp->md_cval);
103140516Swpaul		for (j = 0; j < deps->ls_length; j++) {
103281713Swpaul		    nmp = linker_reloc_ptr(lf, deps->ls_items[j]);
103381713Swpaul		    if (nmp->md_type != MDT_VERSION)
103481713Swpaul			continue;
103581713Swpaul		    nmodname = linker_reloc_ptr(lf, nmp->md_cval);
1036109109Sdes		    if (strcmp(modname, nmodname) == 0)
103781713Swpaul			break;
103881713Swpaul		}
103981713Swpaul		if (j < deps->ls_length)	/* it's a self reference */
104081713Swpaul		    continue;
104181713Swpaul		if (modlist_lookup(modname) == NULL) {
1042109109Sdes		    /* ok, the module isn't here yet, we are not finished */
104381713Swpaul		    resolves = 0;
1044117126Sscottl		}
104581713Swpaul	    }
1046112872Snjl	}
1047112872Snjl	/*
104840516Swpaul	 * OK, if we found our modules, we can link.  So, "provide" the
104981713Swpaul	 * modules inside and add it to the end of the link order list.
1050119868Swpaul	 */
1051119868Swpaul	if (resolves) {
1052119868Swpaul	    if (deps) {
105381713Swpaul		for (i = 0; i < deps->ls_length; i++) {
1054119868Swpaul		    mp = linker_reloc_ptr(lf, deps->ls_items[i]);
1055119868Swpaul		    if (mp->md_type != MDT_VERSION)
1056119868Swpaul			continue;
1057119868Swpaul		    modname = linker_reloc_ptr(lf, mp->md_cval);
1058119868Swpaul		    if (modlist_lookup(modname) != NULL) {
1059119868Swpaul			printf("module %s already present!\n", modname);
1060119868Swpaul			linker_file_unload(lf);
1061119868Swpaul			TAILQ_REMOVE(&loaded_files, lf, loaded);
1062119868Swpaul			goto restart;	/* we changed the tailq next ptr */
1063119868Swpaul		    }
1064112872Snjl		    mod = malloc(sizeof(struct modlist), M_LINKER,
1065112872Snjl			M_NOWAIT|M_ZERO);
106681713Swpaul		    if (mod == NULL)
1067119868Swpaul			panic("no memory for module list");
1068119868Swpaul		    mod->container = lf;
1069119868Swpaul		    mod->name = modname;
1070119868Swpaul		    TAILQ_INSERT_TAIL(&found_modules, mod, link);
1071119868Swpaul		}
1072119868Swpaul	    }
1073119868Swpaul	    TAILQ_REMOVE(&loaded_files, lf, loaded);
1074119868Swpaul	    TAILQ_INSERT_TAIL(&depended_files, lf, loaded);
1075119868Swpaul	    /*
1076119868Swpaul	     * Since we provided modules, we need to restart the sort so
1077119868Swpaul	     * that the previous files that depend on us have a chance.
1078119868Swpaul	     * Also, we've busted the tailq next pointer with the REMOVE.
1079119868Swpaul	     */
1080119868Swpaul	    goto restart;
1081119868Swpaul	}
1082119868Swpaul    }
1083119868Swpaul
1084119868Swpaul    /*
1085119868Swpaul     * At this point, we check to see what could not be resolved..
108650703Swpaul     */
108750703Swpaul    TAILQ_FOREACH(lf, &loaded_files, loaded) {
108850703Swpaul	printf("KLD file %s is missing dependencies\n", lf->filename);
108950703Swpaul	linker_file_unload(lf);
109050703Swpaul	TAILQ_REMOVE(&loaded_files, lf, loaded);
109150703Swpaul    }
109250703Swpaul
109350703Swpaul    /*
109440516Swpaul     * We made it. Finish off the linking in the order we determined.
109540516Swpaul     */
1096121816Sbrooks    TAILQ_FOREACH(lf, &depended_files, loaded) {
109740516Swpaul	if (linker_kernel_file) {
109840516Swpaul	    linker_kernel_file->refs++;
109940516Swpaul	    error = linker_file_add_dependancy(lf, linker_kernel_file);
110040516Swpaul	    if (error)
1101119868Swpaul		panic("cannot add dependency");
110240516Swpaul	}
110340516Swpaul	lf->userrefs++;		/* so we can (try to) kldunload it */
110440516Swpaul	deps = (struct linker_set*)
1105119976Swpaul	    linker_file_lookup_symbol(lf, MDT_SETNAME, 0);
1106119977Swpaul	if (deps) {
1107119868Swpaul	    for (i = 0; i < deps->ls_length; i++) {
1108119976Swpaul		mp = linker_reloc_ptr(lf, deps->ls_items[i]);
1109112872Snjl		if (mp->md_type != MDT_DEPEND)
1110112872Snjl		    continue;
111140516Swpaul		modname = linker_reloc_ptr(lf, mp->md_cval);
111263090Sarchie		mod = modlist_lookup(modname);
111340516Swpaul		mod->container->refs++;
1114106936Ssam		error = linker_file_add_dependancy(lf, mod->container);
1115106157Simp		if (error)
1116113609Snjl		    panic("cannot add dependency");
1117106157Simp	    }
1118119868Swpaul	}
1119106157Simp
1120106157Simp	/* Now do relocation etc using the symbol search paths established by the dependencies */
1121106157Simp	error = LINKER_LINK_PRELOAD_FINISH(lf);
1122113609Snjl	if (error) {
1123106157Simp	    printf("KLD file %s - could not finalize loading\n", lf->filename);
1124106157Simp	    linker_file_unload(lf);
1125106157Simp	    continue;
112640516Swpaul	}
1127112872Snjl
1128112872Snjl	linker_file_register_modules(lf);
1129112872Snjl	sysinits = (struct linker_set*)
1130110601Snjl	    linker_file_lookup_symbol(lf, "sysinit_set", 0);
113140516Swpaul	if (sysinits)
113240516Swpaul	    sysinit_add((struct sysinit **)sysinits->ls_items);
1133113609Snjl	linker_file_register_sysctls(lf);
1134113609Snjl	lf->flags |= LINKER_FILE_LINKED;
1135113609Snjl    }
1136113609Snjl    /* woohoo! we made it! */
1137113609Snjl}
1138113609Snjl
1139113609SnjlSYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0);
1140102335Salfred
1141102335Salfred/*
114250703Swpaul * Search for a not-loaded module by name.
114350703Swpaul *
114450703Swpaul * Modules may be found in the following locations:
114550703Swpaul *
114650703Swpaul * - preloaded (result is just the module name)
114750703Swpaul * - on disk (result is full path to module)
1148112880Sjhb *
114967087Swpaul * If the module name is qualified in any way (contains path, etc.)
115050703Swpaul * the we simply return a copy of it.
115150703Swpaul *
1152113609Snjl * The search path can be manipulated via sysctl.  Note that we use the ';'
1153113812Simp * character as a separator to be consistent with the bootloader.
1154113609Snjl */
1155112872Snjl
1156113609Snjlstatic char def_linker_path[] = "/boot/modules/;/modules/;/boot/kernel/";
1157113609Snjlstatic char linker_path[MAXPATHLEN] = "";
1158112872Snjl
1159113609SnjlSYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path,
116050703Swpaul	      sizeof(linker_path), "module load search path");
1161112872Snjl
1162112872SnjlTUNABLE_STR_DECL("module_path", def_linker_path, linker_path,
1163112872Snjl		 sizeof(linker_path));
1164112872Snjl
1165112872Snjlstatic char *linker_ext_list[] = {
1166112872Snjl	".ko",
116750703Swpaul	"",
1168119868Swpaul	NULL
1169119868Swpaul};
1170119868Swpaul
1171119868Swpaulstatic char *
1172119868Swpaullinker_search_path(const char *name)
1173112872Snjl{
1174112872Snjl    struct nameidata	nd;
1175112872Snjl    struct proc		*p = curproc;	/* XXX */
117650703Swpaul    char		*cp, *ep, *result, **cpp;
117767087Swpaul    int			error, extlen, len, flags;
117867087Swpaul    enum vtype		type;
117950703Swpaul
118050703Swpaul    /* qualified at all? */
118150703Swpaul    if (index(name, '/'))
118250703Swpaul	return(linker_strdup(name));
118340516Swpaul
118440516Swpaul    extlen = 0;
118540516Swpaul    for (cpp = linker_ext_list; *cpp; cpp++) {
1186102335Salfred	len = strlen(*cpp);
1187102335Salfred	if (len > extlen)
118840516Swpaul	    extlen = len;
118940516Swpaul    }
119040516Swpaul    extlen++;	/* trailing '\0' */
119140516Swpaul
119240516Swpaul    /* traverse the linker path */
119340516Swpaul    cp = linker_path;
119440516Swpaul    len = strlen(name);
119545633Swpaul    for (;;) {
119648028Swpaul
119748028Swpaul	/* find the end of this component */
119840516Swpaul	for (ep = cp; (*ep != 0) && (*ep != ';'); ep++)
119940516Swpaul	    ;
120045633Swpaul	result = malloc((len + (ep - cp) + extlen + 1), M_LINKER, M_WAITOK);
120145633Swpaul	if (result == NULL)	/* actually ENOMEM */
120240516Swpaul	    return(NULL);
120340516Swpaul	for (cpp = linker_ext_list; *cpp; cpp++) {
120440516Swpaul	    strncpy(result, cp, ep - cp);
120540516Swpaul	    strcpy(result + (ep - cp), "/");
120640516Swpaul	    strcat(result, name);
120740516Swpaul	    strcat(result, *cpp);
120840516Swpaul	    /*
120940516Swpaul	     * Attempt to open the file, and return the path if we succeed
121040516Swpaul	     * and it's a regular file.
121140516Swpaul	     */
121240516Swpaul	    NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, p);
121340516Swpaul	    flags = FREAD;
121440516Swpaul	    error = vn_open(&nd, &flags, 0);
121540516Swpaul	    if (error == 0) {
121640516Swpaul		NDFREE(&nd, NDF_ONLY_PNBUF);
121772645Sasmodai		type = nd.ni_vp->v_type;
121840516Swpaul		VOP_UNLOCK(nd.ni_vp, 0, p);
121940516Swpaul		vn_close(nd.ni_vp, FREAD, p->p_ucred, p);
122040516Swpaul		if (type == VREG)
122140516Swpaul		    return(result);
122248028Swpaul	    }
122348028Swpaul	}
122478508Sbmilekic	free(result, M_LINKER);
1225109109Sdes
122640516Swpaul	if (*ep == 0)
1227102335Salfred	    break;
1228102335Salfred	cp = ep + 1;
122940516Swpaul    }
123040516Swpaul    return(NULL);
1231109109Sdes}
1232109109Sdes
123340516Swpaulstatic const char *
123440516Swpaullinker_basename(const char* path)
123540516Swpaul{
123640516Swpaul    const char *filename;
123740516Swpaul
123840516Swpaul    filename = rindex(path, '/');
123940516Swpaul    if (filename == NULL)
124040516Swpaul	return path;
1241122689Ssam    if (filename[1])
1242122689Ssam	filename++;
124340516Swpaul    return filename;
124440516Swpaul}
124581713Swpaul
1246108729Sjake/*
124781713Swpaul * Find a file which contains given module and load it,
124840516Swpaul * if "parent" is not NULL, register a reference to it.
124940516Swpaul */
125040516Swpaulstatic int
125140516Swpaullinker_load_module(const char *modname, struct linker_file *parent)
125240516Swpaul{
125340516Swpaul    linker_file_t lfdep;
125440516Swpaul    const char *filename;
125540516Swpaul    char *pathname;
125640516Swpaul    int error;
125740516Swpaul
125842738Swpaul    /*
125994883Sluigi     * There will be a system to look up or guess a file name from
1260102052Ssobomax     * a module name.
126194883Sluigi     * For now we just try to load a file with the same name.
126294883Sluigi     */
126394883Sluigi    pathname = linker_search_path(modname);
126494883Sluigi    if (pathname == NULL)
126594883Sluigi	return ENOENT;
126640516Swpaul
1267108729Sjake    /* Can't load more than one file with the same basename */
126840516Swpaul    filename = linker_basename(pathname);
126940516Swpaul    if (linker_find_file_by_name(filename)) {
127040516Swpaul	error = EEXIST;
127140516Swpaul	goto out;
127240516Swpaul    }
127340516Swpaul
127440516Swpaul    do {
127540516Swpaul	error = linker_load_file(pathname, &lfdep);
127640516Swpaul	if (error)
127740516Swpaul	    break;
127840516Swpaul	if (parent) {
1279109109Sdes	    error = linker_file_add_dependancy(parent, lfdep);
128040516Swpaul	    if (error)
128140516Swpaul		break;
128250703Swpaul	}
128350703Swpaul    } while(0);
128440516Swpaulout:
128540516Swpaul    if (pathname)
1286109109Sdes	free(pathname, M_LINKER);
128740516Swpaul    return error;
128840516Swpaul}
128940516Swpaul
129040516Swpaul/*
129142051Swpaul * This routine is responsible for finding dependencies of userland
129242051Swpaul * initiated kldload(2)'s of files.
129342051Swpaul */
1294109109Sdesint
129542051Swpaullinker_load_dependancies(linker_file_t lf)
129642051Swpaul{
129742051Swpaul    linker_file_t lfdep;
129842051Swpaul    struct linker_set *deps;
129942051Swpaul    struct mod_metadata *mp, *nmp;
130040516Swpaul    modlist_t mod;
130140516Swpaul    char *modname, *nmodname;
130240516Swpaul    int i, j, error = 0;
130340516Swpaul
130440516Swpaul    /*
130540516Swpaul     * All files are dependant on /kernel.
130640516Swpaul     */
130740516Swpaul    if (linker_kernel_file) {
130840516Swpaul	linker_kernel_file->refs++;
130940516Swpaul	error = linker_file_add_dependancy(lf, linker_kernel_file);
131040516Swpaul	if (error)
131140516Swpaul	    return error;
131240516Swpaul    }
131340516Swpaul
131440516Swpaul    deps = (struct linker_set*)
131578508Sbmilekic	linker_file_lookup_symbol(lf, MDT_SETNAME, 0);
131678508Sbmilekic    if (deps == NULL)
131740516Swpaul	return 0;
131840516Swpaul    for (i = 0; i < deps->ls_length; i++) {
131952426Swpaul	mp = linker_reloc_ptr(lf, deps->ls_items[i]);
132040516Swpaul	if (mp->md_type != MDT_VERSION)
132140516Swpaul	    continue;
132248028Swpaul	modname = linker_reloc_ptr(lf, mp->md_cval);
132342051Swpaul	if (modlist_lookup(modname) != NULL) {
132440516Swpaul	    printf("module %s already present!\n", modname);
132578508Sbmilekic	    return EEXIST;
132678508Sbmilekic	}
132740516Swpaul    }
132840516Swpaul    for (i = 0; i < deps->ls_length; i++) {
132978508Sbmilekic	mp = linker_reloc_ptr(lf, deps->ls_items[i]);
133042051Swpaul	if (mp->md_type != MDT_DEPEND)
133140516Swpaul	    continue;
133240516Swpaul	modname = linker_reloc_ptr(lf, mp->md_cval);
133340516Swpaul	nmodname = NULL;
133440516Swpaul	for (j = 0; j < deps->ls_length; j++) {
133540516Swpaul	    nmp = linker_reloc_ptr(lf, deps->ls_items[j]);
133640516Swpaul	    if (nmp->md_type != MDT_VERSION)
133740516Swpaul		continue;
133840516Swpaul	    nmodname = linker_reloc_ptr(lf, nmp->md_cval);
133940516Swpaul	    if (strcmp(modname, nmodname) == 0)
134040516Swpaul		break;
134140516Swpaul	}
134240516Swpaul	if (j < deps->ls_length)	/* early exit, it's a self reference */
1343122689Ssam	    continue;
1344106936Ssam	mod = modlist_lookup(modname);
1345122689Ssam	if (mod) {		/* woohoo, it's loaded already */
134640516Swpaul	    lfdep = mod->container;
134740516Swpaul	    lfdep->refs++;
134840516Swpaul	    error = linker_file_add_dependancy(lf, lfdep);
134940516Swpaul	    if (error)
135040516Swpaul		break;
135140516Swpaul	    continue;
135240516Swpaul	}
135340516Swpaul	error = linker_load_module(modname, lf);
135440516Swpaul	if (error) {
1355102335Salfred	    printf("KLD %s: depends on %s - not available\n",
1356102335Salfred		lf->filename, modname);
135740516Swpaul	    break;
135840516Swpaul	}
135940516Swpaul    }
136040516Swpaul
136140516Swpaul    if (error)
136240516Swpaul	return error;
136340516Swpaul    for (i = 0; i < deps->ls_length; i++) {
136440516Swpaul	mp = linker_reloc_ptr(lf, deps->ls_items[i]);
136540516Swpaul	if (mp->md_type != MDT_VERSION)
136640516Swpaul	    continue;
136740516Swpaul	modname = linker_reloc_ptr(lf, mp->md_cval);
136845633Swpaul	mod = malloc(sizeof(struct modlist), M_LINKER, M_NOWAIT|M_ZERO);
136945633Swpaul	if (mod == NULL)
137045633Swpaul	    panic("no memory for module list");
137145633Swpaul	mod->container = lf;
137240516Swpaul	mod->name = modname;
137340516Swpaul	TAILQ_INSERT_TAIL(&found_modules, mod, link);
137445633Swpaul    }
137540516Swpaul    return error;
137645633Swpaul}
137781713Swpaul