Added all of the old tests from roslib back in
authorKevin Klues <klueska@ros-dev.(none)>
Tue, 30 Mar 2010 04:31:20 +0000 (21:31 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:35:38 +0000 (17:35 -0700)
Also had to chnge the makefiles to support compiling all
c files contained in the tests directory without explicitly
listing them.

32 files changed:
GNUmakefile
tests/Makefrag
tests/badsegment.c [new file with mode: 0644]
tests/breakpoint.c [new file with mode: 0644]
tests/buggyhello.c [new file with mode: 0644]
tests/divzero.c [new file with mode: 0644]
tests/draw_nanwan.c [new file with mode: 0644]
tests/evilhello.c [new file with mode: 0644]
tests/faultread.c [new file with mode: 0644]
tests/faultreadkernel.c [new file with mode: 0644]
tests/faultwrite.c [new file with mode: 0644]
tests/faultwritekernel.c [new file with mode: 0644]
tests/fp_test.c [new file with mode: 0644]
tests/hello.c [new file with mode: 0644]
tests/manycore_test.c [new file with mode: 0644]
tests/mhello.c [new file with mode: 0644]
tests/mproctests.c [new file with mode: 0644]
tests/null.c [new file with mode: 0644]
tests/proctests.c [new file with mode: 0644]
tests/pthread_test.c
tests/softint.c [new file with mode: 0644]
tests/spawn.c [new file with mode: 0644]
tests/testbss.c [new file with mode: 0644]
user/Makefrag
user/include/hart.h
user/include/parlib.h
user/include/rassert.h [new file with mode: 0644]
user/parlib/Makefrag
user/parlib/hart.c
user/parlib/panic.c [new file with mode: 0644]
user/parlib/syscall.c
user/pthread/Makefrag [new file with mode: 0644]

index f523406..e992766 100644 (file)
@@ -124,6 +124,9 @@ LDFLAGS := -nostdlib
 # List of directories that the */Makefrag makefile fragments will add to
 OBJDIRS :=
 
+# List of directories that the */Makefrag makefile fragments will add to
+ROS_USER_LIBS :=
+
 ROS_ARCH_DIR ?= $(TARGET_ARCH)
 
 arch:
@@ -141,9 +144,20 @@ include user/Makefrag
 include tests/Makefrag
 endif
 
-tests: $(TESTS_EXECS)
+ifeq ($(GCCPREFIX),$(TARGET_ARCH)-ros-)
+GCC_ROOT := $(shell which $(GCCPREFIX)gcc | xargs dirname)/../
+tests/: realtests
+tests:
+       @$(MAKE) -j realtests
+realtests: $(TESTS_EXECS)
        @mkdir -p fs/$(TARGET_ARCH)/tests
-       cp -R $(OBJDIR)/$(TESTS_DIR)/* fs/$(TARGET_ARCH)/tests
+       cp -R $(OBJDIR)/$(TESTS_DIR)/* $(TOP_DIR)/fs/$(TARGET_ARCH)/tests
+
+install-libs: $(ROS_USER_LIBS)
+       cp $(ROS_USER_LIBS) $(GCC_ROOT)/$(TARGET_ARCH)-ros/lib
+       cp $(ROS_USER_LIBS) $(TOP_DIR)/fs/$(TARGET_ARCH)/lib
+       cp -R $(USER_DIR)/include/* $(GCC_ROOT)/$(TARGET_ARCH)-ros/include
+endif
 
 # Eliminate default suffix rules
 .SUFFIXES:
@@ -175,6 +189,9 @@ doxyclean:
        rm -rf $(DOXYGEN_DIR)/rosdoc
 
 # For deleting the build
+userclean:
+       @rm -rf $(OBJDIR)/user
+       
 clean:
        @rm -rf $(OBJDIR)
        @echo All clean and pretty!
index ff5ef4d..7b53713 100644 (file)
@@ -5,15 +5,13 @@ OBJDIRS += $(TESTS_DIR)
 TESTS_CFLAGS := $(USER_CFLAGS)  \
                 -I$(USER_DIR)/include
 
-TESTS_LDFLAGS := -static
+ALL_TEST_FILES = $(shell ls $(TESTS_DIR)/*.c)
 
 TESTS_LDDIRS := -L$(OBJDIR)/$(USER_PARLIB_DIR)
 
 TESTS_LDLIBS := -lparlib 
 
-TESTS_SRCS := \
-              $(TESTS_DIR)/hart_test.c \
-              $(TESTS_DIR)/pthread_test.c
+TESTS_SRCS := $(ALL_TEST_FILES)
 
 TESTS_EXECS  := $(patsubst $(TESTS_DIR)/%.c, \
                            $(OBJDIR)/$(TESTS_DIR)/%, \
@@ -26,7 +24,7 @@ $(OBJDIR)/$(TESTS_DIR)/%: $(TESTS_LDDEPENDS)
        @echo + cc [TESTS] $<
        @mkdir -p $(@D)
        $(V)$(CC) $(TESTS_CFLAGS) -o $@ $(TESTS_LDFLAGS) \
-                 $(TESTS_LDDIRS) $(TESTS_LDLIBS) $<
+                 $(TESTS_LDDIRS) $< $(TESTS_LDLIBS)
        $(V)$(OBJDUMP) -S $@ > $@.asm
        $(V)$(NM) -n $@ > $@.sym
 
diff --git a/tests/badsegment.c b/tests/badsegment.c
new file mode 100644 (file)
index 0000000..683d1d5
--- /dev/null
@@ -0,0 +1,12 @@
+// program to cause a general protection exception
+
+int main(int argc, char** argv)
+{
+       // Try to load the kernel's TSS selector into the DS register.
+       //asm volatile("movw $28,%ax; movw %ax,%ds");
+  
+       // DP: 0x28 == 40
+       asm volatile("movw $40,%ax; movw %ax,%ds");
+       return 0;
+}
+
diff --git a/tests/breakpoint.c b/tests/breakpoint.c
new file mode 100644 (file)
index 0000000..2304d83
--- /dev/null
@@ -0,0 +1,8 @@
+// program to cause a breakpoint trap
+
+int main(int argc, char** argv)
+{
+       asm volatile("int $3");
+       return 0;
+}
+
diff --git a/tests/buggyhello.c b/tests/buggyhello.c
new file mode 100644 (file)
index 0000000..05232e9
--- /dev/null
@@ -0,0 +1,11 @@
+// buggy hello world -- unmapped pointer passed to kernel
+// kernel should destroy user process in response
+
+#include <parlib.h>
+
+int main(int argc, char** argv)
+{
+       sys_cputs((char*SAFE)TC(1), 1);
+       return 0;
+}
+
diff --git a/tests/divzero.c b/tests/divzero.c
new file mode 100644 (file)
index 0000000..59dbf18
--- /dev/null
@@ -0,0 +1,12 @@
+// buggy program - causes a divide by zero exception
+
+#include <stdio.h>
+
+int zero;
+
+int main(int argc, char** argv)
+{
+       printf("1/0 is %08x!\n", 1/zero);
+       return 0;
+}
+
diff --git a/tests/draw_nanwan.c b/tests/draw_nanwan.c
new file mode 100644 (file)
index 0000000..16f6663
--- /dev/null
@@ -0,0 +1,34 @@
+#include <stdio.h>
+
+int main(int argc, char** argv)
+{
+       /* Borrowed with love from http://www.geocities.com/SoHo/7373/zoo.htm
+        * (http://www.ascii-art.com/).  Slightly modified to make it 25 lines tall.
+        */
+       printf("\n");
+       printf("             .-.  .-.\n");
+       printf("             |  \\/  |\n");
+       printf("            /,   ,_  `'-.\n");
+       printf("          .-|\\   /`\\     '. \n");
+       printf("        .'  0/   | 0\\  \\_  `\".  \n");
+       printf("     .-'  _,/    '--'.'|#''---'\n");
+       printf("      `--'  |       /   \\#\n");
+       printf("            |      /     \\#\n");
+       printf("            \\     ;|\\    .\\#\n");
+       printf("            |' ' //  \\   ::\\# \n");
+       printf("            \\   /`    \\   ':\\#\n");
+       printf("             `\"`       \\..   \\#\n");
+       printf("                        \\::.  \\#\n");
+       printf("                         \\::   \\#\n");
+       printf("                          \\'  .:\\#\n");
+       printf("                           \\  :::\\#\n");
+       printf("                            \\  '::\\#\n");
+       printf("                             \\     \\#\n");
+       printf("                              \\:.   \\#\n");
+       printf("                               \\::   \\#\n");
+       printf("                                \\'   .\\#\n");
+       printf("                             jgs \\   ::\\#\n");
+       printf("                                  \\      \n");
+       return 0;
+}
+
diff --git a/tests/evilhello.c b/tests/evilhello.c
new file mode 100644 (file)
index 0000000..1edac84
--- /dev/null
@@ -0,0 +1,13 @@
+// evil hello world -- kernel pointer passed to kernel
+// kernel should destroy user process in response
+
+#include <parlib.h>
+
+int main(int argc, char** argv)
+{
+       while(1);
+       // try to print the kernel entry point as a string!  mua ha ha!
+       sys_cputs((char*SAFE)TC(0xc0100020), 100);
+       return 0;
+}
+
diff --git a/tests/faultread.c b/tests/faultread.c
new file mode 100644 (file)
index 0000000..3cf8a3f
--- /dev/null
@@ -0,0 +1,10 @@
+// buggy program - faults with a read from location zero
+
+#include <stdio.h>
+
+int main(int argc, char** argv)
+{ 
+       printf("I read %08x from location 0!\n", *(unsigned*)0);
+       return 0;
+}
+
diff --git a/tests/faultreadkernel.c b/tests/faultreadkernel.c
new file mode 100644 (file)
index 0000000..cef359f
--- /dev/null
@@ -0,0 +1,10 @@
+// buggy program - faults with a read from kernel space
+
+#include <stdio.h>
+
+int main(int argc, char** argv)
+{
+       printf("I read %08x from location 0xf0100000!\n", *(unsigned*)0xf0100000);
+       return 0;
+}
+
diff --git a/tests/faultwrite.c b/tests/faultwrite.c
new file mode 100644 (file)
index 0000000..05b1861
--- /dev/null
@@ -0,0 +1,8 @@
+// buggy program - faults with a write to location zero
+
+int main(int argc, char** argv)
+{
+       *(unsigned*)0 = 0;
+       return 0;
+}
+
diff --git a/tests/faultwritekernel.c b/tests/faultwritekernel.c
new file mode 100644 (file)
index 0000000..8b07449
--- /dev/null
@@ -0,0 +1,9 @@
+// buggy program - faults with a write to a kernel location
+
+
+int main(int argc, char** argv)
+{ 
+       *(unsigned*)0xf0100000 = 0;
+       return 0;
+}
+
diff --git a/tests/fp_test.c b/tests/fp_test.c
new file mode 100644 (file)
index 0000000..eaf8fb2
--- /dev/null
@@ -0,0 +1,15 @@
+#include <stdio.h>
+
+int main(int argc, char** argv) 
+{
+       volatile float x = 2.5;
+       volatile float y = 5.0;
+       volatile float var = x*y;
+       printf("value decimal: %d\n", (int)var);
+//     printf("value floating: %f\n", var);
+
+//     int x = 25;
+//     int y = 50;
+//     int var = x*y;
+//     printf("value: %d\n", var);
+} 
diff --git a/tests/hello.c b/tests/hello.c
new file mode 100644 (file)
index 0000000..db008b1
--- /dev/null
@@ -0,0 +1,8 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+int main(int argc, char** argv)
+{
+       printf("Hello world from newlib!!\n");
+       return 0;
+}
diff --git a/tests/manycore_test.c b/tests/manycore_test.c
new file mode 100644 (file)
index 0000000..04de64c
--- /dev/null
@@ -0,0 +1,29 @@
+#include <stdio.h>
+#include <assert.h>
+#include <hart.h>
+#include <parlib.h>
+
+hart_barrier_t b;
+
+void do_work_son(int vcoreid)
+{
+       int cpuid = sys_getcpuid();
+       int pid = sys_getpid();
+       printf("Hello! My Process ID: %d My VCoreID: %d My CPU: %d\n", pid, vcoreid, cpuid);
+       hart_barrier_wait(&b,vcoreid);
+}
+
+void hart_entry()
+{
+       assert(hart_self() > 0);
+       do_work_son(hart_self());
+}
+
+int main(int argc, char** argv)
+{
+       assert(hart_self() == 0);
+       hart_barrier_init(&b,hart_max_harts());
+       hart_request(hart_max_harts()-1);
+       do_work_son(0);
+       return 0;
+}
diff --git a/tests/mhello.c b/tests/mhello.c
new file mode 100644 (file)
index 0000000..3ca0803
--- /dev/null
@@ -0,0 +1,53 @@
+#include <parlib.h>
+#include <ros/mman.h>
+#include <ros/resource.h>
+#include <stdio.h>
+#include <hart.h>
+
+// ghetto udelay, put in a lib somewhere and export the tsc freq
+#include <arch/arch.h>
+void udelay(uint64_t usec, uint64_t tsc_freq)
+{
+       uint64_t start, end, now;
+
+       start = read_tsc();
+    end = start + (tsc_freq * usec) / 1000000;
+       if (end == 0) printf("This is terribly wrong \n");
+       do {
+        cpu_relax();
+        now = read_tsc();
+       } while (now < end || (now > start && end < start));
+       return;
+}
+
+__thread int temp;
+
+int main(int argc, char** argv)
+{
+       uint32_t vcoreid;
+       int retval;
+
+       if ((vcoreid = hart_self())) {
+               printf("Should never see me! (from vcore %d)\n", vcoreid);
+       } else { // core 0
+               temp = 0xdeadbeef;
+               printf("Hello from vcore %d with temp addr = %p and temp = %p\n",
+                      vcoreid, &temp, temp);
+               printf("Multi-Goodbye, world, from PID: %d!\n", sys_getpid());
+               //retval = sys_resource_req(RES_CORES, 2, 0);
+               retval = hart_request(2);
+               //debug("retval = %d\n", retval);
+       }
+       printf("Vcore %d Done!\n", vcoreid);
+       while (1);
+       return 0;
+}
+
+void hart_entry(void)
+{
+       uint32_t vcoreid = hart_self();
+       temp = 0xcafebabe;
+       printf("Hello from hart_entry in vcore %d with temp addr %p and temp %p\n",
+              vcoreid, &temp, temp);
+       while(1);
+}
diff --git a/tests/mproctests.c b/tests/mproctests.c
new file mode 100644 (file)
index 0000000..19c3ed9
--- /dev/null
@@ -0,0 +1,180 @@
+#include <parlib.h>
+#include <stdlib.h>
+#include <hart.h>
+#include <ros/mman.h>
+#include <ros/resource.h>
+#include <stdio.h>
+
+// ghetto udelay, put in a lib somewhere and export the tsc freq
+#include <arch/arch.h>
+void udelay(uint64_t usec, uint64_t tsc_freq)
+{
+       uint64_t start, end, now;
+
+       start = read_tsc();
+    end = start + (tsc_freq * usec) / 1000000;
+       if (end == 0) printf("This is terribly wrong \n");
+       do {
+        cpu_relax();
+        now = read_tsc();
+       } while (now < end || (now > start && end < start));
+       return;
+}
+
+#define TEST_MMAP                                       1
+#define TEST_ONE_CORE                           2
+#define TEST_ASK_FOR_TOO_MANY_CORES     3
+#define TEST_INCREMENTAL_CHANGES        4
+#define TEST_YIELD_OUT_OF_ORDER                 5
+#define TEST_YIELD_0_OUT_OF_ORDER       6
+#define TEST_YIELD_ALL               7
+#define TEST_SWITCH_TO_RUNNABLE_S       8
+#define TEST_CRAZY_YIELDS                       9
+#define TEST_CONCURRENT_SYSCALLS       10
+
+int test = TEST_SWITCH_TO_RUNNABLE_S;
+
+static void global_tests(uint32_t vcoreid);
+
+int main(int argc, char** argv)
+{
+       uint32_t vcoreid;
+       int retval;
+       hart_init();
+
+       if ((vcoreid = hart_self())) {
+               printf("Should never see me! (from vcore %d)\n", vcoreid);
+       } else { // core 0
+               printf("Hello from else vcore 0\n");
+               printf("Multi-Goodbye, world, from PID: %d!\n", sys_getpid());
+               switch (test) {
+                       case TEST_MMAP:
+                               printf("Testing MMAP\n");
+                               void *CT(8*PGSIZE) addr;
+                               addr = sys_mmap((void*SNT)USTACKTOP - 20*PGSIZE, 8*PGSIZE, 3,
+                                               MAP_FIXED | MAP_ANONYMOUS, -1, 0);
+                               printf("got addr = 0x%08x\n", addr);
+                               *(int*)addr = 0xdeadbeef;
+                               *(int*)(addr + 3*PGSIZE) = 0xcafebabe;
+                               // these should work
+                               printf("reading addr: 0x%08x\n", *(int*)addr);
+                               printf("reading addr+3pg: 0x%08x\n", *(int*)(addr + 3*PGSIZE));
+                               // this should fault
+                               printf("Should page fault and die now.\n");
+                               { TRUSTEDBLOCK
+                               *(int*)(addr - 3*PGSIZE) = 0xdeadbeef;
+                               }
+                               printf("Should not see me!!!!!!!!!!!!!!!!!!\n");
+                               while(1);
+                       case TEST_ONE_CORE:
+                               retval = hart_request(1);
+                               printf("One core test's core0's retval: %d\n", retval);
+                               printf("Check to see it's on a worker core.\n");
+                               while(1);
+                       case TEST_ASK_FOR_TOO_MANY_CORES:
+                               retval = hart_request(12);
+                               printf("Asked for too many, retval: %d\n", retval);
+                               return 0;
+                       case TEST_INCREMENTAL_CHANGES:
+                               retval = hart_request(4);
+                               break;
+                       default:
+                               retval = hart_request(7);
+               }
+               printf("Should see me if you want to relocate core0's context "
+                       "when moving from RUNNING_S\n");
+       }
+
+       // vcore0 only below here
+       switch (test) {
+               case TEST_YIELD_OUT_OF_ORDER:
+                       udelay(10000000, 1995014570);
+                       printf("Core 2 should have yielded, asking for another\n");
+                       retval = hart_request(7);
+                       break;
+               case TEST_YIELD_0_OUT_OF_ORDER:
+                       udelay(5000000, 1995014570);
+                       printf("Core %d yielding\n", vcoreid);
+                       sys_yield();
+                       printf("Core 0 came back where it left off in RUNNING_M!!!\n");
+                       break;
+       }
+       global_tests(vcoreid);
+       printf("Vcore %d Done!\n", vcoreid);
+       while (1);
+       return 0;
+}
+
+void hart_entry(void)
+{
+       uint32_t vcoreid;
+       static int first_time = 1; // used by vcore2
+       int retval;
+
+       vcoreid = hart_self();
+       printf("Hello from hart_entry in vcore %d\n", vcoreid);
+
+       if ((vcoreid == 2) && first_time) {
+               first_time = 0;
+               switch (test) {
+                       case TEST_INCREMENTAL_CHANGES:
+                               // Testing asking for less than we already have
+                               udelay(1000000, 1995014570); // KVM's freq.  Whatever.
+                               printf("Asking for too few:\n");
+                               retval = hart_request(2);
+                               printf("Should be -EINVAL(7): %d\n", retval);
+                               // Testing getting more while running
+                               printf("Asking for more while running:\n");
+                               udelay(1000000, 1995014570);
+                               retval = hart_request(7);
+                               printf("core2's retval: %d\n", retval);
+                               break;
+                       case TEST_YIELD_OUT_OF_ORDER:
+                               printf("Core %d yielding\n", vcoreid);
+                               sys_yield();
+                               break;
+                       case TEST_YIELD_0_OUT_OF_ORDER:
+                               udelay(7500000, 1995014570);
+                               printf("Core 0 should have yielded, asking for another\n");
+                               retval = hart_request(7);
+               }
+       }
+       global_tests(vcoreid);
+       printf("Vcore %d Done!\n", vcoreid);
+}
+
+static void global_tests(uint32_t vcoreid)
+{
+       int retval;
+       switch (test) {
+               case TEST_YIELD_ALL:
+                       printf("Core %d yielding\n", vcoreid);
+                       sys_yield();
+                       // should be RUNNABLE_M now, amt_wanted == 1
+                       while(1);
+               case TEST_SWITCH_TO_RUNNABLE_S:
+                       if (vcoreid == 2) {
+                               printf("Core %d trying to request 0/ switch to _S\n", vcoreid);
+                               udelay(3000000, 1995014570);
+                               retval = hart_request(0);
+                               // will only see this if we are scheduled()
+                               printf("Core %d back up! (retval:%d)\n", vcoreid, retval);
+                               printf("And exiting\n");
+                               exit(0);
+                       } 
+                       while(1);
+               case TEST_CRAZY_YIELDS:
+                       udelay(300000*vcoreid, 1995014570);
+                       hart_request(7);
+                       sys_yield();
+                       printf("should  never see me, unless you slip into *_S\n");
+                       break;
+               case TEST_CONCURRENT_SYSCALLS:
+                       for (int i = 0; i < 10; i++) {
+                               for (int j = 0; j < 100; j++)
+                                       sys_null();
+                               printf("Hello from vcore %d, iteration %d\n", vcoreid, i);
+                       }
+                       break;
+       }
+}
diff --git a/tests/null.c b/tests/null.c
new file mode 100644 (file)
index 0000000..64f1885
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdlib.h>
+
+int main(int argc, char** argv)
+{
+       return 0;
+}
diff --git a/tests/proctests.c b/tests/proctests.c
new file mode 100644 (file)
index 0000000..01d6286
--- /dev/null
@@ -0,0 +1,32 @@
+#include <parlib.h>
+#include <stdio.h>
+#include <arch/arch.h>
+
+/* This runs a variety of process tests.  For now, it just tests single-core
+ * yielding among a bunch of processes (which it creates).  It needs the
+ * manager() to call schedule repeatedly (not panic at some weird point) for it
+ * to make progress. */
+int main(int argc, char** argv)
+{
+       int pid = sys_getpid();
+       /* first instance.  this is ghetto, since it relies on being the first proc
+        * ever.  fix this when we can pass arguments.  (TODO) */
+       #define NUM_KIDS 5
+       int child_pid[NUM_KIDS];
+       if (pid == 0x1000) {
+               for (int i = 0; i < NUM_KIDS; i++)
+                       child_pid[i] = sys_proc_create("roslib_proctests");
+               for (int i = 0; i < NUM_KIDS; i++) {
+                       printf("U: attempting to spawn yielders (pid: %d)\n", child_pid[i]);
+                       sys_proc_run(child_pid[i]);
+               }
+       }
+       printf("Process %x, Started and yielding.\n", pid);
+       sys_yield();
+       printf("Process %x, Return from yield1, starting yield2.\n", pid);
+       sys_yield();
+       printf("Process %x, Return from yield2, starting yield3.\n", pid);
+       sys_yield();
+       printf("Process %x, Return from yield3, exiting.\n", pid);
+       return 0;
+}
index 12055f3..bc10c24 100644 (file)
@@ -1,6 +1,23 @@
 #include <stdio.h>
+#include <pthread.h>
+
+int thread_num;
+pthread_t t0;
+pthread_t t1;
+
+__thread int my_id;
+void *thread(void* arg)
+{      
+       my_id = thread_num++;
+       printf("thread %d\n", my_id);
+}
 
 int main(int argc, char** argv) 
 {
-       printf("Goodby cruel world!!\n");
+       thread_num = 0;
+       pthread_create(&t0, NULL, &thread, NULL);
+//     pthread_create(&t1, NULL, &thread, NULL);
+
+       pthread_join(t0, NULL);
+//     pthread_join(t1, NULL);
 } 
diff --git a/tests/softint.c b/tests/softint.c
new file mode 100644 (file)
index 0000000..c3ae2f5
--- /dev/null
@@ -0,0 +1,14 @@
+// buggy program - causes an illegal software interrupt
+
+int main(int argc, char** argv)
+{
+       // this is a fake page fault.  it can only be used if the DPL is 3
+       // if the DPL = 0, this causes a general prot fault, not a PF
+       asm volatile("int $14");
+
+       // this is a real page fault.  volatile, so the compiler doesn't remove it
+       // this will cause a PF regardless of DPL, since it's a real PF.
+       //volatile int x = *((int*)0xc0000000);
+       return 0;
+}
+
diff --git a/tests/spawn.c b/tests/spawn.c
new file mode 100644 (file)
index 0000000..ad1bb35
--- /dev/null
@@ -0,0 +1,38 @@
+
+#include <stdio.h>
+#include <parlib.h>
+
+int main(int argc, char** argv)
+{
+       #if 0
+       /* try some bad combos */
+       int pid = sys_proc_create("garbagexxx");
+       printf("Garbage pid result: %d\n", pid);
+
+       error_t err = sys_proc_run(2342);
+       printf("sys_proc_run(2342) error: %e\n", err);
+
+       err = sys_proc_run(-1);
+       cprintf("sys_proc_run(-1) error: %e\n", err);
+       #endif
+
+       #define NUM_KIDS 5
+       int child_pid[NUM_KIDS];
+       #if 0
+       printf("U: attempting to create hello(s)\n");
+       for (int i = 0; i < NUM_KIDS; i++)
+               child_pid[i] = sys_proc_create("roslib_hello");
+
+       for (int i = 0; i < NUM_KIDS; i++) {
+               cprintf("U: attempting to run hello (pid: %d)\n", child_pid[i]);
+               sys_proc_run(child_pid[i]);
+       }
+       #endif
+       printf("U: attempting to create and run hello\n");
+       child_pid[0] = sys_proc_create("roslib_hello");
+       sys_proc_run(child_pid[0]);
+       printf("U: attempting to create and run mhello\n");
+       child_pid[1] = sys_proc_create("roslib_mhello");
+       sys_proc_run(child_pid[1]);
+       return 0;
+}
diff --git a/tests/testbss.c b/tests/testbss.c
new file mode 100644 (file)
index 0000000..1dba334
--- /dev/null
@@ -0,0 +1,29 @@
+// test reads and writes to a large bss
+
+#include <stdint.h>
+#include <stdio.h>
+#include <rassert.h>
+
+#define ARRAYSIZE (1024*1024)
+
+uint32_t bigarray[ARRAYSIZE];
+
+int main(int argc, char** argv)
+{
+       int i;
+
+       printf("Making sure bss works right...\n");
+       for (i = 0; i < ARRAYSIZE; i++)
+               if (bigarray[i] != 0)
+                       panic("bigarray[%d] isn't cleared!\n", i);
+       for (i = 0; i < ARRAYSIZE; i++)
+               bigarray[i] = i;
+       for (i = 0; i < ARRAYSIZE; i++)
+               if (bigarray[i] != i)
+                       panic("bigarray[%d] didn't hold its value!\n", i);
+
+       printf("Yes, good.  Now doing a wild write off the end...\n");
+       bigarray[ARRAYSIZE+1024] = 0;
+       panic("SHOULD HAVE TRAPPED!!!");
+       return 0;
+}
index 466118a..03984ee 100644 (file)
@@ -2,4 +2,5 @@ USER_DIR := $(TOP_DIR)/user
 USER_CFLAGS += -std=gnu99 -I$(USER_DIR)/include
 
 include $(USER_DIR)/parlib/Makefrag
+include $(USER_DIR)/pthread/Makefrag
 
index af2a6d2..6f82ad3 100644 (file)
@@ -57,6 +57,7 @@ int hart_self();
 void hart_relax();
 int hart_swap(int* addr, int val);
 
+int hart_init();
 int hart_request(size_t k);
 void hart_yield();
 size_t hart_max_harts();
index c05a5c3..3f5e1dd 100644 (file)
@@ -23,22 +23,26 @@ enum {
 
 ssize_t     sys_cputs(const uint8_t *s, size_t len);
 uint16_t    sys_cgetc(void);
+int         sys_null(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);
+/* Process Management */
+int         sys_getpid(void);
+int         sys_proc_destroy(int pid, int exitcode);
+void        sys_yield(void);
+int         sys_proc_create(char* path);
+int         sys_proc_run(int pid);
 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);
+ssize_t     sys_resource_req(int type, size_t amt_max, size_t amt_min, 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);
diff --git a/user/include/rassert.h b/user/include/rassert.h
new file mode 100644 (file)
index 0000000..6e6e1e9
--- /dev/null
@@ -0,0 +1,18 @@
+/* See COPYRIGHT for copyright information. */
+
+#ifndef ROS_INC_ASSERT_H
+#define ROS_INC_ASSERT_H
+
+void _warn(const char*, int, const char*, ...);
+void _panic(const char*, int, const char*, ...) __attribute__((noreturn));
+
+#define warn(...) _warn(__FILE__, __LINE__, __VA_ARGS__)
+#define panic(...) _panic(__FILE__, __LINE__, __VA_ARGS__)
+
+#define assert(x)              \
+       do { if (!(x)) panic("assertion failed: %s", #x); } while (0)
+
+// static_assert(x) will generate a compile-time error if 'x' is false.
+#define static_assert(x)       switch (x) case 0: case (x):
+
+#endif /* !ROS_INC_ASSERT_H */
index 0c42793..9023b0d 100644 (file)
@@ -7,18 +7,16 @@
 USER_PARLIB_DIR = $(USER_DIR)/parlib
 USER_PARLIB_CFLAGS += $(USER_CFLAGS)
 OBJDIRS += $(USER_PARLIB_DIR)
+ROS_USER_LIBS += $(OBJDIR)/$(USER_PARLIB_DIR)/libparlib.a
 
-# 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
+                 $(USER_PARLIB_DIR)/hart.c \
+                 $(USER_PARLIB_DIR)/panic.c \
+                 $(USER_PARLIB_DIR)/syscall.c 
 
 # Only build files if they exist.
-PARLIB_SRCFILES := $(wildcard $(PARLIB_SRCFILES))
+USER_PARLIB_SRCFILES := $(wildcard $(USER_PARLIB_SRCFILES))
 
 USER_PARLIB_OBJFILES  := $(patsubst $(USER_PARLIB_DIR)/%.c, \
                              $(OBJDIR)/$(USER_PARLIB_DIR)/%.o, \
@@ -27,7 +25,7 @@ USER_PARLIB_OBJFILES  := $(patsubst $(USER_PARLIB_DIR)/%.S, \
                              $(OBJDIR)/$(USER_PARLIB_DIR)/%.o, \
                              $(USER_PARLIB_OBJFILES))
 
-USER_PARLIB_LDDEPENDS := $(PARLIB_OBJFILES) 
+USER_PARLIB_LDDEPENDS := $(USER_PARLIB_OBJFILES)
 
 $(OBJDIR)/$(USER_PARLIB_DIR)/%.o: $(USER_PARLIB_DIR)/%.c
        @echo + cc [USER PARLIB] $<
@@ -39,15 +37,8 @@ $(OBJDIR)/$(USER_PARLIB_DIR)/%.o: $(USER_PARLIB_DIR)/%.S
        @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] $@
+$(OBJDIR)/$(USER_PARLIB_DIR)/libparlib.a: $(USER_PARLIB_LDDEPENDS)
+       @echo + ar [USER PARLIB] $@
        @mkdir -p $(@D)
-       $(V)$(CC) -shared -Wl,-soname,$(@F) -o $@ $(USER_PARLIB_OBJFILES) 2>/dev/null
+       $(V)$(AR) r $@ $(USER_PARLIB_OBJFILES) 2>/dev/null
 
-pthreads:
-       @echo $(OBJDIR)/$(USER_PARLIB_DIR)/libparlib.a  
index 54bfe3f..ac3a79f 100644 (file)
@@ -5,6 +5,14 @@
 #include <unistd.h>
 #include <stdlib.h>
 
+// Only need in this file because _dl_allocate and friends are
+//  internal functions in glibc
+# ifdef __i386__
+#  define internal_function   __attribute ((regparm (3), stdcall))
+# else
+#  define internal_function
+# endif
+
 static size_t _current_harts = 1;
 static hart_lock_t _hart_lock = HART_LOCK_INIT;
 
@@ -12,7 +20,7 @@ extern void** hart_thread_control_blocks;
 
 static void hart_free_tls(int id)
 {
-       extern void _dl_deallocate_tls (void *tcb, bool dealloc_tcb);
+       extern void _dl_deallocate_tls (void *tcb, bool dealloc_tcb) internal_function;
        if(hart_thread_control_blocks[id])
        {
                _dl_deallocate_tls(hart_thread_control_blocks[id],true);
@@ -22,11 +30,16 @@ static void hart_free_tls(int id)
 
 static int hart_allocate_tls(int id)
 {
-       extern void *_dl_allocate_tls (void *mem);
+       #include <stdio.h>
+       extern void *_dl_allocate_tls (void *mem) internal_function;
        // 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)
+
+       printf("About to allocate tls\n");
+       void* tls = _dl_allocate_tls(NULL);
+       printf("Allocated tls: %p\n", tls);
+       if((hart_thread_control_blocks[id] = tls) == NULL)
        {
                errno = ENOMEM;
                return -1;
@@ -54,7 +67,7 @@ static int hart_allocate_stack(int id)
        return 0;
 }
 
-static int hart_init()
+int hart_init()
 {
        static int initialized = 0;
        if(initialized)
@@ -95,7 +108,7 @@ int hart_request(size_t k)
                        goto fail;
        }
 
-       if((ret = sys_resource_req(0,_current_harts+k,0)) == 0)
+       if((ret = sys_resource_req(0,_current_harts+k,0,0)) == 0)
        {
                _current_harts += k;
                goto out;
diff --git a/user/parlib/panic.c b/user/parlib/panic.c
new file mode 100644 (file)
index 0000000..2f7b105
--- /dev/null
@@ -0,0 +1,31 @@
+
+#include <arch/arch.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+char *argv0;
+
+/*
+ * Panic is called on unresolvable fatal errors.
+ * It prints "panic: <message>", then causes a breakpoint exception,
+ * which causes ROS to enter the ROS kernel monitor.
+ */
+void
+_panic(const char *file, int line, const char *fmt,...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+
+       // Print the panic message
+       if (argv0)
+               printf("%s: ", argv0);
+       printf("user panic at %s:%d: ", file, line);
+       vprintf(fmt, ap);
+       printf("\n");
+
+       // Cause a breakpoint exception
+       while (1)
+               breakpoint();
+}
+
index e396f21..aa24fa7 100644 (file)
@@ -32,6 +32,11 @@ uint16_t sys_cgetc(void)
     return ros_syscall(SYS_cgetc, 0, 0, 0, 0, 0);
 }
 
+int sys_null(void)
+{
+    return ros_syscall(SYS_null, 0, 0, 0, 0, 0);
+}
+
 ssize_t sys_shared_page_alloc(void** addr, pid_t p2, 
                               int p1_flags, int p2_flags
                              ) 
@@ -84,9 +89,9 @@ ssize_t sys_eth_read(void* buf, size_t len)
 }
 
 /* Request resources from the kernel.  Flags in ros/resource.h. */
-ssize_t sys_resource_req(int type, size_t amount, uint32_t flags)
+ssize_t sys_resource_req(int type, size_t amt_max, size_t amt_min, uint32_t flags)
 {
-       return ros_syscall(SYS_resource_req, type, amount, flags, 0, 0);
+       return ros_syscall(SYS_resource_req, type, amt_max, amt_min, flags, 0);
 }
 
 void sys_reboot()
@@ -99,6 +104,16 @@ void sys_yield()
        ros_syscall(SYS_yield,0,0,0,0,0);
 }
 
+int sys_proc_create(char* path)
+{
+       return ros_syscall(SYS_proc_create, (uintreg_t)path, 0, 0, 0, 0);
+}
+
+int sys_proc_run(int pid)
+{
+       return ros_syscall(SYS_proc_run, pid, 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
diff --git a/user/pthread/Makefrag b/user/pthread/Makefrag
new file mode 100644 (file)
index 0000000..54bb4bd
--- /dev/null
@@ -0,0 +1,43 @@
+# 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_PTHREAD_DIR = $(USER_DIR)/pthread
+USER_PTHREAD_CFLAGS += $(USER_CFLAGS)
+OBJDIRS += $(USER_PTHREAD_DIR)
+ROS_USER_LIBS += $(OBJDIR)/$(USER_PTHREAD_DIR)/libpthread.a
+
+USER_PTHREAD_SRCFILES := \
+                 $(USER_PARLIB_DIR)/pthread.c \
+                 $(USER_PARLIB_DIR)/hart.c \
+                 $(USER_PARLIB_DIR)/syscall.c 
+
+# Only build files if they exist.
+USER_PTHREAD_SRCFILES := $(wildcard $(USER_PTHREAD_SRCFILES))
+
+USER_PTHREAD_OBJFILES  := $(patsubst $(USER_PARLIB_DIR)/%.c, \
+                             $(OBJDIR)/$(USER_PTHREAD_DIR)/%.o, \
+                             $(USER_PTHREAD_SRCFILES))
+USER_PTHREAD_OBJFILES  := $(patsubst $(USER_PARLIB_DIR)/%.S, \
+                             $(OBJDIR)/$(USER_PTHREAD_DIR)/%.o, \
+                             $(USER_PTHREAD_OBJFILES))
+
+USER_PTHREAD_LDDEPENDS := $(USER_PTHREAD_OBJFILES)
+
+$(OBJDIR)/$(USER_PTHREAD_DIR)/%.o: $(USER_PARLIB_DIR)/%.c
+       @echo + cc [USER PTHREAD] $<
+       @mkdir -p $(@D)
+       $(V)$(CC) $(USER_PTHREAD_CFLAGS) -c -o $@ $<
+
+$(OBJDIR)/$(USER_PTHREAD_DIR)/%.o: $(USER_PTHREAD_DIR)/%.S
+       @echo + as [USER PTHREAD] $<
+       @mkdir -p $(@D)
+       $(V)$(CC) $(USER_PTHREAD_CFLAGS) -D__ASSEMBLER__ -c -o $@ $<
+
+$(OBJDIR)/$(USER_PTHREAD_DIR)/libpthread.a: $(USER_PTHREAD_LDDEPENDS)
+       @echo + ar [USER PTHREAD] $@
+       @mkdir -p $(@D)
+       $(V)$(AR) r $@ $(USER_PTHREAD_OBJFILES) 2>/dev/null
+