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