diff --git a/executer/user/mcexec.c b/executer/user/mcexec.c index fef809a5..6b37dd0e 100644 --- a/executer/user/mcexec.c +++ b/executer/user/mcexec.c @@ -1199,6 +1199,93 @@ int main_loop(int fd, int cpu, pthread_mutex_t *lock) break; } + case __NR_execve: { + + /* Execve phase */ + switch (w.sr.args[0]) { + int ret = -1; + struct program_load_desc *desc; + struct remote_transfer trans; + + /* Load descriptor phase */ + case 1: + if (load_elf_desc((char *)w.sr.args[1], &desc) != 0) { + fprintf(stderr, + "execve(): error loading ELF for file %s\n", + (char *)w.sr.args[1]); + goto return_execve1; + } + + __dprintf("execve(): load_elf_desc() for %s OK, num sections: %d\n", + w.sr.args[1], desc->num_sections); + + /* Copy descriptor to co-kernel side */ + trans.userp = (void*)desc; + trans.rphys = w.sr.args[2]; + trans.size = sizeof(struct program_load_desc) + + sizeof(struct program_image_section) * + desc->num_sections; + trans.direction = MCEXEC_UP_TRANSFER_TO_REMOTE; + + if (ioctl(fd, MCEXEC_UP_TRANSFER, &trans) != 0) { + fprintf(stderr, + "execve(): error transfering ELF for file %s\n", + (char *)w.sr.args[1]); + goto return_execve1; + } + + __dprintf("execve(): load_elf_desc() for %s OK\n", + w.sr.args[1]); + + /* We can't be sure next phase will succeed */ + /* TODO: what shall we do with fp in desc?? */ + free(desc); + + ret = 0; +return_execve1: + do_syscall_return(fd, cpu, ret, 0, 0, 0, 0); + break; + + /* Copy program image phase */ + case 2: + + /* Alloc descriptor */ + desc = malloc(w.sr.args[2]); + if (!desc) { + fprintf(stderr, "execve(): error allocating desc\n"); + goto return_execve2; + } + + /* Copy descriptor from co-kernel side */ + trans.userp = (void*)desc; + trans.rphys = w.sr.args[1]; + trans.size = w.sr.args[2]; + trans.direction = MCEXEC_UP_TRANSFER_FROM_REMOTE; + + if (ioctl(fd, MCEXEC_UP_TRANSFER, &trans) != 0) { + fprintf(stderr, + "execve(): error obtaining ELF descriptor\n"); + goto return_execve1; + } + + printf("execve(): transfer ELF desc OK\n"); + + transfer_image(fd, desc); + __dprintf("execve(): image transferred\n"); + + ret = 0; +return_execve2: + do_syscall_return(fd, cpu, ret, 0, 0, 0, 0); + break; + + default: + fprintf(stderr, "execve(): ERROR: invalid execve phase\n"); + break; + } + + break; + } + default: ret = do_generic_syscall(&w); do_syscall_return(fd, cpu, ret, 0, 0, 0, 0); diff --git a/kernel/include/process.h b/kernel/include/process.h index a7a1475c..0f6e63c4 100644 --- a/kernel/include/process.h +++ b/kernel/include/process.h @@ -212,6 +212,7 @@ void hold_process(struct process *proc); void release_process(struct process *proc); void flush_process_memory(struct process *proc); void free_process_memory(struct process *proc); +void free_process_memory_ranges(struct process *proc); int populate_process_memory(struct process *proc, void *start, size_t len); int add_process_memory_range(struct process *process, diff --git a/kernel/process.c b/kernel/process.c index 5c7491ee..3a9a6314 100644 --- a/kernel/process.c +++ b/kernel/process.c @@ -1423,6 +1423,29 @@ void flush_process_memory(struct process *proc) return; } +void free_process_memory_ranges(struct process *proc) +{ + int error; + struct vm_range *range, *next; + struct process_vm *vm = proc->vm; + + if (vm == NULL) { + return; + } + + ihk_mc_spinlock_lock_noirq(&vm->memory_range_lock); + list_for_each_entry_safe(range, next, &vm->vm_range_list, list) { + error = free_process_memory_range(vm, range); + if (error) { + ekprintf("free_process_memory(%p):" + "free range failed. %lx-%lx %d\n", + proc, range->start, range->end, error); + /* through */ + } + } + ihk_mc_spinlock_unlock_noirq(&vm->memory_range_lock); +} + void free_process_memory(struct process *proc) { struct vm_range *range, *next; diff --git a/kernel/syscall.c b/kernel/syscall.c index b20ad197..ce5e8990 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -97,6 +97,13 @@ void do_signal(long rc, void *regs, struct process *proc, struct sig_pending *pe int copy_from_user(struct process *, void *, const void *, size_t); int copy_to_user(struct process *, void *, const void *, size_t); +int prepare_process_ranges_args_envs(struct process *proc, + struct program_load_desc *pn, + struct program_load_desc *p, + enum ihk_mc_pt_attribute attr, + char *args, int args_len, + char *envs, int envs_len); + #ifdef DCFA_KMOD static void do_mod_exit(int status); #endif @@ -1128,7 +1135,83 @@ SYSCALL_DECLARE(arch_prctl) SYSCALL_DECLARE(execve) { - return -EOPNOTSUPP; + long ret; + const char *filename = (const char *)ihk_mc_syscall_arg0(ctx); + char **argv = (char **)ihk_mc_syscall_arg1(ctx); + char **envp = (char **)ihk_mc_syscall_arg2(ctx); + + char *argv_flat = NULL; + int argv_flat_len = 0; + char *envp_flat = NULL; + int envp_flat_len = 0; + + struct syscall_request request IHK_DMA_ALIGN; + struct program_load_desc *desc; + + desc = ihk_mc_alloc_pages(1, IHK_MC_AP_NOWAIT); + if (!desc) { + kprintf("execve(): ERROR: allocating program descriptor\n"); + return -ENOMEM; + } + + memset((void*)desc, 0, PAGE_SIZE); + + /* Request host to open executable and load ELF section descriptions */ + request.number = __NR_execve; + request.args[0] = 1; /* 1st phase - get ELF desc */ + request.args[1] = (unsigned long)filename; + request.args[2] = virt_to_phys(desc); + ret = do_syscall(&request, ctx, ihk_mc_get_processor_id(), 0); + + if (ret != 0) { + kprintf("execve(): ERROR: host failed to load elf header\n"); + return -EINVAL; + } + + dkprintf("execve(): ELF desc received, num sections: %d\n", + desc->num_sections); + + /* Flatten argv and envp into kernel-space buffers */ + argv_flat_len = flatten_strings(-1, argv, &argv_flat); + if (argv_flat_len == 0) { + kprintf("ERROR: no argv for executable: %s?\n", filename); + return -EINVAL; + } + + envp_flat_len = flatten_strings(-1, envp, &envp_flat); + if (envp_flat_len == 0) { + kprintf("ERROR: no envp for executable: %s?\n", filename); + return -EINVAL; + } + + /* Unmap all memory areas of the process, userspace will be gone */ + free_process_memory_ranges(cpu_local_var(current)); + + /* Create virtual memory ranges and update args/envs */ + if (prepare_process_ranges_args_envs(cpu_local_var(current), desc, desc, + PTATTR_NO_EXECUTE | PTATTR_WRITABLE | PTATTR_FOR_USER, + argv_flat, argv_flat_len, envp_flat, envp_flat_len) != 0) { + kprintf("execve(): PANIC: preparing ranges, args, envs, stack\n"); + panic(""); + } + + /* Request host to transfer ELF image */ + request.number = __NR_execve; + request.args[0] = 2; /* 2nd phase - transfer ELF image */ + request.args[1] = virt_to_phys(desc); + request.args[2] = sizeof(struct program_load_desc) + + sizeof(struct program_image_section) * desc->num_sections; + + ret = do_syscall(&request, ctx, ihk_mc_get_processor_id(), 0); + + if (ret != 0) { + kprintf("execve(): PANIC: host failed to load elf image\n"); + panic(""); + } + + dkprintf("execve(): returning to new process\n"); + + return 0; } SYSCALL_DECLARE(clone)