int elf_unload_kspace( const char *path ) { int fd; int err; void *vnode; struct elf_image_info *image; fd = sys_open(path, 0); if(fd < 0) return fd; err = vfs_get_vnode_from_fd(fd, true, &vnode); if(err < 0) goto error0; mutex_lock(&image_load_lock); image = find_image_by_vnode(vnode); if( !image ) { dprintf( "Tried to unload image that wasn't loaded (%s)\n", path ); err = ERR_NOT_FOUND; goto error; } err = elf_unload_image( image ); error: mutex_unlock(&image_load_lock); error0: if(vnode) vfs_put_vnode_ptr(vnode); sys_close(fd); return err; }
status_t FileDevice::Open(const char* path, int openMode, void** _cookie) { // get the vnode struct vnode* vnode; status_t error = vfs_get_vnode_from_fd(fFD, true, &vnode); if (error != B_OK) return error; // open it int fd = vfs_open_vnode(vnode, openMode, true); if (fd < 0) { vfs_put_vnode(vnode); return fd; } // our vnode reference does now belong to the FD Cookie* cookie = new(std::nothrow) Cookie(fd); if (cookie == NULL) { close(fd); return B_NO_MEMORY; } *_cookie = cookie; return B_OK; }
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; }