kern_linker.c revision 31675
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 *
2631675Sdyson *	$Id: kern_linker.c,v 1.4 1997/11/20 20:07:45 bde Exp $
2725537Sdfr */
2825537Sdfr
2925537Sdfr#include <sys/param.h>
3025537Sdfr#include <sys/kernel.h>
3125537Sdfr#include <sys/systm.h>
3225537Sdfr#include <sys/malloc.h>
3325537Sdfr#include <sys/sysproto.h>
3425537Sdfr#include <sys/sysent.h>
3525537Sdfr#include <sys/proc.h>
3625537Sdfr#include <sys/lock.h>
3725537Sdfr#include <machine/cpu.h>
3825537Sdfr#include <sys/module.h>
3925537Sdfr#include <sys/linker.h>
4031675Sdyson#include <sys/unistd.h>
4125537Sdfr
4231324Sbdelinker_file_t linker_current_file;
4331324Sbde
4425537Sdfrstatic struct lock lock;	/* lock for the file list */
4525537Sdfrstatic linker_class_list_t classes;
4625537Sdfrstatic linker_file_list_t files;
4725537Sdfrstatic int next_file_id = 1;
4825537Sdfr
4925537Sdfrstatic void
5025537Sdfrlinker_init(void* arg)
5125537Sdfr{
5225537Sdfr    lockinit(&lock, PVM, "klink", 0, 0);
5325537Sdfr    TAILQ_INIT(&classes);
5425537Sdfr    TAILQ_INIT(&files);
5525537Sdfr}
5625537Sdfr
5725537SdfrSYSINIT(linker, SI_SUB_KMEM, SI_ORDER_SECOND, linker_init, 0);
5825537Sdfr
5925537Sdfrint
6025537Sdfrlinker_add_class(const char* desc, void* priv,
6125537Sdfr		 struct linker_class_ops* ops)
6225537Sdfr{
6325537Sdfr    linker_class_t lc;
6425537Sdfr
6525537Sdfr    lc = malloc(sizeof(struct linker_class), M_LINKER, M_NOWAIT);
6625537Sdfr    if (!lc)
6725537Sdfr	return ENOMEM;
6825537Sdfr
6925537Sdfr    lc->desc = desc;
7025537Sdfr    lc->priv = priv;
7125537Sdfr    lc->ops = ops;
7225537Sdfr    TAILQ_INSERT_HEAD(&classes, lc, link);
7325537Sdfr
7425537Sdfr    return 0;
7525537Sdfr}
7625537Sdfr
7725537Sdfrstatic void
7825537Sdfrlinker_file_sysinit(linker_file_t lf)
7925537Sdfr{
8025537Sdfr    struct linker_set* sysinits;
8125537Sdfr    struct sysinit** sipp;
8225537Sdfr    struct sysinit** xipp;
8325537Sdfr    struct sysinit* save;
8425537Sdfr
8525537Sdfr    linker_current_file = lf;
8625537Sdfr
8725537Sdfr    KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n",
8825537Sdfr		   lf->filename));
8925537Sdfr
9025537Sdfr    sysinits = (struct linker_set*)
9125537Sdfr	linker_file_lookup_symbol(lf, "sysinit_set", 0);
9225537Sdfr    if (!sysinits)
9325537Sdfr	return;
9425537Sdfr
9525537Sdfr    /*
9625537Sdfr     * Perform a bubble sort of the system initialization objects by
9725537Sdfr     * their subsystem (primary key) and order (secondary key).
9825537Sdfr     *
9925537Sdfr     * Since some things care about execution order, this is the
10025537Sdfr     * operation which ensures continued function.
10125537Sdfr     */
10225537Sdfr    for( sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) {
10325537Sdfr	for( xipp = sipp + 1; *xipp; xipp++) {
10425537Sdfr	    if( (*sipp)->subsystem < (*xipp)->subsystem ||
10525537Sdfr		( (*sipp)->subsystem == (*xipp)->subsystem &&
10625537Sdfr		  (*sipp)->order < (*xipp)->order))
10725537Sdfr		continue;	/* skip*/
10825537Sdfr	    save = *sipp;
10925537Sdfr	    *sipp = *xipp;
11025537Sdfr	    *xipp = save;
11125537Sdfr	}
11225537Sdfr    }
11325537Sdfr
11425537Sdfr
11525537Sdfr    /*
11625537Sdfr     * Traverse the (now) ordered list of system initialization tasks.
11725537Sdfr     * Perform each task, and continue on to the next task.
11825537Sdfr     *
11925537Sdfr     * The last item on the list is expected to be the scheduler,
12025537Sdfr     * which will not return.
12125537Sdfr     */
12225537Sdfr    for( sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) {
12325537Sdfr	if( (*sipp)->subsystem == SI_SUB_DUMMY)
12425537Sdfr	    continue;	/* skip dummy task(s)*/
12525537Sdfr
12625537Sdfr	switch( (*sipp)->type) {
12725537Sdfr	case SI_TYPE_DEFAULT:
12825537Sdfr	    /* no special processing*/
12925537Sdfr	    (*((*sipp)->func))( (*sipp)->udata);
13025537Sdfr	    break;
13125537Sdfr
13225537Sdfr	case SI_TYPE_KTHREAD:
13331675Sdyson#if !defined(SMP)
13425537Sdfr	    /* kernel thread*/
13531675Sdyson	    if (fork1(&proc0, RFFDG|RFPROC|RFMEM))
13631675Sdyson		panic("fork kernel thread");
13731675Sdyson	    cpu_set_fork_handler(pfind(proc0.p_retval[0]),
13831675Sdyson		(*sipp)->func, (*sipp)->udata);
13931675Sdyson	    break;
14031675Sdyson#endif
14131675Sdyson
14231675Sdyson	case SI_TYPE_KPROCESS:
14331675Sdyson	    /* kernel thread*/
14431675Sdyson	    if (fork1(&proc0, RFFDG|RFPROC))
14525537Sdfr		panic("fork kernel process");
14630994Sphk	    cpu_set_fork_handler(pfind(proc0.p_retval[0]),
14730994Sphk		(*sipp)->func, (*sipp)->udata);
14825537Sdfr	    break;
14925537Sdfr
15025537Sdfr	default:
15125537Sdfr	    panic( "linker_file_sysinit: unrecognized init type");
15225537Sdfr	}
15325537Sdfr    }
15425537Sdfr}
15525537Sdfr
15625537Sdfrint
15725537Sdfrlinker_load_file(const char* filename, linker_file_t* result)
15825537Sdfr{
15925537Sdfr    linker_class_t lc;
16025537Sdfr    linker_file_t lf;
16125537Sdfr    int error = 0;
16225537Sdfr
16325537Sdfr    lf = linker_find_file_by_name(filename);
16425537Sdfr    if (lf) {
16525537Sdfr	KLD_DPF(FILE, ("linker_load_file: file %s is already loaded, incrementing refs\n", filename));
16625537Sdfr	*result = lf;
16725537Sdfr	lf->refs++;
16825537Sdfr	goto out;
16925537Sdfr    }
17025537Sdfr
17125537Sdfr    lf = NULL;
17225537Sdfr    for (lc = TAILQ_FIRST(&classes); lc; lc = TAILQ_NEXT(lc, link)) {
17325537Sdfr	KLD_DPF(FILE, ("linker_load_file: trying to load %s as %s\n",
17425537Sdfr		       filename, lc->desc));
17525537Sdfr	if (error = lc->ops->load_file(filename, &lf))
17625537Sdfr	    goto out;
17725537Sdfr	if (lf) {
17825537Sdfr	    linker_file_sysinit(lf);
17925537Sdfr
18025537Sdfr	    *result = lf;
18125537Sdfr	    goto out;
18225537Sdfr	}
18325537Sdfr    }
18425537Sdfr
18525537Sdfr    error = ENOEXEC;		/* format not recognised */
18625537Sdfr
18725537Sdfrout:
18825537Sdfr    return error;
18925537Sdfr}
19025537Sdfr
19125537Sdfrlinker_file_t
19225537Sdfrlinker_find_file_by_name(const char* filename)
19325537Sdfr{
19425537Sdfr    linker_file_t lf = 0;
19525537Sdfr
19625537Sdfr    lockmgr(&lock, LK_SHARED, 0, curproc);
19725537Sdfr    for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link))
19825537Sdfr	if (!strcmp(lf->filename, filename))
19925537Sdfr	    break;
20025537Sdfr    lockmgr(&lock, LK_RELEASE, 0, curproc);
20125537Sdfr
20225537Sdfr    return lf;
20325537Sdfr}
20425537Sdfr
20525537Sdfrlinker_file_t
20625537Sdfrlinker_find_file_by_id(int fileid)
20725537Sdfr{
20825537Sdfr    linker_file_t lf = 0;
20925537Sdfr
21025537Sdfr    lockmgr(&lock, LK_SHARED, 0, curproc);
21125537Sdfr    for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link))
21225537Sdfr	if (lf->id == fileid)
21325537Sdfr	    break;
21425537Sdfr    lockmgr(&lock, LK_RELEASE, 0, curproc);
21525537Sdfr
21625537Sdfr    return lf;
21725537Sdfr}
21825537Sdfr
21925537Sdfrlinker_file_t
22025537Sdfrlinker_make_file(const char* filename, void* priv, struct linker_file_ops* ops)
22125537Sdfr{
22225537Sdfr    linker_file_t lf = 0;
22325537Sdfr    int namelen;
22425537Sdfr
22525537Sdfr    KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename));
22625537Sdfr    lockmgr(&lock, LK_EXCLUSIVE|LK_RETRY, 0, curproc);
22725537Sdfr    namelen = strlen(filename) + 1;
22825537Sdfr    lf = malloc(sizeof(struct linker_file) + namelen, M_LINKER, M_WAITOK);
22925537Sdfr    if (!lf)
23025537Sdfr	goto out;
23125537Sdfr
23225537Sdfr    lf->refs = 1;
23325537Sdfr    lf->userrefs = 0;
23425537Sdfr    lf->filename = (char*) (lf + 1);
23525537Sdfr    strcpy(lf->filename, filename);
23625537Sdfr    lf->id = next_file_id++;
23725537Sdfr    lf->ndeps = 0;
23825537Sdfr    lf->deps = NULL;
23925537Sdfr    STAILQ_INIT(&lf->common);
24025537Sdfr    TAILQ_INIT(&lf->modules);
24125537Sdfr
24225537Sdfr    lf->priv = priv;
24325537Sdfr    lf->ops = ops;
24425537Sdfr    TAILQ_INSERT_TAIL(&files, lf, link);
24525537Sdfr
24625537Sdfrout:
24725537Sdfr    lockmgr(&lock, LK_RELEASE, 0, curproc);
24825537Sdfr    return lf;
24925537Sdfr}
25025537Sdfr
25125537Sdfrint
25225537Sdfrlinker_file_unload(linker_file_t file)
25325537Sdfr{
25425537Sdfr    module_t mod, next;
25525537Sdfr    struct common_symbol* cp;
25625537Sdfr    int error = 0;
25725537Sdfr    int i;
25825537Sdfr
25925537Sdfr    KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", lf->refs));
26025537Sdfr    lockmgr(&lock, LK_EXCLUSIVE|LK_RETRY, 0, curproc);
26125537Sdfr    if (file->refs == 1) {
26225537Sdfr	KLD_DPF(FILE, ("linker_file_unload: file is unloading, informing modules\n"));
26325537Sdfr	/*
26425537Sdfr	 * Inform any modules associated with this file.
26525537Sdfr	 */
26625537Sdfr	for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) {
26725537Sdfr	    next = module_getfnext(mod);
26825537Sdfr
26925537Sdfr	    /*
27025537Sdfr	     * Give the module a chance to veto the unload.
27125537Sdfr	     */
27225537Sdfr	    if (error = module_unload(mod)) {
27325537Sdfr		KLD_DPF(FILE, ("linker_file_unload: module %x vetoes unload\n",
27425537Sdfr			       mod));
27525537Sdfr		lockmgr(&lock, LK_RELEASE, 0, curproc);
27625537Sdfr		goto out;
27725537Sdfr	    }
27825537Sdfr
27925537Sdfr	    module_release(mod);
28025537Sdfr	}
28125537Sdfr    }
28225537Sdfr
28325537Sdfr    file->refs--;
28425537Sdfr    if (file->refs > 0) {
28525537Sdfr	lockmgr(&lock, LK_RELEASE, 0, curproc);
28625537Sdfr	goto out;
28725537Sdfr    }
28825537Sdfr
28925537Sdfr    TAILQ_REMOVE(&files, file, link);
29025537Sdfr    lockmgr(&lock, LK_RELEASE, 0, curproc);
29125537Sdfr
29225537Sdfr    for (i = 0; i < file->ndeps; i++)
29325537Sdfr	linker_file_unload(file->deps[i]);
29425537Sdfr    free(file->deps, M_LINKER);
29525537Sdfr
29625537Sdfr    for (cp = STAILQ_FIRST(&file->common); cp;
29725537Sdfr	 cp = STAILQ_FIRST(&file->common)) {
29825537Sdfr	STAILQ_REMOVE(&file->common, cp, common_symbol, link);
29925537Sdfr	free(cp, M_LINKER);
30025537Sdfr    }
30125537Sdfr
30225537Sdfr    file->ops->unload(file);
30325537Sdfr    free(file, M_LINKER);
30425537Sdfr
30525537Sdfrout:
30625537Sdfr    return error;
30725537Sdfr}
30825537Sdfr
30925537Sdfrint
31025537Sdfrlinker_file_add_dependancy(linker_file_t file, linker_file_t dep)
31125537Sdfr{
31225537Sdfr    linker_file_t* newdeps;
31325537Sdfr
31425537Sdfr    newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t*),
31525537Sdfr		     M_LINKER, M_WAITOK);
31625537Sdfr    if (newdeps == NULL)
31725537Sdfr	return ENOMEM;
31825537Sdfr
31925537Sdfr    if (file->deps) {
32025537Sdfr	bcopy(file->deps, newdeps, file->ndeps * sizeof(linker_file_t*));
32125537Sdfr	free(file->deps, M_LINKER);
32225537Sdfr    }
32325537Sdfr    file->deps = newdeps;
32425537Sdfr    file->deps[file->ndeps] = dep;
32525537Sdfr    file->ndeps++;
32625537Sdfr
32725537Sdfr    return 0;
32825537Sdfr}
32925537Sdfr
33025537Sdfrcaddr_t
33125537Sdfrlinker_file_lookup_symbol(linker_file_t file, const char* name, int deps)
33225537Sdfr{
33325537Sdfr    caddr_t address;
33425537Sdfr    size_t size;
33525537Sdfr    size_t common_size = 0;
33625537Sdfr    int i;
33725537Sdfr
33825537Sdfr    KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d",
33925537Sdfr		  file, name, deps));
34025537Sdfr
34125537Sdfr    if (file->ops->lookup_symbol(file, name, &address, &size) == 0)
34225537Sdfr	if (address == 0)
34325537Sdfr	    /*
34425537Sdfr	     * For commons, first look them up in the dependancies and
34525537Sdfr	     * only allocate space if not found there.
34625537Sdfr	     */
34725537Sdfr	    common_size = size;
34825537Sdfr	else
34925537Sdfr	    return address;
35025537Sdfr
35125537Sdfr    if (deps)
35225537Sdfr	for (i = 0; i < file->ndeps; i++) {
35325537Sdfr	    address = linker_file_lookup_symbol(file->deps[i], name, 0);
35425537Sdfr	    if (address)
35525537Sdfr		return address;
35625537Sdfr	}
35725537Sdfr
35825537Sdfr    if (common_size > 0) {
35925537Sdfr	/*
36025537Sdfr	 * This is a common symbol which was not found in the
36125537Sdfr	 * dependancies.  We maintain a simple common symbol table in
36225537Sdfr	 * the file object.
36325537Sdfr	 */
36425537Sdfr	struct common_symbol* cp;
36525537Sdfr
36625537Sdfr	for (cp = STAILQ_FIRST(&file->common); cp;
36725537Sdfr	     cp = STAILQ_NEXT(cp, link))
36825537Sdfr	    if (!strcmp(cp->name, name))
36925537Sdfr		return cp->address;
37025537Sdfr
37125537Sdfr	/*
37225537Sdfr	 * Round the symbol size up to align.
37325537Sdfr	 */
37425537Sdfr	common_size = (common_size + sizeof(int) - 1) & -sizeof(int);
37525537Sdfr	cp = malloc(sizeof(struct common_symbol)
37625537Sdfr		    + common_size
37725537Sdfr		    + strlen(name) + 1,
37825537Sdfr		    M_LINKER, M_WAITOK);
37925537Sdfr	if (!cp)
38025537Sdfr	    return 0;
38125537Sdfr
38225537Sdfr	cp->address = (caddr_t) (cp + 1);
38325537Sdfr	cp->name = cp->address + common_size;
38425537Sdfr	strcpy(cp->name, name);
38525537Sdfr	bzero(cp->address, common_size);
38625537Sdfr	STAILQ_INSERT_TAIL(&file->common, cp, link);
38725537Sdfr
38825537Sdfr	return cp->address;
38925537Sdfr    }
39025537Sdfr
39125537Sdfr    return 0;
39225537Sdfr}
39325537Sdfr
39425537Sdfr/*
39525537Sdfr * Syscalls.
39625537Sdfr */
39725537Sdfr
39825537Sdfrint
39930994Sphkkldload(struct proc* p, struct kldload_args* uap)
40025537Sdfr{
40125537Sdfr    char* filename = NULL;
40225537Sdfr    linker_file_t lf;
40325537Sdfr    int error = 0;
40425537Sdfr
40530994Sphk    p->p_retval[0] = -1;
40625537Sdfr
40725537Sdfr    if (securelevel > 0)
40825537Sdfr	return EPERM;
40925537Sdfr
41025537Sdfr    if (error = suser(p->p_ucred, &p->p_acflag))
41125537Sdfr	return error;
41225537Sdfr
41325537Sdfr    filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
41425537Sdfr    if (error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL))
41525537Sdfr	goto out;
41625537Sdfr
41725537Sdfr    if (error = linker_load_file(uap->file, &lf))
41825537Sdfr	goto out;
41925537Sdfr
42025537Sdfr    lf->userrefs++;
42130994Sphk    p->p_retval[0] = lf->id;
42225537Sdfr
42325537Sdfrout:
42425537Sdfr    if (filename)
42525537Sdfr	free(filename, M_TEMP);
42625537Sdfr    return error;
42725537Sdfr}
42825537Sdfr
42925537Sdfrint
43030994Sphkkldunload(struct proc* p, struct kldunload_args* uap)
43125537Sdfr{
43225537Sdfr    linker_file_t lf;
43325537Sdfr    int error = 0;
43425537Sdfr
43525537Sdfr    if (securelevel > 0)
43625537Sdfr	return EPERM;
43725537Sdfr
43825537Sdfr    if (error = suser(p->p_ucred, &p->p_acflag))
43925537Sdfr	return error;
44025537Sdfr
44125537Sdfr    lf = linker_find_file_by_id(SCARG(uap, fileid));
44225537Sdfr    if (lf) {
44325537Sdfr	KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs));
44425537Sdfr	if (lf->userrefs == 0) {
44525537Sdfr	    printf("linkerunload: attempt to unload file which was not loaded by user\n");
44625537Sdfr	    error = EBUSY;
44725537Sdfr	    goto out;
44825537Sdfr	}
44925537Sdfr	lf->userrefs--;
45025537Sdfr	error = linker_file_unload(lf);
45125537Sdfr    } else
45225537Sdfr	error = ENOENT;
45325537Sdfr
45425537Sdfrout:
45525537Sdfr    return error;
45625537Sdfr}
45725537Sdfr
45825537Sdfrint
45930994Sphkkldfind(struct proc* p, struct kldfind_args* uap)
46025537Sdfr{
46125537Sdfr    char* filename = NULL;
46225537Sdfr    linker_file_t lf;
46325537Sdfr    int error = 0;
46425537Sdfr
46530994Sphk    p->p_retval[0] = -1;
46625537Sdfr
46725537Sdfr    filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
46825537Sdfr    if (error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL))
46925537Sdfr	goto out;
47025537Sdfr
47125537Sdfr    lf = linker_find_file_by_name(filename);
47225537Sdfr    if (lf)
47330994Sphk	p->p_retval[0] = lf->id;
47425537Sdfr    else
47525537Sdfr	error = ENOENT;
47625537Sdfr
47725537Sdfrout:
47825537Sdfr    if (filename)
47925537Sdfr	free(filename, M_TEMP);
48025537Sdfr    return error;
48125537Sdfr}
48225537Sdfr
48325537Sdfrint
48430994Sphkkldnext(struct proc* p, struct kldnext_args* uap)
48525537Sdfr{
48625537Sdfr    linker_file_t lf;
48725537Sdfr    int error = 0;
48825537Sdfr
48925537Sdfr    if (SCARG(uap, fileid) == 0) {
49025537Sdfr	if (TAILQ_FIRST(&files))
49130994Sphk	    p->p_retval[0] = TAILQ_FIRST(&files)->id;
49225537Sdfr	else
49330994Sphk	    p->p_retval[0] = 0;
49425537Sdfr	return 0;
49525537Sdfr    }
49625537Sdfr
49725537Sdfr    lf = linker_find_file_by_id(SCARG(uap, fileid));
49825537Sdfr    if (lf) {
49925537Sdfr	if (TAILQ_NEXT(lf, link))
50030994Sphk	    p->p_retval[0] = TAILQ_NEXT(lf, link)->id;
50125537Sdfr	else
50230994Sphk	    p->p_retval[0] = 0;
50325537Sdfr    } else
50425537Sdfr	error = ENOENT;
50525537Sdfr
50625537Sdfr    return error;
50725537Sdfr}
50825537Sdfr
50925537Sdfrint
51030994Sphkkldstat(struct proc* p, struct kldstat_args* uap)
51125537Sdfr{
51225537Sdfr    linker_file_t lf;
51325537Sdfr    int error = 0;
51425537Sdfr    int version;
51525537Sdfr    struct kld_file_stat* stat;
51625537Sdfr    int namelen;
51725537Sdfr
51825537Sdfr    lf = linker_find_file_by_id(SCARG(uap, fileid));
51925537Sdfr    if (!lf) {
52025537Sdfr	error = ENOENT;
52125537Sdfr	goto out;
52225537Sdfr    }
52325537Sdfr
52425537Sdfr    stat = SCARG(uap, stat);
52525537Sdfr
52625537Sdfr    /*
52725537Sdfr     * Check the version of the user's structure.
52825537Sdfr     */
52925537Sdfr    if (error = copyin(&stat->version, &version, sizeof(version)))
53025537Sdfr	goto out;
53125537Sdfr    if (version != sizeof(struct kld_file_stat)) {
53225537Sdfr	error = EINVAL;
53325537Sdfr	goto out;
53425537Sdfr    }
53525537Sdfr
53625537Sdfr    namelen = strlen(lf->filename) + 1;
53725537Sdfr    if (namelen > MAXPATHLEN)
53825537Sdfr	namelen = MAXPATHLEN;
53925537Sdfr    if (error = copyout(lf->filename, &stat->name[0], namelen))
54025537Sdfr	goto out;
54125537Sdfr    if (error = copyout(&lf->refs, &stat->refs, sizeof(int)))
54225537Sdfr	goto out;
54325537Sdfr    if (error = copyout(&lf->id, &stat->id, sizeof(int)))
54425537Sdfr	goto out;
54525537Sdfr    if (error = copyout(&lf->address, &stat->address, sizeof(caddr_t)))
54625537Sdfr	goto out;
54725537Sdfr    if (error = copyout(&lf->size, &stat->size, sizeof(size_t)))
54825537Sdfr	goto out;
54925537Sdfr
55030994Sphk    p->p_retval[0] = 0;
55125537Sdfr
55225537Sdfrout:
55325537Sdfr    return error;
55425537Sdfr}
55525537Sdfr
55625537Sdfrint
55730994Sphkkldfirstmod(struct proc* p, struct kldfirstmod_args* uap)
55825537Sdfr{
55925537Sdfr    linker_file_t lf;
56025537Sdfr    int error = 0;
56125537Sdfr
56225537Sdfr    lf = linker_find_file_by_id(SCARG(uap, fileid));
56325537Sdfr    if (lf) {
56425537Sdfr	if (TAILQ_FIRST(&lf->modules))
56530994Sphk	    p->p_retval[0] = module_getid(TAILQ_FIRST(&lf->modules));
56625537Sdfr	else
56730994Sphk	    p->p_retval[0] = 0;
56825537Sdfr    } else
56925537Sdfr	error = ENOENT;
57025537Sdfr
57125537Sdfr    return error;
57225537Sdfr}
573