]> Zhao Yanbai Git Server - minix.git/commitdiff
libexec: mmap support, prealloc variants 07/407/7
authorBen Gras <ben@minix3.org>
Sat, 16 Mar 2013 03:46:37 +0000 (03:46 +0000)
committerBen Gras <ben@minix3.org>
Wed, 24 Apr 2013 10:18:16 +0000 (10:18 +0000)
In libexec, split the memory allocation method into cleared and
non-cleared. Cleared gives zeroed memory, non-cleared gives 'junk'
memory (that will be overwritten anyway, and so needn't be cleared)
that is faster to get.

Also introduce the 'memmap' method that can be used, if available,
to map code and data from executables into a process using the
third-party mmap() mode.

Change-Id: I26694fd3c21deb8b97e01ed675dfc14719b0672b

kernel/arch/earm/protect.c
kernel/arch/i386/protect.c
lib/libexec/exec_elf.c
lib/libexec/exec_general.c
lib/libexec/libexec.h
servers/rs/exec.c
servers/vfs/exec.c
servers/vm/main.c

index fe6df33d97635036238664f971e37da8c663788e..75b3ef897d1790cd5b4497b45823f0447975f2b4 100644 (file)
@@ -138,7 +138,8 @@ void arch_boot_proc(struct boot_image *ip, struct proc *rp)
                /* callbacks for use in the kernel */
                execi.copymem = libexec_copy_memcpy;
                execi.clearmem = libexec_clear_memset;
-               execi.allocmem_prealloc = libexec_pg_alloc;
+               execi.allocmem_prealloc_cleared = libexec_pg_alloc;
+               execi.allocmem_prealloc_junk = libexec_pg_alloc;
                execi.allocmem_ondemand = libexec_pg_alloc;
                execi.clearproc = NULL;
 
index 22acc3350faed09608a5b1d0241d04b0171d9060..5a98a41ad6fbd6f67559f3a68d0b987bdb5ae880 100644 (file)
@@ -414,7 +414,8 @@ void arch_boot_proc(struct boot_image *ip, struct proc *rp)
                /* callbacks for use in the kernel */
                execi.copymem = libexec_copy_memcpy;
                execi.clearmem = libexec_clear_memset;
-               execi.allocmem_prealloc = libexec_pg_alloc;
+               execi.allocmem_prealloc_junk = libexec_pg_alloc;
+               execi.allocmem_prealloc_cleared = libexec_pg_alloc;
                execi.allocmem_ondemand = libexec_pg_alloc;
                execi.clearproc = NULL;
 
index 625b3f0873acc364f099ed27ad929fabdeda279a..24bfed966618ed2d005f5b405096c62656e2d1e3 100644 (file)
@@ -150,7 +150,8 @@ int libexec_load_elf(struct exec_info *execi)
 
        assert(execi->copymem);
        assert(execi->clearmem);
-       assert(execi->allocmem_prealloc);
+       assert(execi->allocmem_prealloc_cleared);
+       assert(execi->allocmem_prealloc_junk);
        assert(execi->allocmem_ondemand);
 
        for (i = 0; i < hdr->e_phnum; i++) {
@@ -167,51 +168,124 @@ int libexec_load_elf(struct exec_info *execi)
        for (i = 0; i < hdr->e_phnum; i++) {
                vir_bytes seg_membytes, page_offset, p_vaddr, vaddr;
                vir_bytes chunk, vfileend, vmemend;
+               off_t foffset, fbytes;
                Elf_Phdr *ph = &phdr[i];
+               int try_mmap = 1;
+               u16_t clearend = 0;
+               int pagechunk;
+               int mmap_prot = PROT_READ;
+
+               if(!(ph->p_flags & PF_R)) {
+                       printf("libexec: warning: unreadable segment\n");
+               }
+
+               if(ph->p_flags & PF_W) {
+                       mmap_prot |= PROT_WRITE;
+#if ELF_DEBUG
+                       printf("libexec: adding PROT_WRITE\n");
+#endif
+               } else {
+#if ELF_DEBUG
+                       printf("libexec: not adding PROT_WRITE\n");
+#endif
+               }
+
                if (ph->p_type != PT_LOAD || ph->p_memsz == 0) continue;
+
+               if((ph->p_vaddr % PAGE_SIZE) != (ph->p_offset % PAGE_SIZE)) {
+                       printf("libexec: unaligned ELF program?\n");
+                       try_mmap = 0;
+               }
+
+               if(!execi->memmap) {
+                       try_mmap = 0;
+               }
+
+               foffset = ph->p_offset;
+               fbytes = ph->p_filesz;
                vaddr = p_vaddr = ph->p_vaddr + execi->load_offset;
                seg_membytes = ph->p_memsz;
+
                page_offset = vaddr % PAGE_SIZE;
                vaddr -= page_offset;
+               foffset -= page_offset;
                seg_membytes += page_offset;
+               fbytes += page_offset;
+               vfileend  = p_vaddr + ph->p_filesz;
+
+               /* if there's usable memory after the file end, we have
+                * to tell VM to clear the memory part of the page when it's
+                * mapped in
+                */
+               if((pagechunk = (vfileend % PAGE_SIZE))
+                       && ph->p_filesz < ph->p_memsz) {
+                       clearend = PAGE_SIZE - pagechunk;
+               }
+
                seg_membytes = roundup(seg_membytes, PAGE_SIZE);
+               fbytes = roundup(fbytes, PAGE_SIZE);
+
                if(first || startv > vaddr) startv = vaddr;
                first = 0;
 
-               /* make us some memory */
-               if(execi->allocmem_prealloc(execi, vaddr, seg_membytes) != OK) {
-                       if(execi->clearproc) execi->clearproc(execi);
-                       return ENOMEM;
-               }
+               if(try_mmap && execi->memmap(execi, vaddr, fbytes, foffset, clearend, mmap_prot) == OK) {
+#if ELF_DEBUG
+                       printf("libexec: mmap 0x%lx-0x%lx done, clearend 0x%x\n",
+                               vaddr, vaddr+fbytes, clearend);
+#endif
 
+                       if(seg_membytes > fbytes) {
+                               int rem_mem = seg_membytes - fbytes;;
+                               vir_bytes remstart = vaddr + fbytes;
+                               if(execi->allocmem_ondemand(execi,
+                                       remstart, rem_mem) != OK) {
+                                       printf("libexec: mmap extra mem failed\n");
+                                       return ENOMEM;
+                               }
 #if ELF_DEBUG
-               printf("mmapped 0x%lx-0x%lx\n", vaddr, vaddr+seg_membytes);
+                               else printf("libexec: allocated 0x%lx-0x%lx\n",
+
+                                       remstart, remstart+rem_mem);
 #endif
+                       }
+               } else {
+                       if(try_mmap) printf("libexec: mmap failed\n");
 
-               /* Copy executable section into it */
-               if(execi->copymem(execi, ph->p_offset, p_vaddr, ph->p_filesz) != OK) {
-                       if(execi->clearproc) execi->clearproc(execi);
-                       return ENOMEM;
-               }
+                       /* make us some memory */
+                       if(execi->allocmem_prealloc_junk(execi, vaddr, seg_membytes) != OK) {
+                               if(execi->clearproc) execi->clearproc(execi);
+                               return ENOMEM;
+                       }
 
 #if ELF_DEBUG
-               printf("copied 0x%lx-0x%lx\n", p_vaddr, p_vaddr+ph->p_filesz);
+                       printf("mmapped 0x%lx-0x%lx\n", vaddr, vaddr+seg_membytes);
 #endif
 
-               /* Clear remaining bits */
-               vfileend  = p_vaddr + ph->p_filesz;
-               vmemend = vaddr + seg_membytes;
-               if((chunk = p_vaddr - vaddr) > 0) {
+                       /* Copy executable section into it */
+                       if(execi->copymem(execi, ph->p_offset, p_vaddr, ph->p_filesz) != OK) {
+                               if(execi->clearproc) execi->clearproc(execi);
+                               return ENOMEM;
+                       }
+
 #if ELF_DEBUG
-                       printf("start clearing 0x%lx-0x%lx\n", vaddr, vaddr+chunk);
+                       printf("copied 0x%lx-0x%lx\n", p_vaddr, p_vaddr+ph->p_filesz);
 #endif
-                       execi->clearmem(execi, vaddr, chunk);
-               }
-               if((chunk = vmemend - vfileend) > 0) {
+
+                       /* Clear remaining bits */
+                       vmemend = vaddr + seg_membytes;
+                       if((chunk = p_vaddr - vaddr) > 0) {
+#if ELF_DEBUG
+                               printf("start clearing 0x%lx-0x%lx\n", vaddr, vaddr+chunk);
+#endif
+                               execi->clearmem(execi, vaddr, chunk);
+                       }
+       
+                       if((chunk = vmemend - vfileend) > 0) {
 #if ELF_DEBUG
-                       printf("end clearing 0x%lx-0x%lx\n", vfileend, vaddr+chunk);
+                               printf("end clearing 0x%lx-0x%lx\n", vfileend, vaddr+chunk);
 #endif
-                       execi->clearmem(execi, vfileend, chunk);
+                               execi->clearmem(execi, vfileend, chunk);
+                       }
                }
        }
 
index 2ac942df958b34ba49d3254ece41c262f4893c13..a1afecfa747c12ba7a96660e75f0e75535d92a3c 100644 (file)
@@ -18,7 +18,7 @@
 #include <sys/mman.h>
 #include <machine/elf.h>
 
-int libexec_alloc_mmap_prealloc(struct exec_info *execi, off_t vaddr, size_t len)
+int libexec_alloc_mmap_prealloc_junk(struct exec_info *execi, off_t vaddr, size_t len)
 {
        if(minix_mmap_for(execi->proc_e, (void *) vaddr, len,
                PROT_READ|PROT_WRITE|PROT_EXEC,
@@ -29,6 +29,17 @@ int libexec_alloc_mmap_prealloc(struct exec_info *execi, off_t vaddr, size_t len
        return OK;
 }
 
+int libexec_alloc_mmap_prealloc_cleared(struct exec_info *execi, off_t vaddr, size_t len)
+{
+       if(minix_mmap_for(execi->proc_e, (void *) vaddr, len,
+               PROT_READ|PROT_WRITE|PROT_EXEC,
+               MAP_ANON|MAP_PREALLOC|MAP_FIXED, -1, 0) == MAP_FAILED) {
+               return ENOMEM;
+       }
+
+       return OK;
+}
+
 int libexec_alloc_mmap_ondemand(struct exec_info *execi, off_t vaddr, size_t len)
 {
        if(minix_mmap_for(execi->proc_e, (void *) vaddr, len,
index 8b6db7618888fdc72584834684a842470b2dde6f..8597e74c31bba4c4864192bbee1b403d6248818e 100644 (file)
@@ -16,6 +16,10 @@ typedef int (*libexec_allocfunc_t)(struct exec_info *execi,
 
 typedef int (*libexec_procclearfunc_t)(struct exec_info *execi);
 
+typedef int (*libexec_mmap_t)(struct exec_info *execi,
+       vir_bytes vaddr, vir_bytes len, vir_bytes foffset, u16_t clearend,
+       int protflags);
+
 struct exec_info {
     /* Filled in by libexec caller */
     endpoint_t  proc_e;                 /* Process endpoint */
@@ -33,9 +37,11 @@ struct exec_info {
     /* Callback pointers for use by libexec */
     libexec_loadfunc_t copymem;                /* Copy callback */
     libexec_clearfunc_t clearmem;      /* Clear callback */
-    libexec_allocfunc_t allocmem_prealloc; /* Alloc callback */
+    libexec_allocfunc_t allocmem_prealloc_cleared; /* Alloc callback */
+    libexec_allocfunc_t allocmem_prealloc_junk; /* Alloc callback */
     libexec_allocfunc_t allocmem_ondemand; /* Alloc callback */
     libexec_procclearfunc_t clearproc; /* Clear process callback */
+    libexec_mmap_t memmap;             /* mmap callback */
     void *opaque;                      /* Callback data */
 
     /* Filled in by libexec load function */
@@ -55,7 +61,8 @@ int libexec_load_elf(struct exec_info *execi);
 
 int libexec_copy_memcpy(struct exec_info *execi, off_t offset, off_t vaddr, size_t len);
 int libexec_clear_memset(struct exec_info *execi, off_t vaddr, size_t len);
-int libexec_alloc_mmap_prealloc(struct exec_info *execi, off_t vaddr, size_t len);
+int libexec_alloc_mmap_prealloc_cleared(struct exec_info *execi, off_t vaddr, size_t len);
+int libexec_alloc_mmap_prealloc_junk(struct exec_info *execi, off_t vaddr, size_t len);
 int libexec_alloc_mmap_ondemand(struct exec_info *execi, off_t vaddr, size_t len);
 int libexec_clearproc_vm_procctl(struct exec_info *execi);
 int libexec_clear_sys_memset(struct exec_info *execi, off_t vaddr, size_t len);
index d0c950f67c004dd1b3dd59ce1c8d617abbbb6c40..ffbab2c7806bf819c56a2417ce72e378ae9bb60f 100644 (file)
@@ -133,7 +133,8 @@ static int do_exec(int proc_e, char *exec, size_t exec_len, char *progname,
        execi.copymem = read_seg;
        execi.clearproc = libexec_clearproc_vm_procctl;
        execi.clearmem = libexec_clear_sys_memset;
-       execi.allocmem_prealloc = libexec_alloc_mmap_prealloc;
+       execi.allocmem_prealloc_cleared = libexec_alloc_mmap_prealloc_cleared;
+       execi.allocmem_prealloc_junk = libexec_alloc_mmap_prealloc_junk;
        execi.allocmem_ondemand = libexec_alloc_mmap_ondemand;
 
        for(i = 0; exec_loaders[i].load_object != NULL; i++) {
index daad6a2fb5169a1f0ecf659a839b1ee09d08b2d1..ce00e56c8f4452ba2de6900d12db23af521a94d9 100644 (file)
@@ -306,7 +306,8 @@ int pm_exec(endpoint_t proc_e, vir_bytes path, size_t path_len,
   execi.args.copymem = read_seg;
   execi.args.clearproc = libexec_clearproc_vm_procctl;
   execi.args.clearmem = libexec_clear_sys_memset;
-  execi.args.allocmem_prealloc = libexec_alloc_mmap_prealloc;
+  execi.args.allocmem_prealloc_cleared = libexec_alloc_mmap_prealloc_cleared;
+  execi.args.allocmem_prealloc_junk = libexec_alloc_mmap_prealloc_junk;
   execi.args.allocmem_ondemand = libexec_alloc_mmap_ondemand;
   execi.args.opaque = &execi;
 
index 9cd14b444edf12b6cef5f97b04d95c0be668f1e9..caf148de50d817858810c62ef3a33047b97a9b9b 100644 (file)
@@ -287,7 +287,8 @@ void exec_bootproc(struct vmproc *vmp, struct boot_image *ip)
         execi->copymem = libexec_copy_physcopy;
         execi->clearproc = NULL;
         execi->clearmem = libexec_clear_sys_memset;
-        execi->allocmem_prealloc = libexec_alloc_vm_prealloc;
+       execi->allocmem_prealloc_junk = libexec_alloc_vm_prealloc;
+       execi->allocmem_prealloc_cleared = libexec_alloc_vm_prealloc;
         execi->allocmem_ondemand = libexec_alloc_vm_ondemand;
 
        if(libexec_load_elf(execi) != OK)