libexec: mmap support, prealloc variants

Change-Id: I26694fd3c21deb8b97e01ed675dfc14719b0672b
This commit is contained in:
Ben Gras 2013-03-16 03:46:37 +00:00
parent 6a2aada8e6
commit 06c61a2de2
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 */
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;

View 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;

View 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("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
/* 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(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
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
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("end clearing 0x%lx-0x%lx\n", vfileend, vaddr+chunk);
printf("start clearing 0x%lx-0x%lx\n", vaddr, vaddr+chunk);
#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 <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,

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_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);

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.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++) {

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.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;

View 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)