kern_linker.c revision 40162
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 * 2640162Speter * $Id: kern_linker.c,v 1.8 1998/10/10 00:07:53 peter 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 5032153SbdeMALLOC_DEFINE(M_LINKER, "kld", "kernel linker"); 5131324Sbdelinker_file_t linker_current_file; 5231324Sbde 5325537Sdfrstatic struct lock lock; /* lock for the file list */ 5425537Sdfrstatic linker_class_list_t classes; 5525537Sdfrstatic linker_file_list_t files; 5625537Sdfrstatic int next_file_id = 1; 5725537Sdfr 5825537Sdfrstatic void 5925537Sdfrlinker_init(void* arg) 6025537Sdfr{ 6125537Sdfr lockinit(&lock, PVM, "klink", 0, 0); 6225537Sdfr TAILQ_INIT(&classes); 6325537Sdfr TAILQ_INIT(&files); 6425537Sdfr} 6525537Sdfr 6640159SpeterSYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0); 6725537Sdfr 6825537Sdfrint 6925537Sdfrlinker_add_class(const char* desc, void* priv, 7025537Sdfr struct linker_class_ops* ops) 7125537Sdfr{ 7225537Sdfr linker_class_t lc; 7325537Sdfr 7425537Sdfr lc = malloc(sizeof(struct linker_class), M_LINKER, M_NOWAIT); 7525537Sdfr if (!lc) 7625537Sdfr return ENOMEM; 7725537Sdfr 7825537Sdfr lc->desc = desc; 7925537Sdfr lc->priv = priv; 8025537Sdfr lc->ops = ops; 8125537Sdfr TAILQ_INSERT_HEAD(&classes, lc, link); 8225537Sdfr 8325537Sdfr return 0; 8425537Sdfr} 8525537Sdfr 8625537Sdfrstatic void 8725537Sdfrlinker_file_sysinit(linker_file_t lf) 8825537Sdfr{ 8925537Sdfr struct linker_set* sysinits; 9025537Sdfr struct sysinit** sipp; 9125537Sdfr struct sysinit** xipp; 9225537Sdfr struct sysinit* save; 9340159Speter moduledata_t *moddata; 9425537Sdfr 9525537Sdfr KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n", 9625537Sdfr lf->filename)); 9725537Sdfr 9825537Sdfr sysinits = (struct linker_set*) 9925537Sdfr linker_file_lookup_symbol(lf, "sysinit_set", 0); 10040159Speter 10140159Speter KLD_DPF(FILE, ("linker_file_sysinit: SYSINITs %p\n", sysinits)); 10225537Sdfr if (!sysinits) 10325537Sdfr return; 10425537Sdfr 10540159Speter /* HACK ALERT! */ 10640159Speter for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) { 10740159Speter if ((*sipp)->func == module_register_init) { 10840159Speter moddata = (*sipp)->udata; 10940159Speter moddata->_file = lf; 11040159Speter } 11140159Speter } 11240159Speter 11325537Sdfr /* 11425537Sdfr * Perform a bubble sort of the system initialization objects by 11525537Sdfr * their subsystem (primary key) and order (secondary key). 11625537Sdfr * 11725537Sdfr * Since some things care about execution order, this is the 11825537Sdfr * operation which ensures continued function. 11925537Sdfr */ 12025537Sdfr for( sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) { 12125537Sdfr for( xipp = sipp + 1; *xipp; xipp++) { 12225537Sdfr if( (*sipp)->subsystem < (*xipp)->subsystem || 12325537Sdfr ( (*sipp)->subsystem == (*xipp)->subsystem && 12425537Sdfr (*sipp)->order < (*xipp)->order)) 12525537Sdfr continue; /* skip*/ 12625537Sdfr save = *sipp; 12725537Sdfr *sipp = *xipp; 12825537Sdfr *xipp = save; 12925537Sdfr } 13025537Sdfr } 13125537Sdfr 13225537Sdfr 13325537Sdfr /* 13425537Sdfr * Traverse the (now) ordered list of system initialization tasks. 13525537Sdfr * Perform each task, and continue on to the next task. 13625537Sdfr * 13725537Sdfr * The last item on the list is expected to be the scheduler, 13825537Sdfr * which will not return. 13925537Sdfr */ 14025537Sdfr for( sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) { 14125537Sdfr if( (*sipp)->subsystem == SI_SUB_DUMMY) 14225537Sdfr continue; /* skip dummy task(s)*/ 14325537Sdfr 14425537Sdfr switch( (*sipp)->type) { 14525537Sdfr case SI_TYPE_DEFAULT: 14625537Sdfr /* no special processing*/ 14725537Sdfr (*((*sipp)->func))( (*sipp)->udata); 14825537Sdfr break; 14925537Sdfr 15025537Sdfr case SI_TYPE_KTHREAD: 15131675Sdyson#if !defined(SMP) 15225537Sdfr /* kernel thread*/ 15331675Sdyson if (fork1(&proc0, RFFDG|RFPROC|RFMEM)) 15431675Sdyson panic("fork kernel thread"); 15531675Sdyson cpu_set_fork_handler(pfind(proc0.p_retval[0]), 15631675Sdyson (*sipp)->func, (*sipp)->udata); 15731675Sdyson break; 15831675Sdyson#endif 15931675Sdyson 16031675Sdyson case SI_TYPE_KPROCESS: 16131675Sdyson /* kernel thread*/ 16231675Sdyson if (fork1(&proc0, RFFDG|RFPROC)) 16325537Sdfr panic("fork kernel process"); 16430994Sphk cpu_set_fork_handler(pfind(proc0.p_retval[0]), 16530994Sphk (*sipp)->func, (*sipp)->udata); 16625537Sdfr break; 16725537Sdfr 16825537Sdfr default: 16925537Sdfr panic( "linker_file_sysinit: unrecognized init type"); 17025537Sdfr } 17125537Sdfr } 17225537Sdfr} 17325537Sdfr 17425537Sdfrint 17525537Sdfrlinker_load_file(const char* filename, linker_file_t* result) 17625537Sdfr{ 17725537Sdfr linker_class_t lc; 17825537Sdfr linker_file_t lf; 17925537Sdfr int error = 0; 18025537Sdfr 18125537Sdfr lf = linker_find_file_by_name(filename); 18225537Sdfr if (lf) { 18325537Sdfr KLD_DPF(FILE, ("linker_load_file: file %s is already loaded, incrementing refs\n", filename)); 18425537Sdfr *result = lf; 18525537Sdfr lf->refs++; 18625537Sdfr goto out; 18725537Sdfr } 18825537Sdfr 18925537Sdfr lf = NULL; 19025537Sdfr for (lc = TAILQ_FIRST(&classes); lc; lc = TAILQ_NEXT(lc, link)) { 19125537Sdfr KLD_DPF(FILE, ("linker_load_file: trying to load %s as %s\n", 19225537Sdfr filename, lc->desc)); 19325537Sdfr if (error = lc->ops->load_file(filename, &lf)) 19425537Sdfr goto out; 19525537Sdfr if (lf) { 19625537Sdfr linker_file_sysinit(lf); 19725537Sdfr 19825537Sdfr *result = lf; 19925537Sdfr goto out; 20025537Sdfr } 20125537Sdfr } 20225537Sdfr error = ENOEXEC; /* format not recognised */ 20325537Sdfr 20425537Sdfrout: 20525537Sdfr return error; 20625537Sdfr} 20725537Sdfr 20825537Sdfrlinker_file_t 20925537Sdfrlinker_find_file_by_name(const char* filename) 21025537Sdfr{ 21125537Sdfr linker_file_t lf = 0; 21225537Sdfr 21325537Sdfr lockmgr(&lock, LK_SHARED, 0, curproc); 21425537Sdfr for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) 21525537Sdfr if (!strcmp(lf->filename, filename)) 21625537Sdfr break; 21725537Sdfr lockmgr(&lock, LK_RELEASE, 0, curproc); 21825537Sdfr 21925537Sdfr return lf; 22025537Sdfr} 22125537Sdfr 22225537Sdfrlinker_file_t 22325537Sdfrlinker_find_file_by_id(int fileid) 22425537Sdfr{ 22525537Sdfr linker_file_t lf = 0; 22625537Sdfr 22725537Sdfr lockmgr(&lock, LK_SHARED, 0, curproc); 22825537Sdfr for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) 22925537Sdfr if (lf->id == fileid) 23025537Sdfr break; 23125537Sdfr lockmgr(&lock, LK_RELEASE, 0, curproc); 23225537Sdfr 23325537Sdfr return lf; 23425537Sdfr} 23525537Sdfr 23625537Sdfrlinker_file_t 23740159Speterlinker_make_file(const char* pathname, void* priv, struct linker_file_ops* ops) 23825537Sdfr{ 23925537Sdfr linker_file_t lf = 0; 24025537Sdfr int namelen; 24140159Speter const char *filename; 24225537Sdfr 24340159Speter filename = rindex(pathname, '/'); 24440159Speter if (filename && filename[1]) 24540159Speter filename++; 24640159Speter else 24740159Speter filename = pathname; 24840159Speter 24925537Sdfr KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename)); 25025537Sdfr lockmgr(&lock, LK_EXCLUSIVE|LK_RETRY, 0, curproc); 25125537Sdfr namelen = strlen(filename) + 1; 25225537Sdfr lf = malloc(sizeof(struct linker_file) + namelen, M_LINKER, M_WAITOK); 25325537Sdfr if (!lf) 25425537Sdfr goto out; 25525537Sdfr 25625537Sdfr lf->refs = 1; 25725537Sdfr lf->userrefs = 0; 25825537Sdfr lf->filename = (char*) (lf + 1); 25925537Sdfr strcpy(lf->filename, filename); 26025537Sdfr lf->id = next_file_id++; 26125537Sdfr lf->ndeps = 0; 26225537Sdfr lf->deps = NULL; 26325537Sdfr STAILQ_INIT(&lf->common); 26425537Sdfr TAILQ_INIT(&lf->modules); 26525537Sdfr 26625537Sdfr lf->priv = priv; 26725537Sdfr lf->ops = ops; 26825537Sdfr TAILQ_INSERT_TAIL(&files, lf, link); 26925537Sdfr 27025537Sdfrout: 27125537Sdfr lockmgr(&lock, LK_RELEASE, 0, curproc); 27225537Sdfr return lf; 27325537Sdfr} 27425537Sdfr 27525537Sdfrint 27625537Sdfrlinker_file_unload(linker_file_t file) 27725537Sdfr{ 27825537Sdfr module_t mod, next; 27925537Sdfr struct common_symbol* cp; 28025537Sdfr int error = 0; 28125537Sdfr int i; 28225537Sdfr 28340159Speter KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs)); 28425537Sdfr lockmgr(&lock, LK_EXCLUSIVE|LK_RETRY, 0, curproc); 28525537Sdfr if (file->refs == 1) { 28625537Sdfr KLD_DPF(FILE, ("linker_file_unload: file is unloading, informing modules\n")); 28725537Sdfr /* 28825537Sdfr * Inform any modules associated with this file. 28925537Sdfr */ 29025537Sdfr for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) { 29125537Sdfr next = module_getfnext(mod); 29225537Sdfr 29325537Sdfr /* 29425537Sdfr * Give the module a chance to veto the unload. 29525537Sdfr */ 29625537Sdfr if (error = module_unload(mod)) { 29725537Sdfr KLD_DPF(FILE, ("linker_file_unload: module %x vetoes unload\n", 29825537Sdfr mod)); 29925537Sdfr lockmgr(&lock, LK_RELEASE, 0, curproc); 30025537Sdfr goto out; 30125537Sdfr } 30225537Sdfr 30325537Sdfr module_release(mod); 30425537Sdfr } 30525537Sdfr } 30625537Sdfr 30725537Sdfr file->refs--; 30825537Sdfr if (file->refs > 0) { 30925537Sdfr lockmgr(&lock, LK_RELEASE, 0, curproc); 31025537Sdfr goto out; 31125537Sdfr } 31225537Sdfr 31325537Sdfr TAILQ_REMOVE(&files, file, link); 31425537Sdfr lockmgr(&lock, LK_RELEASE, 0, curproc); 31540159Speter 31625537Sdfr for (i = 0; i < file->ndeps; i++) 31725537Sdfr linker_file_unload(file->deps[i]); 31825537Sdfr free(file->deps, M_LINKER); 31925537Sdfr 32025537Sdfr for (cp = STAILQ_FIRST(&file->common); cp; 32125537Sdfr cp = STAILQ_FIRST(&file->common)) { 32225537Sdfr STAILQ_REMOVE(&file->common, cp, common_symbol, link); 32325537Sdfr free(cp, M_LINKER); 32425537Sdfr } 32525537Sdfr 32625537Sdfr file->ops->unload(file); 32725537Sdfr free(file, M_LINKER); 32825537Sdfr 32925537Sdfrout: 33025537Sdfr return error; 33125537Sdfr} 33225537Sdfr 33325537Sdfrint 33425537Sdfrlinker_file_add_dependancy(linker_file_t file, linker_file_t dep) 33525537Sdfr{ 33625537Sdfr linker_file_t* newdeps; 33725537Sdfr 33825537Sdfr newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t*), 33925537Sdfr M_LINKER, M_WAITOK); 34025537Sdfr if (newdeps == NULL) 34125537Sdfr return ENOMEM; 34225537Sdfr 34325537Sdfr if (file->deps) { 34425537Sdfr bcopy(file->deps, newdeps, file->ndeps * sizeof(linker_file_t*)); 34525537Sdfr free(file->deps, M_LINKER); 34625537Sdfr } 34725537Sdfr file->deps = newdeps; 34825537Sdfr file->deps[file->ndeps] = dep; 34925537Sdfr file->ndeps++; 35025537Sdfr 35125537Sdfr return 0; 35225537Sdfr} 35325537Sdfr 35425537Sdfrcaddr_t 35525537Sdfrlinker_file_lookup_symbol(linker_file_t file, const char* name, int deps) 35625537Sdfr{ 35738275Sdfr linker_sym_t sym; 35838275Sdfr linker_symval_t symval; 35925537Sdfr caddr_t address; 36025537Sdfr size_t common_size = 0; 36125537Sdfr int i; 36225537Sdfr 36340159Speter KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d\n", 36425537Sdfr file, name, deps)); 36525537Sdfr 36638275Sdfr if (file->ops->lookup_symbol(file, name, &sym) == 0) { 36738275Sdfr file->ops->symbol_values(file, sym, &symval); 36838275Sdfr if (symval.value == 0) 36925537Sdfr /* 37025537Sdfr * For commons, first look them up in the dependancies and 37125537Sdfr * only allocate space if not found there. 37225537Sdfr */ 37338275Sdfr common_size = symval.size; 37440159Speter else { 37540159Speter KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol.value=%x\n", symval.value)); 37638275Sdfr return symval.value; 37740159Speter } 37838275Sdfr } 37925537Sdfr 38025537Sdfr if (deps) 38125537Sdfr for (i = 0; i < file->ndeps; i++) { 38225537Sdfr address = linker_file_lookup_symbol(file->deps[i], name, 0); 38340159Speter if (address) { 38440159Speter KLD_DPF(SYM, ("linker_file_lookup_symbol: deps value=%x\n", address)); 38525537Sdfr return address; 38640159Speter } 38725537Sdfr } 38825537Sdfr 38925537Sdfr if (common_size > 0) { 39025537Sdfr /* 39125537Sdfr * This is a common symbol which was not found in the 39225537Sdfr * dependancies. We maintain a simple common symbol table in 39325537Sdfr * the file object. 39425537Sdfr */ 39525537Sdfr struct common_symbol* cp; 39625537Sdfr 39725537Sdfr for (cp = STAILQ_FIRST(&file->common); cp; 39825537Sdfr cp = STAILQ_NEXT(cp, link)) 39940159Speter if (!strcmp(cp->name, name)) { 40040159Speter KLD_DPF(SYM, ("linker_file_lookup_symbol: old common value=%x\n", cp->address)); 40125537Sdfr return cp->address; 40240159Speter } 40325537Sdfr 40425537Sdfr /* 40525537Sdfr * Round the symbol size up to align. 40625537Sdfr */ 40725537Sdfr common_size = (common_size + sizeof(int) - 1) & -sizeof(int); 40825537Sdfr cp = malloc(sizeof(struct common_symbol) 40925537Sdfr + common_size 41025537Sdfr + strlen(name) + 1, 41125537Sdfr M_LINKER, M_WAITOK); 41240159Speter if (!cp) { 41340159Speter KLD_DPF(SYM, ("linker_file_lookup_symbol: nomem\n")); 41425537Sdfr return 0; 41540159Speter } 41625537Sdfr 41725537Sdfr cp->address = (caddr_t) (cp + 1); 41825537Sdfr cp->name = cp->address + common_size; 41925537Sdfr strcpy(cp->name, name); 42025537Sdfr bzero(cp->address, common_size); 42125537Sdfr STAILQ_INSERT_TAIL(&file->common, cp, link); 42225537Sdfr 42340159Speter KLD_DPF(SYM, ("linker_file_lookup_symbol: new common value=%x\n", cp->address)); 42425537Sdfr return cp->address; 42525537Sdfr } 42625537Sdfr 42740159Speter KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n")); 42825537Sdfr return 0; 42925537Sdfr} 43025537Sdfr 43140159Speter#ifdef DDB 43225537Sdfr/* 43340159Speter * DDB Helpers. DDB has to look across multiple files with their own 43440159Speter * symbol tables and string tables. 43540159Speter * 43640159Speter * Note that we do not obey list locking protocols here. We really don't 43740159Speter * need DDB to hang because somebody's got the lock held. We'll take the 43840159Speter * chance that the files list is inconsistant instead. 43940159Speter */ 44040159Speter 44140159Speterint 44240159Speterlinker_ddb_lookup(char *symstr, linker_sym_t *sym) 44340159Speter{ 44440159Speter linker_file_t lf; 44540159Speter 44640159Speter for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) { 44740159Speter if (lf->ops->lookup_symbol(lf, symstr, sym) == 0) 44840159Speter return 0; 44940159Speter } 45040159Speter return ENOENT; 45140159Speter} 45240159Speter 45340159Speterint 45440159Speterlinker_ddb_search_symbol(caddr_t value, linker_sym_t *sym, long *diffp) 45540159Speter{ 45640159Speter linker_file_t lf; 45740159Speter u_long off = (u_long)value; 45840159Speter u_long diff, bestdiff; 45940159Speter linker_sym_t best; 46040159Speter linker_sym_t es; 46140159Speter 46240159Speter best = 0; 46340159Speter bestdiff = off; 46440159Speter for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) { 46540159Speter if (lf->ops->search_symbol(lf, value, &es, &diff) != 0) 46640159Speter continue; 46740159Speter if (es != 0 && diff < bestdiff) { 46840159Speter best = es; 46940159Speter bestdiff = diff; 47040159Speter } 47140159Speter if (bestdiff == 0) 47240159Speter break; 47340159Speter } 47440159Speter if (best) { 47540159Speter *sym = best; 47640159Speter *diffp = bestdiff; 47740159Speter return 0; 47840159Speter } else { 47940159Speter *sym = 0; 48040159Speter *diffp = off; 48140159Speter return ENOENT; 48240159Speter } 48340159Speter} 48440159Speter 48540159Speterint 48640159Speterlinker_ddb_symbol_values(linker_sym_t sym, linker_symval_t *symval) 48740159Speter{ 48840159Speter linker_file_t lf; 48940159Speter 49040159Speter for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) { 49140159Speter if (lf->ops->symbol_values(lf, sym, symval) == 0) 49240159Speter return 0; 49340159Speter } 49440159Speter return ENOENT; 49540159Speter} 49640159Speter 49740159Speter#endif 49840159Speter 49940159Speter/* 50025537Sdfr * Syscalls. 50125537Sdfr */ 50225537Sdfr 50325537Sdfrint 50430994Sphkkldload(struct proc* p, struct kldload_args* uap) 50525537Sdfr{ 50625537Sdfr char* filename = NULL; 50725537Sdfr linker_file_t lf; 50825537Sdfr int error = 0; 50925537Sdfr 51030994Sphk p->p_retval[0] = -1; 51125537Sdfr 51225537Sdfr if (securelevel > 0) 51325537Sdfr return EPERM; 51425537Sdfr 51525537Sdfr if (error = suser(p->p_ucred, &p->p_acflag)) 51625537Sdfr return error; 51725537Sdfr 51825537Sdfr filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 51925537Sdfr if (error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL)) 52025537Sdfr goto out; 52125537Sdfr 52225537Sdfr if (error = linker_load_file(uap->file, &lf)) 52325537Sdfr goto out; 52425537Sdfr 52525537Sdfr lf->userrefs++; 52630994Sphk p->p_retval[0] = lf->id; 52740159Speter 52825537Sdfrout: 52925537Sdfr if (filename) 53025537Sdfr free(filename, M_TEMP); 53125537Sdfr return error; 53225537Sdfr} 53325537Sdfr 53425537Sdfrint 53530994Sphkkldunload(struct proc* p, struct kldunload_args* uap) 53625537Sdfr{ 53725537Sdfr linker_file_t lf; 53825537Sdfr int error = 0; 53925537Sdfr 54025537Sdfr if (securelevel > 0) 54125537Sdfr return EPERM; 54225537Sdfr 54325537Sdfr if (error = suser(p->p_ucred, &p->p_acflag)) 54425537Sdfr return error; 54525537Sdfr 54625537Sdfr lf = linker_find_file_by_id(SCARG(uap, fileid)); 54725537Sdfr if (lf) { 54825537Sdfr KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs)); 54925537Sdfr if (lf->userrefs == 0) { 55025537Sdfr printf("linkerunload: attempt to unload file which was not loaded by user\n"); 55125537Sdfr error = EBUSY; 55225537Sdfr goto out; 55325537Sdfr } 55425537Sdfr lf->userrefs--; 55525537Sdfr error = linker_file_unload(lf); 55625537Sdfr } else 55725537Sdfr error = ENOENT; 55825537Sdfr 55925537Sdfrout: 56025537Sdfr return error; 56125537Sdfr} 56225537Sdfr 56325537Sdfrint 56430994Sphkkldfind(struct proc* p, struct kldfind_args* uap) 56525537Sdfr{ 56625537Sdfr char* filename = NULL; 56725537Sdfr linker_file_t lf; 56825537Sdfr int error = 0; 56925537Sdfr 57030994Sphk p->p_retval[0] = -1; 57125537Sdfr 57225537Sdfr filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 57325537Sdfr if (error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL)) 57425537Sdfr goto out; 57525537Sdfr 57625537Sdfr lf = linker_find_file_by_name(filename); 57725537Sdfr if (lf) 57830994Sphk p->p_retval[0] = lf->id; 57925537Sdfr else 58025537Sdfr error = ENOENT; 58140159Speter 58225537Sdfrout: 58325537Sdfr if (filename) 58425537Sdfr free(filename, M_TEMP); 58525537Sdfr return error; 58625537Sdfr} 58725537Sdfr 58825537Sdfrint 58930994Sphkkldnext(struct proc* p, struct kldnext_args* uap) 59025537Sdfr{ 59125537Sdfr linker_file_t lf; 59225537Sdfr int error = 0; 59325537Sdfr 59425537Sdfr if (SCARG(uap, fileid) == 0) { 59525537Sdfr if (TAILQ_FIRST(&files)) 59630994Sphk p->p_retval[0] = TAILQ_FIRST(&files)->id; 59725537Sdfr else 59830994Sphk p->p_retval[0] = 0; 59925537Sdfr return 0; 60025537Sdfr } 60140159Speter 60225537Sdfr lf = linker_find_file_by_id(SCARG(uap, fileid)); 60325537Sdfr if (lf) { 60425537Sdfr if (TAILQ_NEXT(lf, link)) 60530994Sphk p->p_retval[0] = TAILQ_NEXT(lf, link)->id; 60625537Sdfr else 60730994Sphk p->p_retval[0] = 0; 60825537Sdfr } else 60925537Sdfr error = ENOENT; 61025537Sdfr 61125537Sdfr return error; 61225537Sdfr} 61325537Sdfr 61425537Sdfrint 61530994Sphkkldstat(struct proc* p, struct kldstat_args* uap) 61625537Sdfr{ 61725537Sdfr linker_file_t lf; 61825537Sdfr int error = 0; 61925537Sdfr int version; 62025537Sdfr struct kld_file_stat* stat; 62125537Sdfr int namelen; 62225537Sdfr 62325537Sdfr lf = linker_find_file_by_id(SCARG(uap, fileid)); 62425537Sdfr if (!lf) { 62525537Sdfr error = ENOENT; 62625537Sdfr goto out; 62725537Sdfr } 62825537Sdfr 62925537Sdfr stat = SCARG(uap, stat); 63025537Sdfr 63125537Sdfr /* 63225537Sdfr * Check the version of the user's structure. 63325537Sdfr */ 63425537Sdfr if (error = copyin(&stat->version, &version, sizeof(version))) 63525537Sdfr goto out; 63625537Sdfr if (version != sizeof(struct kld_file_stat)) { 63725537Sdfr error = EINVAL; 63825537Sdfr goto out; 63925537Sdfr } 64025537Sdfr 64125537Sdfr namelen = strlen(lf->filename) + 1; 64225537Sdfr if (namelen > MAXPATHLEN) 64325537Sdfr namelen = MAXPATHLEN; 64425537Sdfr if (error = copyout(lf->filename, &stat->name[0], namelen)) 64525537Sdfr goto out; 64625537Sdfr if (error = copyout(&lf->refs, &stat->refs, sizeof(int))) 64725537Sdfr goto out; 64825537Sdfr if (error = copyout(&lf->id, &stat->id, sizeof(int))) 64925537Sdfr goto out; 65025537Sdfr if (error = copyout(&lf->address, &stat->address, sizeof(caddr_t))) 65125537Sdfr goto out; 65225537Sdfr if (error = copyout(&lf->size, &stat->size, sizeof(size_t))) 65325537Sdfr goto out; 65425537Sdfr 65530994Sphk p->p_retval[0] = 0; 65625537Sdfr 65725537Sdfrout: 65825537Sdfr return error; 65925537Sdfr} 66025537Sdfr 66125537Sdfrint 66230994Sphkkldfirstmod(struct proc* p, struct kldfirstmod_args* uap) 66325537Sdfr{ 66425537Sdfr linker_file_t lf; 66525537Sdfr int error = 0; 66625537Sdfr 66725537Sdfr lf = linker_find_file_by_id(SCARG(uap, fileid)); 66825537Sdfr if (lf) { 66925537Sdfr if (TAILQ_FIRST(&lf->modules)) 67030994Sphk p->p_retval[0] = module_getid(TAILQ_FIRST(&lf->modules)); 67125537Sdfr else 67230994Sphk p->p_retval[0] = 0; 67325537Sdfr } else 67425537Sdfr error = ENOENT; 67525537Sdfr 67625537Sdfr return error; 67725537Sdfr} 67840159Speter 67940159Speter/* 68040159Speter * Preloaded module support 68140159Speter */ 68240159Speter 68340159Speterstatic void 68440159Speterlinker_preload(void* arg) 68540159Speter{ 68640159Speter caddr_t modptr; 68740159Speter char *modname; 68840162Speter char *modtype; 68940159Speter linker_file_t lf; 69040159Speter linker_class_t lc; 69140159Speter int error; 69240159Speter struct linker_set *sysinits; 69340159Speter struct sysinit **sipp; 69440159Speter moduledata_t *moddata; 69540159Speter 69640159Speter modptr = NULL; 69740159Speter while ((modptr = preload_search_next_name(modptr)) != NULL) { 69840159Speter modname = (char *)preload_search_info(modptr, MODINFO_NAME); 69940162Speter modtype = (char *)preload_search_info(modptr, MODINFO_TYPE); 70040159Speter if (modname == NULL) { 70140159Speter printf("Preloaded module at 0x%p does not have a name!\n", modptr); 70240159Speter continue; 70340159Speter } 70440162Speter if (modtype == NULL) { 70540162Speter printf("Preloaded module at 0x%p does not have a type!\n", modptr); 70640162Speter continue; 70740162Speter } 70840162Speter printf("Preloaded %s \"%s\" at 0x%p.\n", modtype, modname, modptr); 70940159Speter lf = linker_find_file_by_name(modname); 71040159Speter if (lf) { 71140159Speter lf->userrefs++; 71240159Speter continue; 71340159Speter } 71440159Speter lf = NULL; 71540159Speter for (lc = TAILQ_FIRST(&classes); lc; lc = TAILQ_NEXT(lc, link)) { 71640159Speter error = lc->ops->load_file(modname, &lf); 71740159Speter if (error) { 71840159Speter lf = NULL; 71940159Speter break; 72040159Speter } 72140159Speter } 72240159Speter if (lf) { 72340159Speter lf->userrefs++; 72440159Speter 72540159Speter sysinits = (struct linker_set*) 72640159Speter linker_file_lookup_symbol(lf, "sysinit_set", 0); 72740159Speter if (sysinits) { 72840159Speter /* HACK ALERT! 72940159Speter * This is to set the sysinit moduledata so that the module 73040159Speter * can attach itself to the correct containing file. 73140159Speter * The sysinit could be run at *any* time. 73240159Speter */ 73340159Speter for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) { 73440159Speter if ((*sipp)->func == module_register_init) { 73540159Speter moddata = (*sipp)->udata; 73640159Speter moddata->_file = lf; 73740159Speter } 73840159Speter } 73940159Speter sysinit_add((struct sysinit **)sysinits->ls_items); 74040159Speter } 74140159Speter 74240159Speter break; 74340159Speter } 74440159Speter } 74540159Speter} 74640159Speter 74740159SpeterSYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0); 74840159Speter 74940159Speter/* 75040159Speter * Search for a not-loaded module by name. 75140159Speter * 75240159Speter * Modules may be found in the following locations: 75340159Speter * 75440159Speter * - preloaded (result is just the module name) 75540159Speter * - on disk (result is full path to module) 75640159Speter * 75740159Speter * If the module name is qualified in any way (contains path, etc.) 75840159Speter * the we simply return a copy of it. 75940159Speter * 76040159Speter * The search path can be manipulated via sysctl. Note that we use the ';' 76140159Speter * character as a separator to be consistent with the bootloader. 76240159Speter */ 76340159Speter 76440159Speterstatic char linker_path[MAXPATHLEN + 1] = "/;/boot/;/modules/"; 76540159Speter 76640159SpeterSYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path, 76740159Speter sizeof(linker_path), "module load search path"); 76840159Speter 76940159Speterstatic char * 77040159Speterlinker_strdup(const char *str) 77140159Speter{ 77240159Speter char *result; 77340159Speter 77440159Speter if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL) 77540159Speter strcpy(result, str); 77640159Speter return(result); 77740159Speter} 77840159Speter 77940159Speterchar * 78040159Speterlinker_search_path(const char *name) 78140159Speter{ 78240159Speter struct nameidata nd; 78340159Speter struct proc *p = curproc; /* XXX */ 78440159Speter char *cp, *ep, *result; 78540159Speter int error; 78640159Speter enum vtype type; 78740159Speter 78840159Speter /* qualified at all? */ 78940159Speter if (index(name, '/')) 79040159Speter return(linker_strdup(name)); 79140159Speter 79240159Speter /* traverse the linker path */ 79340159Speter cp = linker_path; 79440159Speter for (;;) { 79540159Speter 79640159Speter /* find the end of this component */ 79740159Speter for (ep = cp; (*ep != 0) && (*ep != ';'); ep++) 79840159Speter ; 79940159Speter result = malloc((strlen(name) + (ep - cp) + 1), M_LINKER, M_WAITOK); 80040159Speter if (result == NULL) /* actually ENOMEM */ 80140159Speter return(NULL); 80240159Speter 80340159Speter strncpy(result, cp, ep - cp); 80440159Speter strcpy(result + (ep - cp), name); 80540159Speter 80640159Speter /* 80740159Speter * Attempt to open the file, and return the path if we succeed and it's 80840159Speter * a regular file. 80940159Speter */ 81040159Speter NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, p); 81140159Speter error = vn_open(&nd, FREAD, 0); 81240159Speter if (error == 0) { 81340159Speter type = nd.ni_vp->v_type; 81440159Speter VOP_UNLOCK(nd.ni_vp, 0, p); 81540159Speter vn_close(nd.ni_vp, FREAD, p->p_ucred, p); 81640159Speter if (type == VREG) 81740159Speter return(result); 81840159Speter } 81940159Speter free(result, M_LINKER); 82040159Speter 82140159Speter if (*ep == 0) 82240159Speter break; 82340159Speter cp = ep + 1; 82440159Speter } 82540159Speter return(NULL); 82640159Speter} 827