Fix module loading for vkernel.
[dragonfly.git] / sys / kern / kern_linker.c
index a7ec706..c1159f3 100644 (file)
@@ -24,7 +24,7 @@
  * SUCH DAMAGE.
  *
  * $FreeBSD: src/sys/kern/kern_linker.c,v 1.41.2.3 2001/11/21 17:50:35 luigi Exp $
- * $DragonFly: src/sys/kern/kern_linker.c,v 1.30 2006/09/05 03:48:12 dillon Exp $
+ * $DragonFly: src/sys/kern/kern_linker.c,v 1.38 2007/06/07 22:58:11 corecode Exp $
  */
 
 #include "opt_ddb.h"
 
 #include <vm/vm_zone.h>
 
+#ifdef _KERNEL_VIRTUAL
+#include <dlfcn.h>
+#endif
+
 #ifdef KLD_DEBUG
 int kld_debug = 0;
 #endif
@@ -71,7 +75,7 @@ linker_init(void* arg)
     TAILQ_INIT(&linker_files);
 }
 
-SYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0);
+SYSINIT(linker, SI_BOOT2_KLD, SI_ORDER_FIRST, linker_init, 0);
 
 int
 linker_add_class(const char* desc, void* priv,
@@ -114,7 +118,7 @@ linker_file_sysinit(linker_file_t lf)
            moddata = (*sipp)->udata;
            error = module_register(moddata, lf);
            if (error) {
-               printf("linker_file_sysinit \"%s\" failed to register! %d\n",
+               kprintf("linker_file_sysinit \"%s\" failed to register! %d\n",
                    lf->filename, error);
                return error;
            }
@@ -146,7 +150,7 @@ linker_file_sysinit(linker_file_t lf)
      * Perform each task, and continue on to the next task.
      */
     for (sipp = start; sipp < stop; sipp++) {
-       if ((*sipp)->subsystem == SI_SUB_DUMMY)
+       if ((*sipp)->subsystem == SI_SPECIAL_DUMMY)
            continue;   /* skip dummy task(s)*/
 
        /* Call function */
@@ -194,7 +198,7 @@ linker_file_sysuninit(linker_file_t lf)
      * Perform each task, and continue on to the next task.
      */
     for (sipp = start; sipp < stop; sipp++) {
-       if ((*sipp)->subsystem == SI_SUB_DUMMY)
+       if ((*sipp)->subsystem == SI_SPECIAL_DUMMY)
            continue;   /* skip dummy task(s)*/
 
        /* Call function */
@@ -239,7 +243,7 @@ linker_load_file(const char* filename, linker_file_t* result)
     char *koname = NULL;
 
     /* Refuse to load modules if securelevel raised */
-    if (securelevel > 0)
+    if (securelevel > 0 || kernel_mem_readonly)
        return EPERM; 
 
     lf = linker_find_file_by_name(filename);
@@ -261,7 +265,7 @@ linker_load_file(const char* filename, linker_file_t* result)
        error = ENOMEM;
        goto out;
     }
-    sprintf(koname, "%s.ko", filename);
+    ksprintf(koname, "%s.ko", filename);
     lf = NULL;
     foundfile = 0;
     for (lc = TAILQ_FIRST(&classes); lc; lc = TAILQ_NEXT(lc, link)) {
@@ -324,7 +328,7 @@ linker_find_file_by_name(const char* filename)
     koname = kmalloc(strlen(filename) + 4, M_LINKER, M_WAITOK);
     if (koname == NULL)
        goto out;
-    sprintf(koname, "%s.ko", filename);
+    ksprintf(koname, "%s.ko", filename);
 
     lockmgr(&lock, LK_SHARED);
     for (lf = TAILQ_FIRST(&linker_files); lf; lf = TAILQ_NEXT(lf, link)) {
@@ -405,7 +409,7 @@ linker_file_unload(linker_file_t file)
     int i;
 
     /* Refuse to unload modules if securelevel raised */
-    if (securelevel > 0)
+    if (securelevel > 0 || kernel_mem_readonly)
        return EPERM; 
 
     KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs));
@@ -453,7 +457,7 @@ linker_file_unload(linker_file_t file)
             mod; 
             mod = module_getfnext(mod)
        ) {
-           printf("linker_file_unload: module %p still has refs!\n", mod);
+           kprintf("linker_file_unload: module %p still has refs!\n", mod);
        }
        --file->refs;
     }
@@ -622,6 +626,14 @@ linker_file_lookup_symbol(linker_file_t file, const char* name, int deps, caddr_
        return 0;
     }
 
+#ifdef _KERNEL_VIRTUAL
+    *raddr = dlsym(RTLD_NEXT, name);
+    if (*raddr != NULL) {
+       KLD_DPF(SYM, ("linker_file_lookup_symbol: found dlsym=%x\n", *raddr));
+       return 0;
+    }
+#endif
+
     KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n"));
     return ENOENT;
 }
@@ -708,7 +720,7 @@ sys_kldload(struct kldload_args *uap)
 
     uap->sysmsg_result = -1;
 
-    if (securelevel > 0)       /* redundant, but that's OK */
+    if (securelevel > 0 || kernel_mem_readonly)        /* redundant, but that's OK */
        return EPERM;
 
     if ((error = suser(td)) != 0)
@@ -748,7 +760,7 @@ sys_kldunload(struct kldunload_args *uap)
     linker_file_t lf;
     int error = 0;
 
-    if (securelevel > 0)       /* redundant, but that's OK */
+    if (securelevel > 0 || kernel_mem_readonly)        /* redundant, but that's OK */
        return EPERM;
 
     if ((error = suser(td)) != 0)
@@ -758,7 +770,7 @@ sys_kldunload(struct kldunload_args *uap)
     if (lf) {
        KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs));
        if (lf->userrefs == 0) {
-           printf("linkerunload: attempt to unload file that was loaded by the kernel\n");
+           kprintf("linkerunload: attempt to unload file that was loaded by the kernel\n");
            error = EBUSY;
            goto out;
        }
@@ -1004,11 +1016,11 @@ linker_preload(void* arg)
        modname = (char *)preload_search_info(modptr, MODINFO_NAME);
        modtype = (char *)preload_search_info(modptr, MODINFO_TYPE);
        if (modname == NULL) {
-           printf("Preloaded module at %p does not have a name!\n", modptr);
+           kprintf("Preloaded module at %p does not have a name!\n", modptr);
            continue;
        }
        if (modtype == NULL) {
-           printf("Preloaded module at %p does not have a type!\n", modptr);
+           kprintf("Preloaded module at %p does not have a type!\n", modptr);
            continue;
        }
 
@@ -1016,12 +1028,12 @@ linker_preload(void* arg)
         * This is a hack at the moment, but what's in FreeBSD-5 is even 
         * worse so I'd rather the hack.
         */
-       printf("Preloaded %s \"%s\" at %p", modtype, modname, modptr);
+       kprintf("Preloaded %s \"%s\" at %p", modtype, modname, modptr);
        if (find_mod_metadata(modname)) {
-           printf(" (ignored, already in static kernel)\n");
+           kprintf(" (ignored, already in static kernel)\n");
            continue;
        }
-       printf(".\n");
+       kprintf(".\n");
 
        lf = linker_find_file_by_name(modname);
        if (lf) {
@@ -1051,7 +1063,7 @@ linker_preload(void* arg)
                        moddata = (*sipp)->udata;
                        error = module_register(moddata, lf);
                        if (error)
-                           printf("Preloaded %s \"%s\" failed to register: %d\n",
+                           kprintf("Preloaded %s \"%s\" failed to register: %d\n",
                                modtype, modname, error);
                    }
                }
@@ -1062,7 +1074,7 @@ linker_preload(void* arg)
     }
 }
 
-SYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0);
+SYSINIT(preload, SI_BOOT2_KLD, SI_ORDER_MIDDLE, linker_preload, 0);
 
 /*
  * Search for a not-loaded module by name.
@@ -1079,10 +1091,11 @@ SYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0);
  * character as a separator to be consistent with the bootloader.
  */
 
-static char linker_path[MAXPATHLEN] = "/;/boot/;/modules/";
+static char linker_path[MAXPATHLEN] = "/;/boot;/modules";
 
 SYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path,
              sizeof(linker_path), "module load search path");
+TUNABLE_STR("module_path", linker_path, sizeof(linker_path));
 
 static char *
 linker_strdup(const char *str)
@@ -1099,6 +1112,8 @@ linker_search_path(const char *name)
 {
     struct nlookupdata nd;
     char               *cp, *ep, *result;
+    size_t             name_len, prefix_len;
+    int                        sep;
     int                        error;
     enum vtype         type;
 
@@ -1108,17 +1123,28 @@ linker_search_path(const char *name)
 
     /* traverse the linker path */
     cp = linker_path;
+    name_len = strlen(name);
     for (;;) {
 
        /* find the end of this component */
        for (ep = cp; (*ep != 0) && (*ep != ';'); ep++)
            ;
-       result = kmalloc((strlen(name) + (ep - cp) + 1), M_LINKER, M_WAITOK);
-       if (result == NULL)     /* actually ENOMEM */
-           return(NULL);
+       prefix_len = ep - cp;
+       /* if this component doesn't end with a slash, add one */
+       if (ep == cp || *(ep - 1) != '/')
+           sep = 1;
+       else
+           sep = 0;
+
+       /*
+        * +2 : possible separator, plus terminator.
+        */
+       result = kmalloc(prefix_len + name_len + 2, M_LINKER, M_WAITOK);
 
-       strncpy(result, cp, ep - cp);
-       strcpy(result + (ep - cp), name);
+       strncpy(result, cp, prefix_len);
+       if (sep)
+           result[prefix_len++] = '/';
+       strcpy(result + prefix_len, name);
 
        /*
         * Attempt to open the file, and return the path if we succeed and it's