Exemple #1
0
int
runprogram(char *progname)
{
	struct addrspace *as;
	struct vnode *v;
	vaddr_t entrypoint, stackptr;
	int result;

	/* Open the file. */
	result = vfs_open(progname, O_RDONLY, 0, &v);
	if (result) {
		return result;
	}

	/* We should be a new process. */
	KASSERT(curproc_getas() == NULL);

	/* Create a new address space. */
	#if OPT_A3
	as = as_create(progname);
	#else
	as = as_create();
	#endif
	if (as ==NULL) {
		vfs_close(v);
		return ENOMEM;
	}

	/* Switch to it and activate it. */
	curproc_setas(as);
	as_activate();

	/* Load the executable. */
	result = load_elf(v, &entrypoint);
	if (result) {
		/* p_addrspace will go away when curproc is destroyed */
		vfs_close(v);
		return result;
	}

	/* Done with the file now. */
	vfs_close(v);

	/* Define the user stack in the address space */
	result = as_define_stack(as, &stackptr);
	if (result) {
		/* p_addrspace will go away when curproc is destroyed */
		return result;
	}

	/* Warp to user mode. */
	enter_new_process(0 /*argc*/, NULL /*userspace addr of argv*/,
			  stackptr, entrypoint);
	
	/* enter_new_process does not return. */
	panic("enter_new_process returned\n");
	return EINVAL;
}
Exemple #2
0
/** Parse an executable image in the kernel memory.
 *
 * If the image belongs to a program loader, it is registered as such,
 * (and *task is set to NULL). Otherwise a task is created from the
 * executable image. The task is returned in *task.
 *
 * @param[in]  image_addr Address of an executable program image.
 * @param[in]  name       Name to set for the program's task.
 * @param[out] prg        Buffer for storing program info.
 *                        If image_addr points to a loader image,
 *                        prg->task will be set to NULL and EOK
 *                        will be returned.
 *
 * @return EOK on success or negative error code.
 *
 */
int program_create_from_image(void *image_addr, char *name, program_t *prg)
{
	as_t *as = as_create(0);
	if (!as)
		return ENOMEM;
	
	prg->loader_status = elf_load((elf_header_t *) image_addr, as, 0);
	if (prg->loader_status != EE_OK) {
		as_destroy(as);
		prg->task = NULL;
		prg->main_thread = NULL;
		
		if (prg->loader_status != EE_LOADER)
			return ENOTSUP;
		
		/* Register image as the program loader */
		if (program_loader != NULL)
			return ELIMIT;
		
		program_loader = image_addr;
		printf("Program loader at %p\n", (void *) image_addr);
		
		return EOK;
	}
	
	return program_create(as, ((elf_header_t *) image_addr)->e_entry,
	    name, prg);
}
Exemple #3
0
int main(int argc, const char *argv[]) {
	const int StacksNo = 2;
	Stack *stacks[StacksNo];

    stacks[0] = ls_create(sizeof(int), 5);
	stacks[1] = as_create(sizeof(int), 5);

	int stackIt = 0;
	for (stackIt = 0; stackIt < StacksNo; ++stackIt) {
		Stack *s = stacks[stackIt];
		int i = 0;
		for (i = 0; i < 8; ++i) {
			if (0 != s->push(s, &i)) {
				fprintf(stderr, "Error on pushing %d\n", i);
			}
		}

        int peekData;
		int data;
		while (0 != s->size(s)) {
            s->peek(s, &peekData);
			if (0 == s->pop(s, &data)) {
				printf("Popped %d, peeked %d\n", data, peekData);
			}
			else {
				fprintf(stderr, "Cannot get element\n");
			}
		}
	}

    return 0;
}
Datum
adaptive_counter_update(PG_FUNCTION_ARGS)
{
    
    bytea * data;
    AdaptiveCounter ac;
  
    /* is the counter created (if not, create it - error 1%, 10mil items) */
    if (PG_ARGISNULL(0)) {
      ac = as_create(0.01, 4);
      data = (bytea*)palloc(ac->length + VARHDRSZ);
      SET_VARSIZE(data, ac->length);
      memcpy(VARDATA(data), ac, ac->length);
      elog(NOTICE, "Adaptive Counter: %d bytes", ac->length);
    } else {
      data = PG_GETARG_BYTEA_P(0);
    }
    
    ac = (AdaptiveCounter)VARDATA(data);
      
    /* get the new item */
    text * item = PG_GETARG_TEXT_P(1);
    
    /* in-place update works only if executed as aggregate */
    as_add_element(ac, VARDATA(item), VARSIZE(item) - VARHDRSZ);
    
    /* return the updated bytea */
    PG_RETURN_BYTEA_P(data);
    
}
Exemple #5
0
/** Create a task from the program loader image.
 *
 * @param prg  Buffer for storing program info.
 * @param name Name to set for the program's task.
 *
 * @return EOK on success or negative error code.
 *
 */
int program_create_loader(program_t *prg, char *name)
{
	as_t *as = as_create(0);
	if (!as)
		return ENOMEM;
	
	void *loader = program_loader;
	if (!loader) {
		as_destroy(as);
		printf("Cannot spawn loader as none was registered\n");
		return ENOENT;
	}
	
	prg->loader_status = elf_load((elf_header_t *) program_loader, as,
	    ELD_F_LOADER);
	if (prg->loader_status != EE_OK) {
		as_destroy(as);
		printf("Cannot spawn loader (%s)\n",
		    elf_error(prg->loader_status));
		return ENOENT;
	}
	
	return program_create(as, ((elf_header_t *) program_loader)->e_entry,
	    name, prg);
}
int sys_read(int fd, void *buf, size_t buflen) {
    struct fd* tmp;
    if (!buf || buf == NULL || !valid_address_check(curproc->p_addrspace, (vaddr_t)buf)){      // else if invalid buffer
        errno = EFAULT;
        return -1;
    }
    if (fd < 0 || fd >= MAX_fd_table){       // if fd < 0 || fd > MAX_fd_table or 
        errno = EBADF;
        return -1;
    }
	else if (fd == STDOUT_FILENO || fd == STDERR_FILENO){      // fd == STDOUT_FILENO || STDERR_FILENO
            errno = EIO;
            return -1;
        }
        else if (fd >= 3 && fd < MAX_fd_table){
            tmp = curproc->fd_table[fd];
            if (tmp == NULL || (tmp->file_flag & O_WRONLY)){        // or if file is not readable
                errno = EBADF;  // error
                return -1;
            }
        }

        struct uio u;
        struct iovec iov;
        struct addrspace *as ;
        as = as_create();

        iov.iov_ubase = buf;
        iov.iov_len = buflen;

        u.uio_iov = &iov;
        u.uio_iovcnt = 1;
        u.uio_offset = tmp->offset;
        u.uio_resid = buflen;
        u.uio_segflg = UIO_USERSPACE;
        u.uio_rw = UIO_READ;
        u.uio_space = curproc_getas();
	
	if (fd == STDIN_FILENO){
		struct vnode *vn;
		char *console = NULL; // console string ("con:")
            console = kstrdup("con:"); // set to console
            vfs_open(console,O_RDONLY,0,&vn); // open the console vnode
            kfree(console); // free the console
            int result = VOP_READ(vn,&u);
            if(result < 0){
                    errno = EIO; //A hardware I/O error occurred writing the data
                    return -1;
            }
	} else{
	        int retval = VOP_READ(tmp->file, &u);
		if (retval < 0){
			errno = EIO;
			return -1;
		}
	}
	return buflen - u.uio_resid ;
}
Exemple #7
0
/*
 * Load program "progname" and start running it in usermode.
 * Does not return except on error.
 *
 * Calls vfs_open on progname and thus may destroy it.
 */
int
runprogram(char *progname)
{
	struct vnode *v;
	vaddr_t entrypoint, stackptr;
	int result;

	/* Open the file. */
	result = vfs_open(progname, O_RDONLY, 0, &v);
	if (result) {
		return result;
	}

	/* We should be a new thread. */
	KASSERT(curthread->t_addrspace == NULL);

	/* Create a new address space. */
	curthread->t_addrspace = as_create();
	if (curthread->t_addrspace==NULL) {
		vfs_close(v);
		return ENOMEM;
	}
	curthread->t_filetable = filetable_create();
	if(curthread->t_filetable == NULL){
		return ENOMEM;
	}

	/* Activate it. */
	as_activate(curthread->t_addrspace);

	/* Load the executable. */
	result = load_elf(v, &entrypoint);
	if (result) {
		/* thread_exit destroys curthread->t_addrspace */
		vfs_close(v);
		return result;
	}

	/* Done with the file now. */
	vfs_close(v);

	/* Define the user stack in the address space */
	result = as_define_stack(curthread->t_addrspace, &stackptr);
	if (result) {
		/* thread_exit destroys curthread->t_addrspace */
		return result;
	}

	/* Warp to user mode. */
	enter_new_process(0 /*argc*/, NULL /*userspace addr of argv*/,
			  stackptr, entrypoint);
	
	/* enter_new_process does not return. */
	panic("enter_new_process returned\n");
	return EINVAL;
}
Exemple #8
0
/*
 * Load program "progname" and start running it in usermode.
 * Does not return except on error.
 *
 * Calls vfs_open on progname and thus may destroy it.
 */
int
runprogram(char *progname)
{
	struct vnode *v;
	vaddr_t entrypoint, stackptr;
	int result;

	/* Open the file. */
	result = vfs_open(progname, O_RDONLY, &v);
	if (result) {
		return result;
	}

	/* We should be a new thread. */
	assert(curthread->t_vmspace == NULL);

	/* Create a new address space. */
	curthread->t_vmspace = as_create();
	if (curthread->t_vmspace==NULL) {
		vfs_close(v);
		return ENOMEM;
	}

	//kprintf("\n in runprogram");
	assignPid();
	/* Activate it. */
	as_activate(curthread->t_vmspace);

	/* Load the executable. */
	result = load_elf(v, &entrypoint);
	if (result) {
		/* thread_exit destroys curthread->t_vmspace */
		vfs_close(v);
		return result;
	}

	/* Done with the file now. */
	vfs_close(v);

	/* Define the user stack in the address space */
	result = as_define_stack(curthread->t_vmspace, &stackptr);
	if (result) {
		/* thread_exit destroys curthread->t_vmspace */
		return result;
	}

	/* Warp to user mode. */
	md_usermode(0 /*argc*/, NULL /*userspace addr of argv*/,
		    stackptr, entrypoint);
	
	/* md_usermode does not return */
	panic("md_usermode returned\n");
	return EINVAL;
}
Exemple #9
0
/*
 * as_copy: duplicate an address space. Creates a new address space and
 * copies each vm_object in the source address space into the new one.
 * Implements the VM system part of fork().
 *
 * Synchronization: none.
 */
int
as_copy(struct addrspace *as, struct addrspace **ret)
{
	struct addrspace *newas;
	struct vm_object *vmo, *newvmo;
	int i, result;

	newas = as_create();
	if (newas==NULL) {
		return ENOMEM;
	}

	/*
	 * We assume that as belongs to curthread, and furthermore that
	 * it's not shared with any other threads. (The latter restriction
	 * is easily lifted; the former is not.)
	 *
	 * We assume that nothing is going to modify the source address
	 * space except for the usual page evictions by other processes.
	 */

	assert(as==curthread->t_vmspace);


	/* copy the vmos */
	for (i = 0; i < array_getnum(as->as_objects); i++) {
		vmo = array_getguy(as->as_objects, i);

		result = vm_object_copy(vmo, newas, &newvmo);
		if (result) {
			goto fail;
		}

		result = array_add(newas->as_objects, newvmo);
		if (result) {
			vm_object_destroy(newas, newvmo);
			goto fail;
		}
	}

	*ret = newas;
	return 0;

fail:
	as_destroy(newas);
	return result;
}
Exemple #10
0
int
as_copy(struct addrspace *old, struct addrspace **ret)
{
	struct addrspace *newas;

	newas = as_create();
	if (newas==NULL) {
		return ENOMEM;
	}

	/*
	 * Write this.
	 */

	(void)old;
	
	*ret = newas;
	return 0;
}
Exemple #11
0
int
as_copy(struct addrspace *old, struct addrspace **ret)
{
	struct addrspace *newas;

	newas = as_create();
	if (newas==NULL) {
		return ENOMEM;
	}

	/*
	 * Write this.
	 */
	 //dont worry until end, uses fork

	(void)old;
	
	*ret = newas;
	return 0;
}
Exemple #12
0
int
as_copy(struct addrspace *old, struct addrspace **ret, pid_t pid)
{
	struct addrspace *newas;
	struct page *newpage, *page;
	int i;
	int nindex, oindex;
	paddr_t nf, of;

	newas = as_create();
	if (newas==NULL) {
		return ENOMEM;
	}

	for(i=0;i<array_getnum(old->pages);i++)
	{
		newpage = (struct page *) kmalloc(sizeof(struct page));
		if (newpage==NULL)
			return ENOMEM;
		page = (struct page *) array_getguy(old->pages, i);
		memcpy(newpage, page, sizeof(struct page));
		array_add(newas->pages, newpage);

		oindex = getindex(newpage->vaddr);
		of = FRAME(oindex);

		nindex = addpage(newpage->vaddr,
				pid, 
				newpage->perms & P_R_B,
				newpage->perms & P_W_B,
				newpage->perms & P_X_B,
				PADDR_TO_KVADDR(of));


	}

	*ret = newas;
	return 0;
}
Exemple #13
0
int sys_fork(struct trapframe *tf,struct addrspace *parent_addr_space){
	
	//kprintf("\n in sys_fork");
	struct thread *child_thread=NULL;
	struct thread *test;
	struct addrspace *parent_addr_space_copy;

	//create a new address space
	//kprintf("\n in sys_fork:creating new addr space");
	parent_addr_space_copy=as_create();
	if(parent_addr_space_copy==NULL)
		return ENOMEM;

	//make a copy of the parent's address space
	//kprintf("\n in sys_fork:copying to the addr space %x",parent_addr_space);
	as_copy(parent_addr_space,&parent_addr_space_copy);
	//kprintf("\n in sys_fork:copying to the addr space %x",*(parent_addr_space_copy));

	//make a copy of the parent`s trapframe on kernel heap
	//kprintf("\n in sys_fork:copying trap frame");
	struct trapframe *tf_temp=kmalloc(sizeof(struct trapframe));
	if(tf_temp==NULL){
		kfree(tf_temp);
		return ENOMEM;
	}
	memcpy(tf_temp,tf,sizeof(struct trapframe));

	//call thread_fork
	//pass the trapframe and the address space of the parent to the child`s thread_fork
	//kprintf("\n in sys_fork:forking");
	thread_fork("child thread",tf_temp,(unsigned long)parent_addr_space_copy,md_forkentry,&child_thread);

	//kprintf("\nchild_thread::%x",*(child_thread));
	//copy other required stuff and return with child`s pid
	//test=(child_thread);
	return child_thread->pid;
}
Exemple #14
0
runprogram(char *progname)
#endif
{
	struct addrspace *as;
	struct vnode *v;
	vaddr_t entrypoint, stackptr;
	int result;

	/* Open the file. */
	result = vfs_open(progname, O_RDONLY, 0, &v);
	if (result) {
		return result;
	}

	/* We should be a new process. */
	KASSERT(curproc_getas() == NULL);

	/* Create a new address space. */
	as = as_create();
	if (as ==NULL) {
		vfs_close(v);
		return ENOMEM;
	}

	/* Switch to it and activate it. */
  curproc_setas(as);
  as_activate();

	/* Load the executable. */
	result = load_elf(v, &entrypoint);
	if (result) {
		/* p_addrspace will go away when curproc is destroyed */
		vfs_close(v);
		return result;
	}

	/* Done with the file now. */
	vfs_close(v);

	/* Define the user stack in the address space */
	result = as_define_stack(as, &stackptr);
	if (result) {
		/* p_addrspace will go away when curproc is destroyed */
		return result;
	}

#if OPT_A2
  // How much space do we need for args in stack?
  // We need space for each pointer (4argc)
  // We need space for each character, including NULL termination, plus
  // padding to make multiples of 4
  int stringSpace = 0;
  for (unsigned long i = 0; i < argc; i++) {
    stringSpace += strlen(argv[i]) + 1;
  }

  // Align stack pointer to an 8-byte alignment
  while ((stackptr - (4*argc) - stringSpace) % 8 != 0) {
    stackptr--;
  }

  // Use a vaddr array to track the addresses the strings end up in
  // One bigger than argc to also have the pointer to the final NULL
  // value
  vaddr_t stringAddr[argc+1];

  // Copy argument strings onto stack
  // Array must end with NULL pointer, so do that first
  stackptr -= 4;
  copyout((void *)NULL, (userptr_t)stackptr, (size_t)4);
  stringAddr[argc] = stackptr;
  for (int i = argc-1; i >= 0; i--) {
    stackptr -= strlen(argv[i]) + 1;
    while (stackptr % 4 != 0) stackptr--;
    copyoutstr(argv[i], (userptr_t)stackptr, (size_t)strlen(argv[i]), NULL);
    stringAddr[i] = stackptr;
  }

  // Now use the stored addresses of the string to add the appropriate
  // pointers to the stack
  for (int i = argc; i >= 0; i--) {
    stackptr -= sizeof(vaddr_t);
    copyout(&stringAddr[i], (userptr_t)stackptr, sizeof(vaddr_t));
  }

	/* Warp to user mode. */
	enter_new_process(argc /*argc*/, (userptr_t)stackptr /*userspace addr of argv*/,
			  stackptr, entrypoint);
#else
	/* Warp to user mode. */
	enter_new_process(0 /*argc*/, NULL /*userspace addr of argv*/,
			  stackptr, entrypoint);
#endif

	/* enter_new_process does not return. */
	panic("enter_new_process returned\n");
	return EINVAL;
}
Exemple #15
0
int sys_execv(char* program, char** args) {
	int result;

	char name[strlen(program) + 1];
	result = copyin((userptr_t) program,
				name, (strlen(program) + 1) * sizeof(char));
	//kprintf("%s", name);

	int len_arg = 0;
	while(args[len_arg] != NULL) {
		len_arg++;
	}

	int length_every_arg[len_arg];
	for(int i = 0; i < len_arg; i++) {
		length_every_arg[i] = strlen(args[i]);
	}

	char* kern_args[len_arg];
	for(int i = 0; i < len_arg; i++) {
		kern_args[i] = kmalloc(sizeof(char) * length_every_arg[i] + 1);
		copyin((const_userptr_t)args[i], kern_args[i],
              (length_every_arg[i] + 1) * sizeof(char));
	}
/*
	for(int i = 0; i < len_arg; i++) {
		kprintf("{ _%d__%p__%p_",strlen(kern_args[i]), kern_args[i],args[i]);
		kprintf("%s", kern_args[i]);
		kprintf("}\n");
	}
*/
/////////////////////////////////////////////////////
// this is "copied" from runprogram
  	struct addrspace* old_as;
	struct vnode* v;
	vaddr_t entrypoint, stackptr;

	result = vfs_open(program, O_RDONLY, 0, &v);
	if(result) {
		return result;
	}

	as_deactivate();
	old_as = curproc_setas(NULL);
	as_destroy(old_as);

	struct addrspace* new_as = as_create();
	if(new_as == NULL) {
		vfs_close(v);
		return ENOMEM;
	}
	curproc_setas(new_as);
	as_activate();

	result = load_elf(v, &entrypoint);
	if(result) {
		vfs_close(v);
		return result;
	}

	vfs_close(v);
	
	result = as_define_stack(new_as, &stackptr);
	if(result) {
		return result;
	}
//////////////////////////////////////////////////////////
// kern_args
// the addr of stackptr is 0x8000 0000
	vaddr_t argv = stackptr;
	for(int i = 0; i < len_arg + 1; i++) {
		argv = argv - 4;
	}
   
	vaddr_t start = argv;
	vaddr_t temp = argv;

	copyout(NULL, (userptr_t)(stackptr - 4), 4);
	//starts from 1, because argv[0] is reserved for the program name
	for(int i = 0; i < len_arg; i++) {
		//question? why do I have to add 2
		int m = sizeof(char) * (strlen(kern_args[i]) + 1);
	//	kprintf("the value of m -> %d\n", m);
		argv = argv - m;
		copyout(kern_args[i], (userptr_t)argv, m);
	//	kprintf("***(%d)%s(%p)\n***", m, (char* )argv, (void *) argv);
		copyout(&argv, (userptr_t)temp, sizeof(char* ));
		temp = temp + 4;
	}
	
	for(int i = 0; i < len_arg; i++) {
		kfree(kern_args[i]);
	}
	
	while(argv % 8 != 0) {argv--;}
	 
	enter_new_process(len_arg, (userptr_t)start, (vaddr_t) argv, entrypoint);

//	enter_new_process(0, NULL, stackptr, entrypoint);
	panic("enter_new_process returned");
	return EINVAL;
}
Exemple #16
0
int sys_execv(char* progname, char** args, int *retval, bool iskernel) {
	int result;
	int *args_len;
	size_t len;
	size_t total_len = 0;
	char *temp;
	char **kern_args;
	int nargs = 0;
	userptr_t *usr_argv = NULL;
	char *kern_progname = kmalloc(PATH_MAX);
	args_len = kmalloc(sizeof(int) * ARG_MAX);
	temp = kmalloc(sizeof(char) * ARG_MAX);

	if (kern_progname == NULL || args_len == NULL || temp == NULL){
		*retval = -1;
		return ENOMEM;
	}

	if (args == NULL || progname == NULL) {
		*retval = -1;
		return EFAULT;
	}

	if (!iskernel) {
		result = copyinstr((userptr_t)args, temp, ARG_MAX, &len);
		if (result) {
			*retval = -1;
			return result;
		}
	}

	// Figure out nargs, and the length for each arg string
	while(args[nargs] != NULL) {
		if (iskernel) {
			len = strlen(args[nargs]) + 1;
			if (len == 1) {
				nargs--;
				break;
			}
			strcpy(temp, args[nargs]);
		} else {
			result = copyinstr((userptr_t)args[nargs], temp, ARG_MAX, &len);
			if (result) {
				*retval = -1;
				return result;
			}
		}
		args_len[nargs] = len;
		total_len += len;
		nargs += 1;
	}
	kfree(temp);

	if (total_len > ARG_MAX) {
		*retval = -1;
		return E2BIG;
	}

	kern_args = kmalloc(sizeof(char*) * nargs);

	// Go through args and copy everything over to kern_args using copyinstr
	for (int i = 0; i < nargs; i++) {
		kern_args[i] = kmalloc(sizeof(char) * args_len[i]);
		if (kern_args[i] == NULL) {
			*retval = -1;
			return ENOMEM;
		}

		if (iskernel) {
			strcpy(kern_args[i], args[i]);
			len = strlen(kern_args[i]);
		} else {
			copyinstr((userptr_t)args[i], kern_args[i], ARG_MAX, NULL);
		}
	}

	// This is from runprogram 
	struct addrspace *as;
	struct vnode *v;
	vaddr_t entrypoint, stackptr;


	if (iskernel) {
		strcpy(kern_progname, progname);
		len = strlen(kern_progname);
	} else {
		result = copyinstr((userptr_t)progname, kern_progname, PATH_MAX, NULL);
	}

	if (*kern_progname == 0) {
		*retval = -1;
		return EISDIR;
	}
	if (result) {
		kfree(kern_progname);
		*retval = -1;
		return result;
	}

	/* Open the file. */
	result = vfs_open(kern_progname, O_RDONLY, 0, &v);
	if (result) {
		*retval = -1;
		return result;
	}

	// Blow up the current addrspace. TODO, this may be problematic
	if (!iskernel) {
		as_destroy(curproc->p_addrspace);
		curproc->p_addrspace = NULL;
	}

	/* We should be a new process. */
	KASSERT(proc_getas() == NULL);

	/* Create a new address space. */
	as = as_create();
	if (as == NULL) {
		vfs_close(v);
		*retval = -1;
		return ENOMEM;
	}

	/* Switch to it and activate it. */
	proc_setas(as);
	as_activate();

	/* Intialize file table, not needed for execv */
	if (iskernel)
		filetable_init();

	/* Load the executable. */
	result = load_elf(v, &entrypoint);
	if (result) {
		/* p_addrspace will go away when curproc is destroyed */
		vfs_close(v);
		*retval = -1;
		return result;
	}

	/* Done with the file now. */
	vfs_close(v);

	/* Define the user stack in the address space */
	result = as_define_stack(as, &stackptr);
	if (result) {
		/* p_addrspace will go away when curproc is destroyed */
		*retval = -1;
		return result;
	}

	// Clear space for arg pointers +1 for NULL terminator
	stackptr -= (sizeof(char*)) * (nargs + 1);

	// Convenience method for indexing
	usr_argv = (userptr_t*)stackptr;

	for(int i = 0; i < nargs; i++ ) {
		// Clear out space for an arg string
		stackptr -= sizeof(char) * (strlen(kern_args[i]) + 1);
		// Assign the string's pointer to usr_argv
		usr_argv[i] = (userptr_t)stackptr;
		// Copy over string
		copyout(kern_args[i], usr_argv[i],
			sizeof(char) * (strlen(kern_args[i]) + 1));
	}

	// NULL terminate usr_argv
	usr_argv[nargs] = NULL;

	// Free memory
	for(int i = 0; i < nargs; i++) {
		kfree(kern_args[i]);
	}
	kfree(kern_args);

	/* Warp to user mode. */
	enter_new_process(nargs /*argc*/, (userptr_t)usr_argv /*userspace addr of argv*/,
			  NULL /*userspace addr of environment*/,
			  stackptr, entrypoint);

	/* enter_new_process does not return. */
	panic("enter_new_process returned\n");
	return EINVAL;
}
Exemple #17
0
int sys_execv(userptr_t progname_ptr, userptr_t args_ptr){

	
	char* prog_name = kmalloc(PATH_MAX); 
	size_t prog_name_len;
	if((char*)progname_ptr == NULL || (char**)args_ptr == NULL){
		return EFAULT;
	}
	int argc = 0;
	char** args_ptrs = kmalloc(ARG_MAX);
        while(1){
                char* arg = NULL;
                copyin(args_ptr+argc*sizeof(char*), &arg, sizeof(char*));
		args_ptrs[argc] = arg;
		if(arg != NULL){
			argc++;
		}else{
			break;
		}
	}
	if(argc> 64){
		return E2BIG;
	}

	int result_prog_name = copyinstr(progname_ptr,prog_name,PATH_MAX, &prog_name_len);
	if(result_prog_name != 0){
		return result_prog_name;
	}


	char* argv = kmalloc(ARG_MAX);
	size_t * arg_offsets = kmalloc(argc * sizeof(size_t));
        int offset = 0;
	for(int i = 0; i < argc; i++){
		//char* arg = kmalloc(ARG_MAX);
		size_t arg_len;
		int result = copyinstr((userptr_t)args_ptrs[i],
				 argv+offset, ARG_MAX - offset, &arg_len );
		if(result != 0){
			return result;
		}
		arg_offsets[i] = offset;
		offset += ROUNDUP(arg_len+1,8);
		//argv[i] = arg;
	}

	// prog_name (char*)   AND   argv (char*)

	struct addrspace *curproc_as = curproc_getas();
	

	struct addrspace *as;
	struct vnode *v;
	vaddr_t entrypoint, stackptr;
	vaddr_t cur_ptr;
	int result;
	/* Open the file. */
	result = vfs_open(prog_name, O_RDONLY, 0, &v);
	if (result) {
		return result;
	}

	/* Create a new address space. */
	as = as_create();
	if (as ==NULL) {
		vfs_close(v);
		return ENOMEM;
	}
	/* Switch to it and activate it. */
	curproc_setas(as);
	as_activate();
	/* Load the executable. */
	result = load_elf(v, &entrypoint);
	if (result) {
		/* p_addrspace will go away when curproc is destroyed */
		vfs_close(v);
		return result;
	}
	/* Done with the file now. */
	vfs_close(v);
	/* Define the user stack in the address space */
	result = as_define_stack(as, &stackptr);

	// Have both argc and prog_name ready for runprogram
	cur_ptr = stackptr;
	cur_ptr -= offset;
	result = copyout(argv, (userptr_t)cur_ptr, offset);
	if(result != 0){
		return result;
	}

	userptr_t * arg_offsets_up = kmalloc(sizeof(userptr_t) * (argc+1));
	for(int i = 0; i < argc; i++){
		userptr_t ptr = (userptr_t)cur_ptr +  arg_offsets[i];
		arg_offsets_up[i] = ptr;
	}
	arg_offsets_up[argc] = NULL;

	cur_ptr -= sizeof(userptr_t) * (argc+1);

	result = copyout(arg_offsets_up, (userptr_t)cur_ptr, sizeof(userptr_t) * (argc+1) );

	if(result != 0){
		return result;
	}

	as_destroy(curproc_as);
	kfree(arg_offsets);
	kfree(arg_offsets_up);
	kfree(argv);
	kfree(args_ptrs);
	kfree(prog_name);

	enter_new_process(argc /*argc*/, (userptr_t)cur_ptr /*userspace addr of argv*/,
	cur_ptr, entrypoint);
	/* enter_new_process does not return. */
	panic("enter_new_process returned\n");
	return EINVAL;

	//return 0;
}
Exemple #18
0
int	
sys_execv( userptr_t upname, userptr_t uargs ) {
	struct addrspace		*as_new = NULL;
	struct addrspace		*as_old = NULL;
	struct vnode			*vn = NULL;
	vaddr_t				entry_ptr;
	vaddr_t				stack_ptr;
	int				err;
	char				kpname[MAX_PROG_NAME];
	int				nargs;
	int				buflen;

	KASSERT( curthread != NULL );
	KASSERT( curthread->td_proc != NULL );
	
	(void)uargs;
	
	//lock the execv args
	lock_acquire( lk_exec );

	//copy the old addrspace just in case.
	as_old = curthread->t_addrspace;

	//copyin the program name.
	err = copyinstr( upname, kpname, sizeof( kpname ), NULL );
	if( err ) {
		lock_release( lk_exec );
		return err;
	}
	
	//try to open the given executable.
	err = vfs_open( kpname, O_RDONLY, 0, &vn );
	if( err ) {
		lock_release( lk_exec );
		return err;
	}

	//copy the arguments into the kernel buffer.
	err = copy_args( uargs, &nargs, &buflen );
	if( err ) {
		lock_release( lk_exec );
		vfs_close( vn );
		return err;
	}

	//create the new addrspace.
	as_new = as_create();
	if( as_new == NULL ) {
		lock_release( lk_exec );
		vfs_close( vn );
		return ENOMEM;
	}
	
	//activate the new addrspace.
	as_activate( as_new );

	//temporarily switch the addrspaces.
	curthread->t_addrspace = as_new;

	//load the elf executable.
	err = load_elf( vn, &entry_ptr );
	if( err ) {
		curthread->t_addrspace = as_old;
		as_activate( as_old );
	
		as_destroy( as_new );
		vfs_close( vn );
		lock_release( lk_exec );
		return err;
	}

	//create a stack for the new addrspace.
	err = as_define_stack( as_new, &stack_ptr );
	if( err ) {
		curthread->t_addrspace = as_old;
		as_activate( as_old );

		as_destroy( as_new );
		vfs_close( vn );
		lock_release( lk_exec );
		return err;
	}
	
	//adjust the stackptr to reflect the change
	stack_ptr -= buflen;
	err = adjust_kargbuf( nargs, stack_ptr );
	if( err ) {
		curthread->t_addrspace = as_old;
		as_activate( as_old );

		as_destroy( as_new );
		vfs_close( vn );
		lock_release( lk_exec );
		return err;
	}

	//copy the arguments into the new user stack.
	err = copyout( kargbuf, (userptr_t)stack_ptr, buflen );
	if( err ) {
		curthread->t_addrspace = as_old;
		as_activate( as_old );
		as_destroy( as_new );
		vfs_close( vn );
		lock_release( lk_exec );
		return err;
	}

	//reelase lk_exec
	lock_release( lk_exec );

	//no need for it anymore.
	vfs_close( vn );

	//we are good to go.
	as_destroy( as_old );
	
	//off we go to userland.
	enter_new_process( nargs-1, (userptr_t)stack_ptr, stack_ptr, entry_ptr );
	
	panic( "execv: we should not be here." );
	return EINVAL;
}
/*
 * Load program "progname" and start running it in usermode.
 * Does not return except on error.
 *
 * Calls vfs_open on progname and thus may destroy it.
 */
int
runprogram(char *progname, char **argv, unsigned long argc)
{
	struct vnode *v;
	vaddr_t entrypoint, stackptr;
	int result;
	pid_t pidRetVal;


	/* Open the file. */
	result = vfs_open(progname, O_RDONLY, &v);
	if (result) {
		return result;
	}

	/* We should be a new thread. */
	assert(curthread->t_vmspace == NULL);

	/* Create filetable for process*/
	curthread->ft = create_process_filetable();
	if(curthread->ft == NULL)
	{
		vfs_close(v);
		return ENOMEM;
	}
	
	/* Initialize STDIN, STDOUT, STDERR */
	struct ft_node* standardIn = create_ft_node();
	struct ft_node* standardOut = create_ft_node();
	struct ft_node* standardErr = create_ft_node();

	char console1[] = "con:";
	result = vfs_open(console1, O_RDONLY, &standardIn->v);
	if(result)
	{
		kprintf("Cannot open STDIN\n");
		vfs_close(v);
		return result;
	}
	standardIn->mode = O_RDONLY;
	array_add(curthread->ft->file_descriptors, standardIn);

	char console2[] = "con:";
	result = vfs_open(console2, O_WRONLY, &standardOut->v);
	if(result)
	{
		kprintf("Cannot open STDOUT\n");
		vfs_close(v);
		return result;
	}
	standardOut->mode = O_WRONLY;
	array_add(curthread->ft->file_descriptors, standardOut);

	char console3[] = "con:";
	result = vfs_open(console3, O_WRONLY, &standardErr->v);
	if(result)
	{
		kprintf("Cannot open STDERR\n");
		vfs_close(v);
		return result;
	}
	standardErr->mode = O_WRONLY;
	array_add(curthread->ft->file_descriptors, standardErr);

	/* Allocate initial PID for this first program */
	result = allocate_pid(&pidRetVal);
	if(result)
	{
		kprintf("Could not allocate PID\n");
		vfs_close(v);
		return result;
	}
	curthread->PID = pidRetVal; 
	((struct p_node *)array_getguy(pid_table, curthread->PID))->is_interested = 0;
	
	/* Create a new address space. */
	curthread->t_vmspace = as_create();
	if (curthread->t_vmspace==NULL) {
		vfs_close(v);
		return ENOMEM;
	}

	/* Activate it. */
	as_activate(curthread->t_vmspace);

	/* Load the executable. */
	result = load_elf(v, &entrypoint);
	if (result) {
		/* thread_exit destroys curthread->t_vmspace */
		vfs_close(v);
		return result;
	}
	//kprintf("finished loadelf in runprog\n");

	/* Done with the file now. */
	vfs_close(v);

	/* Define the user stack in the address space */
	result = as_define_stack(curthread->t_vmspace, &stackptr);
	if (result) {
		/* thread_exit destroys curthread->t_vmspace */
		return result;
	}
	vaddr_t stackptrv[argc+1];
	int i;
	size_t actual;
	for(i = argc-1; i >= 0; i--)
	{
		int len = strlen(argv[i]);
		len++;
		int padding = len % 4;
		stackptr -= len + (4 - padding);
		result = copyoutstr(argv[i], (userptr_t)stackptr, len, &actual);
		if(result)
		{

			return result;
		}
		stackptrv[i] = stackptr;
	}
	stackptrv[argc] = 0;
	for(i = argc; i >= 0; i--)
	{
		stackptr -= sizeof(vaddr_t);
		result = copyout(&stackptrv[i], (userptr_t)stackptr, sizeof(vaddr_t));
		if(result)
		{
			return result;
		}
	}
	//kprintf("Before usernmode\n");
	/* Warp to user mode. */
	md_usermode(argc /*argc*/, (userptr_t)stackptr /*userspace addr of argv*/,
		    stackptr, entrypoint);
	
	/* md_usermode does not return */
	panic("md_usermode returned\n");
	return EINVAL;
}
Exemple #20
0
int
sys_execv(const_userptr_t path, const_userptr_t argv)
{
    int err;
    struct process *proc = curthread->t_proc;
    
    char *kpath = kmalloc(PATH_MAX);
    if (kpath == NULL)
        return ENOMEM;
    
    // copy in path
    size_t path_len;
    if ((err = copyinstr(path, kpath, PATH_MAX, &path_len)))
    {
        kfree(kpath);
        return err;
    }
    
    // give the process a new name
    char *old_name = proc->ps_name;
    proc->ps_name = kstrdup(kpath);
    if (proc->ps_name == NULL)
    {
        proc->ps_name = old_name;
        kfree(kpath);
        return ENOMEM;
    }
    
    // copy in args
    size_t argc;
    size_t total_len;
    char **kargv = kmalloc((ARGNUM_MAX + 1) * sizeof(char *));
    err = copyinargs(argv, kargv, &argc, &total_len);
    if (err)
    {
        kfree(proc->ps_name);
        proc->ps_name = old_name;
        kfree(kpath);
        return err;
    }
    
    // Open the file.
    struct vnode *v;
	err = vfs_open(kpath, O_RDONLY, 0, &v);
    kfree(kpath);
	if (err)
    {
        free_kargv(kargv);
        kfree(proc->ps_name);
        proc->ps_name = old_name;
		return err;
    }
    
    // set up new address space
    struct addrspace *old_as = curthread->t_proc->ps_addrspace;
    struct addrspace *as = as_create();
    if (as == NULL)
    {
        vfs_close(v);
        free_kargv(kargv);
        kfree(proc->ps_name);
        proc->ps_name = old_name;
        return ENOMEM;
    }
    proc->ps_addrspace = as;
    
    // Activate the new address space
    as_activate(as);
    
    vaddr_t entrypoint;
    err = load_elf(v, &entrypoint);
    if (err)
    {
        proc->ps_addrspace = old_as;
        as_activate(old_as);
        as_destroy(as);
        vfs_close(v);
        free_kargv(kargv);
        kfree(proc->ps_name);
        proc->ps_name = old_name;
        return err;
    }
    
    // close the file now, since we will not be returning
    // here from user mode.
    vfs_close(v);
    
    // set up user stack
    vaddr_t stackptr;
    err = as_define_stack(as, &stackptr);
    if (err)
    {
        proc->ps_addrspace = old_as;
        as_activate(old_as);
        as_destroy(as);
        free_kargv(kargv);
        kfree(proc->ps_name);
        proc->ps_name = old_name;
        return err;
    }
    
    // copy arguments at base of stack
    stackptr -= total_len;
    stackptr -= (argc + 1) * sizeof(userptr_t);
    err = copyoutargs((userptr_t)stackptr, kargv, argc, total_len);
    if (err)
    {
        proc->ps_addrspace = old_as;
        as_activate(old_as);
        as_destroy(as);
        free_kargv(kargv);
        kfree(proc->ps_name);
        proc->ps_name = old_name;
        return err;
    }
    
    // destroy old address space and free memory
    // that we will no longer need
    as_destroy(old_as);
    kfree(old_name);
    
    
    // Warp to user mode
    enter_new_process(argc, (userptr_t)stackptr, stackptr, entrypoint);
    
    // enter_new_process() does not return
	panic("enter_new_process returned\n");
	return EINVAL;
}
Exemple #21
0
/*
 * Load program "progname" and start running it in usermode.
 * Does not return except on error.
 *
 * Calls vfs_open on progname and thus may destroy it.
 */
int
runprogram(char *progname, char **args, unsigned int nargs)
{
	struct addrspace *as;
	struct vnode *v;
	vaddr_t entrypoint, stackptr;
	int result;

        int argc = nargs;
        char **argv = (char **)kmalloc((argc + 1) * sizeof(char *));
        if(argv == NULL)
        {
            return ENOMEM;
        }

        for(int i = 0; i < argc; ++i)
        {
            argv[i] = args[i];
        }
        argv[argc] = NULL;
       
       
	/* Open the file. */
	result = vfs_open(progname, O_RDONLY, 0, &v);
	if (result) {
		return result;
	}

	/* We should be a new process. */
	KASSERT(curproc_getas() == NULL);

	/* Create a new address space. */
	as = as_create();
	if (as ==NULL) {
		vfs_close(v);
		return ENOMEM;
	}

	/* Switch to it and activate it. */
	curproc_setas(as);
	as_activate();

	/* Load the executable. */
	result = load_elf(v, &entrypoint);
	if (result) {
		/* p_addrspace will go away when curproc is destroyed */
		vfs_close(v);
		return result;
	}

	/* Done with the file now. */
	vfs_close(v);

	/* Define the user stack in the address space */
	result = as_define_stack(as, &stackptr);
	if (result) {
		/* p_addrspace will go away when curproc is destroyed */
		return result;
	}

        /*------copy args to user stack-----------*/
        
        vaddr_t *argPtrs = (vaddr_t *)kmalloc((argc + 1) * sizeof(vaddr_t));
        if(argPtrs == NULL)
        {
            for(int i = 0; i < argc; ++i)
            {
                kfree(argv[i]);
            }
            kfree(argv);
            as_deactivate();
            as = curproc_setas(NULL);
            as_destroy(as);
            return ENOMEM;
        }
        
        for(int i = argc-1; i >= 0; --i)
        {
            //arg length with null
            size_t curArgLen = strlen(argv[i]) + 1;
            
            size_t argLen = ROUNDUP(curArgLen,4);
            
            stackptr -= (argLen * sizeof(char));
            
            //kprintf("copying arg: %s to addr: %p\n", temp, (void *)stackptr);
            
            //copy to stack
            result = copyout((void *) argv[i], (userptr_t)stackptr, curArgLen);
            if(result)
            {
                kfree(argPtrs);
                for(int i = 0; i < argc; ++i)
                {
                    kfree(argv[i]);
                }
                kfree(argv);
                as_deactivate();
                as = curproc_setas(NULL);
                as_destroy(as);
                return result;
            }
            
            argPtrs[i] = stackptr;        
        }    
        
        argPtrs[argc] = (vaddr_t)NULL;
        
        //copy arg pointers
        for(int i = argc; i >= 0; --i)
        {
            stackptr -= sizeof(vaddr_t);
            result = copyout((void *) &argPtrs[i], ((userptr_t)stackptr),sizeof(vaddr_t));
            if(result)
            {
                kfree(argPtrs);
                for(int i = 0; i < argc; ++i)
                {
                    kfree(argv[i]);
                }
                kfree(argv);
                as_deactivate();
                as = curproc_setas(NULL);
                as_destroy(as);
                return result;
            }
        }
        
        
        kfree(argPtrs);
        
        
        
        
        vaddr_t baseAddress = USERSTACK;
        
        vaddr_t argvPtr = stackptr;
        
        vaddr_t offset = ROUNDUP(USERSTACK - stackptr,8);
        
        stackptr = baseAddress - offset;
        
/*
        for(vaddr_t i = baseAddress; i >= stackptr; --i)
        {
            char *temp;
            temp = (char *)i;
            //kprintf("%p: %c\n",(void *)i,*temp);
            
            kprintf("%p: %x\n", (void *)i, *temp & 0xff);
        }
*/
        
        
        /*-done-copy args to user stack-----------*/
        
	/* Warp to user mode. */
	enter_new_process(argc /*argc*/, (userptr_t)argvPtr /*userspace addr of argv*/,
			  stackptr, entrypoint);
	
	/* enter_new_process does not return. */
	panic("enter_new_process returned\n");
	return EINVAL;
}
Exemple #22
0
int
as_copy(struct addrspace *old, struct addrspace **ret)
{
	int spl = splhigh();
	struct addrspace *newas;

	newas = as_create();
	if (newas == NULL) {
		return ENOMEM;
	}
	/******************** copy internal fields ***************/
	// first all regions
	unsigned int i;
	for (i = 0; i < array_getnum(old->as_regions); i++) {
		struct as_region* temp = kmalloc(sizeof(struct as_region));
		*temp = *((struct as_region*)array_getguy(old->as_regions, i));
		array_add(newas->as_regions, temp);
	}

	newas->heap_start = old->heap_start;
	newas->heap_end = old->heap_end;
	newas->temp_text_permis = old->temp_text_permis;
	newas->temp_bss_permis = old->temp_bss_permis;

	// then both the first and second page table
	for (i = 0; i < FIRST_LEVEL_PT_SIZE; i++) {
		if(old->as_master_pagetable[i] != NULL) {
			newas->as_master_pagetable[i] = (struct as_pagetable*)kmalloc(sizeof(struct as_pagetable));
			// what the f**k am i doing?
			// the right thing to do here is to go through all PTEs of the old addrspace, if there's a 
			// valid PTE, meaning there's a page, be it PRESENT or SWAPPED, belonging to this addrspace.
			struct as_pagetable *src_pt = old->as_master_pagetable[i];
			struct as_pagetable *dest_pt = newas->as_master_pagetable[i];
			unsigned int j = 0;
			for (; j < SECOND_LEVEL_PT_SIZE; j++) {
				
				dest_pt->PTE[j] = 0;
				if(src_pt->PTE[j] & PTE_PRESENT) {
					// this source page is PRESENT in memory, we just allocate a page for 
					// the destination addrspace and copy src->dest and update PTE
					paddr_t src_paddr = (src_pt->PTE[j] & PAGE_FRAME);
					vaddr_t dest_vaddr = (i << 22) + (j << 12);
					// allocate a page for the destination addrspace, while making sure
					// that both the source and destination page are in memory
					paddr_t dest_paddr = alloc_page_userspace_with_avoidance(dest_vaddr, src_paddr);
					// sanity check
					// do the copy :)
					memmove((void *) PADDR_TO_KVADDR(dest_paddr),
					(const void*)PADDR_TO_KVADDR(src_paddr), PAGE_SIZE) ;
					// update the PTE of the destination pagetable
					// dest_pt->PTE[j] &= CLEAR_PAGE_FRAME;
					dest_pt->PTE[j] |= dest_paddr;
					dest_pt->PTE[j] |= PTE_PRESENT;

				} else if (src_pt->PTE[j] & PTE_SWAPPED){
					// this source page is SWAPPED, we load it back to mem :)
					vaddr_t src_vaddr = (i << 22) + (j << 12);
					vaddr_t dest_vaddr = src_vaddr;
					paddr_t src_paddr = load_swapped_page(old, src_vaddr);
					// now allocate a user page, but becareful not to swap out the 
					// source page we just brought in...
					paddr_t dest_paddr = alloc_page_userspace_with_avoidance(dest_vaddr, src_paddr);
					// do the copy
					memmove((void *) PADDR_TO_KVADDR(dest_paddr),
					(const void*)PADDR_TO_KVADDR(src_paddr), PAGE_SIZE) ;
					// update the PTE of the destination pagetable
					// dest_pt->PTE[j] &= CLEAR_PAGE_FRAME;
					dest_pt->PTE[j] |= dest_paddr;
					dest_pt->PTE[j] |= PTE_PRESENT;
				} else {
					// this source page is neither PRESENT nor SWAPPED, meaning this
					// page does not exist, we've got nothing to do in this case, nice :)
					dest_pt->PTE[j] = 0;
				}
			}
		} else {
			newas->as_master_pagetable[i] = NULL;
		} 
	}
	*ret = newas;
	splx(spl);
	return 0;
}
runprogram(char *progname)
#endif
{
	struct addrspace *as;
	struct vnode *v;
	vaddr_t entrypoint, stackptr;
	int result;

	//kprintf("bla0\n");
	/* Open the file. */
	result = vfs_open(progname, O_RDONLY, 0, &v);
	if (result) {
		return result;
	}
	//kprintf("bla1\n");
	/* We should be a new process. */
	KASSERT(curproc_getas() == NULL);
	//kprintf("bla2\n");
	/* Create a new address space. */
	as = as_create();
	if (as ==NULL) {
		vfs_close(v);
		return ENOMEM;
	}
	//kprintf("bla3\n");
	/* Switch to it and activate it. */
	curproc_setas(as);
	as_activate();
	//kprintf("bla4\n");
	/* Load the executable. */
	result = load_elf(v, &entrypoint);
	if (result) {
		/* p_addrspace will go away when curproc is destroyed */
		vfs_close(v);
		return result;
	}
	//kprintf("bla5\n");
	/* Done with the file now. */
	vfs_close(v);

	/* Define the user stack in the address space */
	result = as_define_stack(as, &stackptr);
	if (result) {
		/* p_addrspace will go away when curproc is destroyed */
		return result;
	}

#if OPT_A2
	//kprintf("bla6\n");
	if(args == NULL){
		return EFAULT;
	}	
	// copy args to user
	size_t len = sizeof(char *) * (num + 1);
	char **copyargs = kmalloc(len);
 	for(unsigned long int i = 0; i < num; i++){
    	len = strlen(args[i]) + 1;
    	stackptr = stackptr - ROUNDUP(len, 8);//? limit or valid stackptr //new

    	result = copyoutstr(args[i], (userptr_t)stackptr, len, NULL);//new
    	if(result){
    		kfree(copyargs);
      		return result;
    	}

    	copyargs[i] = (char *)stackptr;
  	}
  	copyargs[num] = NULL;

  	// copy arr
  	len = sizeof(char *) * (num + 1);
 	stackptr = stackptr - ROUNDUP(len, 8);
  	result = copyout(copyargs, (userptr_t)stackptr, len);
  	kfree(copyargs);
  	if(result){
    	return result;
  	}

  	userptr_t stackk = (userptr_t)stackptr;

  	enter_new_process(num /*argc*/, stackk /*userspace addr of argv*/,
			  stackptr, entrypoint);
#else
	/* Warp to user mode. */
	enter_new_process(0 /*argc*/, NULL /*userspace addr of argv*/,
			  stackptr, entrypoint);
#endif
	
	/* enter_new_process does not return. */
	panic("enter_new_process returned\n");
	return EINVAL;
}
/*
 * Load program and start running it in usermode
 * in a new thread.
 * This is essentially an amalgam of fork() and execv().
 */
int
runprogram(int nargs, char **args, struct process **created_proc)
{
    if (nargs > ARGNUM_MAX)
        return E2BIG;
    
	struct vnode *v;
	int result;
    struct process *proc;
    
    // copy the string, since vfs_open() will modify it
    char *progname = kstrdup(args[0]);
    if (progname == NULL)
        return ENOMEM;

	/* Open the file. */
	result = vfs_open(progname, O_RDONLY, 0, &v);
	if (result) {
		return result;
	}
    
    // We no longer need the duplicate program name
    kfree(progname);

    // set up new process structure
    proc = process_create(args[0]);
    if (proc == NULL)
    {
        vfs_close(v);
        return ENOMEM;
    }
    
    // Get a PID for the process.  ENPROC is
    // the error code for "no more processes allowed
    // in the system."
    pid_t pid = process_identify(proc);
    if (pid == 0)
    {
        process_cleanup(proc);
        vfs_close(v);
        return ENPROC;
    }
    
    // Create a new file descriptor table
    proc->ps_fdt = fdt_create();
    if (proc->ps_fdt == NULL)
    {
        process_destroy(pid);
        vfs_close(v);
        return ENOMEM;
    }
    
    // Open FDs for stdin, stdout, and stderr
    result = setup_inouterr(proc->ps_fdt);
    if (result)
    {
        process_destroy(pid);
        vfs_close(v);
        return result;
    }
    
	// Create a new address space
	proc->ps_addrspace = as_create();
	if (proc->ps_addrspace==NULL) {
        process_destroy(pid);
		vfs_close(v);
		return ENOMEM;
	}
    
    struct new_process_context *ctxt = kmalloc(sizeof(struct new_process_context));
    if (ctxt == NULL)
    {
        as_activate(NULL);
        process_destroy(pid);
        return ENOMEM;
    }
    ctxt->nargs = nargs;
    ctxt->args = args;
    ctxt->proc = proc;
    ctxt->executable = v;

	// Start a new thread to warp to user mode
    result = thread_fork("user process",
                         run_process,
                         ctxt, 0, NULL);
    if (result)
    {
        kfree(ctxt);
        as_activate(NULL);
        process_destroy(pid);
        return result;
    }
    
    // pass process to caller and return
    *created_proc = proc;
	return 0;
}
Exemple #25
0
int sys_execv(char* progname, char** args){

    struct vnode *v;
    vaddr_t stackptr, entrypoint;
    int result;
    int string_size = 0; //s_size
    int kargc = 0; //kargc
    int err;
    char ** kernel_args; //kargs
    size_t check; //tt
    
	//CHECKS BEFORE WE BEGIN!!
    if(args == NULL)
		return EFAULT;
		
    if(progname == NULL)
		return ENOEXEC;
    
    struct addrspace* temp =(struct addrspace*)kmalloc(sizeof(struct addrspace));
		if(temp == NULL)
			return ENOMEM;
    
		while(args[kargc] != NULL){
			kargc++;
	   }

	   //Copy the address space to the one on the kernel heap.
		err = as_copy(curthread->t_vmspace, &(temp));
		
		//If there is an error on copy.
		if(err){
		kfree(temp);
		return ENOMEM;
		}
   
   //make a copy of the kernel args on the heap.
   kernel_args = (char **)kmalloc((kargc)*sizeof(char*));
		if(kernel_args == NULL){
		 kfree(kernel_args);
		return ENOMEM;
		}
   int i,j;
	//Transfer the items passed in to the kernel heap array.
    for(i = 0; i<kargc; i++){
	string_size = strlen(args[i]);
	kernel_args[i] =(char *)kmalloc(string_size * sizeof(char));
	
	//If there is not enough memory...
	if(kernel_args[i]== NULL){
	    kfree(temp);
	    for(j =0; j<i; j++){
		kfree(kernel_args[j]);
		}
	    kfree(kernel_args);
	    return ENOMEM;
	}
	
	//If we get here, we have successfully copied the arguments. Copy in now.
	
	err = copyinstr(args[i], kernel_args[i], string_size+1, &check);
	
	//Check if copyinstr Success/Fail
	if(err){
	
	    for(i = 0; i<kargc; i++){
		kfree(kernel_args[i]);
		}
	    kfree(temp);
		kfree(kernel_args);
	    return err;
		}
    }
	
    kernel_args[kargc]= NULL;

	//NOW, WE FOLLOW THE SAME PROCEDURE AS RUNPROGRAM!!


/* Open the file. */
    result = vfs_open(progname, O_RDONLY, &v);
    if (result) {
	 kfree(temp);
	for(i = 0; i<kargc; i++)
	    kfree(kernel_args[i]);
		kfree(kernel_args);
	return result;
    }

//Destroy the old address space, and setup the new one!
	
    as_destroy(curthread->t_vmspace);
    curthread->t_vmspace = NULL;

    //Setup new vmspace.
    curthread->t_vmspace = as_create();
	
    if (curthread->t_vmspace==NULL) {
	curthread->t_vmspace = temp;
	
	for(i = 0; i<kargc; i++)
	    kfree(kernel_args[i]);
		kfree(kernel_args);
		vfs_close(v);
		return ENOMEM;
    }

    /* Activate vmspace */
    as_activate(curthread->t_vmspace);

    /* Load the executable. */
    result = load_elf(v, &entrypoint);
    if (result) {
	as_destroy(curthread->t_vmspace);
	curthread->t_vmspace = temp;
	
	 
	for(i = 0; i<kargc; i++)
	    kfree(kernel_args[i]);
	kfree(kernel_args);
	vfs_close(v);
	return result;
    }

    /* Done with the file now. */
    vfs_close(v);

   //We now prepare the user stack by placing the arguments on it, like we did in runprogram.
   
    result = as_define_stack(curthread->t_vmspace, &stackptr);
    
	//If error:
	if (result) {
	as_destroy(curthread->t_vmspace);
	curthread->t_vmspace = temp;

	for(i = 0; i<kargc; i++)
	    kfree(kernel_args[i]);
		kfree(kernel_args);
	return result;
    }
	// new addr space user stack
    vaddr_t new_args[kargc];
    int padding; 
     
    /*place all the strings on the stack*/
    
    for(i = (kargc-1); i>=0 ; i--){
	string_size = strlen(kernel_args[i]);
	padding = ((string_size / 4 ) + 1)*4;
	
	stackptr = stackptr - padding;
	
	//Do a copyout and check if success/fail
	err = copyoutstr(kernel_args[i], stackptr, string_size+1, &check);
		if(err){
			return err;
		}
	
		//Success!
		new_args[i] = stackptr;
    }

  
    new_args[kargc] = NULL;
    for(i = kargc-1; i>=0 ; i--){
	stackptr= stackptr- 4;
	err = copyout(&(new_args[i]), stackptr, 4);
		if(err){
			return err;
		}
   }
    for(i =0; i<kargc; i++){
		kfree(kernel_args[i]);
	}
    kfree(temp);
	kfree(kernel_args);
        
    /* Warp to user mode. */
    md_usermode(kargc, stackptr, stackptr, entrypoint);
	

}
Exemple #26
0
/*
 * Load program "progname" and start running it in usermode.
 * Does not return except on error.
 *
 * Calls vfs_open on progname and thus may destroy it.
 */
int
runprogram(char *progname, int argc, char** args)
{
	struct vnode *v;
	vaddr_t entrypoint, stackptr;
	int result;

	/* Open the file. */
	result = vfs_open(progname, O_RDONLY, 0, &v);
	if (result) {
		return result;
	}

	/* We should be a new thread. */
	KASSERT(curthread->t_addrspace == NULL);

	/* Create a new address space. */
	curthread->t_addrspace = as_create();
	if (curthread->t_addrspace==NULL) {
		vfs_close(v);
		return ENOMEM;
	}

	/* Activate it. */
	as_activate(curthread->t_addrspace);

	/* Load the executable. */
	result = load_elf(v, &entrypoint);
	if (result) {
		/* thread_exit destroys curthread->t_addrspace */
		vfs_close(v);
		return result;
	}

	/* Done with the file now. */
	vfs_close(v);

	/* Define the user stack in the address space */
	result = as_define_stack(curthread->t_addrspace, &stackptr);
	if (result) {
		/* thread_exit destroys curthread->t_addrspace */
		return result;
	}

	/* Initialize an array of pointers that stores the pointer to the
	 * string arguments in the user stack */
	char** argv = (char **)kmalloc((argc + 1) * sizeof(char*));
	if (argv == NULL) {
		return ENOMEM;
	}
	argv[argc] = 0;

	int i;
	size_t actual;
	int total = 0;

	/* Copy string arguments from kernel memory onto the user stack,
	 * and store the user pointer to the argument in argv */
	for (i = argc - 1; i >= 0; i--) {
		int len = strlen(args[i]) + 1;
		total = total + len;
		stackptr = stackptr - len;
		copyoutstr(args[i], (userptr_t)stackptr, len, &actual);
		argv[i] = (char *)stackptr;
	}

	/* Add any necessary padding to the user stack */
	int padding = 4 - (total % 4);
	if (padding) {
		stackptr = stackptr - padding;
	}

	/* Copy the array of user pointers argv onto the user stack  */
	for (i = argc; i >= 0; i--) {
		stackptr = stackptr - 4;
		copyout(&argv[i], (userptr_t)stackptr, 4);
	}

	kfree(argv);

	/* Warp to user mode. */
	enter_new_process(argc, (userptr_t)stackptr /*userspace addr of argv*/,
			  stackptr, entrypoint);
	
	/* enter_new_process does not return. */
	panic("enter_new_process returned\n");
	return EINVAL;
}
Exemple #27
0
/*
 * Load program "progname" and start running it in usermode.
 * Does not return except on error.
 *
 * Calls vfs_open on progname and thus may destroy it.
 */
int
runprogram(char *progname, char **args, int argc)
{
	struct vnode *v;
	vaddr_t entrypoint, stackptr;
	int result;

	// Variables for argument passing
	int i, pad;
	size_t offset, get;
	userptr_t userdest;

    size_t got[argc];
    userptr_t user_argv[argc];

    // Count length of each arg
    i = 0;
    for (i=0; i<argc; i++){
    	got[i] = strlen(args[i]) + 1; // Need +1 to account for /0
    }

    /* We enforce that the kernel is only allowed to start ONE user process
     * directly through runprogram with PID_MIN as its pid. Thereafter any
     * new user process needs to be forked from existing ones.
     */
	KASSERT(process_table[PID_MIN] == NULL);
	curthread->pid = PID_MIN;

	stdio_init();

	/* Open the file. */
	result = vfs_open(progname, O_RDONLY, 0, &v);
	if (result) {
		return result;
	}

	/* We should be a new thread. */
	KASSERT(curthread->t_addrspace == NULL);

	/* Create a new address space. */
	curthread->t_addrspace = as_create();
	if (curthread->t_addrspace==NULL) {
		vfs_close(v);
		return ENOMEM;
	}

	/* Activate it. */
	as_activate(curthread->t_addrspace);

	/* Load the executable. */
	result = load_elf(v, &entrypoint);
	if (result) {
		/* thread_exit destroys curthread->t_addrspace */
		vfs_close(v);
		return result;
	}

	/* Done with the file now. */
	vfs_close(v);

	/* Define the user stack in the address space */
	result = as_define_stack(curthread->t_addrspace, &stackptr);
	if (result) {
		/* thread_exit destroys curthread->t_addrspace */
		return result;
	}

    // Copy args to new addrspace
    offset = 0;
    for (i=argc-1; i>-1; i--){
        pad = (4 - (got[i]%4) ) % 4; // Word align
        offset += pad;
        offset += got[i];

        user_argv[i] = (userptr_t)(stackptr - offset);

        result = copyoutstr((const char*)args[i], user_argv[i], got[i], &get);
        if (result){
            return result;
        }
    }

    // Copy pointers to argv
    userdest = user_argv[0] - 4 * (argc+1);
    stackptr = (vaddr_t)userdest; // Set stack pointer
    for (i=0; i<argc; i++){
        result = copyout((const void *)&user_argv[i], userdest, 4);
        if (result){
        	return result;
        }
        userdest += 4;
    }

	/* Warp to user mode. */
	enter_new_process(argc, (userptr_t)stackptr, stackptr, entrypoint);

	/* enter_new_process does not return. */
	panic("enter_new_process returned\n");
	return EINVAL;
}
Exemple #28
0
int main (int argc, char* argv[])
{                               /* --- main function */
  int    i, k = 0;              /* loop variables, buffer */
  char   *s;                    /* to traverse options */
  char   **optarg = NULL;       /* option argument */
  char   *fn_bc   = NULL;       /* name of classifier file */
  char   *fn_out  = NULL;       /* name of output file */
  char   *blank   = NULL;       /* blank */
  char   *fldsep  = NULL;       /* field  separator */
  char   *recsep  = NULL;       /* record separator */
  int    flags    = AS_ATT;     /* table file write flags */
  double lcorr    = -DBL_MAX;   /* Laplace correction value */
  int    dwnull   = 0;          /* distribute weight of null values */
  int    maxllh   = 0;          /* max. likelihood est. of variance */
  int    tplcnt   = 1000;       /* number of tuples to generate */
  long   seed;                  /* seed for random number generator */
  int    mode;                  /* classifier setup mode */

  prgname = argv[0];            /* get program name for error msgs. */
  seed    = (long)time(NULL);   /* and get a default seed value */

  /* --- print startup/usage message --- */
  if (argc > 1) {               /* if arguments are given */
    fprintf(stderr, "%s - %s\n", argv[0], DESCRIPTION);
    fprintf(stderr, VERSION); } /* print a startup message */
  else {                        /* if no argument given */
    printf("usage: %s [options] bcfile "
                     "[-d|-h hdrfile] tabfile\n", argv[0]);
    printf("%s\n", DESCRIPTION);
    printf("%s\n", VERSION);
    printf("-n#      number of tuples to generate "
                    "(default: %d)\n", tplcnt);
    printf("-s#      seed for random number generator "
                    "(default: time)\n");
    printf("-L#      Laplace correction "
                    "(default: as specified in classifier)\n");
    printf("-v/V     (do not) distribute tuple weight "
                    "for null values\n");
    printf("-m/M     (do not) use maximum likelihood estimate "
                    "for the variance\n");
    printf("-a       align fields (default: do not align)\n");
    printf("-w       do not write field names to the output file\n");
    printf("-b/f/r#  blank character, field and record separator\n"
           "         (default: \" \", \" \", \"\\n\")\n");
    printf("bcfile   file containing classifier description\n");
    printf("tabfile  table file to write\n");
    return 0;                   /* print a usage message */
  }                             /* and abort the program */

  /* --- evaluate arguments --- */
  for (i = 1; i < argc; i++) {  /* traverse arguments */
    s = argv[i];                /* get option argument */
    if (optarg) { *optarg = s; optarg = NULL; continue; }
    if ((*s == '-') && *++s) {  /* -- if argument is an option */
      while (*s) {              /* traverse options */
        switch (*s++) {         /* evaluate option */
          case 'n': tplcnt  = (int)strtol(s, &s, 0); break;
          case 's': seed    =      strtol(s, &s, 0); break;
          case 'L': lcorr   = strtod(s, &s);         break;
          case 'v': dwnull  = NBC_ALL;               break;
          case 'V': dwnull |= NBC_DWNULL|NBC_ALL;    break;
          case 'm': maxllh  = NBC_ALL;               break;
          case 'M': maxllh |= NBC_MAXLLH|NBC_ALL;    break;
          case 'a': flags  |= AS_ALIGN;              break;
          case 'w': flags  &= ~AS_ATT;               break;
          case 'b': optarg  = &blank;                break;
          case 'f': optarg  = &fldsep;               break;
          case 'r': optarg  = &recsep;               break;
          default : error(E_OPTION, *--s);           break;
        }                       /* set option variables */
        if (!*s) break;         /* if at end of string, abort loop */
        if (optarg) { *optarg = s; optarg = NULL; break; }
      } }                       /* get option argument */
    else {                      /* if argument is no option */
      switch (k++) {            /* evaluate non-option */
        case  0: fn_bc  = s;      break;
        case  1: fn_out = s;      break;
        default: error(E_ARGCNT); break;
      }                         /* note filenames */
    }
  }
  if (optarg) error(E_OPTARG);  /* check the option argument */
  if (k != 2) error(E_ARGCNT);  /* and the number of arguments */
  if ((lcorr < 0) && (lcorr > -DBL_MAX))
    error(E_NEGLC);             /* check the Laplace correction */
  if ((flags & AS_ATT) && (flags & AS_ALIGN))
    flags |= AS_ALNHDR;         /* set align to header flag */

  /* --- read Bayes classifier --- */
  scan = sc_create(fn_bc);      /* create a scanner */
  if (!scan) error((!fn_bc || !*fn_bc) ? E_NOMEM : E_FOPEN, fn_bc);
  attset = as_create("domains", att_delete);
  if (!attset) error(E_NOMEM);  /* create an attribute set */
  fprintf(stderr, "\nreading %s ... ", sc_fname(scan));
  if ((sc_nexter(scan)   <  0)  /* start scanning (get first token) */
  ||  (as_parse(attset, scan, AT_ALL) != 0)
  ||  (as_attcnt(attset) <= 0)) /* parse attribute set */
    error(E_PARSE, sc_fname(scan));
  if ((sc_token(scan) == T_ID)  /* determine classifier type */
  &&  (strcmp(sc_value(scan), "fbc") == 0))
       fbc = fbc_parse(attset, scan);
  else nbc = nbc_parse(attset, scan);
  if ((!fbc && !nbc)            /* parse the Bayes classifier */
  ||   !sc_eof(scan))           /* and check for end of file */
    error(E_PARSE, sc_fname(scan));
  sc_delete(scan); scan = NULL; /* delete the scanner */
  fprintf(stderr, "[%d attribute(s)] done.\n", as_attcnt(attset));
  if ((lcorr >= 0) || dwnull || maxllh) {
    if (lcorr < 0)              /* get the classifier's parameters */
      lcorr = (fbc) ? fbc_lcorr(fbc) : nbc_lcorr(nbc);
    mode    = (fbc) ? fbc_mode(fbc)  : nbc_mode(nbc);
    if (dwnull) mode = (mode & ~NBC_DWNULL) | dwnull;
    if (maxllh) mode = (mode & ~NBC_MAXLLH) | maxllh;
                                /* adapt the estimation parameters */
    if (fbc) fbc_setup(fbc, mode, lcorr);
    else     nbc_setup(nbc, mode, lcorr);
  }                             /* set up the classifier anew */

  /* --- generate database --- */
  if (fn_out && *fn_out)        /* if an output file name is given, */
    out = fopen(fn_out, "w");   /* open output file for writing */
  else {                        /* if no output file name is given, */
    out = stdout; fn_out = "<stdout>"; }    /* write to std. output */
  fprintf(stderr, "writing %s ... ", fn_out);
  if (!out) error(E_FOPEN, fn_out);
  if ((flags & AS_ATT)          /* if to write a table header */
  &&  (as_write(attset, out, flags) != 0))
    error(E_FWRITE, fn_out);    /* write the attributes names */
  flags = AS_INST | (flags & ~AS_ATT);
  dseed(seed);                  /* init. random number generator */
  for (i = tplcnt; --i >= 0;) { /* generate random tuples */
    if (fbc) fbc_rand(fbc, drand);   /* instantiate the */
    else     nbc_rand(nbc, drand);   /* attribute set */
    if (as_write(attset, out, flags) != 0)
      error(E_FWRITE,fn_out);   /* write the generated tuple */
  }                             /* to the output file */
  if (out != stdout) {          /* if not written to stdout */
    i = fclose(out); out = NULL;/* close the output file */
    if (i != 0) error(E_FWRITE, fn_out);
  }                             /* print a success message */
  fprintf(stderr, "[%d tuple(s)] done.\n", tplcnt);

  /* --- clean up --- */
  #ifndef NDEBUG
  if (fbc) fbc_delete(fbc, 1);  /* delete full  Bayes classifier */
  if (nbc) nbc_delete(nbc, 1);  /* or     naive Bayes classifier */
  #endif                        /* and underlying attribute set */
  #ifdef STORAGE
  showmem("at end of program"); /* check memory usage */
  #endif
  return 0;                     /* return 'ok' */
}  /* main() */
Exemple #29
0
/*
 * Load program "progname" and start running it in usermode.
 * Does not return except on error.
 *
 * Calls vfs_open on progname and thus may destroy it.
 */
int runprogram(char *progname, char **args, unsigned long nargs) {
	struct vnode *v;
	vaddr_t entrypoint, stackptr;
	int result;

	/*Initialize Console*/

	char *consolein;
	char *consoleout;
	char *consoleerr;

	consolein = kstrdup("con:");
	consoleout = kstrdup("con:");
	consoleerr = kstrdup("con:");

	curthread->t_fdtable[0] = (struct fdesc*) kmalloc(sizeof(struct fdesc));

	if (vfs_open(consolein, O_RDONLY, 0664, &(curthread->t_fdtable[0]->vn))) {
		return EINVAL;
	}

	curthread->t_fdtable[0]->name = consolein;
	curthread->t_fdtable[0]->flag = O_RDONLY;
	curthread->t_fdtable[0]->ref_count = 1;
	curthread->t_fdtable[0]->filelock = lock_create("STDIN");

	kfree(consolein);

	curthread->t_fdtable[1] = (struct fdesc*) kmalloc(sizeof(struct fdesc));

	if (vfs_open(consoleout, O_WRONLY, 0664, &(curthread->t_fdtable[1]->vn))) {
		return EINVAL;
	}

	curthread->t_fdtable[1]->name = consoleout;
	curthread->t_fdtable[1]->flag = O_WRONLY;
	curthread->t_fdtable[1]->ref_count = 1;
	curthread->t_fdtable[1]->filelock = lock_create("STDOUT");

	kfree(consoleout);

	curthread->t_fdtable[2] = (struct fdesc*) kmalloc(sizeof(struct fdesc));

	if (vfs_open(consoleerr, O_WRONLY, 0664, &(curthread->t_fdtable[2]->vn))) {
		return EINVAL;
	}

	curthread->t_fdtable[2]->name = consoleerr;
	curthread->t_fdtable[2]->flag = O_WRONLY;
	curthread->t_fdtable[2]->ref_count = 1;
	curthread->t_fdtable[2]->filelock = lock_create("STDERR");

	kfree(consoleerr);

	/*Console Initialized*/

	/* Open the file. */
	result = vfs_open(progname, O_RDONLY, 0, &v);
	if (result) {
		return result;
	}

	/* We should be a new thread. */
	KASSERT(curthread->t_addrspace == NULL);

	/* Create a new address space. */
	curthread->t_addrspace = as_create();
	if (curthread->t_addrspace == NULL ) {
		vfs_close(v);
		return ENOMEM;
	}

	/* Activate it. */
	as_activate(curthread->t_addrspace);

	/* Load the executable. */
	result = load_elf(v, &entrypoint);
	if (result) {
		/* thread_exit destroys curthread->t_addrspace */
		vfs_close(v);
		return result;
	}

	/* Done with the file now. */
	vfs_close(v);

	/* Define the user stack in the address space */
	result = as_define_stack(curthread->t_addrspace, &stackptr);
	if (result) {
		/* thread_exit destroys curthread->t_addrspace */
		return result;
	}

	int argc = (signed) nargs;
	int err;
	char** argv;

	//kmalloc argv with size of char* times nargs+1
	argv = kmalloc((nargs + 1) * sizeof(userptr_t));

	size_t len;

	for (int i = 0; i < argc; i++) {

		len = strlen(args[i]) + 1;

		len = (len + 4 - 1) & ~(size_t) (4 - 1);

		stackptr -= len;

		if ((err = copyout(args[i], (userptr_t) stackptr, len)) != 0) {

			kprintf("error copyout");
		}

		argv[i] = (char*) stackptr;

	}

	argv[nargs] = NULL;

	stackptr -= (nargs + 1) * sizeof(userptr_t);

	if ((err = copyout(argv, (userptr_t) stackptr, (nargs + 1) * sizeof(char*)))) {
		kprintf("error copying");
	}

	/* Warp to user mode. */
	enter_new_process(argc, (userptr_t) stackptr /*userspace addr of argv*/,
			stackptr, entrypoint);

	/* enter_new_process does not return. */
	panic("enter_new_process returned\n");

	return EINVAL;
}
Exemple #30
0
int sys_execv(const char* program, char** args, int* errno)
{
	int ret;
	// simple error check
	// *************
	if (program == NULL)
	{
		*errno = EFAULT;
		return -1;
	}
	// ************

	// copies progname into kernel buffer
	// ***************
	char* fname = (char*)kmalloc(PATH_MAX);
	ret = copyinstr((userptr_t)program, fname, PATH_MAX, NULL);
	if (ret != 0)
	{
		*errno = EFAULT;
		return -1;
	}
	// opens executable	
	// ***************
	struct vnode* v;
	ret = vfs_open(fname, O_RDONLY, &v);
	if (ret != 0)
	{
		*errno = ret;
		return -1;
	}
	// **************


	// gets argc
	// **************
	int i = 0;
	while (args[i] != NULL)
	{
		i++;
	}
	int argc = i;
	// *************

	// copies all arguments into kernel buffer
	// *****************
	char** argv;
	argv= (char**)kmalloc(PATH_MAX);
	
	ret = copyin(args, argv, sizeof(userptr_t));
	if (ret != 0)
	{
		*errno = EFAULT;
		return -1;
	}
	
	for(i = 0; i < argc; i++)
	{
		argv[i]=(char*)kmalloc(PATH_MAX);
		ret = copyinstr((userptr_t)args[i],argv[i], PATH_MAX, NULL);
		if (ret != 0)
		{
			*errno = EFAULT;
			return -1;
		}
	}
	argv[argc] = NULL;
	// *******************

	// error check
	// ************
	if (curthread->t_vmspace != NULL)
	{
		as_destroy(curthread->t_vmspace);
		curthread->t_vmspace = NULL;
	}
	// **************



	// creates new address space and loads elf into it
	// **************	
	curthread->t_vmspace = as_create();
	if (curthread->t_vmspace == NULL)
	{
		vfs_close(v);
		*errno = ENOMEM;
		return -1;
	}

	vaddr_t entrypoint,stackptr;

	as_activate(curthread->t_vmspace);
	ret = load_elf(v,&entrypoint);
	if (ret != 0){
		vfs_close(v);
		*errno = ret;
		return -1;
	}
	vfs_close(v);
	ret = as_define_stack(curthread->t_vmspace,&stackptr);
	if (ret != 0)
	{
		*errno = ret;
		return -1;
	}
	// ********************

	// copies arguments into userstack and increments stack ptr
	// **************
	unsigned int pstack[argc];
	for (i = argc-1; i >= 0; i--)
	{
		
		int len = strlen(argv[i]) + 1;
		stackptr -= len;
		stackptr -= stackptr%4;
		ret = copyoutstr(argv[i], (userptr_t)stackptr, PATH_MAX, NULL);
		if (ret != 0)
		{
			*errno = EFAULT;
			return -1;
		}
		pstack[i] = stackptr;
	}
	pstack[argc] = (int)NULL;
	for (i = argc-1; i >= 0; i--)
	{
		stackptr -= 4;
		ret = copyout(&pstack[i], (userptr_t)stackptr, sizeof(pstack[i]));
		if (ret != 0)
		{
			*errno = EFAULT;
			return -1;
		}
	}
	
	// free unused memory	
	for (i = 0; i < argc; i++)
	{
		kfree(argv[i]);
	}
	kfree(argv);
	kfree(fname);
	// *******************


	// enters usermode, should not return
	// *******************
	md_usermode(argc, (userptr_t)stackptr, stackptr, entrypoint);
	// ******************
	
	// if usermode returns, that is an error
	// **********
	*errno = EINVAL;
	return -1;
	// ************
}