vkernel - Module loading for vkernel64
authorMatthew Dillon <dillon@apollo.backplane.com>
Fri, 16 Aug 2013 02:35:52 +0000 (19:35 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Fri, 16 Aug 2013 02:35:52 +0000 (19:35 -0700)
* Fix a missing vm_object_drop() in the kldload error path.

* Load modules using sbrk()'d memory (for now).

* Hack rtld to accept a new environment variable, LD_SHAREDLIB_BASE,
  which forces shared libraries to be mmap()'d at the specified address.

* Hack the vkernel64 binary to re-exec itself in order to set
  LD_SHAREDLIB_BASE to low memory.  This forces shared libraries into
  low memory which the KLD module loader can relocate against, instead
  of high memory which it can't.

* test/vkernel/Makefile now builds and installs modules by default

With-fixes-from: tuxillo

libexec/rtld-elf/map_object.c
libexec/rtld-elf/rtld.c
libexec/rtld-elf/rtld.h
sys/kern/link_elf_obj.c
sys/platform/vkernel64/platform/init.c
test/vkernel/Makefile

index 84fcf68..f9815aa 100644 (file)
@@ -64,6 +64,7 @@ map_object(int fd, const char *path, const struct stat *sb)
     Elf_Phdr *phinterp;
     Elf_Phdr *phtls;
     caddr_t mapbase;
+    caddr_t shlib_base;
     size_t mapsize;
     Elf_Addr base_vaddr;
     Elf_Addr base_vlimit;
@@ -92,6 +93,12 @@ map_object(int fd, const char *path, const struct stat *sb)
     if (hdr == NULL)
        return (NULL);
 
+    if (__ld_sharedlib_base) {
+       shlib_base = (void *)(intptr_t)strtoul(__ld_sharedlib_base, NULL, 0);
+    } else {
+       shlib_base = NULL;
+    }
+
     /*
      * Scan the program header entries, and save key information.
      *
@@ -177,8 +184,25 @@ map_object(int fd, const char *path, const struct stat *sb)
     mapsize = base_vlimit - base_vaddr;
     base_addr = (caddr_t) base_vaddr;
 
-    mapbase = mmap(base_addr, mapsize, PROT_NONE, MAP_ANON | MAP_PRIVATE |
-      MAP_NOCORE, -1, 0);
+    if (base_addr == NULL && shlib_base) {
+       size_t limit = 1024 * 256 * 1024;
+       size_t offset;
+
+       for (offset = 0; offset < limit; offset += 256 * 1024) {
+               mapbase = mmap(shlib_base + offset, mapsize,
+                              PROT_NONE,
+                              MAP_ANON | MAP_PRIVATE | MAP_NOCORE |
+                              MAP_TRYFIXED,
+                              -1, 0);
+               if (mapbase != MAP_FAILED)
+                       break;
+       }
+    } else {
+       mapbase = mmap(base_addr, mapsize,
+                      PROT_NONE,
+                      MAP_ANON | MAP_PRIVATE | MAP_NOCORE,
+                      -1, 0);
+    }
     if (mapbase == (caddr_t) -1) {
        _rtld_error("%s: mmap of entire address space failed: %s",
          path, rtld_strerror(errno));
index ee54394..1a9a47f 100644 (file)
@@ -207,6 +207,7 @@ static Objlist list_fini =  /* Objects needing fini() calls */
   STAILQ_HEAD_INITIALIZER(list_fini);
 
 static Elf_Sym sym_zero;       /* For resolving undefined weak refs. */
+const char *__ld_sharedlib_base;
 
 #define GDB_STATE(s,m) r_debug.r_state = s; r_debug_state(&r_debug,m);
 
@@ -404,11 +405,13 @@ _rtld(Elf_Addr *sp, func_ptr_type *exit_proc, Obj_Entry **objp)
            || unsetenv("LD_LIBMAP")
            || unsetenv("LD_LIBMAP_DISABLE")
            || unsetenv("LD_LOADFLTR")
+           || unsetenv("LD_SHAREDLIB_BASE")
        ) {
            _rtld_error("environment corrupt; aborting");
            die();
        }
     }
+    __ld_sharedlib_base = _getenv_ld("LD_SHAREDLIB_BASE");
     ld_debug = _getenv_ld("LD_DEBUG");
     libmap_disable = _getenv_ld("LD_LIBMAP_DISABLE") != NULL;
     libmap_override = (char *)_getenv_ld("LD_LIBMAP");
index 718cf0e..e5e9cb0 100644 (file)
@@ -62,6 +62,7 @@ extern int tls_max_index;
 extern int main_argc;
 extern char **main_argv;
 extern char **environ;
+extern const char *__ld_sharedlib_base;
 
 struct stat;
 struct Struct_Obj_Entry;
index 136b2fa..cbc4d61 100644 (file)
@@ -653,6 +653,7 @@ link_elf_obj_load_file(const char *filename, linker_file_t * result)
         */
 #if defined(__x86_64__) && defined(_KERNEL_VIRTUAL)
        error = vkernel_module_memory_alloc(&mapbase, round_page(mapsize));
+       vm_object_drop(ef->object);
 #else
        mapbase = KERNBASE;
        error = vm_map_find(&kernel_map, ef->object, 0, &mapbase,
index a1152a9..55fa8a1 100644 (file)
@@ -170,6 +170,21 @@ main(int ac, char **av)
        size_t kenv_size;
        size_t kenv_size2;
 
+       /*
+        * Currently a bad hack but rtld-elf needs LD_SHAREDLIB_BASE to
+        * be set to force it to mmap() shared libraries into low memory,
+        * so our module loader can link against the related symbols.
+        */
+       if (getenv("LD_SHAREDLIB_BASE") == NULL) {
+               setenv("LD_SHAREDLIB_BASE", "0x10000000", 1);
+               execv(av[0], av);
+               fprintf(stderr, "Must run %s with full path\n", av[0]);
+               exit(1);
+       }
+
+       /*
+        * Starting for real
+        */
        save_ac = ac;
        save_av = av;
        eflag = 0;
@@ -1413,10 +1428,6 @@ setrealcpu(void)
 int
 vkernel_module_memory_alloc(vm_offset_t *basep, size_t bytes)
 {
-       kprintf("module loading for vkernel64's not currently supported\n");
-       *basep = 0;
-       return ENOMEM;
-#if 0
 #if 1
        size_t xtra;
        xtra = (PAGE_SIZE - (vm_offset_t)sbrk(0)) & PAGE_MASK;
@@ -1429,10 +1440,7 @@ vkernel_module_memory_alloc(vm_offset_t *basep, size_t bytes)
        if ((void *)*basep == MAP_FAILED)
                return ENOMEM;
 #endif
-       kprintf("basep %p %p %zd\n",
-               (void *)vkernel_module_memory_alloc, (void *)*basep, bytes);
        return 0;
-#endif
 }
 
 void
index 2ea451e..44ea53b 100644 (file)
@@ -75,6 +75,9 @@ world: checkq
 kernel: checkq
        cd ${SRCDIR} && make -j 4 KERNCONF=${USEKERNEL} buildkernel
 
+nativekernel: checkq
+       cd ${SRCDIR} && make -j 4 KERNCONF=${USEKERNEL} nativekernel
+
 # Quick build - just rebuild the kernel quickly
 #
 #
@@ -82,7 +85,7 @@ quickworld: checkq
        cd ${SRCDIR} && make -j 4 quickworld
 
 quickkernel: checkq
-       cd ${SRCDIR} && make KERNCONF=${USEKERNEL} quickkernel
+       cd ${SRCDIR} && make -j 4 KERNCONF=${USEKERNEL} quickkernel
 
 # Build and mount an empty filesystem for the emulated root disk
 #
@@ -126,7 +129,6 @@ install: mount
        cd ${SRCDIR} && \
            make -j 4 \
                 DESTDIR=${VKDIR}/root KERNCONF=${USEKERNEL} \
-                NO_MODULES= \
                 installkernel
        cp ${VKDIR}/root/boot/kernel/kernel ${VKDIR}/vkernel
 
@@ -143,7 +145,7 @@ reinstall: mount
 reinstallkernel: mount
        cd ${SRCDIR} && \
            make -j 4 DESTDIR=${VKDIR}/root KERNCONF=${USEKERNEL} \
-                NO_MODULES= installkernel
+                installkernel
        cp ${VKDIR}/root/boot/kernel/kernel ${VKDIR}/vkernel
 
 sysloader: mount