Fixes some syscall issues, esp getpid
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 25 Jan 2010 20:17:24 +0000 (12:17 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 25 Jan 2010 20:17:24 +0000 (12:17 -0800)
Adds sys_getpid to the syscall table, provides return values for calls
like proc_yield, keeps the table entries in the order in ros/syscall.h,
and reorganizes the syscalls into groups.

kern/include/ros/syscall.h
kern/src/syscall.c

index 1f9b5e8..93eb378 100644 (file)
@@ -5,18 +5,24 @@
 #define SYS_null                                        1
 #define SYS_cache_buster                        2
 #define SYS_cache_invalidate            3
-#define SYS_cputs                                       4
-#define SYS_cgetc                                       5
-#define SYS_getcpuid                            6
-#define SYS_getpid                                      7
-#define SYS_proc_destroy                        8
-#define SYS_shared_page_alloc           9
-#define SYS_shared_page_free           10
-#define SYS_yield                                      11
-#define SYS_proc_create                                12
-#define SYS_proc_run                           13
-#define SYS_mmap                                       14
-#define SYS_brk                                                15
+#define SYS_reboot                                      4
+#define SYS_cputs                                       5
+#define SYS_cgetc                                       6
+#define SYS_getcpuid                            7
+#define SYS_getvcoreid                          8
+#define SYS_getpid                                      9
+#define SYS_proc_create                                10
+#define SYS_proc_run                           11
+#define SYS_proc_destroy                       12
+#define SYS_yield                                      13
+#define SYS_run_binary                         14
+#define SYS_fork                                       15
+#define SYS_exec                                       16
+#define SYS_trywait                                    17
+#define SYS_mmap                                       18
+#define SYS_brk                                                19
+#define SYS_shared_page_alloc          20
+#define SYS_shared_page_free           21
 /*
 #define SYS_mprotect
 #define SYS_mremap
 #define SYS_mlock
 #define SYS_msync
 */
-#define SYS_resource_req                       16
-/* Read and write buffers over the serial port */
-#define SYS_serial_write                       17
-#define SYS_serial_read                                18
-/* The next 3 syscalls go with the experimental network driver. These syscalls
- * are used by newlib_backend / our remote binary loader to pull data from /
- * put data into a buffer managed by the network driver.  These should go away
- * as things mature. */
-#define SYS_eth_read                           19
-#define SYS_eth_write                          20
-#define SYS_run_binary                         21
-// forward a syscall to front-end machine
-#define SYS_frontend                           22
-#define SYS_getvcoreid                         23
-#define SYS_reboot                             24
-#define SYS_fork                               25
-#define SYS_exec                               26
-#define SYS_trywait                            27
-// Keep this in sync with the last syscall number
-#define NSYSCALLS                                      27
-// syscall number starts at 1 and goes up to NSYSCALLS, without holes.
-#define INVALID_SYSCALL(syscallno) ((syscallno) > NSYSCALLS)
+#define SYS_resource_req                       22
+/* Platform specific syscalls */
+#define SYS_serial_read                                23
+#define SYS_serial_write                       24
+#define SYS_eth_read                           25
+#define SYS_eth_write                          26
+#define SYS_frontend                           27
 
 /* For Buster Measurement Flags */
 #define BUSTER_SHARED                  0x0001
index 3a372f3..d03fd3b 100644 (file)
@@ -37,50 +37,269 @@ extern char *CT(PACKET_HEADER_SIZE + len) (*packet_wrap)(const char *CT(len) dat
 extern int (*send_frame)(const char *CT(len) data, size_t len);
 #endif
 
-//Do absolutely nothing.  Used for profiling.
-static void sys_null(void)
+/************** Utility Syscalls **************/
+
+static int sys_null(void)
 {
-       return;
+       return 0;
 }
 
-//Write a buffer over the serial port
-static ssize_t sys_serial_write(env_t* e, const char *DANGEROUS buf, size_t len)
+// Writes 'val' to 'num_writes' entries of the well-known array in the kernel
+// address space.  It's just #defined to be some random 4MB chunk (which ought
+// to be boot_alloced or something).  Meant to grab exclusive access to cache
+// lines, to simulate doing something useful.
+static int sys_cache_buster(struct proc *p, uint32_t num_writes,
+                             uint32_t num_pages, uint32_t flags)
+{ TRUSTEDBLOCK /* zra: this is not really part of the kernel */
+       #define BUSTER_ADDR             0xd0000000  // around 512 MB deep
+       #define MAX_WRITES              1048576*8
+       #define MAX_PAGES               32
+       #define INSERT_ADDR     (UINFO + 2*PGSIZE) // should be free for these tests
+       uint32_t* buster = (uint32_t*)BUSTER_ADDR;
+       static spinlock_t buster_lock = SPINLOCK_INITIALIZER;
+       uint64_t ticks = -1;
+       page_t* a_page[MAX_PAGES];
+
+       /* Strided Accesses or Not (adjust to step by cachelines) */
+       uint32_t stride = 1;
+       if (flags & BUSTER_STRIDED) {
+               stride = 16;
+               num_writes *= 16;
+       }
+
+       /* Shared Accesses or Not (adjust to use per-core regions)
+        * Careful, since this gives 8MB to each core, starting around 512MB.
+        * Also, doesn't separate memory for core 0 if it's an async call.
+        */
+       if (!(flags & BUSTER_SHARED))
+               buster = (uint32_t*)(BUSTER_ADDR + core_id() * 0x00800000);
+
+       /* Start the timer, if we're asked to print this info*/
+       if (flags & BUSTER_PRINT_TICKS)
+               ticks = start_timing();
+
+       /* Allocate num_pages (up to MAX_PAGES), to simulate doing some more
+        * realistic work.  Note we don't write to these pages, even if we pick
+        * unshared.  Mostly due to the inconvenience of having to match up the
+        * number of pages with the number of writes.  And it's unnecessary.
+        */
+       if (num_pages) {
+               spin_lock(&buster_lock);
+               for (int i = 0; i < MIN(num_pages, MAX_PAGES); i++) {
+                       upage_alloc(p, &a_page[i],1);
+                       page_insert(p->env_pgdir, a_page[i], (void*)INSERT_ADDR + PGSIZE*i,
+                                   PTE_USER_RW);
+               }
+               spin_unlock(&buster_lock);
+       }
+
+       if (flags & BUSTER_LOCKED)
+               spin_lock(&buster_lock);
+       for (int i = 0; i < MIN(num_writes, MAX_WRITES); i=i+stride)
+               buster[i] = 0xdeadbeef;
+       if (flags & BUSTER_LOCKED)
+               spin_unlock(&buster_lock);
+
+       if (num_pages) {
+               spin_lock(&buster_lock);
+               for (int i = 0; i < MIN(num_pages, MAX_PAGES); i++) {
+                       page_remove(p->env_pgdir, (void*)(INSERT_ADDR + PGSIZE * i));
+                       page_decref(a_page[i]);
+               }
+               spin_unlock(&buster_lock);
+       }
+
+       /* Print info */
+       if (flags & BUSTER_PRINT_TICKS) {
+               ticks = stop_timing(ticks);
+               printk("%llu,", ticks);
+       }
+       return 0;
+}
+
+static int sys_cache_invalidate(void)
 {
-       if (len == 0)
-               return 0;
-       #ifdef SERIAL_IO
-               char *COUNT(len) _buf = user_mem_assert(e, buf, len, PTE_USER_RO);
-               for(int i =0; i<len; i++)
-                       serial_send_byte(buf[i]);
-               return (ssize_t)len;
-       #else
-               return -EINVAL;
+       #ifdef __i386__
+               wbinvd();
        #endif
+       return 0;
 }
 
-//Read a buffer over the serial port
-static ssize_t sys_serial_read(env_t* e, char *DANGEROUS _buf, size_t len)
+/* sys_reboot(): called directly from dispatch table. */
+
+// Print a string to the system console.
+// The string is exactly 'len' characters long.
+// Destroys the environment on memory errors.
+static ssize_t sys_cputs(env_t* e, const char *DANGEROUS s, size_t len)
 {
-       if (len == 0)
+       // Check that the user has permission to read memory [s, s+len).
+       // Destroy the environment if not.
+       char *COUNT(len) _s = user_mem_assert(e, s, len, PTE_USER_RO);
+
+       // Print the string supplied by the user.
+       printk("%.*s", len, _s);
+       return (ssize_t)len;
+}
+
+// Read a character from the system console.
+// Returns the character.
+static uint16_t sys_cgetc(env_t* e)
+{
+       uint16_t c;
+
+       // The cons_getc() primitive doesn't wait for a character,
+       // but the sys_cgetc() system call does.
+       while ((c = cons_getc()) == 0)
+               cpu_relax();
+
+       return c;
+}
+
+/* Returns the id of the cpu this syscall is executed on. */
+static uint32_t sys_getcpuid(void)
+{
+       return core_id();
+}
+
+// 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;
 
-       #ifdef SERIAL_IO
-           char *COUNT(len) buf = user_mem_assert(e, _buf, len, PTE_USER_RO);
-               size_t bytes_read = 0;
-               int c;
-               while((c = serial_read_byte()) != -1) {
-                       buf[bytes_read++] = (uint8_t)c;
-                       if(bytes_read == len) break;
-               }
-               return (ssize_t)bytes_read;
-       #else
+       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()!");
+}
+
+/************** Process management syscalls **************/
+
+/* Returns the calling process's pid */
+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
+ */
+static int sys_proc_create(struct proc *p, const char *DANGEROUS path)
+{
+       #define MAX_PATH_LEN 256 // totally arbitrary
+       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);
+       int kfs_inode = kfs_lookup_path(tpath);
+       if (kfs_inode < 0)
                return -EINVAL;
-       #endif
+       struct proc *new_p = kfs_proc_create(kfs_inode);
+       pid = new_p->pid;
+       proc_decref(new_p, 1); // let go of the reference created in proc_create()
+       return pid;
+}
+
+/* Makes process PID runnable.  Consider moving the functionality to process.c */
+static error_t sys_proc_run(struct proc *p, unsigned pid)
+{
+       struct proc *target = pid2proc(pid);
+       error_t retval = 0;
+
+       if (!target)
+               return -EBADPROC;
+       // note we can get interrupted here. it's not bad.
+       spin_lock_irqsave(&p->proc_lock);
+       // make sure we have access and it's in the right state to be activated
+       if (!proc_controls(p, target)) {
+               proc_decref(target, 1);
+               retval = -EPERM;
+       } else if (target->state != PROC_CREATED) {
+               proc_decref(target, 1);
+               retval = -EINVAL;
+       } else {
+               __proc_set_state(target, PROC_RUNNABLE_S);
+               schedule_proc(target);
+       }
+       spin_unlock_irqsave(&p->proc_lock);
+       proc_decref(target, 1);
+       return retval;
+}
+
+/* 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 exitcode)
+{
+       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.
+               p->exitcode = exitcode;
+               proc_decref(p, 1);
+               printd("[PID %d] proc exiting gracefully (code %d)\n", p->pid,exitcode);
+       } else {
+               panic("Destroying other processes is not supported yet.");
+               //printk("[%d] destroying proc %d\n", p->pid, p_to_die->pid);
+       }
+       proc_destroy(p_to_die);
+       return ESUCCESS;
 }
 
-//
-/* START OF REMOTE SYSTEMCALL SUPPORT SYSCALLS. THESE WILL GO AWAY AS THINGS MATURE */
-//
+static int sys_proc_yield(struct proc *p)
+{
+       proc_yield(p);
+       return 0;
+}
+
+static ssize_t sys_run_binary(env_t* e, void *DANGEROUS binary_buf, size_t len,
+                              void*DANGEROUS arg, size_t num_colors)
+{
+       env_t* env = proc_create(NULL,0);
+       assert(env != NULL);
+
+       static_assert(PROCINFO_NUM_PAGES == 1);
+       assert(memcpy_from_user(e,env->env_procinfo->argv_buf,arg,PROCINFO_MAX_ARGV_SIZE) == ESUCCESS);
+       *(intptr_t*)env->env_procinfo->env_buf = 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_decref(env, 1);
+       proc_yield(e);
+       return 0;
+}
 
 static ssize_t sys_fork(env_t* e)
 {
@@ -116,21 +335,53 @@ static ssize_t sys_fork(env_t* e)
                        assert(upage_alloc(env,&pp,0) == 0);
                        assert(page_insert(env->env_pgdir,pp,va,perms) == 0);
 
-                       pte_t* pte = pgdir_walk(e->env_pgdir,va,0);
-                       assert(pte);
-                       pagecopy(page2kva(pp),ppn2kva(PTE2PPN(*pte)));
-               }
+                       pte_t* pte = pgdir_walk(e->env_pgdir,va,0);
+                       assert(pte);
+                       pagecopy(page2kva(pp),ppn2kva(PTE2PPN(*pte)));
+               }
+       }
+
+       __proc_set_state(env, PROC_RUNNABLE_S);
+       schedule_proc(env);
+
+       // don't decref the new process.
+       // that will happen when the parent waits for it.
+
+       printd("[PID %d] fork PID %d\n",e->pid,env->pid);
+
+       return env->pid;
+}
+
+static ssize_t sys_exec(env_t* e, void *DANGEROUS binary_buf, size_t len,
+                        void*DANGEROUS arg, void*DANGEROUS env)
+{
+       // TODO: right now we only support exec for single-core processes
+       if(e->state != PROC_RUNNING_S)
+               return -1;
+
+       if(memcpy_from_user(e,e->env_procinfo->argv_buf,arg,PROCINFO_MAX_ARGV_SIZE))
+               return -1;
+       if(memcpy_from_user(e,e->env_procinfo->env_buf,env,PROCINFO_MAX_ENV_SIZE))
+               return -1;
+
+       void* binary = kmalloc(len,0);
+       if(binary == NULL)
+               return -1;
+       if(memcpy_from_user(e,binary,binary_buf,len))
+       {
+               kfree(binary);
+               return -1;
        }
 
-       __proc_set_state(env, PROC_RUNNABLE_S);
-       schedule_proc(env);
-
-       // don't decref the new process.
-       // that will happen when the parent waits for it.
+       // TODO: this breaks with mmap
+       env_segment_free(e,0,(intptr_t)e->heap_top);
+       env_segment_free(e,(void*)USTACKBOT,USTACKTOP-USTACKBOT);
 
-       printd("[PID %d] fork PID %d\n",e->pid,env->pid);
+       proc_init_trapframe(current_tf,0);
+       env_load_icode(e,NULL,binary,len);
 
-       return env->pid;
+       kfree(binary);
+       return 0;
 }
 
 static ssize_t sys_trywait(env_t* e, pid_t pid, int* status)
@@ -177,138 +428,36 @@ static ssize_t sys_trywait(env_t* e, pid_t pid, int* status)
        return -1;
 }
 
-static ssize_t sys_exec(env_t* e, void *DANGEROUS binary_buf, size_t len,
-                        void*DANGEROUS arg, void*DANGEROUS env)
-{
-       // TODO: right now we only support exec for single-core processes
-       if(e->state != PROC_RUNNING_S)
-               return -1;
-
-       if(memcpy_from_user(e,e->env_procinfo->argv_buf,arg,PROCINFO_MAX_ARGV_SIZE))
-               return -1;
-       if(memcpy_from_user(e,e->env_procinfo->env_buf,env,PROCINFO_MAX_ENV_SIZE))
-               return -1;
-
-       void* binary = kmalloc(len,0);
-       if(binary == NULL)
-               return -1;
-       if(memcpy_from_user(e,binary,binary_buf,len))
-       {
-               kfree(binary);
-               return -1;
-       }
-
-       // TODO: this breaks with mmap
-       env_segment_free(e,0,(intptr_t)e->heap_top);
-       env_segment_free(e,(void*)USTACKBOT,USTACKTOP-USTACKBOT);
-
-       proc_init_trapframe(current_tf,0);
-       env_load_icode(e,NULL,binary,len);
-
-       kfree(binary);
-       return 0;
-}
+/************** Memory Management Syscalls **************/
 
-static ssize_t sys_run_binary(env_t* e, void *DANGEROUS binary_buf, size_t len,
-                              void*DANGEROUS arg, size_t num_colors)
+static void *sys_mmap(struct proc* p, uintreg_t a1, uintreg_t a2, uintreg_t a3,
+                      uintreg_t* a456)
 {
-       env_t* env = proc_create(NULL,0);
-       assert(env != NULL);
-
-       static_assert(PROCINFO_NUM_PAGES == 1);
-       assert(memcpy_from_user(e,env->env_procinfo->argv_buf,arg,PROCINFO_MAX_ARGV_SIZE) == ESUCCESS);
-       *(intptr_t*)env->env_procinfo->env_buf = 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_decref(env, 1);
-       proc_yield(e);
-       return 0;
+       uintreg_t _a456[3];
+       if(memcpy_from_user(p,_a456,a456,3*sizeof(uintreg_t)))
+               sys_proc_destroy(p,p->pid,-1);
+       return mmap(p,a1,a2,a3,_a456[0],_a456[1],_a456[2]);
 }
 
-#ifdef __NETWORK__
-// This is not a syscall we want. Its hacky. Here just for syscall stuff until get a stack.
-static ssize_t sys_eth_write(env_t* e, const char *DANGEROUS buf, size_t len)
-{
-       extern int eth_up;
-
-       if (eth_up) {
-
-               if (len == 0)
-                       return 0;
-
-               char *COUNT(len) _buf = user_mem_assert(e, buf, len, PTE_U);
-               int total_sent = 0;
-               int just_sent = 0;
-               int cur_packet_len = 0;
-               while (total_sent != len) {
-                       cur_packet_len = ((len - total_sent) > MAX_PACKET_DATA) ? MAX_PACKET_DATA : (len - total_sent);
-                       char* wrap_buffer = packet_wrap(_buf + total_sent, cur_packet_len);
-                       just_sent = send_frame(wrap_buffer, cur_packet_len + PACKET_HEADER_SIZE);
-
-                       if (just_sent < 0)
-                               return 0; // This should be an error code of its own
-
-                       if (wrap_buffer)
-                               kfree(wrap_buffer);
-
-                       total_sent += cur_packet_len;
-               }
+static void* sys_brk(struct proc *p, void* addr) {
+       size_t range;
 
-               return (ssize_t)len;
+       if((addr < p->heap_bottom) || (addr >= (void*)USTACKBOT))
+               goto out;
 
+       if (addr > p->heap_top) {
+               range = addr - p->heap_top;
+               env_segment_alloc(p, p->heap_top, range);
        }
-       else
-               return -EINVAL;
-}
-
-// This is not a syscall we want. Its hacky. Here just for syscall stuff until get a stack.
-static ssize_t sys_eth_read(env_t* e, char *DANGEROUS buf, size_t len)
-{
-       extern int eth_up;
-
-       if (eth_up) {
-               extern int packet_waiting;
-               extern int packet_buffer_size;
-               extern char*CT(packet_buffer_size) packet_buffer;
-               extern char*CT(MAX_FRAME_SIZE) packet_buffer_orig;
-               extern int packet_buffer_pos;
-
-               if (len == 0)
-                       return 0;
-
-               char *CT(len) _buf = user_mem_assert(e, buf,len, PTE_U);
-
-               if (packet_waiting == 0)
-                       return 0;
-
-               int read_len = ((packet_buffer_pos + len) > packet_buffer_size) ? packet_buffer_size - packet_buffer_pos : len;
-
-               memcpy(_buf, packet_buffer + packet_buffer_pos, read_len);
-
-               packet_buffer_pos = packet_buffer_pos + read_len;
-
-               if (packet_buffer_pos == packet_buffer_size) {
-                       kfree(packet_buffer_orig);
-                       packet_waiting = 0;
-               }
-
-               return read_len;
+       else if (addr < p->heap_top) {
+               range = p->heap_top - addr;
+               env_segment_free(p, addr, range);
        }
-       else
-               return -EINVAL;
-}
-#endif // Network
+       p->heap_top = addr;
 
-//
-/* END OF REMOTE SYSTEMCALL SUPPORT SYSCALLS. */
-//
+out:
+       return p->heap_top;
+}
 
 static ssize_t sys_shared_page_alloc(env_t* p1,
                                      void**DANGEROUS _addr, pid_t p2_id,
@@ -340,277 +489,144 @@ static ssize_t sys_shared_page_alloc(env_t* p1,
        }
 
        void* p1_addr = page_insert_in_range(p1->env_pgdir, page,
-                       (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;
-       proc_decref(p2, 1);
-       return ESUCCESS;
-}
-
-static void sys_shared_page_free(env_t* p1, void*DANGEROUS addr, pid_t p2)
-{
-}
-
-// Invalidate the cache of this core.  Only useful if you want a cold cache for
-// performance testing reasons.
-static void sys_cache_invalidate(void)
-{
-       #ifdef __i386__
-               wbinvd();
-       #endif
-       return;
-}
-
-// Writes 'val' to 'num_writes' entries of the well-known array in the kernel
-// address space.  It's just #defined to be some random 4MB chunk (which ought
-// to be boot_alloced or something).  Meant to grab exclusive access to cache
-// lines, to simulate doing something useful.
-static void sys_cache_buster(struct proc *p, uint32_t num_writes,
-                             uint32_t num_pages, uint32_t flags)
-{ TRUSTEDBLOCK /* zra: this is not really part of the kernel */
-       #define BUSTER_ADDR             0xd0000000  // around 512 MB deep
-       #define MAX_WRITES              1048576*8
-       #define MAX_PAGES               32
-       #define INSERT_ADDR     (UINFO + 2*PGSIZE) // should be free for these tests
-       uint32_t* buster = (uint32_t*)BUSTER_ADDR;
-       static spinlock_t buster_lock = SPINLOCK_INITIALIZER;
-       uint64_t ticks = -1;
-       page_t* a_page[MAX_PAGES];
-
-       /* Strided Accesses or Not (adjust to step by cachelines) */
-       uint32_t stride = 1;
-       if (flags & BUSTER_STRIDED) {
-               stride = 16;
-               num_writes *= 16;
-       }
-
-       /* Shared Accesses or Not (adjust to use per-core regions)
-        * Careful, since this gives 8MB to each core, starting around 512MB.
-        * Also, doesn't separate memory for core 0 if it's an async call.
-        */
-       if (!(flags & BUSTER_SHARED))
-               buster = (uint32_t*)(BUSTER_ADDR + core_id() * 0x00800000);
-
-       /* Start the timer, if we're asked to print this info*/
-       if (flags & BUSTER_PRINT_TICKS)
-               ticks = start_timing();
-
-       /* Allocate num_pages (up to MAX_PAGES), to simulate doing some more
-        * realistic work.  Note we don't write to these pages, even if we pick
-        * unshared.  Mostly due to the inconvenience of having to match up the
-        * number of pages with the number of writes.  And it's unnecessary.
-        */
-       if (num_pages) {
-               spin_lock(&buster_lock);
-               for (int i = 0; i < MIN(num_pages, MAX_PAGES); i++) {
-                       upage_alloc(p, &a_page[i],1);
-                       page_insert(p->env_pgdir, a_page[i], (void*)INSERT_ADDR + PGSIZE*i,
-                                   PTE_USER_RW);
-               }
-               spin_unlock(&buster_lock);
-       }
-
-       if (flags & BUSTER_LOCKED)
-               spin_lock(&buster_lock);
-       for (int i = 0; i < MIN(num_writes, MAX_WRITES); i=i+stride)
-               buster[i] = 0xdeadbeef;
-       if (flags & BUSTER_LOCKED)
-               spin_unlock(&buster_lock);
-
-       if (num_pages) {
-               spin_lock(&buster_lock);
-               for (int i = 0; i < MIN(num_pages, MAX_PAGES); i++) {
-                       page_remove(p->env_pgdir, (void*)(INSERT_ADDR + PGSIZE * i));
-                       page_decref(a_page[i]);
-               }
-               spin_unlock(&buster_lock);
-       }
-
-       /* Print info */
-       if (flags & BUSTER_PRINT_TICKS) {
-               ticks = stop_timing(ticks);
-               printk("%llu,", ticks);
+                       (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;
        }
-       return;
+       *addr = p1_addr;
+       proc_decref(p2, 1);
+       return ESUCCESS;
 }
 
-// Print a string to the system console.
-// The string is exactly 'len' characters long.
-// Destroys the environment on memory errors.
-static ssize_t sys_cputs(env_t* e, const char *DANGEROUS s, size_t len)
+static int sys_shared_page_free(env_t* p1, void*DANGEROUS addr, pid_t p2)
 {
-       // Check that the user has permission to read memory [s, s+len).
-       // Destroy the environment if not.
-       char *COUNT(len) _s = user_mem_assert(e, s, len, PTE_USER_RO);
-
-       // Print the string supplied by the user.
-       printk("%.*s", len, _s);
-       return (ssize_t)len;
+       return -1;
 }
 
-// Read a character from the system console.
-// Returns the character.
-static uint16_t sys_cgetc(env_t* e)
-{
-       uint16_t c;
 
-       // The cons_getc() primitive doesn't wait for a character,
-       // but the sys_cgetc() system call does.
-       while ((c = cons_getc()) == 0)
-               cpu_relax();
+/************** Resource Request Syscalls **************/
 
-       return c;
-}
+/* sys_resource_req(): called directly from dispatch table. */
 
-/* Returns the calling process's pid */
-static pid_t sys_getpid(struct proc *p)
+/************** Platform Specific Syscalls **************/
+
+//Read a buffer over the serial port
+static ssize_t sys_serial_read(env_t* e, char *DANGEROUS _buf, size_t len)
 {
-       return p->pid;
+       if (len == 0)
+               return 0;
+
+       #ifdef SERIAL_IO
+           char *COUNT(len) buf = user_mem_assert(e, _buf, len, PTE_USER_RO);
+               size_t bytes_read = 0;
+               int c;
+               while((c = serial_read_byte()) != -1) {
+                       buf[bytes_read++] = (uint8_t)c;
+                       if(bytes_read == len) break;
+               }
+               return (ssize_t)bytes_read;
+       #else
+               return -EINVAL;
+       #endif
 }
 
-/* Returns the id of the cpu this syscall is executed on. */
-static uint32_t sys_getcpuid(void)
+//Write a buffer over the serial port
+static ssize_t sys_serial_write(env_t* e, const char *DANGEROUS buf, size_t len)
 {
-       return core_id();
+       if (len == 0)
+               return 0;
+       #ifdef SERIAL_IO
+               char *COUNT(len) _buf = user_mem_assert(e, buf, len, PTE_USER_RO);
+               for(int i =0; i<len; i++)
+                       serial_send_byte(buf[i]);
+               return (ssize_t)len;
+       #else
+               return -EINVAL;
+       #endif
 }
 
-// TODO: Temporary hack until thread-local storage is implemented on i386
-static size_t sys_getvcoreid(env_t* e)
+#ifdef __NETWORK__
+// This is not a syscall we want. Its hacky. Here just for syscall stuff until get a stack.
+static ssize_t sys_eth_read(env_t* e, char *DANGEROUS buf, size_t len)
 {
-       if(e->state == PROC_RUNNING_S)
-               return 0;
+       extern int eth_up;
 
-       size_t i;
-       for(i = 0; i < e->num_vcores; i++)
-               if(core_id() == e->vcoremap[i])
-                       return i;
+       if (eth_up) {
+               extern int packet_waiting;
+               extern int packet_buffer_size;
+               extern char*CT(packet_buffer_size) packet_buffer;
+               extern char*CT(MAX_FRAME_SIZE) packet_buffer_orig;
+               extern int packet_buffer_pos;
 
-       panic("virtual core id not found in sys_getvcoreid()!");
-}
+               if (len == 0)
+                       return 0;
 
-/* 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 exitcode)
-{
-       error_t r;
-       struct proc *p_to_die = pid2proc(pid);
+               char *CT(len) _buf = user_mem_assert(e, buf,len, PTE_U);
 
-       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.
-               p->exitcode = exitcode;
-               proc_decref(p, 1);
-               printd("[PID %d] proc exiting gracefully (code %d)\n", p->pid,exitcode);
-       } else {
-               panic("Destroying other processes is not supported yet.");
-               //printk("[%d] destroying proc %d\n", p->pid, p_to_die->pid);
-       }
-       proc_destroy(p_to_die);
-       return ESUCCESS;
-}
+               if (packet_waiting == 0)
+                       return 0;
 
-/*
- * 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
- */
-static int sys_proc_create(struct proc *p, const char *DANGEROUS path)
-{
-       #define MAX_PATH_LEN 256 // totally arbitrary
-       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);
-       int kfs_inode = kfs_lookup_path(tpath);
-       if (kfs_inode < 0)
+               int read_len = ((packet_buffer_pos + len) > packet_buffer_size) ? packet_buffer_size - packet_buffer_pos : len;
+
+               memcpy(_buf, packet_buffer + packet_buffer_pos, read_len);
+
+               packet_buffer_pos = packet_buffer_pos + read_len;
+
+               if (packet_buffer_pos == packet_buffer_size) {
+                       kfree(packet_buffer_orig);
+                       packet_waiting = 0;
+               }
+
+               return read_len;
+       }
+       else
                return -EINVAL;
-       struct proc *new_p = kfs_proc_create(kfs_inode);
-       pid = new_p->pid;
-       proc_decref(new_p, 1); // let go of the reference created in proc_create()
-       return pid;
 }
 
-/* Makes process PID runnable.  Consider moving the functionality to process.c */
-static error_t sys_proc_run(struct proc *p, unsigned pid)
+// This is not a syscall we want. Its hacky. Here just for syscall stuff until get a stack.
+static ssize_t sys_eth_write(env_t* e, const char *DANGEROUS buf, size_t len)
 {
-       struct proc *target = pid2proc(pid);
-       error_t retval = 0;
+       extern int eth_up;
 
-       if (!target)
-               return -EBADPROC;
-       // note we can get interrupted here. it's not bad.
-       spin_lock_irqsave(&p->proc_lock);
-       // make sure we have access and it's in the right state to be activated
-       if (!proc_controls(p, target)) {
-               proc_decref(target, 1);
-               retval = -EPERM;
-       } else if (target->state != PROC_CREATED) {
-               proc_decref(target, 1);
-               retval = -EINVAL;
-       } else {
-               __proc_set_state(target, PROC_RUNNABLE_S);
-               schedule_proc(target);
-       }
-       spin_unlock_irqsave(&p->proc_lock);
-       proc_decref(target, 1);
-       return retval;
-}
+       if (eth_up) {
 
-static void* sys_brk(struct proc *p, void* addr) {
-       size_t range;
+               if (len == 0)
+                       return 0;
 
-       if((addr < p->heap_bottom) || (addr >= (void*)USTACKBOT))
-               goto out;
+               char *COUNT(len) _buf = user_mem_assert(e, buf, len, PTE_U);
+               int total_sent = 0;
+               int just_sent = 0;
+               int cur_packet_len = 0;
+               while (total_sent != len) {
+                       cur_packet_len = ((len - total_sent) > MAX_PACKET_DATA) ? MAX_PACKET_DATA : (len - total_sent);
+                       char* wrap_buffer = packet_wrap(_buf + total_sent, cur_packet_len);
+                       just_sent = send_frame(wrap_buffer, cur_packet_len + PACKET_HEADER_SIZE);
 
-       if (addr > p->heap_top) {
-               range = addr - p->heap_top;
-               env_segment_alloc(p, p->heap_top, range);
-       }
-       else if (addr < p->heap_top) {
-               range = p->heap_top - addr;
-               env_segment_free(p, addr, range);
-       }
-       p->heap_top = addr;
+                       if (just_sent < 0)
+                               return 0; // This should be an error code of its own
 
-out:
-       return p->heap_top;
-}
+                       if (wrap_buffer)
+                               kfree(wrap_buffer);
 
-void* sys_mmap(struct proc* p, uintreg_t a1, uintreg_t a2, uintreg_t a3,
-               uintreg_t* a456)
-{
-       uintreg_t _a456[3];
-       if(memcpy_from_user(p,_a456,a456,3*sizeof(uintreg_t)))
-               sys_proc_destroy(p,p->pid,-1);
-       return mmap(p,a1,a2,a3,_a456[0],_a456[1],_a456[2]);
+                       total_sent += cur_packet_len;
+               }
+
+               return (ssize_t)len;
+
+       }
+       else
+               return -EINVAL;
 }
 
+#endif // Network
+
+/* sys_frontend_syscall_from_user(): called directly from dispatch table. */
+
+/************** Syscall Invokation **************/
+
 /* Executes the given syscall.
  *
  * Note tf is passed in, which points to the tf of the context on the kernel
@@ -630,32 +646,33 @@ intreg_t syscall(struct proc *p, uintreg_t syscallno, uintreg_t a1,
                [SYS_null] = (syscall_t)sys_null,
                [SYS_cache_buster] = (syscall_t)sys_cache_buster,
                [SYS_cache_invalidate] = (syscall_t)sys_cache_invalidate,
-               [SYS_shared_page_alloc] = (syscall_t)sys_shared_page_alloc,
-               [SYS_shared_page_free] = (syscall_t)sys_shared_page_free,
+               [SYS_reboot] = (syscall_t)reboot,
                [SYS_cputs] = (syscall_t)sys_cputs,
                [SYS_cgetc] = (syscall_t)sys_cgetc,
                [SYS_getcpuid] = (syscall_t)sys_getcpuid,
                [SYS_getvcoreid] = (syscall_t)sys_getvcoreid,
-               [SYS_proc_destroy] = (syscall_t)sys_proc_destroy,
-               [SYS_yield] = (syscall_t)proc_yield,
+               [SYS_getpid] = (syscall_t)sys_getpid,
                [SYS_proc_create] = (syscall_t)sys_proc_create,
                [SYS_proc_run] = (syscall_t)sys_proc_run,
+               [SYS_proc_destroy] = (syscall_t)sys_proc_destroy,
+               [SYS_yield] = (syscall_t)sys_proc_yield,
+               [SYS_run_binary] = (syscall_t)sys_run_binary,
+               [SYS_fork] = (syscall_t)sys_fork,
+               [SYS_exec] = (syscall_t)sys_exec,
+               [SYS_trywait] = (syscall_t)sys_trywait,
                [SYS_mmap] = (syscall_t)sys_mmap,
                [SYS_brk] = (syscall_t)sys_brk,
+               [SYS_shared_page_alloc] = (syscall_t)sys_shared_page_alloc,
+               [SYS_shared_page_free] = (syscall_t)sys_shared_page_free,
                [SYS_resource_req] = (syscall_t)resource_req,
        #ifdef __i386__
                [SYS_serial_read] = (syscall_t)sys_serial_read,
                [SYS_serial_write] = (syscall_t)sys_serial_write,
        #endif
-               [SYS_run_binary] = (syscall_t)sys_run_binary,
        #ifdef __NETWORK__
                [SYS_eth_read] = (syscall_t)sys_eth_read,
                [SYS_eth_write] = (syscall_t)sys_eth_write,
        #endif
-               [SYS_reboot] = (syscall_t)reboot,
-               [SYS_fork] = (syscall_t)sys_fork,
-               [SYS_trywait] = (syscall_t)sys_trywait,
-               [SYS_exec] = (syscall_t)sys_exec,
        #ifdef __sparc_v8__
                [SYS_frontend] = (syscall_t)frontend_syscall_from_user,
                [SYS_read] = (syscall_t)sys_read,
@@ -667,6 +684,10 @@ intreg_t syscall(struct proc *p, uintreg_t syscallno, uintreg_t a1,
 
        const int max_syscall = sizeof(syscall_table)/sizeof(syscall_table[0]);
 
+       //printk("Incoming syscall on core: %d number: %d\n    a1: %x\n   "
+       //       " a2: %x\n    a3: %x\n    a4: %x\n    a5: %x\n", core_id(),
+       //       syscallno, a1, a2, a3, a4, a5);
+
        if(syscallno > max_syscall || syscall_table[syscallno] == NULL)
                panic("Invalid syscall number %d for proc %x!", syscallno, *p);