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;
}
Example #2
0
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;
}