static uint32_t _load(const int8_t *path) { void *physical; void (*init)(void) = 0; physical = vfs_get_physical(path); if (!physical) return 0; elf_relocate(physical); init = (void (*)(void)) elf_get_symbol(physical, "init"); if (!init) return 0; init(); return 1; }
image_id elf_load_kspace(const char *path, const char *sym_prepend) { struct Elf32_Ehdr *eheader; struct Elf32_Phdr *pheaders; struct elf_image_info *image; void *vnode = NULL; int fd; int err; int i; ssize_t len; addr_t lowest_address = 0; addr_t highest_address = 0; dprintf("elf_load_kspace: entry path '%s'\n", path); fd = sys_open(path, 0); if(fd < 0) return fd; err = vfs_get_vnode_from_fd(fd, true, &vnode); if(err < 0) goto error0; // XXX awful hack to keep someone else from trying to load this image // probably not a bad thing, shouldn't be too many races mutex_lock(&image_load_lock); // make sure it's not loaded already. Search by vnode image = find_image_by_vnode(vnode); if( image ) { atomic_add( &image->ref_count, 1 ); //err = ERR_NOT_ALLOWED; goto done; } eheader = (struct Elf32_Ehdr *)kmalloc( sizeof( *eheader )); if( !eheader ) { err = ERR_NO_MEMORY; goto error; } len = sys_read(fd, eheader, 0, sizeof(*eheader)); if(len < 0) { err = len; goto error1; } if(len != sizeof(*eheader)) { // short read err = ERR_INVALID_BINARY; goto error1; } err = verify_eheader(eheader); if(err < 0) goto error1; image = create_image_struct(); if(!image) { err = ERR_NO_MEMORY; goto error1; } image->vnode = vnode; image->eheader = eheader; pheaders = kmalloc(eheader->e_phnum * eheader->e_phentsize); if(pheaders == NULL) { dprintf("error allocating space for program headers\n"); err = ERR_NO_MEMORY; goto error2; } // dprintf("reading in program headers at 0x%x, len 0x%x\n", eheader.e_phoff, eheader.e_phnum * eheader.e_phentsize); len = sys_read(fd, pheaders, eheader->e_phoff, eheader->e_phnum * eheader->e_phentsize); if(len < 0) { err = len; dprintf("error reading in program headers\n"); goto error3; } if(len != eheader->e_phnum * eheader->e_phentsize) { dprintf("short read while reading in program headers\n"); err = -1; goto error3; } for(i=0; i < eheader->e_phnum; i++) { char region_name[64]; bool ro_segment_handled = false; bool rw_segment_handled = false; int image_region; int lock; // dprintf("looking at program header %d\n", i); switch(pheaders[i].p_type) { case PT_LOAD: break; case PT_DYNAMIC: image->dynamic_ptr = pheaders[i].p_vaddr; continue; default: dprintf("unhandled pheader type 0x%x\n", pheaders[i].p_type); continue; } // we're here, so it must be a PT_LOAD segment if((pheaders[i].p_flags & (PF_R | PF_W | PF_X)) == (PF_R | PF_W)) { // this is the writable segment if(rw_segment_handled) { // we've already created this segment continue; } rw_segment_handled = true; image_region = 1; lock = LOCK_RW|LOCK_KERNEL; sprintf(region_name, "%s_seg1", path); } else if((pheaders[i].p_flags & (PF_R | PF_X)) == (PF_R | PF_X)) { // this is the non-writable segment if(ro_segment_handled) { // we've already created this segment continue; } ro_segment_handled = true; image_region = 0; // lock = LOCK_RO|LOCK_KERNEL; lock = LOCK_RW|LOCK_KERNEL; sprintf(region_name, "%s_seg0", path); } else { dprintf("weird program header flags 0x%x\n", pheaders[i].p_flags); continue; } image->regions[image_region].size = ROUNDUP(pheaders[i].p_memsz + (pheaders[i].p_vaddr % PAGE_SIZE), PAGE_SIZE); if(i == 0) { // put region zero anywhere image->regions[image_region].id = vm_create_anonymous_region(vm_get_kernel_aspace_id(), region_name, (void **)&image->regions[image_region].start, REGION_ADDR_ANY_ADDRESS, image->regions[image_region].size, REGION_WIRING_WIRED, lock); } else { // try to line the other regions up so that their relative distances are according to the ELF header image->regions[image_region].start = ROUNDOWN(pheaders[i].p_vaddr + image->regions[0].delta, PAGE_SIZE); // dprintf("elf: region 0.delta 0x%x region %d.pvaddr 0x%x region %d.start 0x%x\n", // image->regions[0].delta, i, pheaders[i].p_vaddr, i, image->regions[image_region].start); image->regions[image_region].id = vm_create_anonymous_region(vm_get_kernel_aspace_id(), region_name, (void **)&image->regions[image_region].start, REGION_ADDR_EXACT_ADDRESS, image->regions[image_region].size, REGION_WIRING_WIRED, lock); } if(image->regions[image_region].id < 0) { dprintf("error allocating region!\n"); err = ERR_INVALID_BINARY; goto error4; } image->regions[image_region].delta = image->regions[image_region].start - ROUNDOWN(pheaders[i].p_vaddr, PAGE_SIZE); // dprintf("elf_load_kspace: created a region at 0x%x\n", image->regions[image_region].start); len = sys_read(fd, (void *)(image->regions[image_region].start + (pheaders[i].p_vaddr % PAGE_SIZE)), pheaders[i].p_offset, pheaders[i].p_filesz); if(len < 0) { err = len; dprintf("error reading in seg %d\n", i); goto error4; } if(lowest_address == 0 || image->regions[image_region].start < lowest_address) lowest_address = image->regions[image_region].start; if(highest_address == 0 || (image->regions[image_region].start + image->regions[image_region].size) > highest_address) highest_address = image->regions[image_region].start + image->regions[image_region].size; } if(image->regions[1].start != 0) { if(image->regions[0].delta != image->regions[1].delta) { dprintf("could not load binary, fix the region problem!\n"); dump_image_info(image); err = ERR_NO_MEMORY; goto error4; } } // modify the dynamic ptr by the delta of the regions image->dynamic_ptr += image->regions[0].delta; err = elf_parse_dynamic_section(image); if(err < 0) goto error4; err = elf_relocate(image, sym_prepend); if(err < 0) goto error4; err = 0; kfree(pheaders); sys_close(fd); insert_image_in_list(image); done: mutex_unlock(&image_load_lock); dprintf("elf_load_kspace: syncing icache from 0x%lx to 0x%lx\n", lowest_address, highest_address); arch_cpu_sync_icache((void *)lowest_address, highest_address - lowest_address); dprintf("elf_load_kspace: done!\n"); return image->id; error4: if(image->regions[1].id >= 0) vm_delete_region(vm_get_kernel_aspace_id(), image->regions[1].id); if(image->regions[0].id >= 0) vm_delete_region(vm_get_kernel_aspace_id(), image->regions[0].id); error3: kfree(image); error2: kfree(pheaders); error1: kfree(eheader); error: mutex_unlock(&image_load_lock); error0: if(vnode) vfs_put_vnode_ptr(vnode); sys_close(fd); return err; }