Merge remote branch 'origin/sparc-dev'
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 3 Dec 2009 03:14:54 +0000 (19:14 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Thu, 3 Dec 2009 03:14:54 +0000 (19:14 -0800)
Still a few outstanding issues, like fully merging roslib into parlib
and sorting brk() and mmap().

Conflicts:
GNUmakefile
kern/arch/i386/atomic.h
kern/arch/sparc/trap.c
kern/include/env.h
kern/include/page_alloc.h
kern/include/ros/procdata.h
kern/src/env.c
kern/src/init.c
kern/src/kfs.c
kern/src/manager.c
kern/src/page_alloc.c
kern/src/syscall.c
user/apps/roslib/mhello.c

29 files changed:
1  2 
GNUmakefile
kern/arch/i386/atomic.h
kern/arch/i386/pmap.c
kern/arch/i386/smp_boot.c
kern/arch/sparc/atomic.h
kern/arch/sparc/init.c
kern/arch/sparc/pmap.c
kern/arch/sparc/smp.c
kern/arch/sparc/trap.c
kern/include/env.h
kern/include/page_alloc.h
kern/include/process.h
kern/include/ros/procdata.h
kern/include/testing.h
kern/src/Makefrag
kern/src/env.c
kern/src/init.c
kern/src/kfs.c
kern/src/manager.c
kern/src/page_alloc.c
kern/src/pmap.c
kern/src/process.c
kern/src/slab.c
kern/src/syscall.c
kern/src/testing.c
user/apps/parlib/run_binary.c
user/apps/parlib/run_binary_colored.c
user/parlib/src/i386/entry.S
user/roslib/inc/lib.h

diff --cc GNUmakefile
Simple merge
@@@ -32,12 -19,9 +32,13 @@@ static inline void atomic_set(atomic_t 
  static inline void atomic_inc(atomic_t *number);
  static inline void atomic_dec(atomic_t *number);
  static inline void atomic_andb(volatile uint8_t RACY* number, uint8_t mask);
 -static inline void spin_lock(volatile uint32_t SRACY*COUNT(1) lock);
 -static inline void spin_unlock(volatile uint32_t SRACY* lock);
+ static inline void atomic_orb(volatile uint8_t RACY* number, uint8_t mask);
 +static inline uint32_t spin_locked(spinlock_t *SAFE lock);
 +static inline void __spin_lock(volatile uint32_t SRACY*CT(1) rlock);
 +static inline void spin_lock(spinlock_t *lock);
 +static inline void spin_unlock(spinlock_t *lock);
 +static inline void spinlock_init(spinlock_t *lock);
 +void spinlock_debug(spinlock_t *lock);
  
  /* Inlined functions declared above */
  static inline void atomic_init(atomic_t *number, int32_t val)
@@@ -73,13 -57,12 +74,18 @@@ static inline void atomic_andb(volatil
        asm volatile("lock andb %1,%0" : "=m"(*number) : "r"(mask) : "cc");
  }
  
 -static inline void spin_lock(volatile uint32_t* lock)
+ static inline void atomic_orb(volatile uint8_t RACY*number, uint8_t mask)
+ {
+       asm volatile("lock orb %1,%0" : "=m"(*number) : "r"(mask) : "cc");
+ }
 +static inline uint32_t spin_locked(spinlock_t *SAFE lock)
 +{
 +      // the lock status is the lowest byte of the lock
 +      return lock->rlock & 0xff;
 +}
 +
 +static inline void __spin_lock(volatile uint32_t *rlock)
  {
        asm volatile(
                        "1:                       "
Simple merge
Simple merge
@@@ -21,8 -21,8 +21,9 @@@ static inline void atomic_set(atomic_t
  static inline void atomic_add(atomic_t* number, int32_t inc);
  static inline void atomic_inc(atomic_t* number);
  static inline void atomic_dec(atomic_t* number);
+ static inline uint32_t atomic_swap(uint32_t* addr, uint32_t val);
  static inline uint32_t spin_trylock(spinlock_t*SAFE lock);
 +static inline uint32_t spin_locked(spinlock_t*SAFE lock);
  static inline void spin_lock(spinlock_t*SAFE lock);
  static inline void spin_unlock(spinlock_t*SAFE lock);
  
@@@ -9,6 -32,7 +32,7 @@@ init_argc_argv(
  void arch_init()
  {             
        // this returns when all other cores are done and ready to receive IPIs
+       init_argc_argv();
        smp_boot();
 -      env_init();
 +      proc_init();
  }
Simple merge
Simple merge
@@@ -140,15 -157,16 +157,17 @@@ unhandled_trap(trapframe_t* state
        uint32_t trap_type = (state->tbr >> 4) & 0xFF;
        get_trapname(trap_type,buf);
  
-       print_trapframe(state);
        if(state->psr & PSR_PS)
+       {
+               print_trapframe(state);
                panic("Unhandled trap in kernel!\nTrap type: %s",buf);
+       }
        else
        {
+               print_trapframe(state);
                warn("Unhandled trap in user!\nTrap type: %s",buf);
                assert(current);
 +              proc_incref(current, 1);
                proc_destroy(current);
                panic("I shouldn't have gotten here!");
        }
@@@ -226,24 -268,14 +269,25 @@@ handle_syscall(trapframe_t* state
        state->pc = state->npc;
        state->npc += 4;
  
-       //env_push_ancillary_state(current); // remove this if you don't need it
 +      // this comment is from i386.  we don't save silly state early either
 +      // hopefully you don't need to save it now.  let me know if otherwise
 +      static_assert(0);
 +      /* Note we are not preemptively saving the TF in the env_tf.  We do maintain
 +       * a reference to it in current_tf (a per-cpu pointer).
 +       * In general, only save the tf and any silly state once you know it
 +       * is necessary (blocking).  And only save it in env_tf when you know you
 +       * are single core (PROC_RUNNING_S) */
 +      set_current_tf(tf);
 -      // if we want them to migrate, block, etc.
 -      if(current->vcoremap[0] == core_id())
 -              env_push_ancillary_state(current);
+       // TODO: must save other cores' ancillary state
++      //if(current->vcoremap[0] == core_id())
++      //      env_push_ancillary_state(current); // remove this if you don't need it
  
 -      state->gpr[8] = syscall(current,state,num,a1,a2,a3,a4,a5);
 +      // syscall code wants an edible reference for current
 +      proc_incref(current, 1);
 +      state->gpr[8] = syscall(current,num,a1,a2,a3,a4,a5);
 +      proc_decref(current, 1);
  
-       trap_handled();
+       proc_startcore(current,state);
  }
  
  void
@@@ -280,9 -312,10 +324,12 @@@ handle_breakpoint(trapframe_t* state
        state->pc = state->npc;
        state->npc += 4;
  
-       //env_push_ancillary_state(current);
 +      // see comment above about tf's
 +      static_assert(0);
 -      if(current->vcoremap[0] == core_id())
 -              env_push_ancillary_state(current);
+       // TODO: must save other cores' ancillary state
+       // if we want them to migrate, block, etc.
++      //if(current->vcoremap[0] == core_id())
++      //      env_push_ancillary_state(current);
  
        // run the monitor
        monitor(state);
@@@ -22,13 -44,12 +22,11 @@@ typedef struct Env env_t
  struct Env {
        TAILQ_ENTRY(Env) proc_link NOINIT;      // Free list link pointers
        spinlock_t proc_lock;
-       trapframe_t env_tf                                              // Saved registers
-         __attribute__((aligned (8)));                 // for sparc --asw
-       ancillary_state_t env_ancillary_state   // State saved when descheduled
-         __attribute__((aligned (8)));                 // for sparc --asw
+       trapframe_t env_tf;                                             // Saved registers
+       ancillary_state_t env_ancillary_state;  // State saved when descheduled
 -      envid_t env_id;                         // Unique environment identifier
 -      envid_t env_parent_id;          // env_id of this env's parent
 +      pid_t pid;
 +      pid_t ppid;                 // Parent's PID
        uint32_t state;                         // Status of the process
 -      uint32_t env_runs;                      // Number of times environment has run
        uint32_t env_refcnt;            // Reference count of kernel contexts using this
        uint32_t env_flags;
        uint32_t env_entry;
        /* Info about this process's resources (granted, desired) for each type. */
        struct resource resources[MAX_NUM_RESOURCES];
  
 -      void* end_text_segment;
 -      void* end_data_segment;
+       /* Keeps track of this process's current memory allocation 
+      * (i.e. its heap pointer) */
++      void* heap_bottom;
++      void* heap_top;
        // Address space
        pde_t *COUNT(NPDENTRIES) env_pgdir;                     // Kernel virtual address of page dir
        physaddr_t env_cr3;                     // Physical address of page dir
  };
  
  /* Process Flags */
 -// None yet
 +#define PROC_TRANSITION_TO_M                  0x0001
  
 -extern env_t *CT(NENV) RO envs;               // All environments
  extern atomic_t num_envs;             // Number of envs
 -// TODO: consider moving this to struct per_cpu_info
 -extern env_t * (RO curenvs)[MAX_NUM_CPUS];
 -
 -static inline env_t *
 -get_cpu_curenv() TRUSTED
 -{
 -      return curenvs[core_id()];
 -}
 -
 -static inline void
 -set_cpu_curenv(env_t *p) TRUSTED
 -{
 -      curenvs[core_id()] = p;
 -}
 -
 -void  env_init(void);
 -int           env_alloc(env_t *SAFE*SAFE e, envid_t parent_id);
 +
 +int           env_setup_vm(env_t *e);
- void  load_icode(env_t *SAFE e, uint8_t *COUNT(size) binary, size_t size);
  void  env_push_ancillary_state(env_t* e);
  void  env_pop_ancillary_state(env_t* e);
 -void  env_free(env_t *SAFE e);
  void  env_user_mem_free(env_t* e);
 -env_t*        env_create();
+ void  env_segment_alloc(env_t *e, void *SNT va, size_t len);
+ void  env_segment_free(env_t *e, void *SNT va, size_t len);
+ void  env_load_icode(env_t* e, env_t* binary_env, uint8_t *COUNT(size) binary, size_t size);
  
 -/*
 - * Allows the kernel to figure out what process is running on its core.
 - * Can be used just like a pointer to a struct process.
 - */
 -#define current (get_cpu_curenv())
 -//#define current (curenvs[core_id()])
 -
 -int   envid2env(envid_t envid, env_t **env_store, bool checkperm);
  // The following three functions do not return
  void  env_pop_tf(trapframe_t *tf) __attribute__((noreturn));
  
@@@ -38,14 -39,18 +39,18 @@@ extern page_list_t LCKD(&colored_page_f
  
  /*************** Functional Interface *******************/
  void page_alloc_init(void);
- error_t page_alloc(page_t *SAFE *page);
+ void colored_page_alloc_init(void);
+ error_t upage_alloc(struct proc* p, page_t *SAFE *page);
+ error_t kpage_alloc(page_t *SAFE *page);
+ error_t upage_alloc_specific(struct proc* p, page_t *SAFE *page, size_t ppn);
+ error_t kpage_alloc_specific(page_t *SAFE *page, size_t ppn);
+ error_t colored_upage_alloc(uint8_t* map, page_t *SAFE *page, size_t color);
+ error_t page_free(page_t *SAFE page);
 -void *get_cont_pages(size_t order, int flags);
 +void *CT(1 << order) get_cont_pages(size_t order, int flags);
  void free_cont_pages(void *buf, size_t order);
- error_t page_alloc_specific(page_t *SAFE *page, size_t ppn);
- error_t l1_page_alloc(page_t *SAFE *page, size_t color);
- error_t l2_page_alloc(page_t *SAFE *page, size_t color);
- error_t l3_page_alloc(page_t *SAFE *page, size_t color);
- error_t page_free(page_t *SAFE page);
  void page_incref(page_t *SAFE page);
  void page_decref(page_t *SAFE page);
  size_t page_getref(page_t *SAFE page);
Simple merge
@@@ -9,8 -9,16 +9,17 @@@
  #include <ros/error.h>
  #include <ros/common.h>
  
+ #define PROCINFO_MAX_ARGC 32
+ #define PROCINFO_MAX_ARGV_SIZE 1024
  typedef struct procinfo {
 -      pid_t id;
 +      pid_t pid;
+       size_t max_harts;
++      // Temp way to pass arguments to a new process
+       size_t argc;
+       char* argv[PROCINFO_MAX_ARGC];
+       char argv_buf[PROCINFO_MAX_ARGV_SIZE];
  } procinfo_t;
  #define PROCINFO_NUM_PAGES  ((sizeof(procinfo_t)-1)/PGSIZE + 1)       
  
Simple merge
@@@ -50,8 -55,9 +50,10 @@@ KERN_APPFILES := 
                   $(USER_APPS_ROSLIB_DIR)/spawn \
                   $(USER_APPS_ROSLIB_DIR)/hello \
                   $(USER_APPS_ROSLIB_DIR)/mhello \
 +                 $(USER_APPS_ROSLIB_DIR)/mproctests \
                   $(USER_APPS_ROSLIB_DIR)/measurements \
+                  $(USER_APPS_PARLIB_PTHREAD_DIR)/pthread_test \
+                  $(USER_APPS_PARLIB_PTHREAD_DIR)/blackscholes \
                   $(USER_APPS_PARLIB_DIR)/draw_nanwan_standalone \
                   $(USER_APPS_PARLIB_DIR)/channel_test_client \
                   $(USER_APPS_PARLIB_DIR)/channel_test_server \
diff --cc kern/src/env.c
  #include <ros/syscall.h>
  #include <ros/error.h>
  
 -env_t *envs = NULL;           // All environments
  atomic_t num_envs;
 -// TODO: make this a struct of info including the pointer and cacheline-align it
 -// This lets the kernel know what process is running on the core it traps into.
 -// A lot of the Env business, including this and its usage, will change when we
 -// redesign the env as a multi-process.
 -env_t* (RO curenvs)[MAX_NUM_CPUS] = {[0 ... (MAX_NUM_CPUS-1)] NULL};
  
--#define ENVGENSHIFT   12              // >= LOGNENV
 -
 -//
 -// Converts an envid to an env pointer.
 -//
 -// RETURNS
 -//   0 on success, -EBADENV on error.
 -//   On success, sets *env_store to the environment.
 -//   On error, sets *env_store to NULL.
 -//
 -int
 -envid2env(envid_t envid, env_t **env_store, bool checkperm)
 -{
 -      env_t *e;
 -
 -      // If envid is zero, return the current environment.
 -      if (envid == 0) {
 -              *env_store = current;
 -              return 0;
 -      }
 -
 -      // Look up the Env structure via the index part of the envid,
 -      // then check the env_id field in that env_t
 -      // to ensure that the envid is not stale
 -      // (i.e., does not refer to a _previous_ environment
 -      // that used the same slot in the envs[] array).
 -      e = &envs[ENVX(envid)];
 -      if (e->state == ENV_FREE || e->env_id != envid) {
 -              *env_store = 0;
 -              return -EBADENV;
 -      }
 -
 -      // Check that the calling environment has legitimate permission
 -      // to manipulate the specified environment.
 -      // If checkperm is set, the specified environment
 -      // must be either the current environment
 -      // or an immediate child of the current environment.
 -      // TODO: should check for current being null
 -      if (checkperm && e != current && e->env_parent_id != current->env_id) {
 -              *env_store = 0;
 -              return -EBADENV;
 -      }
 -
 -      *env_store = e;
 -      return 0;
 -}
 -
 -//
 -// Mark all environments in 'envs' as free, set their env_ids to 0,
 -// and insert them into the proc_freelist.
 -// Insert in reverse order, so that the first call to env_alloc()
 -// returns envs[0].
 -// TODO: get rid of this whole array bullshit
 -//
 -void
 -env_init(void)
 -{
 -      int i;
 -
 -      schedule_init();
 -      // core 0 is not idle, all others are (for now)
 -      spin_lock(&idle_lock);
 -      num_idlecores = num_cpus; // hack to use all cores
 -      for (i = 0; i < num_idlecores; i++)
 -              idlecoremap[i] = i; // hack to use all cores
 -      spin_unlock(&idle_lock);
 -      atomic_init(&num_envs, 0);
 -      TAILQ_INIT(&proc_freelist);
 -      assert(envs != NULL);
 -      for (i = NENV-1; i >= 0; i--) {
 -              // these should already be set from when i memset'd the array to 0
 -              envs[i].state = ENV_FREE;
 -              envs[i].end_text_segment = (void*)UTEXT;
 -              envs[i].end_data_segment = (void*)UTEXT;
 -              envs[i].env_id = 0;
 -              TAILQ_INSERT_HEAD(&proc_freelist, &envs[i], proc_link);
 -      }
 -}
--
--//
  // Initialize the kernel virtual memory layout for environment e.
  // Allocate a page directory, set e->env_pgdir and e->env_cr3 accordingly,
  // and initialize the kernel portion of the new environment's address space.
@@@ -147,10 -232,142 +145,52 @@@ env_setup_vm_error
        return -ENOMEM;
  }
  
- //
+ static void
+ proc_init_procinfo(struct proc* p)
+ {
 -      p->env_procinfo->id = (p->env_id & 0x3FF);
++      p->env_procinfo->pid = p->pid;
+       // TODO: maybe do something smarter here
+       p->env_procinfo->max_harts = MAX(1,num_cpus); // hack to use all cores
+ }
+ // Sets up argc/argv in procinfo.  Returns number of
+ // args successfully imported (because of size restrictions).
+ // The procinfo pages must have been mapped into the user's
+ // address space before this function can be called.
+ size_t
+ proc_init_argc_argv(struct proc* p, size_t nargs, const char** args)
+ {
+       // TODO: right now we assume procinfo can be directly addressed
+       // by the kernel (i.e. it's continguous.
+       static_assert(sizeof(struct procinfo) <= PGSIZE);
+       if(nargs > PROCINFO_MAX_ARGC)
+               nargs = PROCINFO_MAX_ARGC;
+       char* argv[PROCINFO_MAX_ARGC] = {0};
+       static_assert(sizeof(argv) == sizeof(p->env_procinfo->argv));
+       size_t size = 0, argc;
+       for(argc = 0; argc < nargs; argc++)
+       {
+               size_t len = strnlen(args[argc],PROCINFO_MAX_ARGV_SIZE);
+               if(size+len+1 > PROCINFO_MAX_ARGV_SIZE)
+                       break;
+               memcpy(&p->env_procinfo->argv_buf[size],args[argc],len+1);
+               argv[argc] = (char*)(UINFO+offsetof(struct procinfo,argv_buf)+size);
+               size += len+1;
+       }
+       p->env_procinfo->argc = argc;
+       memcpy(p->env_procinfo->argv,argv,sizeof(argv));
+       return argc;
+ }
 -//
 -// Allocates and initializes a new environment.
 -// On success, the new environment is stored in *newenv_store.
 -//
 -// Returns 0 on success, < 0 on failure.  Errors include:
 -//    -ENOFREEENV if all NENVS environments are allocated
 -//    -ENOMEM on memory exhaustion
 -//
 -int
 -env_alloc(env_t **newenv_store, envid_t parent_id)
 -{
 -      int32_t generation;
 -      int r;
 -      env_t *e;
 -
 -      spin_lock(&freelist_lock);
 -      e = TAILQ_FIRST(&proc_freelist);
 -      if (e) {
 -              TAILQ_REMOVE(&proc_freelist, e, proc_link);
 -              spin_unlock(&freelist_lock);
 -      } else {
 -              spin_unlock(&freelist_lock);
 -              return -ENOFREEENV;
 -      }
 -
 -    { INITSTRUCT(*e)
 -
 -      // Setup the default map of where to get cache colors from
 -      e->cache_colors_map = global_cache_colors_map;
 -      e->next_cache_color = 0;
 -
 -      // Allocate and set up the page directory for this environment.
 -      if ((r = env_setup_vm(e)) < 0) {
 -              spin_lock(&freelist_lock);
 -              TAILQ_INSERT_HEAD(&proc_freelist, e, proc_link);
 -              spin_unlock(&freelist_lock);
 -              return r;
 -      }
 -
 -      // Generate an env_id for this environment.
 -      generation = (e->env_id + (1 << ENVGENSHIFT)) & ~(NENV - 1);
 -      if (generation <= 0)    // Don't create a negative env_id.
 -              generation = 1 << ENVGENSHIFT;
 -      e->env_id = generation | (e - envs);
 -
 -      // Set the basic status variables.
 -      e->proc_lock = 0;
 -      e->env_parent_id = parent_id;
 -      proc_set_state(e, PROC_CREATED);
 -      e->env_runs = 0;
 -      e->env_refcnt = 1;
 -      e->env_flags = 0;
 -      e->env_entry = 0; // cheating.  this really gets set in load_icode
 -      e->num_vcores = 0;
 -      for (int i = 0; i < MAX_NUM_CPUS; i++)
 -              e->vcoremap[i] = -1;
 -      memset(&e->resources, 0, sizeof(e->resources));
 -
 -      memset(&e->env_ancillary_state, 0, sizeof(e->env_ancillary_state));
 -      memset(&e->env_tf, 0, sizeof(e->env_tf));
 -      proc_init_trapframe(&e->env_tf);
 -
 -      proc_init_procinfo(e);
 -
 -      /*
 -       * Initialize the contents of the e->env_procdata structure
 -       */
 -      // Initialize the generic syscall ring buffer
 -      SHARED_RING_INIT(&e->env_procdata->syscallring);
 -      // Initialize the backend of the syscall ring buffer
 -      BACK_RING_INIT(&e->syscallbackring,
 -                     &e->env_procdata->syscallring,
 -                     SYSCALLRINGSIZE);
 -
 -      // Initialize the generic sysevent ring buffer
 -      SHARED_RING_INIT(&e->env_procdata->syseventring);
 -      // Initialize the frontend of the sysevent ring buffer
 -      FRONT_RING_INIT(&e->syseventfrontring,
 -                      &e->env_procdata->syseventring,
 -                      SYSEVENTRINGSIZE);
 -
 -      *newenv_store = e;
 -      atomic_inc(&num_envs);
 -
 -      printk("[%08x] new env %08x\n", current ? current->env_id : 0, e->env_id);
 -      } // INIT_STRUCT
 -      return 0;
 -}
 -
 -//
  // Allocate len bytes of physical memory for environment env,
  // and map it at virtual address va in the environment's address space.
- // Does not zero or otherwise initialize the mapped pages in any way.
+ // Pages are zeroed by upage_alloc.
  // Pages should be writable by user and kernel.
  // Panic if any allocation attempt fails.
  //
@@@ -188,6 -402,80 +225,80 @@@ env_segment_alloc(env_t *e, void *SNT v
        }
  }
  
 -static error_t
 -load_icode_memcpy(env_t* e, env_t* binary_env, void* dest, const void* src, size_t len)
+ void
+ env_segment_free(env_t *e, void *SNT va, size_t len)
+ {
+       void *SNT start, *SNT end;
+       size_t num_pages;
+       page_t *page;
+       pte_t *pte;
+       // Round this up this time so we don't free the page that va is actually on
+       start = ROUNDUP(va, PGSIZE);
+       end = ROUNDUP(va + len, PGSIZE);
+       if (start >= end)
+               panic("Wrap-around in memory free addresses!");
+       if ((uintptr_t)end > UTOP)
+               panic("Attempting to unmap above UTOP!");
+       // page_insert/pgdir_walk alloc a page and read/write to it via its address
+       // starting from pgdir (e's), so we need to be using e's pgdir
+       assert(e->env_cr3 == rcr3());
+       num_pages = LA2PPN(end - start);
+       for (int i = 0; i < num_pages; i++, start += PGSIZE) {
+               // skip if a page is already unmapped. 
+               pte = pgdir_walk(e->env_pgdir, start, 0);
+               if (pte && *pte & PTE_P)
+                       page_remove(e->env_pgdir,start);
+       }
+ }
+ // this helper function handles all cases of copying to/from user/kernel
+ // or between two users.
 -              if(binary_env == NULL)
++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(e == NULL)
 -                      return memcpy_from_user(binary_env,dest,src,len);
++              if(src_p == NULL)
+                       return -EFAULT;
 -                              if(memcpy_from_user(binary_env,kbuf,src,thislen))
++              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_to_user(e,dest,kbuf,thislen))
++                              if (memcpy_from_user(src_p, kbuf, src, thislen))
+                                       return -EFAULT;
 -              if(binary_env != NULL)
++                              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(e == NULL)
 -                      memcpy(dest,src,len);
 -              else if(memcpy_to_user(e,dest,src,len))
++              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.
  // 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.
- void load_icode(env_t *SAFE e, uint8_t *COUNT(size) binary, size_t size)
 -static void*
 -load_icode(env_t *SAFE e, env_t* binary_env, uint8_t *COUNT(size) binary, size_t size)
++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;
-       memcpy(&elfhdr, binary, sizeof(elfhdr));
+       void* _end = 0;
 -      assert(load_icode_memcpy(NULL,binary_env,&elfhdr, binary, sizeof(elfhdr)) == ESUCCESS);
++      assert(load_icode_memcpy(NULL,binary_env,&elfhdr, binary, sizeof(elfhdr))
++             == ESUCCESS);
  
        int i, r;
  
        proc_set_program_counter(&e->env_tf, elfhdr.e_entry);
        e->env_entry = elfhdr.e_entry;
  
-       // Now map one page for the program's initial stack
-       // at virtual address USTACKTOP - PGSIZE.
-       segment_alloc(e, (void*SNT)(USTACKTOP - PGSIZE), PGSIZE);
+       // Now map USTACK_NUM_PAGES pages for the program's initial stack
+       // starting at virtual address USTACKTOP - USTACK_NUM_PAGES*PGSIZE.
+       env_segment_alloc(e, (void*SNT)(USTACKTOP - USTACK_NUM_PAGES*PGSIZE), 
+                         USTACK_NUM_PAGES*PGSIZE);
+       
+       return _end;
+ }
  
-       // reload the original address space
-       lcr3(old_cr3);
-       proc_decref(e, 1);
 -//
 -// Allocates a new env and loads the named elf binary into it.
 -//
 -env_t* env_create()
 -{
 -      env_t *e;
 -      int r;
 -      envid_t curid;
 -
 -      curid = (current ? current->env_id : 0);
 -      if ((r = env_alloc(&e, curid)) < 0)
 -              panic("env_create: %e", r);
 -
 -      // default PC: will cause page fault if not otherwise set.
 -      proc_set_program_counter(&e->env_tf, 0);
 -      e->end_text_segment = 0;
 -      e->end_data_segment = 0;
 -
 -      return e;
 -}
 -
+ 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->end_text_segment = load_icode(e, binary_env, binary, size);
 -      e->end_data_segment = e->end_text_segment;
++      e->heap_bottom = load_icode(e, binary_env, binary, size);
++      e->heap_top = e->heap_bottom;
  }
  
 -//
 -// Frees env e and all memory it uses.
 -//
 -void
 -env_free(env_t *e)
 -{
 -      physaddr_t pa;
 -
 -      // Note the environment's demise.
 -      printk("[%08x] free env %08x\n", current ? current->env_id : 0, e->env_id);
 -      // All parts of the kernel should have decref'd before env_free was called.
 -      assert(e->env_refcnt == 0);
 -
 -      // Free any colors allocated to this process
 -      if(e->cache_colors_map != global_cache_colors_map) {
 -              for(int i=0; i<llc_cache->num_colors; i++)
 -                      cache_color_free(llc_cache, e->cache_colors_map);
 -              cache_colors_map_free(e->cache_colors_map);
 -      }
 -
 -      // Flush all mapped pages in the user portion of the address space
 -      env_user_mem_free(e);
 -
 -      // free the page directory
 -      pa = e->env_cr3;
 -      e->env_pgdir = 0;
 -      e->env_cr3 = 0;
 -      page_decref(pa2page(pa));
 -
 -      // return the environment to the free list
 -      e->state = ENV_FREE;
 -      spin_lock(&freelist_lock);
 -      TAILQ_INSERT_HEAD(&proc_freelist, e, proc_link);
 -      spin_unlock(&freelist_lock);
 -}
 -
 -
  #define PER_CPU_THING(type,name)\
  type SLOCKED(name##_lock) * RWPROTECT name;\
  type SLOCKED(name##_lock) *\
diff --cc kern/src/init.c
  #include <manager.h>
  #include <testing.h>
  #include <kmalloc.h>
 +#include <hashtable.h>
  
  #include <arch/init.h>
+ #include <arch/bitmask.h>
  #include <slab.h>
+ #include <kfs.h>
  
  // zra: flag for Ivy
  int booting = 1;
@@@ -61,17 -62,17 +63,18 @@@ void kernel_init(multiboot_info_t *mboo
  
        multiboot_print_memory_map((multiboot_info_t*CT(1))KADDR((physaddr_t)mboot_info));
  
--      vm_init();
--
--      cache_init();
--      page_init();
-       page_check();
--      kmem_cache_init();
++      vm_init();                      // Sets up pages tables, turns on paging
++      cache_init();                                   // Determine systems's cache properties
++      page_init();                                    // Initializes free page list, etc
++      kmem_cache_init();              // Sets up slab allocator
        kmalloc_init();
 -      cache_color_alloc_init();
 -      colored_page_alloc_init();
 +      hashtable_init();
++      cache_color_alloc_init();       // Inits data structs
++      colored_page_alloc_init();      // Allocates colors for agnostic processes
+       page_check();
  
        idt_init();
 +      active_msg_init();
        sysenter_init();
        timer_init();
        
diff --cc kern/src/kfs.c
Simple merge
  #include <kfs.h>
  #include <stdio.h>
  #include <timing.h>
 +#include <resource.h>
 +#include <monitor.h>
+ #include <colored_caches.h>
+ #include <string.h>
  
  /*
   * Currently, if you leave this function by way of proc_run (process_workqueue
   */
  void manager(void)
  {
+       #ifndef DEVELOPER_NAME
+               #define DEVELOPER_NAME brho
+       #endif
+       // LoL
+       #define PASTE(s1,s2) s1 ## s2
+       #define MANAGER_FUNC(dev) PASTE(manager_,dev)
+       void MANAGER_FUNC(DEVELOPER_NAME)(void);
+       MANAGER_FUNC(DEVELOPER_NAME)();
+ }
+ void manager_brho(void)
+ {
        static uint8_t RACY progress = 0;
  
-       struct proc *envs[256];
-       static struct proc *p;
+       static struct proc *envs[256];
+       static struct proc *p ;
  
 +      // for testing taking cores, check in case 1 for usage
        uint32_t corelist[MAX_NUM_CPUS];
        uint32_t num = 3;
  
-       /*
-       // This is a bypass of the standard manager structure, for network use
-       // If enabled, this spawns parlib_matrix, and allows the execution
-       // of a remote binary to function correctly (schedule() call below)
-       if (progress++ == 0) {
-               envs[0] = kfs_proc_create(kfs_lookup_path("parlib_matrix"));
-               __proc_set_state(envs[0], PROC_RUNNABLE_S);
-               proc_run(envs[0]);
-       }
-       schedule();
-       */
        switch (progress++) {
                case 0:
 -                      //p = kfs_proc_create(kfs_lookup_path("roslib_proctests"));
 -                      p = kfs_proc_create(kfs_lookup_path("roslib_mhello"));
 +                      // TODO: need to store the pid for future manager runs, not the *p
 +                      //p = kfs_proc_create(kfs_lookup_path("roslib_mhello"));
 +                      p = kfs_proc_create(kfs_lookup_path("roslib_mproctests"));
 +                      //p = kfs_proc_create(kfs_lookup_path("roslib_spawn"));
                        // being proper and all:
                        spin_lock_irqsave(&p->proc_lock);
 -                      proc_set_state(p, PROC_RUNNABLE_S);
 +                      __proc_set_state(p, PROC_RUNNABLE_S);
                        // normal single-cored way
                        spin_unlock_irqsave(&p->proc_lock);
                        proc_run(p);
                        proc_run(envs[0]);
                        break;
                        #endif
--      #ifdef __i386__
                case 2:
                        #if 0
                        panic("Do not panic");
                        break;
                        #endif
                case 3:
--      #else // sparc
--              case 2:
--                      panic("Do not panic");
--                      envs[0] = kfs_proc_create(kfs_lookup_path("roslib_proctests"));
--                      envs[1] = kfs_proc_create(kfs_lookup_path("roslib_proctests"));
--                      envs[2] = kfs_proc_create(kfs_lookup_path("roslib_proctests"));
--                      envs[3] = kfs_proc_create(kfs_lookup_path("roslib_fptest"));
--                      envs[4] = kfs_proc_create(kfs_lookup_path("roslib_fptest"));
--                      envs[4] = kfs_proc_create(kfs_lookup_path("roslib_fptest"));
--                      envs[5] = kfs_proc_create(kfs_lookup_path("roslib_hello"));
--                      envs[6] = kfs_proc_create(kfs_lookup_path("roslib_null"));
--                      proc_run(envs[0]);
--                      break;
--              case 3:
--                      #if 0
--                      // reminder of how to spawn remotely
--                      for (int i = 0; i < 8; i++) {
--                              envs[i] = kfs_proc_create(kfs_lookup_path("roslib_hello"));
-                               __proc_set_state(envs[i], PROC_RUNNABLE_S);
 -                              proc_set_state(envs[i], PROC_RUNNABLE_S);
--                              smp_call_function_single(i, run_env_handler, envs[i], 0);
--                      }
--                      process_workqueue();
--                      #endif
--      #endif
--
                #if 0
                case 4:
                        printk("Beginning Tests\n");
        */
        return;
  }
 -              proc_set_state(envs[0], PROC_RUNNABLE_S);
+ void manager_klueska()
+ {
+       static struct proc *envs[256];
+       static uint8_t progress = 0;
+       if (progress++ == 0) {
+               envs[0] = kfs_proc_create(kfs_lookup_path("parlib_matrix"));
++              __proc_set_state(envs[0], PROC_RUNNABLE_S);
+               proc_run(envs[0]);
+       }
+       schedule();
+       panic("DON'T PANIC");
+ }
+ #ifdef __sparc_v8__
+ static char*
+ itoa(int num, char* buf0, size_t base)
+ {
+       if(base > 16)
+               return NULL;
+       char* buf = buf0;
+       int len = 0, i;
+       if(num < 0)
+       {
+               *buf++ = '-';
+               num = -num;
+       }
+       do {
+               buf[len++] = "0123456789abcdef"[num%base];
+               num /= base;
+       } while(num);
+       for(i = 0; i < len/2; i++)
+       {
+               char temp = buf[i];
+               buf[i] = buf[len-i-1];
+               buf[len-i-1] = temp;
+       }
+       buf[len] = 0;
+       return buf0;
+ }
+ void gsf_set_frame_cycles(int cycles)
+ {
+       store_alternate(26*4,2,cycles);
+ }
+ void gsf_set_partition_credits(int partition, int credits)
+ {
+       store_alternate((32+partition)*4,2,credits);
+ }
+ void gsf_set_core_partition(int core, int partition)
+ {
+       store_alternate((64+core)*4,2,partition);
+ }
+ #endif
+ void manager_waterman()
+ {
+ #ifdef __sparc_v8__
+         static uint8_t progress = 0;
+       if(progress > 0)
+               goto run_some_apps;     
+       #define MAX_APPS 2
+       struct app
+       {
+               int threads;
+               int colors;
+               int credits;
+               int argc;
+               char** argv;
+       };
+       static struct app apps[MAX_APPS];
+       static int napps = 0;
+       // arg format:
+       // #apps [#threads #colors #credits name args] - [#threads ...] - ...
+       assert(argc > 0);
+       napps = atoi(argv[0]);
+       assert(napps <= MAX_APPS);
+       argc--; argv++;
+       for(int a = 0; a < napps; a++)
+       {
+               assert(argc >= 4);
+               apps[a].threads = atoi(argv[0]);
+               apps[a].colors = atoi(argv[1]);
+               apps[a].credits = atoi(argv[2]);
+               argc -= 3; argv += 3;
+               apps[a].argc = 0;
+               apps[a].argv = argv;
+               while(argc)
+               {
+                       argc--;
+                       if(strcmp(*argv++,"-") != 0)
+                               apps[a].argc++;
+                       else
+                               break;
+               }
+               printk("app %d: %d threads, %d colors, %d credits\ncommand line: ",a,apps[a].threads,apps[a].colors,apps[a].credits);
+               for(int i = 0; i < apps[a].argc; i++)
+                       printk("%s ",apps[a].argv[i]);
+               printk("\n");
+       }
+       // DRAM can process requests every 40 cycles.
+       // In a 480-cycle window, this gives us 12 total credits.
+       gsf_set_frame_cycles(482);
+       for(int a = 0, cores_used = 0; a < napps; a++)
+       {
+               gsf_set_partition_credits(a,apps[a].credits);
+               for(int i = 0; i < apps[a].threads; i++, cores_used++)
+                       gsf_set_core_partition(num_cpus-cores_used-1,a);
+       }
+ run_some_apps:
+       ;
+       static struct proc *envs[MAX_APPS];
+       int apps_running = napps;
+       int envs_free[MAX_APPS] = {0};
+       if(progress == napps)
+       {
+               while(apps_running)
+               {
+                       for(int i = 0; i < napps; i++)
+                       {
+                               if(*(volatile uint32_t*)&envs[i]->state == ENV_FREE && !envs_free[i])
+                               {
+                                       envs_free[i] = 1;
+                                       apps_running--;
+                                       printk("Finished application %d at cycle %lld\n", i, read_tsc()); 
+                               }
+                       }
+               }
+               reboot();
+       }
+       else
+       {
+               envs[progress] = kfs_proc_create(kfs_lookup_path(apps[progress].argv[0]));
+               envs[progress]->cache_colors_map = cache_colors_map_alloc();
+               for(int i = 0; i < apps[progress].colors; i++)
+                       assert(cache_color_alloc(llc_cache, envs[progress]->cache_colors_map) == ESUCCESS);
+               proc_set_state(envs[progress], PROC_RUNNABLE_S);
+               if(apps[progress].argc)
+                       proc_init_argc_argv(envs[progress],apps[progress].argc,(const char**)apps[progress].argv);
+               proc_run(envs[progress++]);
+               schedule();
+       }
+ #endif
+       panic("professional bomb technician at work.  if you see me running, try to keep up!");
+ }
  #include <page_alloc.h>
  #include <pmap.h>
  #include <string.h>
+ #include <kmalloc.h>
+ #define l1 (available_caches.l1)
+ #define l2 (available_caches.l2)
+ #define l3 (available_caches.l3)
  
 -static void __page_decref(page_t *page);
 -static void __page_incref(page_t *page);
 +static void __page_decref(page_t *CT(1) page);
++static void __page_incref(page_t *CT(1) page);
  static error_t __page_alloc_specific(page_t** page, size_t ppn);
 -static error_t __page_free(page_t* page);
 +static error_t __page_free(page_t *CT(1) page);
  
+ // Global list of colors allocated to the general purpose memory allocator
+ uint8_t* global_cache_colors_map;
+ void colored_page_alloc_init()
+ {
+       global_cache_colors_map = 
+              kmalloc(BYTES_FOR_BITMASK(llc_cache->num_colors), 0);
+       CLR_BITMASK(global_cache_colors_map, llc_cache->num_colors);
+       cache_color_alloc(llc_cache, global_cache_colors_map);
+       cache_color_alloc(llc_cache, global_cache_colors_map);
+       cache_color_alloc(llc_cache, global_cache_colors_map);
+       cache_color_alloc(llc_cache, global_cache_colors_map);
+       cache_color_alloc(llc_cache, global_cache_colors_map);
+ }
  /**
   * @brief Clear a Page structure.
   *
diff --cc kern/src/pmap.c
@@@ -379,10 -379,10 +379,10 @@@ user_mem_assert(env_t *env, const void 
                return NULL;
        }
        
-     void *COUNT(len) res = user_mem_check(env,va,len,perm | PTE_USER_RO);
+       void *COUNT(len) res = user_mem_check(env,va,len,perm | PTE_USER_RO);
        if (!res) {
                cprintf("[%08x] user_mem_check assertion failure for "
 -                      "va %08x\n", env->env_id, user_mem_check_addr);
 +                      "va %08x\n", env->pid, user_mem_check_addr);
                proc_destroy(env);      // may not return
          return NULL;
        }
@@@ -155,163 -98,17 +155,176 @@@ int __proc_set_state(struct proc *p, ui
        return 0;
  }
  
 -/* Change this when we aren't using an array */
 -struct proc *get_proc(unsigned pid)
 +/* Returns a pointer to the proc with the given pid, or 0 if there is none */
 +struct proc *pid2proc(pid_t pid)
 +{
 +      spin_lock(&pid_hash_lock);
 +      struct proc *p = hashtable_search(pid_hash, (void*)pid);
 +      spin_unlock(&pid_hash_lock);
 +      /* if the refcnt was 0, decref and return 0 (we failed). (TODO) */
 +      if (p)
 +              proc_incref(p, 1); // TODO:(REF) to do this all atomically and not panic
 +      return p;
 +}
 +
 +/* Performs any intialization related to processes, such as create the proc
 + * cache, prep the scheduler, etc.  When this returns, we should be ready to use
 + * any process related function. */
 +void proc_init(void)
 +{
 +      proc_cache = kmem_cache_create("proc", sizeof(struct proc),
 +                   MAX(HW_CACHE_ALIGN, __alignof__(struct proc)), 0, 0, 0);
 +      /* Init PID mask and hash.  pid 0 is reserved. */
 +      SET_BITMASK_BIT(pid_bmask, 0);
 +      spinlock_init(&pid_hash_lock);
 +      spin_lock(&pid_hash_lock);
 +      pid_hash = create_hashtable(100, __generic_hash, __generic_eq);
 +      spin_unlock(&pid_hash_lock);
 +      schedule_init();
 +      /* Init idle cores.  core 0 is not idle, all others are (for now) */
 +      spin_lock(&idle_lock);
 +      num_idlecores = num_cpus - 1;
 +      for (int i = 0; i < num_idlecores; i++)
 +              idlecoremap[i] = i + 1;
 +      spin_unlock(&idle_lock);
 +      atomic_init(&num_envs, 0);
 +}
 +
 +/* Allocates and initializes a process, with the given parent.  Currently
 + * writes the *p into **pp, and returns 0 on success, < 0 for an error.
 + * Errors include:
 + *  - ENOFREEPID if it can't get a PID
 + *  - ENOMEM on memory exhaustion */
 +static error_t proc_alloc(struct proc *SAFE*SAFE pp, pid_t parent_id)
 +{
 +      error_t r;
 +      struct proc *p;
 +
 +      if (!(p = kmem_cache_alloc(proc_cache, 0)))
 +              return -ENOMEM;
 +
 +    { INITSTRUCT(*p)
 +
++      // Setup the default map of where to get cache colors from
++      p->cache_colors_map = global_cache_colors_map;
++      p->next_cache_color = 0;
++
 +      /* Initialize the address space */
 +      if ((r = env_setup_vm(p)) < 0) {
 +              kmem_cache_free(proc_cache, p);
 +              return r;
 +      }
 +
 +      /* Get a pid, then store a reference in the pid_hash */
 +      if (!(p->pid = get_free_pid())) {
 +              kmem_cache_free(proc_cache, p);
 +              return -ENOFREEPID;
 +      }
 +      spin_lock(&pid_hash_lock);
 +      hashtable_insert(pid_hash, (void*)p->pid, p);
 +      spin_unlock(&pid_hash_lock);
 +
 +      /* Set the basic status variables. */
 +    spinlock_init(&p->proc_lock);
 +      p->ppid = parent_id;
 +      __proc_set_state(p, PROC_CREATED);
 +      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->num_vcores = 0;
++      p->heap_bottom = (void*)UTEXT;
++      p->heap_top = (void*)UTEXT;
 +      memset(&p->vcoremap, -1, sizeof(p->vcoremap));
 +      memset(&p->resources, 0, sizeof(p->resources));
 +      memset(&p->env_ancillary_state, 0, sizeof(p->env_ancillary_state));
 +      memset(&p->env_tf, 0, sizeof(p->env_tf));
 +      proc_init_trapframe(&p->env_tf);
 +
 +      /* Initialize the contents of the e->env_procinfo structure */
 +      p->env_procinfo->pid = p->pid;
 +      /* Initialize the contents of the e->env_procdata structure */
 +
 +      /* Initialize the generic syscall ring buffer */
 +      SHARED_RING_INIT(&p->env_procdata->syscallring);
 +      /* Initialize the backend of the syscall ring buffer */
 +      BACK_RING_INIT(&p->syscallbackring,
 +                     &p->env_procdata->syscallring,
 +                     SYSCALLRINGSIZE);
 +
 +      /* Initialize the generic sysevent ring buffer */
 +      SHARED_RING_INIT(&p->env_procdata->syseventring);
 +      /* Initialize the frontend of the sysevent ring buffer */
 +      FRONT_RING_INIT(&p->syseventfrontring,
 +                      &p->env_procdata->syseventring,
 +                      SYSEVENTRINGSIZE);
 +      *pp = p;
 +      atomic_inc(&num_envs);
 +
 +      printk("[%08x] new process %08x\n", current ? current->pid : 0, p->pid);
 +      } // INIT_STRUCT
 +      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)
 +{
 +      struct proc *p;
 +      error_t r;
 +      pid_t curid;
 +
 +      curid = (current ? current->pid : 0);
 +      if ((r = proc_alloc(&p, curid)) < 0)
 +              panic("proc_create: %e", r); // one of 3 quaint usages of %e.
-       load_icode(p, binary, size);
++      env_load_icode(p, NULL, binary, size);
 +      return p;
 +}
 +
 +/* This is called by proc_decref, once the last reference to the process is
 + * gone.  Don't call this otherwise (it will panic).  It will clean up the
 + * address space and deallocate any other used memory. */
 +static void __proc_free(struct proc *p)
  {
 -      // should have some error checking when we do this for real
 -      return &envs[ENVX(pid)];
 +      physaddr_t pa;
 +
 +      printk("[PID %d] freeing proc: %d\n", current ? current->pid : 0, p->pid);
 +      // All parts of the kernel should have decref'd before __proc_free is called
 +      assert(p->env_refcnt == 0);
 +
++      // Free any colors allocated to this process
++      if(p->cache_colors_map != global_cache_colors_map) {
++              for(int i=0; i<llc_cache->num_colors; i++)
++                      cache_color_free(llc_cache, p->cache_colors_map);
++              cache_colors_map_free(p->cache_colors_map);
++      }
++
 +      // Flush all mapped pages in the user portion of the address space
 +      env_user_mem_free(p);
 +
 +      // free the page directory
 +      pa = p->env_cr3;
 +      p->env_pgdir = 0;
 +      p->env_cr3 = 0;
 +      page_decref(pa2page(pa));
 +
 +      /* Remove self from the pid hash, return PID.  Note the reversed order. */
 +      spin_lock(&pid_hash_lock);
 +      if (!hashtable_remove(pid_hash, (void*)p->pid))
 +              panic("Proc not in the pid table in %s", __FUNCTION__);
 +      spin_unlock(&pid_hash_lock);
 +      put_free_pid(p->pid);
 +      atomic_dec(&num_envs);
 +
 +      /* Dealloc the struct proc */
 +      kmem_cache_free(proc_cache, p);
  }
  
 -/* Whether or not actor can control target */
 +/* Whether or not actor can control target.  Note we currently don't need
 + * locking for this. TODO: think about that, esp wrt proc's dying. */
  bool proc_controls(struct proc *actor, struct proc *target)
  {
 -      return target->env_parent_id == actor->env_id;
 +      return ((actor == target) || (target->ppid == actor->pid));
  }
  
  /* Dispatches a process to run, either on the current core in the case of a
@@@ -939,7 -720,7 +952,8 @@@ void __startcore(trapframe_t *tf, uint3
        trapframe_t local_tf;
        trapframe_t *tf_to_pop = (trapframe_t *CT(1))a1;
  
-       printk("[kernel] Startcore on physical core %d\n", coreid);
 -      printk("[kernel] Startcore on physical core %d for Process %d\n", coreid, p_to_run->env_id);
++      printk("[kernel] Startcore on physical core %d for Process %d\n",
++             coreid, p_to_run->pid);
        assert(p_to_run);
        // TODO: handle silly state (HSS)
        if (!tf_to_pop) {
diff --cc kern/src/slab.c
Simple merge
@@@ -81,20 -83,19 +83,19 @@@ static ssize_t sys_serial_read(env_t* e
  //
  
  static ssize_t sys_run_binary(env_t* e, void *DANGEROUS binary_buf,
-                               void*DANGEROUS arg, size_t len) {
-       uint8_t *CT(len) checked_binary_buf;
-       checked_binary_buf = user_mem_assert(e, binary_buf, len, PTE_USER_RO);
-       uint8_t* new_binary = kmalloc(len, 0);
-       if(new_binary == NULL)
-               return -ENOMEM;
-       memcpy(new_binary, checked_binary_buf, len);
-       env_t* env = proc_create(new_binary, len);
-       kfree(new_binary);
+                   void*DANGEROUS arg, size_t len, size_t num_colors)
+ {
 -      env_t* env = env_create();
 -      env_load_icode(env,e,binary_buf,len);
 -
++      env_t* env = proc_create(0, 0);
++      env_load_icode(env, e, binary_buf, len);
 +      __proc_set_state(env, PROC_RUNNABLE_S);
 +      schedule_proc(env);
+       if(num_colors > 0) {
+               env->cache_colors_map = cache_colors_map_alloc();
+               for(int i=0; i<num_colors; i++)
+                       cache_color_alloc(llc_cache, env->cache_colors_map);
+       }
 -      proc_set_state(env, PROC_RUNNABLE_S);
 -      schedule_proc(env);
 +      proc_decref(env, 1);
+       proc_yield(e);
        return 0;
  }
  
@@@ -186,31 -187,21 +187,31 @@@ static ssize_t sys_shared_page_alloc(en
  
        void * COUNT(1) * COUNT(1) addr = user_mem_assert(p1, _addr, sizeof(void *),
                                                        PTE_USER_RW);
-       env_t* p2 = pid2proc(p2_id);
++      struct proc *p2 = pid2proc(p2_id);
 +      if (!p2)
 +              return -EBADPROC;
 +
        page_t* page;
-       error_t e = page_alloc(&page);
 -      env_t* p2 = &(envs[ENVX(p2_id)]);
+       error_t e = upage_alloc(p1, &page);
 -
 -      if(e < 0) return e;
 +      if (e < 0) {
 +              proc_decref(p2, 1);
 +              return e;
 +      }
  
        void* p2_addr = page_insert_in_range(p2->env_pgdir, page,
-                                            (void*SNT)UTEXT, (void*SNT)UTOP, p2_flags);
+                       (void*SNT)UTEXT, (void*SNT)UTOP, p2_flags);
 -      if(p2_addr == NULL)
 +      if (p2_addr == NULL) {
 +              page_free(page);
 +              proc_decref(p2, 1);
                return -EFAIL;
 +      }
  
        void* p1_addr = page_insert_in_range(p1->env_pgdir, page,
-                                           (void*SNT)UTEXT, (void*SNT)UTOP, p1_flags);
+                       (void*SNT)UTEXT, (void*SNT)UTOP, p1_flags);
        if(p1_addr == NULL) {
                page_remove(p2->env_pgdir, p2_addr);
 +              page_free(page);
 +              proc_decref(p2, 1);
                return -EFAIL;
        }
        *addr = p1_addr;
@@@ -274,8 -264,8 +275,8 @@@ static void sys_cache_buster(struct pro
        if (num_pages) {
                spin_lock(&buster_lock);
                for (int i = 0; i < MIN(num_pages, MAX_PAGES); i++) {
-                       page_alloc(&a_page[i]);
 -                      upage_alloc(e, &a_page[i]);
 -                      page_insert(e->env_pgdir, a_page[i], (void*)INSERT_ADDR + PGSIZE*i,
++                      upage_alloc(p, &a_page[i]);
 +                      page_insert(p->env_pgdir, a_page[i], (void*)INSERT_ADDR + PGSIZE*i,
                                    PTE_USER_RW);
                }
                spin_unlock(&buster_lock);
@@@ -345,30 -336,39 +346,44 @@@ static uint32_t sys_getcpuid(void
        return core_id();
  }
  
 -// TODO FIX Me!!!! for processes
 -// Destroy a given environment (possibly the currently running environment).
 -//
 -// Returns 0 on success, < 0 on error.  Errors are:
 -//    -EBADENV if environment envid doesn't currently exist,
 -//            or the caller doesn't have permission to change envid.
 -static error_t sys_env_destroy(env_t* e, envid_t envid)
+ // TODO: Temporary hack until thread-local storage is implemented on i386
+ static size_t sys_getvcoreid(env_t* e)
+ {
+       if(e->state == PROC_RUNNING_S)
+               return 0;
+       size_t i;
+       for(i = 0; i < e->num_vcores; i++)
+               if(core_id() == e->vcoremap[i])
+                       return i;
+       panic("virtual core id not found in sys_getvcoreid()!");
+ }
 +/* Destroy proc pid.  If this is called by the dying process, it will never
 + * return.  o/w it will return 0 on success, or an error.  Errors include:
 + * - EBADPROC: if there is no such process with pid
 + * - EPERM: if caller does not control pid */
 +static error_t sys_proc_destroy(struct proc *p, pid_t pid)
  {
 -      int r;
 -      env_t *env_to_die;
 -
 -      if ((r = envid2env(envid, &env_to_die, 1)) < 0)
 -              return r;
 -      if (env_to_die == e)
 -              printk("[%08x] exiting gracefully\n", e->env_id);
 -      else
 +      error_t r;
 +      struct proc *p_to_die = pid2proc(pid);
 +
 +      if (!p_to_die)
 +              return -EBADPROC;
 +      if (!proc_controls(p, p_to_die)) {
 +              proc_decref(p_to_die, 1);
 +              return -EPERM;
 +      }
 +      if (p_to_die == p) {
 +              // syscall code and pid2proc both have edible references, only need 1.
 +              proc_decref(p, 1);
 +              printk("[PID %d] proc exiting gracefully\n", p->pid);
 +      } else {
                panic("Destroying other processes is not supported yet.");
 -              //printk("[%08x] destroying %08x\n", e->env_id, env_to_die->env_id);
 -      proc_destroy(env_to_die);
 +              //printk("[%d] destroying proc %d\n", p->pid, p_to_die->pid);
 +      }
 +      proc_destroy(p_to_die);
        return ESUCCESS;
  }
  
@@@ -433,6 -424,26 +448,26 @@@ static error_t sys_proc_run(struct pro
        return retval;
  }
  
 -      if((addr < p->end_text_segment) || (addr >= (void*)USTACKBOT))
+ static error_t sys_brk(struct proc *p, void* addr) {
+       size_t range;
 -      if(addr == p->end_data_segment)
++      if((addr < p->heap_bottom) || (addr >= (void*)USTACKBOT))
+               return -EINVAL;
 -      if (addr > p->end_data_segment) {
 -              range = addr - p->end_data_segment;
 -              env_segment_alloc(p, p->end_data_segment, range);
++      if(addr == p->heap_top)
+               return ESUCCESS;
 -      else if (addr < p->end_data_segment) {
 -              range = p->end_data_segment - addr;
++      if (addr > p->heap_top) {
++              range = addr - p->heap_top;
++              env_segment_alloc(p, p->heap_top, range);
+       }
 -      p->end_data_segment = addr;
++      else if (addr < p->heap_top) {
++              range = p->heap_top - addr;
+               env_segment_free(p, addr, range);
+       }
++      p->heap_top = addr;
+       return ESUCCESS;
+ }
  /* Executes the given syscall.
   *
   * Note tf is passed in, which points to the tf of the context on the kernel
@@@ -482,10 -494,12 +517,12 @@@ intreg_t syscall(struct proc *p, uintre
                        return sys_cgetc(p); // this will need to block
                case SYS_getcpuid:
                        return sys_getcpuid();
+               case SYS_getvcoreid:
+                       return sys_getvcoreid(p);
                case SYS_getpid:
 -                      return sys_getenvid(p);
 +                      return sys_getpid(p);
                case SYS_proc_destroy:
 -                      return sys_env_destroy(p, (envid_t)a1);
 +                      return sys_proc_destroy(p, (pid_t)a1);
                case SYS_yield:
                        proc_yield(p);
                        return ESUCCESS;
                        _a6 = args[2];
                        return (intreg_t) mmap(p, a1, a2, a3, _a4, _a5, _a6);
                case SYS_brk:
-                       printk("brk not implemented yet\n");
-                       return -EINVAL;
+                       return sys_brk(p, (void*)a1);
                case SYS_resource_req:
 -                      /* preemptively set the return code to 0.  if it's not, it will get
 -                       * overwriten on a proper return path.  if it ends up being a core
 -                       * request from a RUNNING_S, it will never return out this way
 -                       */
 -                      proc_set_syscall_retval(tf, ESUCCESS);
 -                      return resource_req(p, a1, a2, a3);
 +                      return resource_req(p, a1, a2, a3, a4);
  
        #ifdef __i386__
                case SYS_serial_write:
                        return frontend_syscall_from_user(p,a1,a2,a3,a4);
        #endif
  
+               case SYS_reboot:
+                       reboot();
+                       return 0;
                default:
                        // or just return -EINVAL
 -                      panic("Invalid syscall number %d for env %x!", syscallno, *p);
 +                      panic("Invalid syscall number %d for proc %x!", syscallno, *p);
        }
        return 0xdeadbeef;
  }
  #include <pmap.h>
  #include <slab.h>
  #include <kmalloc.h>
 +#include <hashtable.h>
  
+ #define l1 (available_caches.l1)
+ #define l2 (available_caches.l2)
+ #define l3 (available_caches.l3)
  #ifdef __i386__
  
  void test_ipi_sending(void)
@@@ -69,5 -73,5 +73,6 @@@ void run_binary(
        }
        free(binary_buf);
        close(fd);
++      syscall(SYS_yield,0,0,0,0,0);
  }
  
index 0000000,b0d25c6..9e60ba0
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,86 +1,87 @@@
+ #include <string.h>
+ #include <stdlib.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <fcntl.h>
+ #include <stdint.h>
+ #include <stdio.h>
+ #include <unistd.h>
+ #include <parlib.h>
+ extern char * readline(const char *prompt);
+ #define READ_SIZE       1024
+ uint8_t* binary_buf;
+ static void fd_error() {
+       fprintf(stderr, "Error: Unable to run remote binary (fd error): %s\n", 
+                                                             strerror(errno));
+ }
+ static void malloc_error() {
+       fprintf(stderr, 
+               "Error: Unable to run remote binary: No more memory avaialable!\n");
+ }
+ static void read_error(void* buf, int fd) {
+       free(binary_buf);
+       close(fd);
+       fprintf(stderr, "Error: Unable to run remote binary (read error): %s\n", 
+                                                               strerror(errno));
+ }
+ static void realloc_error(void* buf, int fd) {
+       free(binary_buf);
+       close(fd);
+       fprintf(stderr, 
+               "Error: Unable to run remote binary: No more memory available!\n");
+ }
+ void run_binary_colored()
+ {     
+       char* name = readline("\nEnter name of binary to execute: ");
+       if (name == NULL) {
+               printf("Error reading from console.\n");
+               return;
+       }
+       char* file_name = name;
+       //char * file_name = malloc(strlen(name) + 8);
+       //sprintf(file_name, "./apps/%s", name);
+       int fd = open(file_name, O_RDONLY, 0);
+       //free(file_name);
+       if(fd < 0) { fd_error(); return; };
+       char* colors = readline("\nEnter number of colors: ");
+       if (colors == NULL) {
+               printf("Error reading from console.\n");
+               return;
+       }
+       size_t num_colors = atoi(colors);
+       
+       int iters = 1;
+       binary_buf = malloc(READ_SIZE);
+       if(binary_buf == NULL) { malloc_error(); return; }
+       
+       int total_bytes_read = 0;
+       int bytes_read = read(fd, binary_buf, READ_SIZE);
+       if(bytes_read < 0) { read_error(binary_buf, fd); return; }
+       
+       while(bytes_read > 0) {
+               total_bytes_read += bytes_read; 
+               void* temp_buf = realloc(binary_buf, READ_SIZE*(++iters));
+               if(temp_buf == NULL) { realloc_error(binary_buf, fd); return; } 
+               binary_buf = temp_buf;
+               bytes_read = read(fd, binary_buf+total_bytes_read, READ_SIZE);
+               if(bytes_read < 0) { read_error(binary_buf, fd); return; }
+       }
+       printf("Loading Binary: %s, ROMSIZE: %d\n", name, total_bytes_read);
+       ssize_t error = sys_run_binary(binary_buf, NULL, 
+                           total_bytes_read, num_colors);
+       if(error < 0) {
+               fprintf(stderr, "Error: Unable to run remote binary\n");
+       }
+       free(binary_buf);
+       close(fd);
++      syscall(SYS_yield,0,0,0,0,0);
+ }
        .set procinfo, UINFO
        .globl procdata
        .set procdata, UDATA
-       .globl pages
-       .set pages, UPAGES
-       .globl vpt
-       .set vpt, UVPT
-       .globl vpd
-       .set vpd, (UVPT+(UVPT>>12)*4)
+ // Stack pointers, to be allocated by the hart lib
+       .globl stack_ptr_array
+       stack_ptr_array:
+               .word 0
++      .globl tls_array
++      tls_array:
++              .word 0
+ // TODO: We're not exposing these yet.  Think about how to do so judiciously.
+ //    .globl vpt
+ //    .set vpt, UVPT
+ //    .globl vpd
+ //    .set vpd, (UVPT+(UVPT>>12)*4)
  
  
  // Entrypoint - this is where the kernel (or our parent environment)
Simple merge