Added support for building simple user programs
authorKevin Klues <klueska@ros-dev.(none)>
Fri, 26 Mar 2010 08:06:16 +0000 (01:06 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:38 +0000 (17:35 -0700)
This includes the addition of some files in the
tests directory that test libraries built in user/parlib

18 files changed:
GNUmakefile
lib/glibc [deleted symlink]
lib/parlib/hart.c [deleted file]
lib/parlib/hart.h [deleted file]
lib/parlib/parlib.h [deleted file]
lib/parlib/syscall.c [deleted file]
tests/Makefrag [new file with mode: 0644]
tests/hart_test.c [new file with mode: 0644]
tests/pthread_test.c [new file with mode: 0644]
user/Makefrag [new file with mode: 0644]
user/glibc [new symlink]
user/include/hart.h [new file with mode: 0644]
user/include/parlib.h [new file with mode: 0644]
user/include/pthread.h [new file with mode: 0644]
user/parlib/Makefrag [new file with mode: 0644]
user/parlib/hart.c [new file with mode: 0644]
user/parlib/pthread.c [new file with mode: 0644]
user/parlib/syscall.c [new file with mode: 0644]

index bd46a42..86027bb 100644 (file)
@@ -134,8 +134,14 @@ symlinks: error
 # Include Makefrags for subdirectories
 ifneq ($(TARGET_ARCH),)
 include kern/Makefrag
+include user/Makefrag
+include tests/Makefrag
 endif
 
+tests: $(TESTS_EXECS)
+       @mkdir -p fs/$(TARGET_ARCH)/tests
+       cp -R $(OBJDIR)/$(TESTS_DIR)/* fs/$(TARGET_ARCH)/tests
+
 # Eliminate default suffix rules
 .SUFFIXES:
 
diff --git a/lib/glibc b/lib/glibc
deleted file mode 120000 (symlink)
index abdd6b1..0000000
--- a/lib/glibc
+++ /dev/null
@@ -1 +0,0 @@
-../tools/compilers/gcc-glibc/glibc-2.11.1-ros/sysdeps/ros
\ No newline at end of file
diff --git a/lib/parlib/hart.c b/lib/parlib/hart.c
deleted file mode 100644 (file)
index 54bfe3f..0000000
+++ /dev/null
@@ -1,245 +0,0 @@
-#include <stdbool.h>
-#include <errno.h>
-#include <hart.h>
-#include <parlib.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-static size_t _current_harts = 1;
-static hart_lock_t _hart_lock = HART_LOCK_INIT;
-
-extern void** hart_thread_control_blocks;
-
-static void hart_free_tls(int id)
-{
-       extern void _dl_deallocate_tls (void *tcb, bool dealloc_tcb);
-       if(hart_thread_control_blocks[id])
-       {
-               _dl_deallocate_tls(hart_thread_control_blocks[id],true);
-               hart_thread_control_blocks[id] = 0;
-       }
-}
-
-static int hart_allocate_tls(int id)
-{
-       extern void *_dl_allocate_tls (void *mem);
-       // instead of freeing any old tls that may be present, and then
-       // reallocating it, we could instead just reinitialize it.
-       hart_free_tls(id);
-       if((hart_thread_control_blocks[id] = _dl_allocate_tls(NULL)) == NULL)
-       {
-               errno = ENOMEM;
-               return -1;
-       }
-       return 0;
-}
-
-#define HART_STACK_SIZE (32*1024)
-
-static void hart_free_stack(int id)
-{
-       // don't actually free stacks
-}
-
-static int hart_allocate_stack(int id)
-{
-       if(__procdata.stack_pointers[id])
-               return 0; // reuse old stack
-
-       if(!(__procdata.stack_pointers[id] = (uintptr_t)malloc(HART_STACK_SIZE)))
-       {
-               errno = ENOMEM;
-               return -1;
-       }
-       return 0;
-}
-
-static int hart_init()
-{
-       static int initialized = 0;
-       if(initialized)
-               return 0;
-
-       hart_thread_control_blocks = (void**)calloc(hart_max_harts(),sizeof(void*));
-
-       if(!hart_thread_control_blocks)
-       {
-               free(hart_thread_control_blocks);
-               errno = ENOMEM;
-               return -1;
-       }
-
-       initialized = 1;
-       return 0;
-}
-
-int hart_request(size_t k)
-{
-       int ret = -1;
-       size_t i,j;
-
-       if(hart_init() < 0)
-               return -1;
-
-       hart_lock_lock(&_hart_lock);
-
-       if(k < 0 || _current_harts+k > hart_max_harts())
-       {
-               errno = EAGAIN;
-               goto out;
-       }
-
-       for(i = _current_harts, j = 0; i < _current_harts+k; i++, j++)
-       {
-               if(hart_allocate_stack(i) || hart_allocate_tls(i))
-                       goto fail;
-       }
-
-       if((ret = sys_resource_req(0,_current_harts+k,0)) == 0)
-       {
-               _current_harts += k;
-               goto out;
-       }
-
-fail:
-       for(i = _current_harts; i < _current_harts+k; i++)
-       {
-               hart_free_tls(i);
-               hart_free_stack(i);
-       }
-
-out:
-       hart_lock_unlock(&_hart_lock);
-       return ret;
-}
-
-void hart_yield()
-{
-       int id = hart_self();
-
-       hart_lock_lock(&_hart_lock);
-       _current_harts--;
-       if(_current_harts == 0)
-               exit(0);
-       hart_lock_unlock(&_hart_lock);
-
-       sys_yield();
-}
-
-size_t hart_max_harts()
-{
-       return __procinfo.max_harts < HART_MAX_MAX_HARTS ? __procinfo.max_harts : HART_MAX_MAX_HARTS;
-}
-
-size_t hart_current_harts()
-{
-       return _current_harts;
-}
-
-// MCS locks!!
-void hart_lock_init(hart_lock_t* lock)
-{
-       memset(lock,0,sizeof(hart_lock_t));
-}
-
-static inline hart_lock_qnode_t* hart_qnode_swap(hart_lock_qnode_t** addr, hart_lock_qnode_t* val)
-{
-       return (hart_lock_qnode_t*)hart_swap((int*)addr,(int)val);
-}
-
-void hart_lock_lock(hart_lock_t* lock)
-{
-       hart_lock_qnode_t* qnode = &lock->qnode[hart_self()];
-       qnode->next = 0;
-       hart_lock_qnode_t* predecessor = hart_qnode_swap(&lock->lock,qnode);
-       if(predecessor)
-       {
-               qnode->locked = 1;
-               predecessor->next = qnode;
-               while(qnode->locked);
-       }
-}
-
-void hart_lock_unlock(hart_lock_t* lock)
-{
-       hart_lock_qnode_t* qnode = &lock->qnode[hart_self()];
-       if(qnode->next == 0)
-       {
-               hart_lock_qnode_t* old_tail = hart_qnode_swap(&lock->lock,0);
-               if(old_tail == qnode)
-                       return;
-
-               hart_lock_qnode_t* usurper = hart_qnode_swap(&lock->lock,old_tail);
-               while(qnode->next == 0);
-               if(usurper)
-                       usurper->next = qnode->next;
-               else
-                       qnode->next->locked = 0;
-       }
-       else
-               qnode->next->locked = 0;
-}
-
-// MCS dissemination barrier!
-int hart_barrier_init(hart_barrier_t* b, size_t np)
-{
-       if(np > hart_max_harts())
-               return -1;
-       b->allnodes = (hart_dissem_flags_t*)malloc(np*sizeof(hart_dissem_flags_t));
-       memset(b->allnodes,0,np*sizeof(hart_dissem_flags_t));
-       b->nprocs = np;
-
-       b->logp = (np & (np-1)) != 0;
-       while(np >>= 1)
-               b->logp++;
-
-       size_t i,k;
-       for(i = 0; i < b->nprocs; i++)
-       {
-               b->allnodes[i].parity = 0;
-               b->allnodes[i].sense = 1;
-
-               for(k = 0; k < b->logp; k++)
-               {
-                       size_t j = (i+(1<<k)) % b->nprocs;
-                       b->allnodes[i].partnerflags[0][k] = &b->allnodes[j].myflags[0][k];
-                       b->allnodes[i].partnerflags[1][k] = &b->allnodes[j].myflags[1][k];
-               } 
-       }
-
-       return 0;
-}
-
-void hart_barrier_wait(hart_barrier_t* b, size_t pid)
-{
-       hart_dissem_flags_t* localflags = &b->allnodes[pid];
-       size_t i;
-       for(i = 0; i < b->logp; i++)
-       {
-               *localflags->partnerflags[localflags->parity][i] = localflags->sense;
-               while(localflags->myflags[localflags->parity][i] != localflags->sense);
-       }
-       if(localflags->parity)
-               localflags->sense = 1-localflags->sense;
-       localflags->parity = 1-localflags->parity;
-}
-
-int
-hart_self()
-{
-       // defined in ros/arch/hart.h
-       return __hart_self();
-}
-
-int
-hart_swap(int* addr, int val)
-{
-       return __hart_swap(addr,val);
-}
-
-void
-hart_relax()
-{
-       __hart_relax();
-}
-
diff --git a/lib/parlib/hart.h b/lib/parlib/hart.h
deleted file mode 100644 (file)
index af2a6d2..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-#ifndef _HART_H
-#define _HART_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <ros/arch/hart.h>
-#include <string.h>
-
-#define HART_LOG2_MAX_MAX_HARTS 6
-#define HART_MAX_MAX_HARTS (1 << HART_LOG2_MAX_MAX_HARTS)
-
-typedef struct hart_lock_qnode
-{
-       volatile struct hart_lock_qnode* volatile next;
-       volatile int locked;
-       char pad[HART_CL_SIZE-sizeof(void*)-sizeof(int)];
-} hart_lock_qnode_t;
-
-typedef struct
-{
-       hart_lock_qnode_t* lock;
-       char pad[HART_CL_SIZE-sizeof(hart_lock_qnode_t*)];
-       hart_lock_qnode_t qnode[HART_MAX_MAX_HARTS] __attribute__((aligned(8)));
-} hart_lock_t;
-
-#define HART_LOCK_INIT {0}
-
-typedef struct
-{
-       volatile int myflags[2][HART_LOG2_MAX_MAX_HARTS];
-       volatile int* partnerflags[2][HART_LOG2_MAX_MAX_HARTS];
-       int parity;
-       int sense;
-       char pad[HART_CL_SIZE];
-} hart_dissem_flags_t;
-
-typedef struct
-{
-       size_t nprocs;
-       hart_dissem_flags_t* allnodes;
-       size_t logp;
-} hart_barrier_t;
-
-extern void hart_entry();
-
-int hart_barrier_init(hart_barrier_t* b, size_t nprocs);
-void hart_barrier_wait(hart_barrier_t* b, size_t vcoreid);
-
-void hart_lock_init(hart_lock_t* lock);
-void hart_lock_unlock(hart_lock_t* lock);
-void hart_lock_lock(hart_lock_t* l);
-
-// "int" rather than size_t because of a newlib compiling issue
-int hart_self();
-void hart_relax();
-int hart_swap(int* addr, int val);
-
-int hart_request(size_t k);
-void hart_yield();
-size_t hart_max_harts();
-size_t hart_current_harts();
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/lib/parlib/parlib.h b/lib/parlib/parlib.h
deleted file mode 100644 (file)
index c05a5c3..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-// Main public header file for our user-land support library,
-// whose code lives in the lib directory.
-// This library is roughly our OS's version of a standard C library,
-// and is intended to be linked into all user-mode applications
-// (NOT the kernel or boot loader).
-
-#ifndef ROS_INC_PARLIB_H
-#define ROS_INC_PARLIB_H 1
-
-#ifndef __ASSEMBLER__
-
-#include <ros/common.h>
-#include <ros/memlayout.h>
-#include <ros/syscall.h>
-#include <ros/procinfo.h>
-#include <ros/procdata.h>
-#include <stdint.h>
-
-enum {
-       PG_RDONLY = 4,
-       PG_RDWR   = 6,
-};
-
-ssize_t     sys_cputs(const uint8_t *s, size_t len);
-uint16_t    sys_cgetc(void);
-ssize_t     sys_serial_write(void* buf, size_t len); 
-ssize_t     sys_serial_read(void* buf, size_t len);
-ssize_t     sys_eth_write(void *COUNT(len) buf, size_t len); 
-ssize_t     sys_eth_read(void *COUNT(len) buf, size_t len);
-ssize_t     sys_run_binary(void* binary_buf, size_t len,
-                           const procinfo_t* pi, size_t num_colors);
-int         sys_getpid(void);
-size_t      sys_getcpuid(void);
-void *      sys_brk(void* addr);
-int     sys_proc_destroy(int pid, int exitcode);
-ssize_t     sys_shared_page_alloc(void *COUNT(PGSIZE) *addr, pid_t p2, 
-                                  int p1_flags, int p2_flags);
-ssize_t     sys_shared_page_free(void *COUNT(PGSIZE) addr, pid_t p2);
-ssize_t     sys_resource_req(int type, size_t amount, uint32_t flags);
-void        sys_reboot();
-void        sys_yield();
-int         gettimeofday(struct timeval* tp, void* tzp);
-void *COUNT(length) sys_mmap(void *SNT addr, size_t length, int prot, int flags,
-                             int fd, size_t offset);
-
-#endif // !ASSEMBLER
-
-#endif // !ROS_INC_PARLIB_H
diff --git a/lib/parlib/syscall.c b/lib/parlib/syscall.c
deleted file mode 100644 (file)
index e396f21..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-// System call stubs.
-
-#include <parlib.h>
-
-int sys_proc_destroy(int pid, int exitcode)
-{
-       return ros_syscall(SYS_proc_destroy, pid, exitcode, 0, 0, 0);
-}
-
-void* sys_brk(void* addr)
-{
-       return (void*)ros_syscall(SYS_brk, addr, 0, 0, 0, 0);
-}
-
-int sys_getpid(void)
-{
-        return ros_syscall(SYS_getpid, 0, 0, 0, 0, 0);
-}
-
-size_t sys_getcpuid(void)
-{
-        return ros_syscall(SYS_getcpuid, 0, 0, 0, 0, 0);
-}
-
-ssize_t sys_cputs(const uint8_t *s, size_t len)
-{
-    return ros_syscall(SYS_cputs, s,  len, 0, 0, 0);
-}
-
-uint16_t sys_cgetc(void)
-{
-    return ros_syscall(SYS_cgetc, 0, 0, 0, 0, 0);
-}
-
-ssize_t sys_shared_page_alloc(void** addr, pid_t p2, 
-                              int p1_flags, int p2_flags
-                             ) 
-{
-       return ros_syscall(SYS_shared_page_alloc, addr, 
-                      p2, p1_flags, p2_flags, 0);
-}
-
-ssize_t sys_shared_page_free(void* addr, pid_t p2) 
-{
-       return ros_syscall(SYS_shared_page_free, addr, p2, 0,0,0);
-}
-
-//Write a buffer over the serial port
-ssize_t sys_serial_write(void* buf, size_t len) 
-{
-       return ros_syscall(SYS_serial_write, buf, len, 0, 0, 0);
-}
-
-//Read a buffer over the serial port
-ssize_t sys_serial_read(void* buf, size_t len) 
-{
-       return ros_syscall(SYS_serial_read, buf, len, 0, 0, 0);
-}
-
-//Run a binary loaded at the specificed address with the specified arguments
-ssize_t sys_run_binary(void* binary_buf, size_t len,
-                       const procinfo_t* pi, size_t num_colors) 
-{
-       return ros_syscall(SYS_run_binary, binary_buf, len,
-                                       pi,num_colors,0);
-}
-
-//Write a buffer over ethernet
-ssize_t sys_eth_write(void* buf, size_t len) 
-{
-       if (len == 0)
-               return 0;
-       
-       return ros_syscall(SYS_eth_write, buf, len, 0, 0, 0);
-}
-
-//Read a buffer via ethernet
-ssize_t sys_eth_read(void* buf, size_t len) 
-{
-       if (len == 0)
-               return 0;
-               
-       return ros_syscall(SYS_eth_read, buf, len, 0, 0, 0);
-}
-
-/* Request resources from the kernel.  Flags in ros/resource.h. */
-ssize_t sys_resource_req(int type, size_t amount, uint32_t flags)
-{
-       return ros_syscall(SYS_resource_req, type, amount, flags, 0, 0);
-}
-
-void sys_reboot()
-{
-       ros_syscall(SYS_reboot,0,0,0,0,0);
-}
-
-void sys_yield()
-{
-       ros_syscall(SYS_yield,0,0,0,0,0);
-}
-
-/* We need to do some hackery to pass 6 arguments.  Arg4 pts to the real arg4,
- * arg5, and arg6.  Keep this in sync with kern/src/syscall.c.
- * TODO: consider a syscall_multi that can take more args, and keep it in sync
- * with the kernel.  Maybe wait til we fix sysenter to have 5 or 6 args. */
-void *CT(length) sys_mmap(void *SNT addr, size_t length, int prot, int flags,
-                          int fd, size_t offset)
-{
-       struct args {
-               int _flags;
-               int _fd;
-               size_t _offset;
-       } extra_args;
-       extra_args._flags = flags;
-       extra_args._fd = fd;
-       extra_args._offset = offset;
-       // TODO: deputy bitches about this
-       return (void*CT(length))TC(ros_syscall(SYS_mmap, addr, length,
-                                              prot, &extra_args, 0));
-}
-
diff --git a/tests/Makefrag b/tests/Makefrag
new file mode 100644 (file)
index 0000000..ff5ef4d
--- /dev/null
@@ -0,0 +1,32 @@
+TESTS_DIR = $(TOP_DIR)/tests
+TESTS_CFLAGS += $(USER_FLAGS)
+OBJDIRS += $(TESTS_DIR)
+
+TESTS_CFLAGS := $(USER_CFLAGS)  \
+                -I$(USER_DIR)/include
+
+TESTS_LDFLAGS := -static
+
+TESTS_LDDIRS := -L$(OBJDIR)/$(USER_PARLIB_DIR)
+
+TESTS_LDLIBS := -lparlib 
+
+TESTS_SRCS := \
+              $(TESTS_DIR)/hart_test.c \
+              $(TESTS_DIR)/pthread_test.c
+
+TESTS_EXECS  := $(patsubst $(TESTS_DIR)/%.c, \
+                           $(OBJDIR)/$(TESTS_DIR)/%, \
+                           $(TESTS_SRCS))
+
+TESTS_LDDEPENDS := $(TESTS_DIR)/%.c \
+                   $(OBJDIR)/$(USER_PARLIB_DIR)/libparlib.a
+
+$(OBJDIR)/$(TESTS_DIR)/%: $(TESTS_LDDEPENDS)
+       @echo + cc [TESTS] $<
+       @mkdir -p $(@D)
+       $(V)$(CC) $(TESTS_CFLAGS) -o $@ $(TESTS_LDFLAGS) \
+                 $(TESTS_LDDIRS) $(TESTS_LDLIBS) $<
+       $(V)$(OBJDUMP) -S $@ > $@.asm
+       $(V)$(NM) -n $@ > $@.sym
+
diff --git a/tests/hart_test.c b/tests/hart_test.c
new file mode 100644 (file)
index 0000000..51fb0d4
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int main(int argc, char** argv) 
+{
+       printf("Goodbye cruel world!!\n");
+} 
diff --git a/tests/pthread_test.c b/tests/pthread_test.c
new file mode 100644 (file)
index 0000000..12055f3
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int main(int argc, char** argv) 
+{
+       printf("Goodby cruel world!!\n");
+} 
diff --git a/user/Makefrag b/user/Makefrag
new file mode 100644 (file)
index 0000000..466118a
--- /dev/null
@@ -0,0 +1,5 @@
+USER_DIR := $(TOP_DIR)/user
+USER_CFLAGS += -std=gnu99 -I$(USER_DIR)/include
+
+include $(USER_DIR)/parlib/Makefrag
+
diff --git a/user/glibc b/user/glibc
new file mode 120000 (symlink)
index 0000000..abdd6b1
--- /dev/null
@@ -0,0 +1 @@
+../tools/compilers/gcc-glibc/glibc-2.11.1-ros/sysdeps/ros
\ No newline at end of file
diff --git a/user/include/hart.h b/user/include/hart.h
new file mode 100644 (file)
index 0000000..af2a6d2
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef _HART_H
+#define _HART_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <ros/arch/hart.h>
+#include <string.h>
+
+#define HART_LOG2_MAX_MAX_HARTS 6
+#define HART_MAX_MAX_HARTS (1 << HART_LOG2_MAX_MAX_HARTS)
+
+typedef struct hart_lock_qnode
+{
+       volatile struct hart_lock_qnode* volatile next;
+       volatile int locked;
+       char pad[HART_CL_SIZE-sizeof(void*)-sizeof(int)];
+} hart_lock_qnode_t;
+
+typedef struct
+{
+       hart_lock_qnode_t* lock;
+       char pad[HART_CL_SIZE-sizeof(hart_lock_qnode_t*)];
+       hart_lock_qnode_t qnode[HART_MAX_MAX_HARTS] __attribute__((aligned(8)));
+} hart_lock_t;
+
+#define HART_LOCK_INIT {0}
+
+typedef struct
+{
+       volatile int myflags[2][HART_LOG2_MAX_MAX_HARTS];
+       volatile int* partnerflags[2][HART_LOG2_MAX_MAX_HARTS];
+       int parity;
+       int sense;
+       char pad[HART_CL_SIZE];
+} hart_dissem_flags_t;
+
+typedef struct
+{
+       size_t nprocs;
+       hart_dissem_flags_t* allnodes;
+       size_t logp;
+} hart_barrier_t;
+
+extern void hart_entry();
+
+int hart_barrier_init(hart_barrier_t* b, size_t nprocs);
+void hart_barrier_wait(hart_barrier_t* b, size_t vcoreid);
+
+void hart_lock_init(hart_lock_t* lock);
+void hart_lock_unlock(hart_lock_t* lock);
+void hart_lock_lock(hart_lock_t* l);
+
+// "int" rather than size_t because of a newlib compiling issue
+int hart_self();
+void hart_relax();
+int hart_swap(int* addr, int val);
+
+int hart_request(size_t k);
+void hart_yield();
+size_t hart_max_harts();
+size_t hart_current_harts();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/user/include/parlib.h b/user/include/parlib.h
new file mode 100644 (file)
index 0000000..c05a5c3
--- /dev/null
@@ -0,0 +1,48 @@
+// Main public header file for our user-land support library,
+// whose code lives in the lib directory.
+// This library is roughly our OS's version of a standard C library,
+// and is intended to be linked into all user-mode applications
+// (NOT the kernel or boot loader).
+
+#ifndef ROS_INC_PARLIB_H
+#define ROS_INC_PARLIB_H 1
+
+#ifndef __ASSEMBLER__
+
+#include <ros/common.h>
+#include <ros/memlayout.h>
+#include <ros/syscall.h>
+#include <ros/procinfo.h>
+#include <ros/procdata.h>
+#include <stdint.h>
+
+enum {
+       PG_RDONLY = 4,
+       PG_RDWR   = 6,
+};
+
+ssize_t     sys_cputs(const uint8_t *s, size_t len);
+uint16_t    sys_cgetc(void);
+ssize_t     sys_serial_write(void* buf, size_t len); 
+ssize_t     sys_serial_read(void* buf, size_t len);
+ssize_t     sys_eth_write(void *COUNT(len) buf, size_t len); 
+ssize_t     sys_eth_read(void *COUNT(len) buf, size_t len);
+ssize_t     sys_run_binary(void* binary_buf, size_t len,
+                           const procinfo_t* pi, size_t num_colors);
+int         sys_getpid(void);
+size_t      sys_getcpuid(void);
+void *      sys_brk(void* addr);
+int     sys_proc_destroy(int pid, int exitcode);
+ssize_t     sys_shared_page_alloc(void *COUNT(PGSIZE) *addr, pid_t p2, 
+                                  int p1_flags, int p2_flags);
+ssize_t     sys_shared_page_free(void *COUNT(PGSIZE) addr, pid_t p2);
+ssize_t     sys_resource_req(int type, size_t amount, uint32_t flags);
+void        sys_reboot();
+void        sys_yield();
+int         gettimeofday(struct timeval* tp, void* tzp);
+void *COUNT(length) sys_mmap(void *SNT addr, size_t length, int prot, int flags,
+                             int fd, size_t offset);
+
+#endif // !ASSEMBLER
+
+#endif // !ROS_INC_PARLIB_H
diff --git a/user/include/pthread.h b/user/include/pthread.h
new file mode 100644 (file)
index 0000000..f369049
--- /dev/null
@@ -0,0 +1,117 @@
+#ifndef _PTHREAD_H
+#define _PTHREAD_H
+
+#include <hart.h>
+
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
+struct pthread_wqt
+{
+  void* (*start_routine)(void*);
+  void* arg;
+  int finished;
+  int detached;
+  struct pthread_wqt* next;
+};
+
+typedef struct
+{
+  int type;
+} pthread_mutexattr_t;
+
+typedef struct
+{
+  const pthread_mutexattr_t* attr;
+  int lock;
+} pthread_mutex_t;
+
+typedef struct
+{
+  int local_sense[32*HART_MAX_MAX_HARTS];
+  volatile int sense;
+  int count;
+  int nprocs;
+  hart_lock_t lock;
+} pthread_barrier_t;
+
+typedef struct
+{
+  int pshared;
+} pthread_condattr_t;
+
+typedef struct
+{
+  const pthread_condattr_t* attr;
+  int waiters[HART_MAX_MAX_HARTS];
+} pthread_cond_t;
+
+typedef struct pthread_wqt work_queue_t;
+typedef work_queue_t* pthread_t;
+typedef int pthread_attr_t;
+typedef int pthread_barrierattr_t;
+typedef int pthread_once_t;
+typedef void** pthread_key_t;
+
+#define PTHREAD_ONCE_INIT 0
+#define PTHREAD_BARRIER_SERIAL_THREAD 12345
+#define PTHREAD_MUTEX_INITIALIZER {0}
+#define PTHREAD_MUTEX_NORMAL 0
+#define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL
+#define PTHREAD_COND_INITIALIZER {0}
+#define PTHREAD_PROCESS_PRIVATE 0
+
+int pthread_attr_init(pthread_attr_t *);
+int pthread_attr_destroy(pthread_attr_t *);
+int pthread_create(pthread_t *, const pthread_attr_t *,
+                   void *(*)(void *), void *);
+int pthread_join(pthread_t, void **);
+
+int pthread_mutex_destroy(pthread_mutex_t *);
+int pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *);
+int pthread_mutex_lock(pthread_mutex_t *);
+int pthread_mutex_trylock(pthread_mutex_t *);
+int pthread_mutex_unlock(pthread_mutex_t *);
+int pthread_mutex_destroy(pthread_mutex_t *);
+
+int pthread_mutexattr_init(pthread_mutexattr_t *);
+int pthread_mutexattr_destroy(pthread_mutexattr_t *);
+int pthread_mutexattr_gettype(const pthread_mutexattr_t *, int *);
+int pthread_mutexattr_settype(pthread_mutexattr_t *, int);
+
+int pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *);
+int pthread_cond_destroy(pthread_cond_t *);
+int pthread_cond_broadcast(pthread_cond_t *);
+int pthread_cond_signal(pthread_cond_t *);
+int pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *);
+
+int pthread_condattr_init(pthread_condattr_t *);
+int pthread_condattr_destroy(pthread_condattr_t *);
+int pthread_condattr_setpshared(pthread_condattr_t *, int);
+int pthread_condattr_getpshared(pthread_condattr_t *, int *);
+
+#define pthread_rwlock_t pthread_mutex_t
+#define pthread_rwlockattr_t pthread_mutexattr_t
+#define pthread_rwlock_destroy pthread_mutex_destroy
+#define pthread_rwlock_init pthread_mutex_init
+#define pthread_rwlock_unlock pthread_mutex_unlock
+#define pthread_rwlock_rdlock pthread_mutex_lock
+#define pthread_rwlock_wrlock pthread_mutex_lock
+#define pthread_rwlock_tryrdlock pthread_mutex_trylock
+#define pthread_rwlock_trywrlock pthread_mutex_trylock
+
+pthread_t pthread_self();
+int pthread_equal(pthread_t t1, pthread_t t2);
+void pthread_exit(void* ret);
+int pthread_once(pthread_once_t* once_control, void (*init_routine)(void));
+
+int pthread_barrier_init(pthread_barrier_t* b, const pthread_barrierattr_t* a, int count);
+int pthread_barrier_wait(pthread_barrier_t* b);
+int pthread_barrier_destroy(pthread_barrier_t* b);
+
+#ifdef __cplusplus
+  }
+#endif
+
+#endif
diff --git a/user/parlib/Makefrag b/user/parlib/Makefrag
new file mode 100644 (file)
index 0000000..0c42793
--- /dev/null
@@ -0,0 +1,53 @@
+# Makefile fragment for ROS kernel.
+# This is NOT a complete makefile;
+# you must run GNU make in the top-level directory
+# where the GNUmakefile is located.
+#
+
+USER_PARLIB_DIR = $(USER_DIR)/parlib
+USER_PARLIB_CFLAGS += $(USER_CFLAGS)
+OBJDIRS += $(USER_PARLIB_DIR)
+
+# entry.S must be first, so that it's the first code in the text segment!!!
+#
+# We also snatch the use of a couple handy source files
+# from the lib directory, to avoid gratuitous code duplication.
+USER_PARLIB_SRCFILES := \
+                 $(USER_PARLIB_DIR)/hart.c \
+                 $(USER_PARLIB_DIR)/pthread.c \
+                 $(USER_PARLIB_DIR)/syscall.c
+
+# Only build files if they exist.
+PARLIB_SRCFILES := $(wildcard $(PARLIB_SRCFILES))
+
+USER_PARLIB_OBJFILES  := $(patsubst $(USER_PARLIB_DIR)/%.c, \
+                             $(OBJDIR)/$(USER_PARLIB_DIR)/%.o, \
+                             $(USER_PARLIB_SRCFILES))
+USER_PARLIB_OBJFILES  := $(patsubst $(USER_PARLIB_DIR)/%.S, \
+                             $(OBJDIR)/$(USER_PARLIB_DIR)/%.o, \
+                             $(USER_PARLIB_OBJFILES))
+
+USER_PARLIB_LDDEPENDS := $(PARLIB_OBJFILES) 
+
+$(OBJDIR)/$(USER_PARLIB_DIR)/%.o: $(USER_PARLIB_DIR)/%.c
+       @echo + cc [USER PARLIB] $<
+       @mkdir -p $(@D)
+       $(V)$(CC) $(USER_PARLIB_CFLAGS) -c -o $@ $<
+
+$(OBJDIR)/$(USER_PARLIB_DIR)/%.o: $(USER_PARLIB_DIR)/%.S
+       @echo + as [USER PARLIB] $<
+       @mkdir -p $(@D)
+       $(V)$(CC) $(USER_PARLIB_CFLAGS) -D__ASSEMBLER__ -c -o $@ $<
+
+$(OBJDIR)/$(USER_PARLIB_DIR)/libparlib.a: $(USER_PARLIB_OBJFILES)
+       @echo + ar [USER PARLIB.A] $@
+       @mkdir -p $(@D)
+       $(V)$(AR) r $@ $(USER_PARLIB_SRC_OBJFILES) 2>/dev/null
+
+$(OBJDIR)/$(USER_PARLIB_DIR)/libparlib.so: $(USER_PARLIB_OBJFILES)
+       @echo + gcc [USER PARLIB.SO] $@
+       @mkdir -p $(@D)
+       $(V)$(CC) -shared -Wl,-soname,$(@F) -o $@ $(USER_PARLIB_OBJFILES) 2>/dev/null
+
+pthreads:
+       @echo $(OBJDIR)/$(USER_PARLIB_DIR)/libparlib.a  
diff --git a/user/parlib/hart.c b/user/parlib/hart.c
new file mode 100644 (file)
index 0000000..54bfe3f
--- /dev/null
@@ -0,0 +1,245 @@
+#include <stdbool.h>
+#include <errno.h>
+#include <hart.h>
+#include <parlib.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+static size_t _current_harts = 1;
+static hart_lock_t _hart_lock = HART_LOCK_INIT;
+
+extern void** hart_thread_control_blocks;
+
+static void hart_free_tls(int id)
+{
+       extern void _dl_deallocate_tls (void *tcb, bool dealloc_tcb);
+       if(hart_thread_control_blocks[id])
+       {
+               _dl_deallocate_tls(hart_thread_control_blocks[id],true);
+               hart_thread_control_blocks[id] = 0;
+       }
+}
+
+static int hart_allocate_tls(int id)
+{
+       extern void *_dl_allocate_tls (void *mem);
+       // instead of freeing any old tls that may be present, and then
+       // reallocating it, we could instead just reinitialize it.
+       hart_free_tls(id);
+       if((hart_thread_control_blocks[id] = _dl_allocate_tls(NULL)) == NULL)
+       {
+               errno = ENOMEM;
+               return -1;
+       }
+       return 0;
+}
+
+#define HART_STACK_SIZE (32*1024)
+
+static void hart_free_stack(int id)
+{
+       // don't actually free stacks
+}
+
+static int hart_allocate_stack(int id)
+{
+       if(__procdata.stack_pointers[id])
+               return 0; // reuse old stack
+
+       if(!(__procdata.stack_pointers[id] = (uintptr_t)malloc(HART_STACK_SIZE)))
+       {
+               errno = ENOMEM;
+               return -1;
+       }
+       return 0;
+}
+
+static int hart_init()
+{
+       static int initialized = 0;
+       if(initialized)
+               return 0;
+
+       hart_thread_control_blocks = (void**)calloc(hart_max_harts(),sizeof(void*));
+
+       if(!hart_thread_control_blocks)
+       {
+               free(hart_thread_control_blocks);
+               errno = ENOMEM;
+               return -1;
+       }
+
+       initialized = 1;
+       return 0;
+}
+
+int hart_request(size_t k)
+{
+       int ret = -1;
+       size_t i,j;
+
+       if(hart_init() < 0)
+               return -1;
+
+       hart_lock_lock(&_hart_lock);
+
+       if(k < 0 || _current_harts+k > hart_max_harts())
+       {
+               errno = EAGAIN;
+               goto out;
+       }
+
+       for(i = _current_harts, j = 0; i < _current_harts+k; i++, j++)
+       {
+               if(hart_allocate_stack(i) || hart_allocate_tls(i))
+                       goto fail;
+       }
+
+       if((ret = sys_resource_req(0,_current_harts+k,0)) == 0)
+       {
+               _current_harts += k;
+               goto out;
+       }
+
+fail:
+       for(i = _current_harts; i < _current_harts+k; i++)
+       {
+               hart_free_tls(i);
+               hart_free_stack(i);
+       }
+
+out:
+       hart_lock_unlock(&_hart_lock);
+       return ret;
+}
+
+void hart_yield()
+{
+       int id = hart_self();
+
+       hart_lock_lock(&_hart_lock);
+       _current_harts--;
+       if(_current_harts == 0)
+               exit(0);
+       hart_lock_unlock(&_hart_lock);
+
+       sys_yield();
+}
+
+size_t hart_max_harts()
+{
+       return __procinfo.max_harts < HART_MAX_MAX_HARTS ? __procinfo.max_harts : HART_MAX_MAX_HARTS;
+}
+
+size_t hart_current_harts()
+{
+       return _current_harts;
+}
+
+// MCS locks!!
+void hart_lock_init(hart_lock_t* lock)
+{
+       memset(lock,0,sizeof(hart_lock_t));
+}
+
+static inline hart_lock_qnode_t* hart_qnode_swap(hart_lock_qnode_t** addr, hart_lock_qnode_t* val)
+{
+       return (hart_lock_qnode_t*)hart_swap((int*)addr,(int)val);
+}
+
+void hart_lock_lock(hart_lock_t* lock)
+{
+       hart_lock_qnode_t* qnode = &lock->qnode[hart_self()];
+       qnode->next = 0;
+       hart_lock_qnode_t* predecessor = hart_qnode_swap(&lock->lock,qnode);
+       if(predecessor)
+       {
+               qnode->locked = 1;
+               predecessor->next = qnode;
+               while(qnode->locked);
+       }
+}
+
+void hart_lock_unlock(hart_lock_t* lock)
+{
+       hart_lock_qnode_t* qnode = &lock->qnode[hart_self()];
+       if(qnode->next == 0)
+       {
+               hart_lock_qnode_t* old_tail = hart_qnode_swap(&lock->lock,0);
+               if(old_tail == qnode)
+                       return;
+
+               hart_lock_qnode_t* usurper = hart_qnode_swap(&lock->lock,old_tail);
+               while(qnode->next == 0);
+               if(usurper)
+                       usurper->next = qnode->next;
+               else
+                       qnode->next->locked = 0;
+       }
+       else
+               qnode->next->locked = 0;
+}
+
+// MCS dissemination barrier!
+int hart_barrier_init(hart_barrier_t* b, size_t np)
+{
+       if(np > hart_max_harts())
+               return -1;
+       b->allnodes = (hart_dissem_flags_t*)malloc(np*sizeof(hart_dissem_flags_t));
+       memset(b->allnodes,0,np*sizeof(hart_dissem_flags_t));
+       b->nprocs = np;
+
+       b->logp = (np & (np-1)) != 0;
+       while(np >>= 1)
+               b->logp++;
+
+       size_t i,k;
+       for(i = 0; i < b->nprocs; i++)
+       {
+               b->allnodes[i].parity = 0;
+               b->allnodes[i].sense = 1;
+
+               for(k = 0; k < b->logp; k++)
+               {
+                       size_t j = (i+(1<<k)) % b->nprocs;
+                       b->allnodes[i].partnerflags[0][k] = &b->allnodes[j].myflags[0][k];
+                       b->allnodes[i].partnerflags[1][k] = &b->allnodes[j].myflags[1][k];
+               } 
+       }
+
+       return 0;
+}
+
+void hart_barrier_wait(hart_barrier_t* b, size_t pid)
+{
+       hart_dissem_flags_t* localflags = &b->allnodes[pid];
+       size_t i;
+       for(i = 0; i < b->logp; i++)
+       {
+               *localflags->partnerflags[localflags->parity][i] = localflags->sense;
+               while(localflags->myflags[localflags->parity][i] != localflags->sense);
+       }
+       if(localflags->parity)
+               localflags->sense = 1-localflags->sense;
+       localflags->parity = 1-localflags->parity;
+}
+
+int
+hart_self()
+{
+       // defined in ros/arch/hart.h
+       return __hart_self();
+}
+
+int
+hart_swap(int* addr, int val)
+{
+       return __hart_swap(addr,val);
+}
+
+void
+hart_relax()
+{
+       __hart_relax();
+}
+
diff --git a/user/parlib/pthread.c b/user/parlib/pthread.c
new file mode 100644 (file)
index 0000000..d4989e6
--- /dev/null
@@ -0,0 +1,301 @@
+#include <pthread.h>
+#include <hart.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+
+int threads_active = 1;
+hart_lock_t work_queue_lock = HART_LOCK_INIT;
+pthread_t work_queue_head = 0;
+pthread_t work_queue_tail = 0;
+pthread_once_t init_once = PTHREAD_ONCE_INIT;
+pthread_t active_threads[HART_MAX_MAX_HARTS] = {0};
+
+void queue_insert(pthread_t* head, pthread_t* tail, pthread_t node)
+{
+  node->next = 0;
+  if(*head == 0)
+    *head = node;
+  else
+    (*tail)->next = node;
+  *tail = node;
+}
+
+pthread_t queue_remove(pthread_t* head, pthread_t* tail)
+{
+  pthread_t node = *head;
+  *head = (*head)->next;
+  if(*head == 0)
+    *tail = 0;
+  node->next = 0;
+  return node;
+}
+
+void hart_entry()
+{
+  pthread_t node = NULL;
+  while(1)
+  {
+    hart_lock_lock(&work_queue_lock);
+    if(work_queue_head)
+      node = queue_remove(&work_queue_head,&work_queue_tail);
+    hart_lock_unlock(&work_queue_lock);
+
+    if(node)
+      break;
+    hart_relax();
+  }
+
+  active_threads[hart_self()] = node;
+
+  pthread_exit(node->start_routine(node->arg));
+}
+
+void _pthread_init()
+{
+  // if we allocated active_threads dynamically, we'd do so here
+}
+
+int pthread_attr_init(pthread_attr_t *a)
+{
+  return 0;
+}
+
+int pthread_attr_destroy(pthread_attr_t *a)
+{
+  return 0;
+}
+
+int pthread_create(pthread_t* thread, const pthread_attr_t* attr,
+                   void *(*start_routine)(void *), void* arg)
+{
+  pthread_once(&init_once,&_pthread_init);
+
+  *thread = (pthread_t)malloc(sizeof(work_queue_t));
+  (*thread)->start_routine = start_routine;
+  (*thread)->arg = arg;
+  (*thread)->next = 0;
+  (*thread)->finished = 0;
+  (*thread)->detached = 0;
+
+  hart_lock_lock(&work_queue_lock);
+  {
+    threads_active++;
+    queue_insert(&work_queue_head,&work_queue_tail,*thread);
+    // don't return until we get a hart
+    while(threads_active > hart_current_harts() && hart_request(1));
+  }
+  hart_lock_unlock(&work_queue_lock);
+
+  return 0;
+}
+
+int pthread_join(pthread_t t, void** arg)
+{
+  volatile pthread_t thread = t;
+  while(!thread->finished);
+  if(arg) *arg = thread->arg;
+  free(thread);
+  return 0;
+}
+
+int pthread_mutexattr_init(pthread_mutexattr_t* attr)
+{
+  attr->type = PTHREAD_MUTEX_DEFAULT;
+  return 0;
+}
+
+int pthread_mutexattr_destroy(pthread_mutexattr_t* attr)
+{
+  return 0;
+}
+
+int pthread_mutexattr_gettype(const pthread_mutexattr_t* attr, int* type)
+{
+  *type = attr ? attr->type : PTHREAD_MUTEX_DEFAULT;
+  return 0;
+}
+
+int pthread_mutexattr_settype(pthread_mutexattr_t* attr, int type)
+{
+  if(type != PTHREAD_MUTEX_NORMAL)
+    return -EINVAL;
+  attr->type = type;
+  return 0;
+}
+
+int pthread_mutex_init(pthread_mutex_t* m, const pthread_mutexattr_t* attr)
+{
+  m->attr = attr;
+  m->lock = 0;
+  return 0;
+}
+
+int pthread_mutex_lock(pthread_mutex_t* m)
+{
+  while(pthread_mutex_trylock(m))
+    while(*(volatile size_t*)&m->lock);
+  return 0;
+}
+
+int pthread_mutex_trylock(pthread_mutex_t* m)
+{
+  return hart_swap(&m->lock,1) == 0 ? 0 : -EBUSY;
+}
+
+int pthread_mutex_unlock(pthread_mutex_t* m)
+{
+  m->lock = 0;
+  return 0;
+}
+
+int pthread_mutex_destroy(pthread_mutex_t* m)
+{
+  return 0;
+}
+
+int pthread_cond_init(pthread_cond_t *c, const pthread_condattr_t *a)
+{
+  c->attr = a;
+  memset(c->waiters,0,sizeof(c->waiters));
+  return 0;
+}
+
+int pthread_cond_destroy(pthread_cond_t *c)
+{
+  return 0;
+}
+
+int pthread_cond_broadcast(pthread_cond_t *c)
+{
+  memset(c->waiters,0,sizeof(c->waiters));
+  return 0;
+}
+
+int pthread_cond_signal(pthread_cond_t *c)
+{
+  int i;
+  for(i = 0; i < hart_max_harts(); i++)
+  {
+    if(c->waiters[i])
+    {
+      c->waiters[i] = 0;
+      break;
+    }
+  }
+  return 0;
+}
+
+int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m)
+{
+  c->waiters[hart_self()] = 1;
+  pthread_mutex_unlock(m);
+
+  volatile int* poll = &c->waiters[hart_self()];
+  while(*poll);
+
+  pthread_mutex_lock(m);
+
+  return 0;
+}
+
+int pthread_condattr_init(pthread_condattr_t *a)
+{
+  a = PTHREAD_PROCESS_PRIVATE;
+  return 0;
+}
+
+int pthread_condattr_destroy(pthread_condattr_t *a)
+{
+  return 0;
+}
+
+int pthread_condattr_setpshared(pthread_condattr_t *a, int s)
+{
+  a->pshared = s;
+  return 0;
+}
+
+int pthread_condattr_getpshared(pthread_condattr_t *a, int *s)
+{
+  *s = a->pshared;
+  return 0;
+}
+
+pthread_t pthread_self()
+{
+  return active_threads[hart_self()];
+}
+
+int pthread_equal(pthread_t t1, pthread_t t2)
+{
+  return t1 == t2;
+}
+
+void pthread_exit(void* ret)
+{
+  pthread_once(&init_once,&_pthread_init);
+
+  pthread_t t = pthread_self();
+
+  hart_lock_lock(&work_queue_lock);
+  threads_active--;
+  if(threads_active == 0)
+    exit(0);
+  hart_lock_unlock(&work_queue_lock);
+
+  if(t)
+  {
+    t->arg = ret;
+    t->finished = 1;
+    if(t->detached)
+      free(t);
+  }
+
+  hart_entry();
+}
+
+int pthread_once(pthread_once_t* once_control, void (*init_routine)(void))
+{
+  if(hart_swap(once_control,1) == 0)
+    init_routine();
+  return 0;
+}
+
+int pthread_barrier_init(pthread_barrier_t* b, const pthread_barrierattr_t* a, int count)
+{
+  memset(b->local_sense,0,sizeof(b->local_sense));
+
+  b->sense = 0;
+  b->nprocs = b->count = count;
+  hart_lock_init(&b->lock);
+  return 0;
+}
+
+int pthread_barrier_wait(pthread_barrier_t* b)
+{
+  int id = hart_self();
+  int ls = b->local_sense[32*id] = 1 - b->local_sense[32*id];
+
+  hart_lock_lock(&b->lock);
+  int count = --b->count;
+  hart_lock_unlock(&b->lock);
+
+  if(count == 0)
+  {
+    b->count = b->nprocs;
+    b->sense = ls;
+    return PTHREAD_BARRIER_SERIAL_THREAD;
+  }
+  else
+  {
+    while(b->sense != ls);
+    return 0;
+  }
+}
+
+int pthread_barrier_destroy(pthread_barrier_t* b)
+{
+  return 0;
+}
diff --git a/user/parlib/syscall.c b/user/parlib/syscall.c
new file mode 100644 (file)
index 0000000..e396f21
--- /dev/null
@@ -0,0 +1,121 @@
+// System call stubs.
+
+#include <parlib.h>
+
+int sys_proc_destroy(int pid, int exitcode)
+{
+       return ros_syscall(SYS_proc_destroy, pid, exitcode, 0, 0, 0);
+}
+
+void* sys_brk(void* addr)
+{
+       return (void*)ros_syscall(SYS_brk, addr, 0, 0, 0, 0);
+}
+
+int sys_getpid(void)
+{
+        return ros_syscall(SYS_getpid, 0, 0, 0, 0, 0);
+}
+
+size_t sys_getcpuid(void)
+{
+        return ros_syscall(SYS_getcpuid, 0, 0, 0, 0, 0);
+}
+
+ssize_t sys_cputs(const uint8_t *s, size_t len)
+{
+    return ros_syscall(SYS_cputs, s,  len, 0, 0, 0);
+}
+
+uint16_t sys_cgetc(void)
+{
+    return ros_syscall(SYS_cgetc, 0, 0, 0, 0, 0);
+}
+
+ssize_t sys_shared_page_alloc(void** addr, pid_t p2, 
+                              int p1_flags, int p2_flags
+                             ) 
+{
+       return ros_syscall(SYS_shared_page_alloc, addr, 
+                      p2, p1_flags, p2_flags, 0);
+}
+
+ssize_t sys_shared_page_free(void* addr, pid_t p2) 
+{
+       return ros_syscall(SYS_shared_page_free, addr, p2, 0,0,0);
+}
+
+//Write a buffer over the serial port
+ssize_t sys_serial_write(void* buf, size_t len) 
+{
+       return ros_syscall(SYS_serial_write, buf, len, 0, 0, 0);
+}
+
+//Read a buffer over the serial port
+ssize_t sys_serial_read(void* buf, size_t len) 
+{
+       return ros_syscall(SYS_serial_read, buf, len, 0, 0, 0);
+}
+
+//Run a binary loaded at the specificed address with the specified arguments
+ssize_t sys_run_binary(void* binary_buf, size_t len,
+                       const procinfo_t* pi, size_t num_colors) 
+{
+       return ros_syscall(SYS_run_binary, binary_buf, len,
+                                       pi,num_colors,0);
+}
+
+//Write a buffer over ethernet
+ssize_t sys_eth_write(void* buf, size_t len) 
+{
+       if (len == 0)
+               return 0;
+       
+       return ros_syscall(SYS_eth_write, buf, len, 0, 0, 0);
+}
+
+//Read a buffer via ethernet
+ssize_t sys_eth_read(void* buf, size_t len) 
+{
+       if (len == 0)
+               return 0;
+               
+       return ros_syscall(SYS_eth_read, buf, len, 0, 0, 0);
+}
+
+/* Request resources from the kernel.  Flags in ros/resource.h. */
+ssize_t sys_resource_req(int type, size_t amount, uint32_t flags)
+{
+       return ros_syscall(SYS_resource_req, type, amount, flags, 0, 0);
+}
+
+void sys_reboot()
+{
+       ros_syscall(SYS_reboot,0,0,0,0,0);
+}
+
+void sys_yield()
+{
+       ros_syscall(SYS_yield,0,0,0,0,0);
+}
+
+/* We need to do some hackery to pass 6 arguments.  Arg4 pts to the real arg4,
+ * arg5, and arg6.  Keep this in sync with kern/src/syscall.c.
+ * TODO: consider a syscall_multi that can take more args, and keep it in sync
+ * with the kernel.  Maybe wait til we fix sysenter to have 5 or 6 args. */
+void *CT(length) sys_mmap(void *SNT addr, size_t length, int prot, int flags,
+                          int fd, size_t offset)
+{
+       struct args {
+               int _flags;
+               int _fd;
+               size_t _offset;
+       } extra_args;
+       extra_args._flags = flags;
+       extra_args._fd = fd;
+       extra_args._offset = offset;
+       // TODO: deputy bitches about this
+       return (void*CT(length))TC(ros_syscall(SYS_mmap, addr, length,
+                                              prot, &extra_args, 0));
+}
+