Guts load_icode and proc_create() takes a path
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 23 Jul 2010 21:21:15 +0000 (14:21 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:49 +0000 (17:35 -0700)
This guts the old load_icode() way of making a process and makes
proc_create() play with the filesystem.  proc_create() also takes args,
but the syscall doesn't.  Will sort that eventually.

kern/include/env.h
kern/include/process.h
kern/src/env.c
kern/src/manager.c
kern/src/monitor.c
kern/src/process.c
kern/src/syscall.c
tests/spawn.c

index b82a7fd..3f5c672 100644 (file)
@@ -83,7 +83,6 @@ void  env_push_ancillary_state(env_t* e);
 void   env_pop_ancillary_state(env_t* e);
 void   env_user_mem_free(env_t* e, void* start, size_t len);
 void   env_pagetable_free(env_t* e);
-void   env_load_icode(env_t* e, env_t* binary_env, uint8_t *COUNT(size) binary, size_t size);
 
 typedef int (*mem_walk_callback_t)(env_t* e, pte_t* pte, void* va, void* arg);
 int            env_user_mem_walk(env_t* e, void* start, size_t len, mem_walk_callback_t callback, void* arg);
index d960dd0..e4dc7ff 100644 (file)
@@ -1,11 +1,9 @@
-/*
- * Copyright (c) 2009 The Regents of the University of California
+/* Copyright (c) 2009, 2010 The Regents of the University of California
  * Barret Rhoden <brho@cs.berkeley.edu>
  * See LICENSE for details.
  *
  * All things processes!  As we move away from the old envs to processes,
- * we'll move things into here that are designed for multicore processes.
- */
+ * we'll move things into here that are designed for multicore processes. */
 
 #ifndef ROS_KERN_PROCESS_H
 #define ROS_KERN_PROCESS_H
@@ -71,7 +69,8 @@ void proc_init(void);
 void proc_init_procinfo(struct proc *p);
 
 /* Process management: */
-struct proc *proc_create(uint8_t *COUNT(size) binary, size_t size);
+error_t proc_alloc(struct proc **pp, struct proc *parent);
+struct proc *proc_create(struct file *prog, char **argv, char **envp);
 int __proc_set_state(struct proc *p, uint32_t state) WRITES(p->state);
 struct proc *pid2proc(pid_t pid);
 bool proc_controls(struct proc *SAFE actor, struct proc *SAFE target);
index e7a9a0f..02bf991 100644 (file)
@@ -128,135 +128,6 @@ env_setup_vm_error_i:
        return -ENOMEM;
 }
 
-// this helper function handles all cases of copying to/from user/kernel
-// or between two users.
-static error_t load_icode_memcpy(struct proc *dest_p, struct proc *src_p,
-                                 void* dest, const void* src, size_t len)
-{
-       if(src < (void*)UTOP)
-       {
-               if(src_p == NULL)
-                       return -EFAULT;
-
-               if(dest_p == NULL)
-                       return memcpy_from_user(src_p, dest, src, len);
-               else
-               {
-                       // TODO: do something more elegant & faster here.
-                       // e.g. a memcpy_from_user_to_user
-                       uint8_t kbuf[1024];
-                       while(len > 0)
-                       {
-                               size_t thislen = MIN(len,sizeof(kbuf));
-                               if (memcpy_from_user(src_p, kbuf, src, thislen))
-                                       return -EFAULT;
-                               if (memcpy_to_user(dest_p, dest, kbuf, thislen))
-                                       panic("destination env isn't mapped!");
-                               len -= thislen;
-                               src += thislen;
-                               dest += thislen;
-                       }
-                       return ESUCCESS;
-               }
-
-       }
-       else
-       {
-               if(src_p != NULL)
-                       return -EFAULT;
-
-               if(dest_p == NULL)
-                       memcpy(dest, src, len);
-               else if(memcpy_to_user(dest_p, dest, src, len))
-                       panic("destination env isn't mapped!");
-
-               return ESUCCESS;
-       }
-}
-
-//
-// Set up the initial program binary, stack, and processor flags
-// for a user process.
-//
-// This function loads all loadable segments from the ELF binary image
-// into the environment's user memory, starting at the appropriate
-// virtual addresses indicated in the ELF program header.
-// At the same time it clears to zero any portions of these segments
-// that are marked in the program header as being mapped
-// but not actually present in the ELF file - i.e., the program's bss section.
-//
-// Finally, this function maps one page for the program's initial stack.
-static void* load_icode(env_t *SAFE e, env_t* binary_env,
-                        uint8_t *COUNT(size) binary, size_t size)
-{
-       // asw: copy the headers because they might not be aligned.
-       elf_t elfhdr;
-       proghdr_t phdr;
-       void* _end = 0;
-
-       assert(load_icode_memcpy(NULL,binary_env,&elfhdr, binary,
-                                sizeof(elfhdr)) == ESUCCESS);
-
-       int i, r;
-
-       // is this an elf?
-       assert(elfhdr.e_magic == ELF_MAGIC);
-       // make sure we have proghdrs to load
-       assert(elfhdr.e_phnum);
-
-       // TODO: how do we do a runtime COUNT?
-       {TRUSTEDBLOCK // zra: TRUSTEDBLOCK until validation is done.
-       for (i = 0; i < elfhdr.e_phnum; i++) {
-               // copy phdr to kernel mem
-               assert(load_icode_memcpy(NULL,binary_env,&phdr, binary + elfhdr.e_phoff + i*sizeof(phdr), sizeof(phdr)) == ESUCCESS);
-
-               if (phdr.p_type != ELF_PROG_LOAD)
-                       continue;
-               // TODO: validate elf header fields!
-               // seg alloc creates PTE_U|PTE_W pages.  if you ever want to change
-               // this, there will be issues with overlapping sections
-               _end = MAX(_end, (void*)(phdr.p_va + phdr.p_memsz));
-
-               // use mmap to allocate memory.  don't clobber other sections.
-               // this is ugly but will go away once we stop using load_icode
-               uintptr_t pgstart = ROUNDDOWN((uintptr_t)phdr.p_va,PGSIZE);
-               uintptr_t pgend = ROUNDUP((uintptr_t)phdr.p_va+phdr.p_memsz,PGSIZE);
-               for(uintptr_t addr = pgstart; addr < pgend; addr += PGSIZE)
-               {
-                       pte_t* pte = pgdir_walk(e->env_pgdir, (void*)addr, 0);
-                       if(!pte || PAGE_UNMAPPED(*pte))
-                               assert(do_mmap(e,addr,PGSIZE,PROT_READ|PROT_WRITE|PROT_EXEC,
-                                          MAP_ANONYMOUS|MAP_FIXED,NULL,0) != MAP_FAILED);
-               }
-
-               // copy section to user mem
-               assert(load_icode_memcpy(e,binary_env,(void*)phdr.p_va, binary + phdr.p_offset, phdr.p_filesz) == ESUCCESS);
-
-               //no need to memclr the remaining p_memsz-p_filesz bytes
-               //because upage_alloc'd pages are zeroed
-       }}
-
-       proc_init_trapframe(&e->env_tf, 0, elfhdr.e_entry, USTACKTOP);
-       e->env_entry = elfhdr.e_entry;
-
-       // Now map USTACK_NUM_PAGES pages for the program's initial stack
-       // starting at virtual address USTACKTOP - USTACK_NUM_PAGES*PGSIZE.
-       uintptr_t stacksz = USTACK_NUM_PAGES*PGSIZE;
-       assert(do_mmap(e, USTACKTOP-stacksz, stacksz, PROT_READ | PROT_WRITE,
-                      MAP_FIXED | MAP_ANONYMOUS | MAP_POPULATE, NULL, 0)
-              != MAP_FAILED);
-       
-       return _end;
-}
-
-void env_load_icode(env_t* e, env_t* binary_env, uint8_t* binary, size_t size)
-{
-       /* Load the binary and set the current locations of the elf segments.
-        * All end-of-segment pointers are page aligned (invariant) */
-       e->heap_top = load_icode(e, binary_env, binary, size);
-       e->procinfo->heap_bottom = e->heap_top;
-}
-
 #define PER_CPU_THING(type,name)\
 type SLOCKED(name##_lock) * RWPROTECT name;\
 type SLOCKED(name##_lock) *\
index ac88dd9..92b600b 100644 (file)
@@ -207,8 +207,10 @@ void manager_waterman()
        static int init = 0;
        if(!init)
        {
+               warn("Old file creation might not work");
                init = 1;
-               struct proc* p = proc_create(NULL,0);
+               struct proc *p;
+               proc_alloc(&p, 0);
 
                char* argv[] = {"/bin/sh","-l",0};
                char* envp[] = {"LD_LIBRARY_PATH=/lib",0};
index aafe6de..5773082 100644 (file)
@@ -290,13 +290,10 @@ int mon_bin_run(int argc, char *NTS *NT COUNT(argc) argv, trapframe_t *tf)
                printk("No such program!\n");
                return 1;
        }
-       /* TODO: push this into proc_create */
-       struct proc *p = proc_create(NULL, 0);
-       char* p_argv[] = {0, 0, 0};
-       char* p_envp[] = {"LD_LIBRARY_PATH=/lib",0};
+       char *p_argv[] = {0, 0, 0};
+       char *p_envp[] = {"LD_LIBRARY_PATH=/lib", 0};   /* for /bin/sh, i think */
        p_argv[0] = file_name(program);
-       procinfo_pack_args(p->procinfo, p_argv, p_envp);
-       assert(load_elf(p, program) == 0);
+       struct proc *p = proc_create(program, p_argv, p_envp);
 
        spin_lock(&p->proc_lock);
        __proc_set_state(p, PROC_RUNNABLE_S);
index 89736f5..ec4c3b7 100644 (file)
@@ -1,8 +1,6 @@
-/*
- * Copyright (c) 2009 The Regents of the University of California
+/* Copyright (c) 2009, 2010 The Regents of the University of California
  * Barret Rhoden <brho@cs.berkeley.edu>
- * See LICENSE for details.
- */
+ * See LICENSE for details. */
 
 #ifdef __SHARC__
 #pragma nosharc
@@ -27,6 +25,7 @@
 #include <frontend.h>
 #include <monitor.h>
 #include <resource.h>
+#include <elf.h>
 
 /* Process Lists */
 struct proc_list proc_runnablelist = TAILQ_HEAD_INITIALIZER(proc_runnablelist);
@@ -242,7 +241,7 @@ proc_init_procinfo(struct proc* p)
  * Errors include:
  *  - ENOFREEPID if it can't get a PID
  *  - ENOMEM on memory exhaustion */
-static error_t proc_alloc(struct proc *SAFE*SAFE pp, struct proc *parent)
+error_t proc_alloc(struct proc **pp, struct proc *parent)
 {
        error_t r;
        struct proc *p;
@@ -278,7 +277,7 @@ static error_t proc_alloc(struct proc *SAFE*SAFE pp, struct proc *parent)
        p->state = PROC_CREATED; // shouldn't go through state machine for init
        p->env_refcnt = 2; // one for the object, one for the ref we pass back
        p->env_flags = 0;
-       p->env_entry = 0; // cheating.  this really gets set in load_icode
+       p->env_entry = 0; // cheating.  this really gets set later
        p->procinfo->heap_bottom = (void*)UTEXT;
        p->heap_top = (void*)UTEXT;
        memset(&p->resources, 0, sizeof(p->resources));
@@ -333,18 +332,16 @@ static error_t proc_alloc(struct proc *SAFE*SAFE pp, struct proc *parent)
        return 0;
 }
 
-/* Creates a process from the specified binary, which is of size size.
- * Currently, the binary must be a contiguous block of memory, which needs to
- * change.  On any failure, it just panics, which ought to be sorted. */
-struct proc *proc_create(uint8_t *binary, size_t size)
+/* Creates a process from the specified file, argvs, and envps.  Tempted to get
+ * rid of proc_alloc's style, but it is so quaint... */
+struct proc *proc_create(struct file *prog, char **argv, char **envp)
 {
        struct proc *p;
        error_t r;
-
        if ((r = proc_alloc(&p, current)) < 0)
-               panic("proc_create: %e", r); // one of 3 quaint usages of %e.
-       if(binary != NULL)
-               env_load_icode(p, NULL, binary, size);
+               panic("proc_create: %e", r);    /* one of 3 quaint usages of %e */
+       procinfo_pack_args(p->procinfo, argv, envp);
+       assert(load_elf(p, prog) == 0);
        return p;
 }
 
index 47a898c..64dc73a 100644 (file)
@@ -193,40 +193,25 @@ static pid_t sys_getpid(struct proc *p)
        return p->pid;
 }
 
-/*
- * Creates a process found at the user string 'path'.  Currently uses KFS.
- * Not runnable by default, so it needs it's status to be changed so that the
- * next call to schedule() will try to run it.
- * TODO: once we have a decent VFS, consider splitting this up
- * and once there's an mmap, can have most of this in process.c
- */
+/* Creates a process from the file 'path'.  The process is not runnable by
+ * default, so it needs it's status to be changed so that the next call to
+ * schedule() will try to run it.  TODO: take args/envs from userspace. */
 static int sys_proc_create(struct proc *p, const char *DANGEROUS path)
 {
        int pid = 0;
-       char tpath[MAX_PATH_LEN];
-       /*
-        * There's a bunch of issues with reading in the path, which we'll
-        * need to sort properly in the VFS.  Main concerns are TOCTOU (copy-in),
-        * whether or not it's a big deal that the pointer could be into kernel
-        * space, and resolving both of these without knowing the length of the
-        * string. (TODO)
-        * Change this so that all syscalls with a pointer take a length.
-        *
-        * zra: I've added this user_mem_strlcpy, which I think eliminates the
-     * the TOCTOU issue. Adding a length arg to this call would allow a more
-        * efficient implementation, though, since only one call to user_mem_check
-        * would be required.
-        */
-       int ret = user_mem_strlcpy(p,tpath, path, MAX_PATH_LEN, PTE_USER_RO);
-       return 0;
-#if 0
-       int kfs_inode = kfs_lookup_path(tpath);
-       if (kfs_inode < 0)
-               return -EINVAL;
-       struct proc *new_p = kfs_proc_create(kfs_inode);
+       char t_path[MAX_PATH_LEN];
+       struct file *program;
+       struct proc *new_p;
+
+       /* Copy in.  TODO: make syscalls come with a length */
+       user_mem_strlcpy(p, t_path, path, MAX_PATH_LEN, PTE_USER_RO);
+       program = path_to_file(t_path);
+       if (!program)
+               return -1;
+       new_p = proc_create(program, 0, 0);
        pid = new_p->pid;
-       proc_decref(new_p, 1); // let go of the reference created in proc_create()
-#endif
+       proc_decref(new_p, 1);  /* give up the reference created in proc_create() */
+       atomic_dec(&program->f_refcnt);         /* TODO: REF / KREF */
        return pid;
 }
 
@@ -296,11 +281,12 @@ static int sys_proc_yield(struct proc *p, bool being_nice)
 static ssize_t sys_run_binary(env_t* e, void *DANGEROUS binary_buf, size_t len,
                               procinfo_t*DANGEROUS procinfo, size_t num_colors)
 {
+       printk("sys_run_binary() is deprecated and does nothing, pending removal.");
+#if 0
        env_t* env = proc_create(NULL,0);
        assert(env != NULL);
 
        // let me know if you use this.  we need to sort process creation better.
-       printk("sys_run_binary() is deprecated.  Use at your own risk.");
        if(memcpy_from_user(e,e->procinfo,procinfo,sizeof(*procinfo)))
                return -1;
        proc_init_procinfo(e);
@@ -315,6 +301,7 @@ static ssize_t sys_run_binary(env_t* e, void *DANGEROUS binary_buf, size_t len,
        }
        proc_decref(env, 1);
        proc_yield(e, 0);
+#endif
        return 0;
 }
 
@@ -327,7 +314,8 @@ static ssize_t sys_fork(env_t* e)
                return -1;
        }
 
-       env_t* env = proc_create(NULL,0);
+       env_t* env;
+       assert(!proc_alloc(&env, current));
        assert(env != NULL);
 
        env->heap_top = e->heap_top;
index 933e0a2..413a577 100644 (file)
@@ -29,10 +29,10 @@ int main(int argc, char** argv)
        }
        #endif
        printf("U: attempting to create and run hello\n");
-       child_pid[0] = sys_proc_create("roslib_hello");
+       child_pid[0] = sys_proc_create("/bin/hello");
        sys_proc_run(child_pid[0]);
-       printf("U: attempting to create and run mhello\n");
-       child_pid[1] = sys_proc_create("roslib_mhello");
+       printf("U: attempting to create and run another hello\n");
+       child_pid[1] = sys_proc_create("/bin/hello");
        sys_proc_run(child_pid[1]);
        return 0;
 }