libexec: mmap support, prealloc variants

Change-Id: I26694fd3c21deb8b97e01ed675dfc14719b0672b
This commit is contained in:
Ben Gras 2013-03-16 03:46:37 +00:00
parent 915bb62c97
commit 150e19f885
8 changed files with 129 additions and 32 deletions

View File

@ -138,7 +138,8 @@ void arch_boot_proc(struct boot_image *ip, struct proc *rp)
/* callbacks for use in the kernel */ /* callbacks for use in the kernel */
execi.copymem = libexec_copy_memcpy; execi.copymem = libexec_copy_memcpy;
execi.clearmem = libexec_clear_memset; 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.allocmem_ondemand = libexec_pg_alloc;
execi.clearproc = NULL; execi.clearproc = NULL;

View File

@ -414,7 +414,8 @@ void arch_boot_proc(struct boot_image *ip, struct proc *rp)
/* callbacks for use in the kernel */ /* callbacks for use in the kernel */
execi.copymem = libexec_copy_memcpy; execi.copymem = libexec_copy_memcpy;
execi.clearmem = libexec_clear_memset; 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.allocmem_ondemand = libexec_pg_alloc;
execi.clearproc = NULL; execi.clearproc = NULL;

View File

@ -150,7 +150,8 @@ int libexec_load_elf(struct exec_info *execi)
assert(execi->copymem); assert(execi->copymem);
assert(execi->clearmem); assert(execi->clearmem);
assert(execi->allocmem_prealloc); assert(execi->allocmem_prealloc_cleared);
assert(execi->allocmem_prealloc_junk);
assert(execi->allocmem_ondemand); assert(execi->allocmem_ondemand);
for (i = 0; i < hdr->e_phnum; i++) { 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++) { for (i = 0; i < hdr->e_phnum; i++) {
vir_bytes seg_membytes, page_offset, p_vaddr, vaddr; vir_bytes seg_membytes, page_offset, p_vaddr, vaddr;
vir_bytes chunk, vfileend, vmemend; vir_bytes chunk, vfileend, vmemend;
off_t foffset, fbytes;
Elf_Phdr *ph = &phdr[i]; 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_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; vaddr = p_vaddr = ph->p_vaddr + execi->load_offset;
seg_membytes = ph->p_memsz; seg_membytes = ph->p_memsz;
page_offset = vaddr % PAGE_SIZE; page_offset = vaddr % PAGE_SIZE;
vaddr -= page_offset; vaddr -= page_offset;
foffset -= page_offset;
seg_membytes += 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); seg_membytes = roundup(seg_membytes, PAGE_SIZE);
fbytes = roundup(fbytes, PAGE_SIZE);
if(first || startv > vaddr) startv = vaddr; if(first || startv > vaddr) startv = vaddr;
first = 0; first = 0;
/* make us some memory */ if(try_mmap && execi->memmap(execi, vaddr, fbytes, foffset, clearend, mmap_prot) == OK) {
if(execi->allocmem_prealloc(execi, vaddr, seg_membytes) != OK) {
if(execi->clearproc) execi->clearproc(execi);
return ENOMEM;
}
#if ELF_DEBUG #if ELF_DEBUG
printf("mmapped 0x%lx-0x%lx\n", vaddr, vaddr+seg_membytes); printf("libexec: mmap 0x%lx-0x%lx done, clearend 0x%x\n",
vaddr, vaddr+fbytes, clearend);
#endif #endif
/* Copy executable section into it */ if(seg_membytes > fbytes) {
if(execi->copymem(execi, ph->p_offset, p_vaddr, ph->p_filesz) != OK) { int rem_mem = seg_membytes - fbytes;;
if(execi->clearproc) execi->clearproc(execi); vir_bytes remstart = vaddr + fbytes;
return ENOMEM; if(execi->allocmem_ondemand(execi,
} remstart, rem_mem) != OK) {
printf("libexec: mmap extra mem failed\n");
return ENOMEM;
}
#if ELF_DEBUG
else printf("libexec: allocated 0x%lx-0x%lx\n",
remstart, remstart+rem_mem);
#endif
}
} else {
if(try_mmap) printf("libexec: mmap failed\n");
/* 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 #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 #endif
/* Clear remaining bits */ /* Copy executable section into it */
vfileend = p_vaddr + ph->p_filesz; if(execi->copymem(execi, ph->p_offset, p_vaddr, ph->p_filesz) != OK) {
vmemend = vaddr + seg_membytes; if(execi->clearproc) execi->clearproc(execi);
if((chunk = p_vaddr - vaddr) > 0) { return ENOMEM;
}
#if ELF_DEBUG #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 #endif
execi->clearmem(execi, vaddr, chunk);
} /* Clear remaining bits */
if((chunk = vmemend - vfileend) > 0) { vmemend = vaddr + seg_membytes;
if((chunk = p_vaddr - vaddr) > 0) {
#if ELF_DEBUG #if ELF_DEBUG
printf("end clearing 0x%lx-0x%lx\n", vfileend, vaddr+chunk); printf("start clearing 0x%lx-0x%lx\n", vaddr, vaddr+chunk);
#endif #endif
execi->clearmem(execi, vfileend, chunk); execi->clearmem(execi, vaddr, chunk);
}
if((chunk = vmemend - vfileend) > 0) {
#if ELF_DEBUG
printf("end clearing 0x%lx-0x%lx\n", vfileend, vaddr+chunk);
#endif
execi->clearmem(execi, vfileend, chunk);
}
} }
} }

View File

@ -18,7 +18,7 @@
#include <sys/mman.h> #include <sys/mman.h>
#include <machine/elf.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, if(minix_mmap_for(execi->proc_e, (void *) vaddr, len,
PROT_READ|PROT_WRITE|PROT_EXEC, 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; 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) 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, if(minix_mmap_for(execi->proc_e, (void *) vaddr, len,

View 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_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 { struct exec_info {
/* Filled in by libexec caller */ /* Filled in by libexec caller */
endpoint_t proc_e; /* Process endpoint */ endpoint_t proc_e; /* Process endpoint */
@ -33,9 +37,11 @@ struct exec_info {
/* Callback pointers for use by libexec */ /* Callback pointers for use by libexec */
libexec_loadfunc_t copymem; /* Copy callback */ libexec_loadfunc_t copymem; /* Copy callback */
libexec_clearfunc_t clearmem; /* Clear 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_allocfunc_t allocmem_ondemand; /* Alloc callback */
libexec_procclearfunc_t clearproc; /* Clear process callback */ libexec_procclearfunc_t clearproc; /* Clear process callback */
libexec_mmap_t memmap; /* mmap callback */
void *opaque; /* Callback data */ void *opaque; /* Callback data */
/* Filled in by libexec load function */ /* 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_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_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_alloc_mmap_ondemand(struct exec_info *execi, off_t vaddr, size_t len);
int libexec_clearproc_vm_procctl(struct exec_info *execi); int libexec_clearproc_vm_procctl(struct exec_info *execi);
int libexec_clear_sys_memset(struct exec_info *execi, off_t vaddr, size_t len); int libexec_clear_sys_memset(struct exec_info *execi, off_t vaddr, size_t len);

View 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.copymem = read_seg;
execi.clearproc = libexec_clearproc_vm_procctl; execi.clearproc = libexec_clearproc_vm_procctl;
execi.clearmem = libexec_clear_sys_memset; 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; execi.allocmem_ondemand = libexec_alloc_mmap_ondemand;
for(i = 0; exec_loaders[i].load_object != NULL; i++) { for(i = 0; exec_loaders[i].load_object != NULL; i++) {

View 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.copymem = read_seg;
execi.args.clearproc = libexec_clearproc_vm_procctl; execi.args.clearproc = libexec_clearproc_vm_procctl;
execi.args.clearmem = libexec_clear_sys_memset; 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.allocmem_ondemand = libexec_alloc_mmap_ondemand;
execi.args.opaque = &execi; execi.args.opaque = &execi;

View File

@ -287,7 +287,8 @@ void exec_bootproc(struct vmproc *vmp, struct boot_image *ip)
execi->copymem = libexec_copy_physcopy; execi->copymem = libexec_copy_physcopy;
execi->clearproc = NULL; execi->clearproc = NULL;
execi->clearmem = libexec_clear_sys_memset; 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; execi->allocmem_ondemand = libexec_alloc_vm_ondemand;
if(libexec_load_elf(execi) != OK) if(libexec_load_elf(execi) != OK)