#include "elf.h" #include #include #include #include #include #include #include #define STACK_SIZE 0x10000 enum launch_status launch_ctx_init(struct launch_ctx *ctx) { memset(ctx, 0x0, sizeof *ctx); return LAUNCH_OK; } void launch_ctx_cleanup(struct launch_ctx *ctx) { } static kern_handle_t get_library( struct launch_ctx *ctx, const char *name, void *arg) { enum launch_status status = LAUNCH_ERR_CANNOT_RESOLVE_DEPENDENCY; kern_handle_t result = KERN_HANDLE_INVALID; if (ctx->ctx_resolve_library) { status = ctx->ctx_resolve_library(ctx, name, &result, arg); } return result; } enum launch_status launch_ctx_execute( struct launch_ctx *ctx, const struct launch_parameters *params, enum launch_flags flags, struct launch_result *result) { kern_status_t kstatus; kern_handle_t stack_vmo; kstatus = vm_object_create( "stack", 5, STACK_SIZE, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER, &stack_vmo); size_t name_len = params->p_task_name ? strlen(params->p_task_name) : 0; kern_handle_t remote_task = KERN_HANDLE_INVALID, remote_address_space = KERN_HANDLE_INVALID; kstatus = task_create( params->p_parent_task, params->p_task_name, name_len, &remote_task, &remote_address_space); if (kstatus != KERN_OK) { kern_handle_close(stack_vmo); return LAUNCH_ERR_TASK_CREATION_FAILED; } struct elf_image image; elf_image_init(&image); enum launch_status status = elf_image_load( &image, params->p_executable, params->p_local_address_space, remote_address_space); if (status == LAUNCH_ERR_INTERPRETER_REQUIRED) { kern_handle_t interp = get_library( ctx, image.e_interp, params->p_resolver_arg); if (interp == KERN_HANDLE_INVALID) { elf_image_cleanup(&image); kern_handle_close(stack_vmo); kern_handle_close(remote_address_space); kern_handle_close(remote_task); return status; } elf_image_init(&image); status = elf_image_load( &image, interp, params->p_local_address_space, remote_address_space); } if (status != LAUNCH_OK) { elf_image_cleanup(&image); kern_handle_close(stack_vmo); kern_handle_close(remote_address_space); kern_handle_close(remote_task); return status; } virt_addr_t stack_buf; kstatus = vm_region_map_relative( remote_address_space, VM_REGION_ANY_OFFSET, stack_vmo, 0, STACK_SIZE, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER, &stack_buf); kern_handle_close(stack_vmo); if (kstatus != KERN_OK) { elf_image_cleanup(&image); kern_handle_close(remote_address_space); kern_handle_close(remote_task); return LAUNCH_ERR_MEMORY_MAP_FAILED; } virt_addr_t ip = image.e_hdr.e_entry + image.e_remote_base; virt_addr_t sp = stack_buf + STACK_SIZE; kern_handle_t thread; kstatus = task_create_thread(remote_task, ip, sp, NULL, 0, &thread); if (kstatus != KERN_OK) { elf_image_cleanup(&image); kern_handle_close(remote_address_space); kern_handle_close(remote_task); return LAUNCH_ERR_THREAD_CREATION_FAILED; } thread_start(thread); kern_handle_close(thread); elf_image_cleanup(&image); return LAUNCH_OK; }