Major overhaul to testing infrastructure
authorKevin Klues <klueska@cs.berkeley.edu>
Sat, 3 May 2014 00:46:10 +0000 (17:46 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 5 May 2014 23:47:42 +0000 (16:47 -0700)
20 files changed:
Makefile
kern/Kconfig.testing
kern/include/ktest.h [new file with mode: 0644]
kern/include/ros/common.h
kern/src/Kbuild
kern/src/ktest.c [new file with mode: 0644]
kern/src/manager.c
kern/src/pb_ktests.c [new file with mode: 0644]
kern/src/tests_pb_kernel.c [deleted file]
tests/Makefile
tools/jenkins/launcher.sh
tools/jenkins/utils/test_reporter.py
user/tests/Makefile [deleted file]
user/tests/example.c [deleted file]
user/tests/include/testing.h [deleted file]
user/tests/runall.sh [deleted file]
user/utest/Makefile [new file with mode: 0644]
user/utest/example.c [new file with mode: 0644]
user/utest/include/utest.h [new file with mode: 0644]
user/utest/runall.sh [new file with mode: 0644]

index f1df434..7a7967c 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -564,6 +564,10 @@ tests/: tests
 tests: install-libs
        @$(MAKE) -f tests/Makefile
 
+PHONY += utest
+utest: $(user-dirs)
+       @cd user/$@ && $(MAKE) 
+
 testclean:
        @$(MAKE) -f tests/Makefile clean
 
@@ -574,14 +578,20 @@ XCC_SO_FILES = $(addprefix $(XCC_TARGET_ROOT)/lib/, *.so*)
 $(OBJDIR)/.dont-force-fill-kfs:
        $(Q)rm -rf $(addprefix $(FIRST_KFS_PATH)/lib/, $(notdir $(XCC_SO_FILES)))
        @echo "Cross Compiler 'so' files removed from KFS"
-       @$(MAKE) -f tests/Makefile unfill-kfs
+       @$(MAKE) -f tests/Makefile uninstall
+       @echo "Apps from /test removed from KFS"
+       @cd user/utest && $(MAKE) uninstall
+       @echo "User space tests removed from KFS"
        @touch $(OBJDIR)/.dont-force-fill-kfs
 
 fill-kfs: $(OBJDIR)/.dont-force-fill-kfs install-libs
        @mkdir -p $(FIRST_KFS_PATH)/lib
        $(Q)cp -uP $(XCC_SO_FILES) $(FIRST_KFS_PATH)/lib
        @echo "Cross Compiler 'so' files installed to KFS"
-       @$(MAKE) -f tests/Makefile fill-kfs
+       @$(MAKE) -f tests/Makefile install
+       @echo "Apps from /test installed to KFS"
+       @cd user/utest && $(MAKE) install
+       @echo "User space tests installed to KFS"
 
 # Use doxygen to make documentation for ROS (Untested since 2010 or so)
 doxygen-dir := $(CUR_DIR)/Documentation/doxygen
index 4787b5d..6d9d239 100644 (file)
 menu "Testing"
 
-menuconfig POSTBOOT_KERNEL_TESTING
+menuconfig KERNEL_POSTBOOT_TESTING
     bool "Post-boot kernel testing"
     default n
     help
         Run unit tests for after the kernel has booted.
 
 config TEST_ipi_sending
-    depends on POSTBOOT_KERNEL_TESTING && X86
+    depends on KERNEL_POSTBOOT_TESTING && X86
     bool "IPI sending test"
     default n
     help
         Run the ipi_sending test
 
 config TEST_pic_reception
-    depends on POSTBOOT_KERNEL_TESTING && X86
+    depends on KERNEL_POSTBOOT_TESTING && X86
     bool "PIC reception test"
     default n
     help
         Run the pic_reception
 
 config TEST_ioapic_pit_reroute 
-    depends on POSTBOOT_KERNEL_TESTING && X86
+    depends on KERNEL_POSTBOOT_TESTING && X86
     bool "IOAPIC PIT reroute test"
     default n
     help
         Run the ioapic_pit_reroute test
 
 config TEST_lapic_status_bit
-    depends on POSTBOOT_KERNEL_TESTING && X86
+    depends on KERNEL_POSTBOOT_TESTING && X86
     bool "LAPIC status bit test"
     default n
     help
         Run the lapic_status_bit
 
 config TEST_pit
-    depends on POSTBOOT_KERNEL_TESTING && X86
+    depends on KERNEL_POSTBOOT_TESTING && X86
     bool "PIT test"
     default n
     help
         Run the pit test
 
 config TEST_circ_buffer
-    depends on POSTBOOT_KERNEL_TESTING && X86
+    depends on KERNEL_POSTBOOT_TESTING && X86
     bool "Circular buffer test"
     default n
     help
         Run the circ_buffer test
 
 config TEST_kernel_messages
-    depends on POSTBOOT_KERNEL_TESTING && X86
+    depends on KERNEL_POSTBOOT_TESTING && X86
     bool "Kernel messages test"
     default n
     help
         Run the kernel_messages test
 
 config TEST_page_coloring
-    depends on POSTBOOT_KERNEL_TESTING && PAGE_COLORING
+    depends on KERNEL_POSTBOOT_TESTING && PAGE_COLORING
     bool "Page coloring test"
     default n
     help
         Run the page_coloring test
 
 config TEST_color_alloc
-    depends on POSTBOOT_KERNEL_TESTING && PAGE_COLORING
+    depends on KERNEL_POSTBOOT_TESTING && PAGE_COLORING
     bool "Color allocation test"
     default n
     help
         Run the color_alloc test
 
 config TEST_print_info
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "Print info test"
     default n
     help
         Run the print_info test
 
 config TEST_barrier
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "Barrier test"
     default n
     help
         Run the barrier test
 
 config TEST_interrupts_irqsave
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "Interrupts irqsave test"
     default y
     help
         Run the interrupts_irqsave test
 
 config TEST_bitmasks
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "Bitmasks test"
     default y
     help
         Run the bitmasks test
 
 config TEST_checklists
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "Checklists test"
     default n
     help
         Run the checklists test
 
 config TEST_smp_call_functions
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "SMP call functions test"
     default n
     help
         Run the smp_call_functions test
 
 config TEST_slab
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "Slab test"
     default n
     help
         Run the slab test
 
 config TEST_kmalloc
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "Kmalloc test"
     default n
     help
         Run the kmalloc test
 
 config TEST_hashtable
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "Hashtable test"
     default y
     help
         Run the hashtable test
 
 config TEST_bcq
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "BCQ test"
     default n
     help
         Run the bcq test
 
 config TEST_ucq
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "UCQ test"
     default n
     help
         Run the ucq test
 
 config TEST_vm_regions
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "VM regions test"
     default y
     help
         Run the vm_regions test
 
 config TEST_radix_tree
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "Radix Tree test"
     default y
     help
         Run the radix_tree test
 
 config TEST_random_fs
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "Random FS test"
     default n
     help
         Run the random_fs test
 
 config TEST_kthreads
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "Kthreads test"
     default n
     help
         Run the kthreads test
 
 config TEST_kref
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "Kref test"
     default n
     help
         Run the kref test
 
 config TEST_atomics
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "Atomics test"
     default y
     help
         Run the atomics test
 
 config TEST_abort_halt
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "Abort halt test"
     default n
     help
         Run the abort_halt test
 
 config TEST_cv
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "Condition Variable test"
     default n
     help
         Run the cv test
 
 config TEST_memset
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "Memset test"
     default y
     help
         Run the memset test
 
 config TEST_setjmp
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "Setjmp test"
     default n
     help
         Run the setjmp test
 
 config TEST_apipe
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "Apipe test"
     default n
     help
         Run the apipe test
 
 config TEST_rwlock
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "Rwlock test"
     default n
     help
         Run the rwlock test
 
 config TEST_rv
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "Rendezvous test"
     default n
     help
         Run the rv test
 
 config TEST_alarm
-    depends on POSTBOOT_KERNEL_TESTING
+    depends on KERNEL_POSTBOOT_TESTING
     bool "Alarm test"
     default n
     help
@@ -253,7 +253,7 @@ menuconfig USERSPACE_TESTING
 config USERSPACE_TESTING_SCRIPT
     depends on USERSPACE_TESTING
     string "Path to test launcher script."
-    default /bin/tests/user/runall.sh
+    default /bin/tests/utest/runall.sh
     help
         Run userspace unit tests from the specified path. 
 
diff --git a/kern/include/ktest.h b/kern/include/ktest.h
new file mode 100644 (file)
index 0000000..a3d46ac
--- /dev/null
@@ -0,0 +1,73 @@
+#ifndef ROS_INC_KTEST_H
+#define ROS_INC_KTEST_H
+
+/*
+ * Header file with infrastructure needed for kernel unit tests:
+ *  - Assertion functions.
+ *  - Test structures.
+ */
+
+#include <common.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <kmalloc.h>
+#include <arch/arch.h>
+#include <time.h>
+
+/* Global string used to report info about the last completed test */
+extern char ktest_msg[1024];
+
+/* Macros for assertions. 
+ */
+#define KT_ASSERT(test)                                                          \
+       KT_ASSERT_M("", test)
+
+#define KT_ASSERT_M(message, test)                                               \
+       do {                                                                         \
+               if (!(test)) {                                                           \
+                       char fmt[] = "Assertion failure in %s() at %s:%d: %s";               \
+                       snprintf(ktest_msg, sizeof(ktest_msg), fmt, __FUNCTION__,            \
+                                __FILE__, __LINE__, message);                               \
+                       return false;                                                        \
+               }                                                                        \
+       } while (0)
+
+struct ktest {
+       char name[256]; // Name of the test function.
+       bool (*func)(void); // Name of the test function, should be equal to 'name'.
+       bool enabled; // Whether to run or not the test.
+};
+
+/* Macro for registering a kernel test. */
+#define KTEST_REG(name, config) \
+       {"test_" #name, test_##name, is_defined(config)}
+
+static void run_ktests(char *suite_name, struct ktest tests[], int num_tests)
+{
+       extern char ktest_msg[];
+       printk("<-- BEGIN_KERNEL_%s_TESTS -->\n", suite_name);
+
+       for (int i=0; i<num_tests; i++) {
+               struct ktest *test = &tests[i];
+               if (test->enabled) {
+                       uint64_t start = read_tsc();
+                       bool result = test->func();
+                       uint64_t end = read_tsc();
+                       uint64_t et_us = tsc2usec(end - start) % 1000000;
+                       uint64_t et_s = tsc2sec(end - start);
+
+                       char fmt[] = "\t%s   [%s](%llu.%06llus)   %s\n";
+                       if (result) {
+                               printk(fmt, "PASSED", test->name, et_s, et_us, "");
+                       } else {
+                               printk(fmt, "FAILED", test->name, et_s, et_us, ktest_msg);
+                       }
+               } else {
+                       printk("\tDISABLED [%s]\n", test->name);
+               }
+       }
+
+       printk("<-- END_KERNEL_%s_TESTS -->\n", suite_name);
+}
+
+#endif // ROS_INC_KTEST_H
index 84bb474..307c7a9 100644 (file)
@@ -46,6 +46,14 @@ typedef unsigned long uintreg_t;
 #define STRINGIFY(s) __STRINGIFY(s)
 #define __STRINGIFY(s) #s
 
+/* A macro for testing if another macro has been #defined or not.  Can be used
+ * wherever you need a boolean defined.  Returns 0 or 1. */
+#define is_defined(macro) is_defined_(macro)
+#define is_defined_test_1 ,
+#define is_defined_(value) is_defined__(is_defined_test_##value, value)
+#define is_defined__(comma, value) is_defined___(comma 1, 0)
+#define is_defined___(_, v, ...) v
+
 // Efficient min and max operations
 #ifdef ROS_KERNEL /* Glibc has their own */
 #define MIN(_a, _b)                                            \
index 4ef02fd..a7054e4 100644 (file)
@@ -45,7 +45,7 @@ obj-y                                         += string.o
 obj-y                                          += strstr.o
 obj-y                                          += syscall.o
 obj-y                                          += sysevent.o
-obj-y                                          += tests.o
+obj-y                                          += ktest.o
 obj-y                                          += time.o
 obj-y                                          += trace.o
 obj-y                                          += trap.o
diff --git a/kern/src/ktest.c b/kern/src/ktest.c
new file mode 100644 (file)
index 0000000..886f911
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Declaration of all the tests to be ran.
+ */
+
+#include <stdbool.h>
+#include <ktest.h>
+#include "pb_ktests.c"
+
+/* Global string used to report info about the last completed test */
+char ktest_msg[1024];
+
+/* Postboot kernel tests declarations. */
+struct ktest pb_ktests[] = {
+#ifdef CONFIG_X86
+       KTEST_REG(ipi_sending,        CONFIG_TEST_ipi_sending),
+       KTEST_REG(pic_reception,      CONFIG_TEST_pic_reception),
+       KTEST_REG(ioapic_pit_reroute, CONFIG_TEST_ioapic_status_bit),
+       KTEST_REG(lapic_status_bit,   CONFIG_TEST_lapic_status_bit),
+       KTEST_REG(pit,                CONFIG_TEST_pit),
+       KTEST_REG(circ_buffer,        CONFIG_TEST_circ_buffer),
+       KTEST_REG(kernel_messages,    CONFIG_TEST_kernel_messages),
+#endif // CONFIG_X86
+#ifdef CONFIG_PAGE_COLORING
+       KTEST_REG(page_coloring,      CONFIG_TEST_page_coloring),
+       KTEST_REG(color_alloc,        CONFIG_TEST_color_alloc),
+#endif // CONFIG_PAGE_COLORING
+       KTEST_REG(print_info,         CONFIG_TEST_print_info),
+       KTEST_REG(barrier,            CONFIG_TEST_barrier),
+       KTEST_REG(interrupts_irqsave, CONFIG_TEST_interrupts_irqsave),
+       KTEST_REG(bitmasks,           CONFIG_TEST_bitmasks),
+       KTEST_REG(checklists,         CONFIG_TEST_checklists),
+       KTEST_REG(smp_call_functions, CONFIG_TEST_smp_call_functions),
+       KTEST_REG(slab,               CONFIG_TEST_slab),
+       KTEST_REG(kmalloc,            CONFIG_TEST_kmalloc),
+       KTEST_REG(hashtable,          CONFIG_TEST_hashtable),
+       KTEST_REG(bcq,                CONFIG_TEST_bcq),
+       KTEST_REG(ucq,                CONFIG_TEST_ucq),
+       KTEST_REG(vm_regions,         CONFIG_TEST_vm_regions),
+       KTEST_REG(radix_tree,         CONFIG_TEST_radix_tree),
+       KTEST_REG(random_fs,          CONFIG_TEST_random_fs),
+       KTEST_REG(kthreads,           CONFIG_TEST_kthreads),
+       KTEST_REG(kref,               CONFIG_TEST_kref),
+       KTEST_REG(atomics,            CONFIG_TEST_atomics),
+       KTEST_REG(abort_halt,         CONFIG_TEST_abort_halt),
+       KTEST_REG(cv,                 CONFIG_TEST_cv),
+       KTEST_REG(memset,             CONFIG_TEST_memset),
+       KTEST_REG(setjmp,             CONFIG_TEST_setjmp),
+       KTEST_REG(apipe,              CONFIG_TEST_apipe),
+       KTEST_REG(rwlock,             CONFIG_TEST_rwlock),
+       KTEST_REG(rv,                 CONFIG_TEST_rv),
+       KTEST_REG(alarm,              CONFIG_TEST_alarm)
+};
+int num_pb_ktests = sizeof(pb_ktests) / sizeof(struct ktest);
+
index 9b23c3a..49309ed 100644 (file)
@@ -22,7 +22,7 @@
 #include <process.h>
 #include <schedule.h>
 #include <syscall.h>
-#include <test_infrastructure.h>
+#include <ktest.h>
 #include <kfs.h>
 #include <stdio.h>
 #include <time.h>
 #include <time.h>
 #include <ros/arch/membar.h>
 
-char *kern_test_msg; // Variable defined in test_infrastructure.h.
-
-
-void postboot_kernel_tests(void)
-{
-       printk("\nRunning %d postboot Kernel tests:\n", 
-                  num_pb_kernel_tests);
-
-       // Do not remove this line, it is being used by Jenkins.
-       printk("<-- BEGIN_KERNEL_POSTBOOT_TESTS -->\n");
-       for (int i=0; i<num_pb_kernel_tests; i++) {
-               struct pb_kernel_test *test = &pb_kernel_tests[i];
-               if (test->enabled) {
-                       uint64_t start = read_tsc();
-                       bool result = test->func();
-                       uint64_t end = read_tsc();
-                       uint64_t et_us = tsc2usec(end - start) % 1000000;
-                       uint64_t et_s = tsc2sec(end - start);
-
-                       if (result) {
-                               printk("\tPASSED   [%s](%llu.%06llus)\n", test->name, et_s, 
-                                      et_us);
-                       } else {
-                               printk("\tFAILED   [%s](%llu.%06llus)  %s\n", test->name, et_s, 
-                                      et_us, kern_test_msg);
-                               kfree(kern_test_msg);
-                       }
-               } else {
-                       printk("\tDISABLED [%s]\n", test->name);
-               }
-       }
-       // Do not remove this line, it is being used by Jenkins.
-       printk("<-- END_KERNEL_POSTBOOT_TESTS -->\n");
-}
-
 /*
  * Currently, if you leave this function by way of proc_run (process_workqueue
  * that proc_runs), you will never come back to where you left off, and the
@@ -76,27 +41,18 @@ void postboot_kernel_tests(void)
  */
 void manager(void)
 {
-       #ifndef DEVELOPER_NAME
-               #define DEVELOPER_NAME brho
-       #endif
-
        // LoL
        #define PASTE(s1,s2) s1 ## s2
        #define MANAGER_FUNC(dev) PASTE(manager_,dev)
 
-       // Run Kernel post boot tests (from tests_postboot_kernel.c).
-       #ifdef CONFIG_POSTBOOT_KERNEL_TESTING
-               postboot_kernel_tests();
+       #if !defined(DEVELOPER_NAME) && \
+           (defined(CONFIG_KERNEL_POSTBOOT_TESTING) || \
+            defined(CONFIG_USERSPACE_TESTING))
+               #define DEVELOPER_NAME jenkins
        #endif
-       // Run userspace tests (from config specified path).
-       #ifdef CONFIG_USERSPACE_TESTING
-       if (strlen(CONFIG_USERSPACE_TESTING_SCRIPT) != 0)
-       {
-               char *usp_args[] = {"bin_run", "ash", CONFIG_USERSPACE_TESTING_SCRIPT};
-               mon_bin_run(3, usp_args, NULL);
-       } else {
-               printk("No user-space launcher file specified.\n");
-       }
+
+       #ifndef DEVELOPER_NAME
+               #define DEVELOPER_NAME brho
        #endif
 
        void MANAGER_FUNC(DEVELOPER_NAME)(void);
@@ -271,6 +227,35 @@ void manager_brho(void)
 #endif
 }
 
+void manager_jenkins()
+{
+       #ifdef CONFIG_KERNEL_POSTBOOT_TESTING
+               extern struct ktest pb_ktests[];
+               extern int num_pb_ktests;
+               run_ktests("POSTBOOT", pb_ktests, num_pb_ktests);
+       #endif
+       // Run userspace tests (from config specified path).
+       #ifdef CONFIG_USERSPACE_TESTING
+       if (strlen(CONFIG_USERSPACE_TESTING_SCRIPT) != 0) {
+               char exec[] = "/bin/ash";
+               char *p_argv[] = {exec, CONFIG_USERSPACE_TESTING_SCRIPT, 0};
+               char *p_envp[] = {"LD_LIBRARY_PATH=/lib", 0};
+
+               struct file *program = do_file_open(exec, 0, 0);
+               struct proc *p = proc_create(program, p_argv, p_envp);
+               proc_wakeup(p);
+               proc_decref(p); /* let go of the reference created in proc_create() */
+               kref_put(&program->f_kref);
+               run_scheduler();
+           // Need a way to wait for p to finish
+       } else {
+               printk("No user-space launcher file specified.\n");
+       }
+       #endif
+       smp_idle();
+       assert(0);
+}
+
 void manager_klueska()
 {
        static struct proc *envs[256];
diff --git a/kern/src/pb_ktests.c b/kern/src/pb_ktests.c
new file mode 100644 (file)
index 0000000..71be1e0
--- /dev/null
@@ -0,0 +1,2120 @@
+/*
+ * Postboot kernel tests: Tests to be ran after boot in kernel mode.
+ * TODO: Some of the tests here may not necessarily be tests to be ran after
+ *       boot. If that is the case, change them in
+ */
+
+#ifdef __SHARC__
+#pragma nosharc
+#endif
+
+#include <arch/mmu.h>
+#include <arch/arch.h>
+#include <bitmask.h>
+#include <smp.h>
+
+#include <ros/memlayout.h>
+#include <ros/common.h>
+#include <ros/bcq.h>
+#include <ros/ucq.h>
+
+#include <atomic.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <testing.h>
+#include <trap.h>
+#include <process.h>
+#include <syscall.h>
+#include <time.h>
+#include <kfs.h>
+#include <multiboot.h>
+#include <pmap.h>
+#include <page_alloc.h>
+#include <pmap.h>
+#include <slab.h>
+#include <kmalloc.h>
+#include <hashtable.h>
+#include <radix.h>
+#include <monitor.h>
+#include <kthread.h>
+#include <schedule.h>
+#include <umem.h>
+#include <ucq.h>
+#include <setjmp.h>
+
+#include <apipe.h>
+#include <rwlock.h>
+#include <rendez.h>
+
+#define l1 (available_caches.l1)
+#define l2 (available_caches.l2)
+#define l3 (available_caches.l3)
+
+#ifdef CONFIG_X86
+
+// TODO: Do test if possible inside this function, and add assertions.
+bool test_ipi_sending(void)
+{
+       int8_t state = 0;
+
+       register_irq(I_TESTING, test_hello_world_handler, NULL,
+                    MKBUS(BusIPI, 0, 0, 0));
+       enable_irqsave(&state);
+       cprintf("\nCORE 0 sending broadcast\n");
+       send_broadcast_ipi(I_TESTING);
+       udelay(3000000);
+       cprintf("\nCORE 0 sending all others\n");
+       send_all_others_ipi(I_TESTING);
+       udelay(3000000);
+       cprintf("\nCORE 0 sending self\n");
+       send_self_ipi(I_TESTING);
+       udelay(3000000);
+       cprintf("\nCORE 0 sending ipi to physical 1\n");
+       send_ipi(0x01, I_TESTING);
+       udelay(3000000);
+       cprintf("\nCORE 0 sending ipi to physical 2\n");
+       send_ipi(0x02, I_TESTING);
+       udelay(3000000);
+       cprintf("\nCORE 0 sending ipi to physical 3\n");
+       send_ipi(0x03, I_TESTING);
+       udelay(3000000);
+       cprintf("\nCORE 0 sending ipi to physical 15\n");
+       send_ipi(0x0f, I_TESTING);
+       udelay(3000000);
+       cprintf("\nCORE 0 sending ipi to logical 2\n");
+       send_group_ipi(0x02, I_TESTING);
+       udelay(3000000);
+       cprintf("\nCORE 0 sending ipi to logical 1\n");
+       send_group_ipi(0x01, I_TESTING);
+       udelay(3000000);
+       cprintf("\nDone!\n");
+       disable_irqsave(&state);
+
+       return true;
+}
+
+// TODO: Refactor to make it return and add assertions.
+// Note this never returns and will muck with any other timer work
+bool test_pic_reception(void)
+{
+       register_irq(IdtPIC + IrqCLOCK, test_hello_world_handler, NULL,
+                    MKBUS(BusISA, 0, 0, 0));
+       pit_set_timer(100,TIMER_RATEGEN); // totally arbitrary time
+       pic_unmask_irq(0, 0);
+       cprintf("PIC1 Mask = 0x%04x\n", inb(PIC1_DATA));
+       cprintf("PIC2 Mask = 0x%04x\n", inb(PIC2_DATA));
+       unmask_lapic_lvt(LAPIC_LVT_LINT0);
+       cprintf("Core %d's LINT0: 0x%08x\n", core_id(), read_mmreg32(LAPIC_LVT_LINT0));
+       enable_irq();
+       while(1);
+
+       return true;
+}
+
+// TODO: Add assertions.
+bool test_ioapic_pit_reroute(void) 
+{
+       register_irq(IdtPIC + IrqCLOCK, test_hello_world_handler, NULL,
+                    MKBUS(BusISA, 0, 0, 0));
+#ifdef CONFIG_ENABLE_MPTABLES
+#warning "not routing the irq"
+       //ioapic_route_irq(0, 3);       
+#endif
+
+       cprintf("Starting pit on core 3....\n");
+       udelay(3000000);
+       pit_set_timer(0xFFFE,TIMER_RATEGEN); // totally arbitrary time
+       
+       udelay(3000000);
+#ifdef CONFIG_ENABLE_MPTABLES
+#warning "NOT unrouting the irq"
+       //ioapic_unroute_irq(0);
+#endif
+       udelay(300000);
+       cprintf("Masked pit. Waiting before return...\n");
+       udelay(3000000);
+
+       return true;
+}
+
+#endif // CONFIG_X86
+
+// TODO: Assert printed info follows the standard (or whatever we want to test).
+bool test_print_info(void)
+{
+       cprintf("\nCORE 0 asking all cores to print info:\n");
+       smp_call_function_all(test_print_info_handler, NULL, 0);
+       cprintf("\nDone!\n");
+       return true;
+}
+
+// TODO: Add assertions. Possibly the way to go is to extract relevant info 
+//       from cache properties and make assertions on the colored pages lists 
+//       based on those.
+// TODO: The test was commented out. Figure out why was it like that and fix it.
+bool test_page_coloring(void) 
+{
+       /*
+       //Print the different cache properties of our machine
+       print_cache_properties("L1", l1);
+       cprintf("\n");
+       print_cache_properties("L2", l2);
+       cprintf("\n");
+       print_cache_properties("L3", l3);
+       cprintf("\n");
+
+       //Print some stats about our memory
+       cprintf("Max Address: %llu\n", MAX_VADDR);
+       cprintf("Num Pages: %u\n", npages);
+
+       //Declare a local variable for allocating pages 
+       page_t* page;
+
+       cprintf("Contents of the page free list:\n");
+       for(int i=0; i<llc_cache->num_colors; i++) {
+               cprintf("  COLOR %d:\n", i);
+               LIST_FOREACH(page, &colored_page_free_list[i], pg_link) {
+                       cprintf("    Page: %d\n", page2ppn(page));
+               }
+       }
+
+       //Run through and allocate all pages through l1_page_alloc
+       cprintf("Allocating from L1 page colors:\n");
+       for(int i=0; i<get_cache_num_page_colors(l1); i++) {
+               cprintf("  COLOR %d:\n", i);
+               while(colored_page_alloc(l1, &page, i) != -ENOMEM)
+                       cprintf("    Page: %d\n", page2ppn(page));
+       }
+
+       //Put all the pages back by reinitializing
+       page_init();
+       
+       //Run through and allocate all pages through l2_page_alloc
+       cprintf("Allocating from L2 page colors:\n");
+       for(int i=0; i<get_cache_num_page_colors(l2); i++) {
+               cprintf("  COLOR %d:\n", i);
+               while(colored_page_alloc(l2, &page, i) != -ENOMEM)
+                       cprintf("    Page: %d\n", page2ppn(page));
+       }
+
+       //Put all the pages back by reinitializing
+       page_init();
+       
+       //Run through and allocate all pages through l3_page_alloc
+       cprintf("Allocating from L3 page colors:\n");
+       for(int i=0; i<get_cache_num_page_colors(l3); i++) {
+               cprintf("  COLOR %d:\n", i);
+               while(colored_page_alloc(l3, &page, i) != -ENOMEM)
+                       cprintf("    Page: %d\n", page2ppn(page));
+       }
+       
+       //Put all the pages back by reinitializing
+       page_init();
+       
+       //Run through and allocate all pages through page_alloc
+       cprintf("Allocating from global allocator:\n");
+       while(upage_alloc(&page) != -ENOMEM)
+               cprintf("    Page: %d\n", page2ppn(page));
+       
+       if(colored_page_alloc(l2, &page, 0) != -ENOMEM)
+               cprintf("Should not get here, all pages should already be gone!\n");
+       cprintf("All pages gone for sure...\n");
+       
+       //Now lets put a few pages back using page_free..
+       cprintf("Reinserting pages via page_free and reallocating them...\n");
+       page_free(&pages[0]);
+       page_free(&pages[15]);
+       page_free(&pages[7]);
+       page_free(&pages[6]);
+       page_free(&pages[4]);
+
+       while(upage_alloc(&page) != -ENOMEM)
+               cprintf("Page: %d\n", page2ppn(page));  
+       
+       page_init();
+       */
+       return true;
+}
+
+// TODO: Add assertions.
+bool test_color_alloc(void) {
+       size_t checkpoint = 0;
+       uint8_t* colors_map = kmalloc(BYTES_FOR_BITMASK(llc_cache->num_colors), 0);
+       cache_color_alloc(l2, colors_map);
+       cache_color_alloc(l3, colors_map);
+       cache_color_alloc(l3, colors_map);
+       cache_color_alloc(l2, colors_map);
+       cache_color_free(llc_cache, colors_map);
+       cache_color_free(llc_cache, colors_map);
+       cache_color_free(llc_cache, colors_map);
+       cache_color_free(llc_cache, colors_map);
+       cache_color_free(llc_cache, colors_map);
+       cache_color_free(llc_cache, colors_map);
+       cache_color_free(llc_cache, colors_map);
+       cache_color_free(llc_cache, colors_map);
+       cache_color_free(llc_cache, colors_map);
+       cache_color_free(llc_cache, colors_map);
+       cache_color_free(llc_cache, colors_map);
+       cache_color_free(llc_cache, colors_map);
+       cache_color_free(llc_cache, colors_map);
+       cache_color_free(llc_cache, colors_map);
+       cache_color_free(llc_cache, colors_map);
+       cache_color_free(llc_cache, colors_map);
+       cache_color_free(l2, colors_map);
+       cache_color_free(llc_cache, colors_map);
+       cache_color_free(llc_cache, colors_map);
+
+print_cache_colors:
+       printk("L1 free colors, tot colors: %d\n", l1->num_colors);
+       PRINT_BITMASK(l1->free_colors_map, l1->num_colors);
+       printk("L2 free colors, tot colors: %d\n", l2->num_colors);
+       PRINT_BITMASK(l2->free_colors_map, l2->num_colors);
+       printk("L3 free colors, tot colors: %d\n", l3->num_colors);
+       PRINT_BITMASK(l3->free_colors_map, l3->num_colors);
+       printk("Process allocated colors\n");
+       PRINT_BITMASK(colors_map, llc_cache->num_colors);
+       printk("test_color_alloc() complete!\n");
+
+       return true;
+}
+
+barrier_t test_cpu_array;
+
+// TODO: Add assertions, try to do everything from within this same function.
+bool test_barrier(void)
+{
+       cprintf("Core 0 initializing barrier\n");
+       init_barrier(&test_cpu_array, num_cpus);
+       cprintf("Core 0 asking all cores to print ids, barrier, rinse, repeat\n");
+       smp_call_function_all(test_barrier_handler, NULL, 0);
+
+       return true;
+}
+
+// TODO: Maybe remove all the printing statements and instead use the 
+//       KT_ASSERT_M macro to include a message on assertions.
+bool test_interrupts_irqsave(void)
+{
+       int8_t state = 0;
+       printd("Testing Nesting Enabling first, turning ints off:\n");
+       disable_irq();
+       printd("Interrupts are: %x\n", irq_is_enabled());
+       KT_ASSERT(!irq_is_enabled());
+       printd("Enabling IRQSave\n");
+       enable_irqsave(&state);
+       printd("Interrupts are: %x\n", irq_is_enabled());
+       KT_ASSERT(irq_is_enabled());
+       printd("Enabling IRQSave Again\n");
+       enable_irqsave(&state);
+       printd("Interrupts are: %x\n", irq_is_enabled());
+       KT_ASSERT(irq_is_enabled());
+       printd("Disabling IRQSave Once\n");
+       disable_irqsave(&state);
+       printd("Interrupts are: %x\n", irq_is_enabled());
+       KT_ASSERT(irq_is_enabled());
+       printd("Disabling IRQSave Again\n");
+       disable_irqsave(&state);
+       printd("Interrupts are: %x\n", irq_is_enabled());
+       KT_ASSERT(!irq_is_enabled());
+       printd("Done.  Should have been 0, 200, 200, 200, 0\n");
+
+       printd("Testing Nesting Disabling first, turning ints on:\n");
+       state = 0;
+       enable_irq();
+       printd("Interrupts are: %x\n", irq_is_enabled());
+       KT_ASSERT(irq_is_enabled());
+       printd("Disabling IRQSave Once\n");
+       disable_irqsave(&state);
+       printd("Interrupts are: %x\n", irq_is_enabled());
+       KT_ASSERT(!irq_is_enabled());
+       printd("Disabling IRQSave Again\n");
+       disable_irqsave(&state);
+       printd("Interrupts are: %x\n", irq_is_enabled());
+       KT_ASSERT(!irq_is_enabled());
+       printd("Enabling IRQSave Once\n");
+       enable_irqsave(&state);
+       printd("Interrupts are: %x\n", irq_is_enabled());
+       KT_ASSERT(!irq_is_enabled());
+       printd("Enabling IRQSave Again\n");
+       enable_irqsave(&state);
+       printd("Interrupts are: %x\n", irq_is_enabled());
+       KT_ASSERT(irq_is_enabled());
+       printd("Done.  Should have been 200, 0, 0, 0, 200 \n");
+
+       state = 0;
+       disable_irq();
+       printd("Ints are off, enabling then disabling.\n");
+       enable_irqsave(&state);
+       printd("Interrupts are: %x\n", irq_is_enabled());
+       KT_ASSERT(irq_is_enabled());
+       disable_irqsave(&state);
+       printd("Interrupts are: %x\n", irq_is_enabled());
+       KT_ASSERT(!irq_is_enabled());
+       printd("Done.  Should have been 200, 0\n");
+
+       state = 0;
+       enable_irq();
+       printd("Ints are on, enabling then disabling.\n");
+       enable_irqsave(&state);
+       printd("Interrupts are: %x\n", irq_is_enabled());
+       KT_ASSERT(irq_is_enabled());
+       disable_irqsave(&state);
+       printd("Interrupts are: %x\n", irq_is_enabled());
+       KT_ASSERT(irq_is_enabled());
+       printd("Done.  Should have been 200, 200\n");
+
+       state = 0;
+       disable_irq();
+       printd("Ints are off, disabling then enabling.\n");
+       disable_irqsave(&state);
+       printd("Interrupts are: %x\n", irq_is_enabled());
+       KT_ASSERT(!irq_is_enabled());
+       enable_irqsave(&state);
+       printd("Interrupts are: %x\n", irq_is_enabled());
+       KT_ASSERT(!irq_is_enabled());
+       printd("Done.  Should have been 0, 0\n");
+
+       state = 0;
+       enable_irq();
+       printd("Ints are on, disabling then enabling.\n");
+       disable_irqsave(&state);
+       printd("Interrupts are: %x\n", irq_is_enabled());
+       KT_ASSERT(!irq_is_enabled());
+       enable_irqsave(&state);
+       printd("Interrupts are: %x\n", irq_is_enabled());
+       KT_ASSERT(irq_is_enabled());
+       printd("Done.  Should have been 0, 200\n");
+
+       disable_irq();
+       return true;
+}
+
+// TODO: Maybe remove PRINT_BITMASK statements and use KT_ASSERT_M instead
+//       somehow.
+bool test_bitmasks(void)
+{
+#define masksize 67
+       DECL_BITMASK(mask, masksize);
+       CLR_BITMASK(mask, masksize);
+//     PRINT_BITMASK(mask, masksize);
+       SET_BITMASK_BIT(mask, 0);
+       SET_BITMASK_BIT(mask, 11);
+       SET_BITMASK_BIT(mask, 17);
+       SET_BITMASK_BIT(mask, masksize-1);
+//     PRINT_BITMASK(mask, masksize);
+       DECL_BITMASK(mask2, masksize);
+       COPY_BITMASK(mask2, mask, masksize);
+//     printk("copy of original mask, should be the same as the prev\n");
+//     PRINT_BITMASK(mask2, masksize);
+       CLR_BITMASK_BIT(mask, 11);
+//     PRINT_BITMASK(mask, masksize);
+       KT_ASSERT_M("Bit 17 should be 1", 1 == GET_BITMASK_BIT(mask, 17));
+       KT_ASSERT_M("Bit 11 should be 0", 0 == GET_BITMASK_BIT(mask, 11));
+       FILL_BITMASK(mask, masksize);
+//     PRINT_BITMASK(mask, masksize);
+       KT_ASSERT_M("Bitmask should not be clear after calling FILL_BITMASK", 
+                   0 == BITMASK_IS_CLEAR(mask,masksize));
+       CLR_BITMASK(mask, masksize);
+//     PRINT_BITMASK(mask, masksize);
+       KT_ASSERT_M("Bitmask should be clear after calling CLR_BITMASK", 
+                   1 == BITMASK_IS_CLEAR(mask,masksize));
+       return true;
+}
+
+checklist_t *RO the_global_list;
+
+static void test_checklist_handler(struct hw_trapframe *hw_tf, void *data)
+{
+       udelay(1000000);
+       cprintf("down_checklist(%x,%d)\n", the_global_list, core_id());
+       down_checklist(the_global_list);
+}
+
+// TODO: Add assertions
+bool test_checklists(void)
+{
+       INIT_CHECKLIST(a_list, MAX_NUM_CPUS);
+       the_global_list = &a_list;
+       printk("Checklist Build, mask size: %d\n", sizeof(a_list.mask.bits));
+       printk("mask\n");
+       PRINT_BITMASK(a_list.mask.bits, a_list.mask.size);
+       SET_BITMASK_BIT(a_list.mask.bits, 11);
+       printk("Set bit 11\n");
+       PRINT_BITMASK(a_list.mask.bits, a_list.mask.size);
+
+       CLR_BITMASK(a_list.mask.bits, a_list.mask.size);
+       INIT_CHECKLIST_MASK(a_mask, MAX_NUM_CPUS);
+       FILL_BITMASK(a_mask.bits, num_cpus);
+       //CLR_BITMASK_BIT(a_mask.bits, core_id());
+       //SET_BITMASK_BIT(a_mask.bits, 1);
+       //printk("New mask (1, 17, 25):\n");
+       printk("Created new mask, filled up to num_cpus\n");
+       PRINT_BITMASK(a_mask.bits, a_mask.size);
+       printk("committing new mask\n");
+       commit_checklist_wait(&a_list, &a_mask);
+       printk("Old mask (copied onto):\n");
+       PRINT_BITMASK(a_list.mask.bits, a_list.mask.size);
+       //smp_call_function_single(1, test_checklist_handler, 0, 0);
+
+       smp_call_function_all(test_checklist_handler, NULL, 0);
+
+       printk("Waiting on checklist\n");
+       waiton_checklist(&a_list);
+       printk("Done Waiting!\n");
+
+       return true;
+}
+
+atomic_t a, b, c;
+
+static void test_incrementer_handler(struct hw_trapframe *tf, void *data)
+{
+       assert(data);
+       atomic_inc(data);
+}
+
+static void test_null_handler(struct hw_trapframe *tf, void *data)
+{
+       asm volatile("nop");
+}
+
+// TODO: Add assertions.
+bool test_smp_call_functions(void)
+{
+       int i;
+       atomic_init(&a, 0);
+       atomic_init(&b, 0);
+       atomic_init(&c, 0);
+       handler_wrapper_t *waiter0 = 0, *waiter1 = 0, *waiter2 = 0, *waiter3 = 0,
+                         *waiter4 = 0, *waiter5 = 0;
+       uint8_t me = core_id();
+       printk("\nCore %d: SMP Call Self (nowait):\n", me);
+       printk("---------------------\n");
+       smp_call_function_self(test_hello_world_handler, NULL, 0);
+       printk("\nCore %d: SMP Call Self (wait):\n", me);
+       printk("---------------------\n");
+       smp_call_function_self(test_hello_world_handler, NULL, &waiter0);
+       smp_call_wait(waiter0);
+       printk("\nCore %d: SMP Call All (nowait):\n", me);
+       printk("---------------------\n");
+       smp_call_function_all(test_hello_world_handler, NULL, 0);
+       printk("\nCore %d: SMP Call All (wait):\n", me);
+       printk("---------------------\n");
+       smp_call_function_all(test_hello_world_handler, NULL, &waiter0);
+       smp_call_wait(waiter0);
+       printk("\nCore %d: SMP Call All-Else Individually, in order (nowait):\n", me);
+       printk("---------------------\n");
+       for(i = 1; i < num_cpus; i++)
+               smp_call_function_single(i, test_hello_world_handler, NULL, 0);
+       printk("\nCore %d: SMP Call Self (wait):\n", me);
+       printk("---------------------\n");
+       smp_call_function_self(test_hello_world_handler, NULL, &waiter0);
+       smp_call_wait(waiter0);
+       printk("\nCore %d: SMP Call All-Else Individually, in order (wait):\n", me);
+       printk("---------------------\n");
+       for(i = 1; i < num_cpus; i++)
+       {
+               smp_call_function_single(i, test_hello_world_handler, NULL, &waiter0);
+               smp_call_wait(waiter0);
+       }
+       printk("\nTesting to see if any IPI-functions are dropped when not waiting:\n");
+       printk("A: %d, B: %d, C: %d (should be 0,0,0)\n", atomic_read(&a), atomic_read(&b), atomic_read(&c));
+       smp_call_function_all(test_incrementer_handler, &a, 0);
+       smp_call_function_all(test_incrementer_handler, &b, 0);
+       smp_call_function_all(test_incrementer_handler, &c, 0);
+       // if i can clobber a previous IPI, the interleaving might do it
+       smp_call_function_single(1 % num_cpus, test_incrementer_handler, &a, 0);
+       smp_call_function_single(2 % num_cpus, test_incrementer_handler, &b, 0);
+       smp_call_function_single(3 % num_cpus, test_incrementer_handler, &c, 0);
+       smp_call_function_single(4 % num_cpus, test_incrementer_handler, &a, 0);
+       smp_call_function_single(5 % num_cpus, test_incrementer_handler, &b, 0);
+       smp_call_function_single(6 % num_cpus, test_incrementer_handler, &c, 0);
+       smp_call_function_all(test_incrementer_handler, &a, 0);
+       smp_call_function_single(3 % num_cpus, test_incrementer_handler, &c, 0);
+       smp_call_function_all(test_incrementer_handler, &b, 0);
+       smp_call_function_single(1 % num_cpus, test_incrementer_handler, &a, 0);
+       smp_call_function_all(test_incrementer_handler, &c, 0);
+       smp_call_function_single(2 % num_cpus, test_incrementer_handler, &b, 0);
+       // wait, so we're sure the others finish before printing.
+       // without this, we could (and did) get 19,18,19, since the B_inc
+       // handler didn't finish yet
+       smp_call_function_self(test_null_handler, NULL, &waiter0);
+       // need to grab all 5 handlers (max), since the code moves to the next free.
+       smp_call_function_self(test_null_handler, NULL, &waiter1);
+       smp_call_function_self(test_null_handler, NULL, &waiter2);
+       smp_call_function_self(test_null_handler, NULL, &waiter3);
+       smp_call_function_self(test_null_handler, NULL, &waiter4);
+       smp_call_wait(waiter0);
+       smp_call_wait(waiter1);
+       smp_call_wait(waiter2);
+       smp_call_wait(waiter3);
+       smp_call_wait(waiter4);
+       printk("A: %d, B: %d, C: %d (should be 19,19,19)\n", atomic_read(&a), atomic_read(&b), atomic_read(&c));
+       printk("Attempting to deadlock by smp_calling with an outstanding wait:\n");
+       smp_call_function_self(test_null_handler, NULL, &waiter0);
+       printk("Sent one\n");
+       smp_call_function_self(test_null_handler, NULL, &waiter1);
+       printk("Sent two\n");
+       smp_call_wait(waiter0);
+       printk("Wait one\n");
+       smp_call_wait(waiter1);
+       printk("Wait two\n");
+       printk("\tMade it through!\n");
+       printk("Attempting to deadlock by smp_calling more than are available:\n");
+       printk("\tShould see an Insufficient message and a kernel warning.\n");
+       if (smp_call_function_self(test_null_handler, NULL, &waiter0))
+               printk("\tInsufficient handlers to call function (0)\n");
+       if (smp_call_function_self(test_null_handler, NULL, &waiter1))
+               printk("\tInsufficient handlers to call function (1)\n");
+       if (smp_call_function_self(test_null_handler, NULL, &waiter2))
+               printk("\tInsufficient handlers to call function (2)\n");
+       if (smp_call_function_self(test_null_handler, NULL, &waiter3))
+               printk("\tInsufficient handlers to call function (3)\n");
+       if (smp_call_function_self(test_null_handler, NULL, &waiter4))
+               printk("\tInsufficient handlers to call function (4)\n");
+       if (smp_call_function_self(test_null_handler, NULL, &waiter5))
+               printk("\tInsufficient handlers to call function (5)\n");
+       smp_call_wait(waiter0);
+       smp_call_wait(waiter1);
+       smp_call_wait(waiter2);
+       smp_call_wait(waiter3);
+       smp_call_wait(waiter4);
+       smp_call_wait(waiter5);
+       printk("\tMade it through!\n");
+
+       printk("Done\n");
+
+       return true;
+}
+
+#ifdef CONFIG_X86
+// TODO: Fix the KT_ASSERTs
+bool test_lapic_status_bit(void)
+{
+       register_irq(I_TESTING, test_incrementer_handler, &a,
+                    MKBUS(BusIPI, 0, 0, 0));
+       #define NUM_IPI 100000
+       atomic_set(&a,0);
+       printk("IPIs received (should be 0): %d\n", a);
+       // KT_ASSERT_M("IPIs received should be 0", (0 == a));
+       for(int i = 0; i < NUM_IPI; i++) {
+               send_ipi(7, I_TESTING);
+               lapic_wait_to_send();
+       }
+       // need to wait a bit to let those IPIs get there
+       udelay(5000000);
+       printk("IPIs received (should be %d): %d\n", a, NUM_IPI);
+       // KT_ASSERT_M("IPIs received should be 100000", (NUM_IPI == a));
+       // hopefully that handler never fires again.  leaving it registered for now.
+
+       return true;
+}
+#endif // CONFIG_X86
+
+/************************************************************/
+/* ISR Handler Functions */
+
+void test_hello_world_handler(struct hw_trapframe *hw_tf, void *data)
+{
+       int trapno;
+       #if defined(CONFIG_X86)
+       trapno = hw_tf->tf_trapno;
+       #else
+       trapno = 0;
+       #endif
+
+       cprintf("Incoming IRQ, ISR: %d on core %d with tf at %p\n",
+               trapno, core_id(), hw_tf);
+}
+
+spinlock_t print_info_lock = SPINLOCK_INITIALIZER_IRQSAVE;
+
+void test_print_info_handler(struct hw_trapframe *hw_tf, void *data)
+{
+       uint64_t tsc = read_tsc();
+
+       spin_lock_irqsave(&print_info_lock);
+       cprintf("----------------------------\n");
+       cprintf("This is Core %d\n", core_id());
+       cprintf("Timestamp = %lld\n", tsc);
+#ifdef CONFIG_X86
+       cprintf("Hardware core %d\n", hw_core_id());
+       cprintf("MTRR_DEF_TYPE = 0x%08x\n", read_msr(IA32_MTRR_DEF_TYPE));
+       cprintf("MTRR Phys0 Base = 0x%016llx, Mask = 0x%016llx\n",
+               read_msr(0x200), read_msr(0x201));
+       cprintf("MTRR Phys1 Base = 0x%016llx, Mask = 0x%016llx\n",
+               read_msr(0x202), read_msr(0x203));
+       cprintf("MTRR Phys2 Base = 0x%016llx, Mask = 0x%016llx\n",
+               read_msr(0x204), read_msr(0x205));
+       cprintf("MTRR Phys3 Base = 0x%016llx, Mask = 0x%016llx\n",
+               read_msr(0x206), read_msr(0x207));
+       cprintf("MTRR Phys4 Base = 0x%016llx, Mask = 0x%016llx\n",
+               read_msr(0x208), read_msr(0x209));
+       cprintf("MTRR Phys5 Base = 0x%016llx, Mask = 0x%016llx\n",
+               read_msr(0x20a), read_msr(0x20b));
+       cprintf("MTRR Phys6 Base = 0x%016llx, Mask = 0x%016llx\n",
+               read_msr(0x20c), read_msr(0x20d));
+       cprintf("MTRR Phys7 Base = 0x%016llx, Mask = 0x%016llx\n",
+               read_msr(0x20e), read_msr(0x20f));
+#endif // CONFIG_X86
+       cprintf("----------------------------\n");
+       spin_unlock_irqsave(&print_info_lock);
+}
+
+void test_barrier_handler(struct hw_trapframe *hw_tf, void *data)
+{
+       cprintf("Round 1: Core %d\n", core_id());
+       waiton_barrier(&test_cpu_array);
+       waiton_barrier(&test_cpu_array);
+       waiton_barrier(&test_cpu_array);
+       waiton_barrier(&test_cpu_array);
+       waiton_barrier(&test_cpu_array);
+       waiton_barrier(&test_cpu_array);
+       cprintf("Round 2: Core %d\n", core_id());
+       waiton_barrier(&test_cpu_array);
+       cprintf("Round 3: Core %d\n", core_id());
+       // uncomment to see it fucked up
+       //cprintf("Round 4: Core %d\n", core_id());
+}
+
+static void test_waiting_handler(struct hw_trapframe *hw_tf, void *data)
+{
+       atomic_dec(data);
+}
+
+#ifdef CONFIG_X86
+// TODO: Add assertions.
+bool test_pit(void)
+{
+       cprintf("Starting test for PIT now (10s)\n");
+       udelay_pit(10000000);
+       cprintf("End now\n");
+       cprintf("Starting test for TSC (if stable) now (10s)\n");
+       udelay(10000000);
+       cprintf("End now\n");
+
+       cprintf("Starting test for LAPIC (if stable) now (10s)\n");
+       enable_irq();
+       lapic_set_timer(10000000, FALSE);
+
+       atomic_t waiting;
+       atomic_init(&waiting, 1);
+       register_irq(I_TESTING, test_waiting_handler, &waiting,
+                    MKBUS(BusIPI, 0, 0, 0));
+       while(atomic_read(&waiting))
+               cpu_relax();
+       cprintf("End now\n");
+
+       return true;
+}
+
+// TODO: Add assertions.
+bool test_circ_buffer(void)
+{
+       int arr[5] = {0, 1, 2, 3, 4};
+
+       for (int i = 0; i < 5; i++) {
+               FOR_CIRC_BUFFER(i, 5, j)
+                       printk("Starting with current = %d, each value = %d\n", i, j);
+       }
+       
+       return true;
+}
+
+static void test_km_handler(uint32_t srcid, long a0, long a1, long a2)
+{
+       printk("Received KM on core %d from core %d: arg0= %p, arg1 = %p, "
+              "arg2 = %p\n", core_id(), srcid, a0, a1, a2);
+       return;
+}
+
+// TODO: Add assertions. Try to do everything inside this function.
+bool test_kernel_messages(void)
+{
+       printk("Testing Kernel Messages\n");
+       /* Testing sending multiples, sending different types, alternating, and
+        * precendence (the immediates should trump the others) */
+       printk("sending 5 IMMED to core 1, sending (#,deadbeef,0)\n");
+       for (int i = 0; i < 5; i++)
+               send_kernel_message(1, test_km_handler, (long)i, 0xdeadbeef, 0,
+                                   KMSG_IMMEDIATE);
+       udelay(5000000);
+       printk("sending 5 routine to core 1, sending (#,cafebabe,0)\n");
+       for (int i = 0; i < 5; i++)
+               send_kernel_message(1, test_km_handler, (long)i, 0xcafebabe, 0,
+                                   KMSG_ROUTINE);
+       udelay(5000000);
+       printk("sending 10 routine and 3 immediate to core 2\n");
+       for (int i = 0; i < 10; i++)
+               send_kernel_message(2, test_km_handler, (long)i, 0xcafebabe, 0,
+                                   KMSG_ROUTINE);
+       for (int i = 0; i < 3; i++)
+               send_kernel_message(2, test_km_handler, (long)i, 0xdeadbeef, 0,
+                                   KMSG_IMMEDIATE);
+       udelay(5000000);
+       printk("sending 5 ea alternating to core 2\n");
+       for (int i = 0; i < 5; i++) {
+               send_kernel_message(2, test_km_handler, (long)i, 0xdeadbeef, 0,
+                                   KMSG_IMMEDIATE);
+               send_kernel_message(2, test_km_handler, (long)i, 0xcafebabe, 0,
+                                   KMSG_ROUTINE);
+       }
+       udelay(5000000);
+       
+       return true;
+}
+#endif // CONFIG_X86
+static void test_single_cache(int iters, size_t size, int align, int flags,
+                              void (*ctor)(void *, size_t),
+                              void (*dtor)(void *, size_t))
+{
+       struct kmem_cache *test_cache;
+       void *objects[iters];
+       test_cache = kmem_cache_create("test_cache", size, align, flags, ctor, dtor);
+       printk("Testing Kmem Cache:\n");
+       print_kmem_cache(test_cache);
+       for (int i = 0; i < iters; i++) {
+               objects[i] = kmem_cache_alloc(test_cache, 0);
+               printk("Buffer %d addr = %p\n", i, objects[i]);
+       }
+       for (int i = 0; i < iters; i++) {
+               kmem_cache_free(test_cache, objects[i]);
+       }
+       kmem_cache_destroy(test_cache);
+       printk("\n\n\n\n");
+}
+
+void a_ctor(void *buf, size_t size)
+{
+       printk("constructin tests\n");
+}
+void a_dtor(void *buf, size_t size)
+{
+       printk("destructin tests\n");
+}
+
+// TODO: Make test_single_cache return something, and then add assertions here.
+bool test_slab(void)
+{
+       test_single_cache(10, 128, 512, 0, 0, 0);
+       test_single_cache(10, 128, 4, 0, a_ctor, a_dtor);
+       test_single_cache(10, 1024, 16, 0, 0, 0);
+
+       return true;
+}
+
+// TODO: Add assertions.
+bool test_kmalloc(void)
+{
+       printk("Testing Kmalloc\n");
+       void *bufs[NUM_KMALLOC_CACHES + 1];     
+       size_t size;
+       for (int i = 0; i < NUM_KMALLOC_CACHES + 1; i++){
+               size = (KMALLOC_SMALLEST << i) - sizeof(struct kmalloc_tag);
+               bufs[i] = kmalloc(size, 0);
+               printk("Size %d, Addr = %p\n", size, bufs[i]);
+       }
+       for (int i = 0; i < NUM_KMALLOC_CACHES; i++) {
+               printk("Freeing buffer %d\n", i);
+               kfree(bufs[i]);
+       }
+       printk("Testing a large kmalloc\n");
+       size = (KMALLOC_LARGEST << 2);
+       bufs[0] = kmalloc(size, 0);
+       printk("Size %d, Addr = %p\n", size, bufs[0]);
+       kfree(bufs[0]);
+
+       return true;
+}
+
+static size_t test_hash_fn_col(void *k)
+{
+       return (size_t)k % 2; // collisions in slots 0 and 1
+}
+
+bool test_hashtable(void)
+{
+       struct test {int x; int y;};
+       struct test tstruct[10];
+
+       struct hashtable *h;
+       uintptr_t k = 5;
+       struct test *v = &tstruct[0];
+
+       h = create_hashtable(32, __generic_hash, __generic_eq);
+       
+       // test inserting one item, then finding it again
+       KT_ASSERT_M("It should be possible to insert items to a hashtable", 
+                   hashtable_insert(h, (void*)k, v));
+       v = NULL;
+       KT_ASSERT_M("It should be possible to find inserted stuff in a hashtable", 
+                   (v = hashtable_search(h, (void*)k)));
+
+       KT_ASSERT_M("The extracted element should be the same we inserted", 
+                   (v == &tstruct[0]));
+
+       v = NULL;
+
+       KT_ASSERT_M("It should be possible to remove an existing element", 
+                   (v = hashtable_remove(h, (void*)k)));
+
+       KT_ASSERT_M("An element should not remain in a hashtable after deletion", 
+                   !(v = hashtable_search(h, (void*)k)));
+
+       /* Testing a bunch of items, insert, search, and removal */
+       for (int i = 0; i < 10; i++) {
+               k = i; // vary the key, we don't do KEY collisions
+               KT_ASSERT_M("It should be possible to insert elements to a hashtable", 
+                           (hashtable_insert(h, (void*)k, &tstruct[i])));
+       }
+       // read out the 10 items
+       for (int i = 0; i < 10; i++) {
+               k = i;
+               KT_ASSERT_M("It should be possible to find inserted stuff in a hashtable", 
+                           (v = hashtable_search(h, (void*)k)));
+               KT_ASSERT_M("The extracted element should be the same we inserted", 
+                           (v == &tstruct[i]));
+       }
+
+       KT_ASSERT_M("The total count of number of elements should be 10", 
+                   (10 == hashtable_count(h)));
+
+       // remove the 10 items
+       for (int i = 0; i < 10; i++) {
+               k = i;
+               KT_ASSERT_M("It should be possible to remove an existing element", 
+                           (v = hashtable_remove(h, (void*)k)));
+
+       }
+       // make sure they are all gone
+       for (int i = 0; i < 10; i++) {
+               k = i;
+               KT_ASSERT_M("An element should not remain in a hashtable after deletion", 
+                           !(v = hashtable_search(h, (void*)k)));
+       }
+
+       KT_ASSERT_M("The hashtable should be empty", 
+                   (0 == hashtable_count(h)));
+
+       hashtable_destroy(h);
+
+       // same test of a bunch of items, but with collisions.
+       /* Testing a bunch of items with collisions, etc. */
+       h = create_hashtable(32, test_hash_fn_col, __generic_eq);
+       // insert 10 items
+       for (int i = 0; i < 10; i++) {
+               k = i; // vary the key, we don't do KEY collisions
+
+               KT_ASSERT_M("It should be possible to insert elements to a hashtable", 
+                           (hashtable_insert(h, (void*)k, &tstruct[i])));
+       }
+       // read out the 10 items
+       for (int i = 0; i < 10; i++) {
+               k = i;
+               KT_ASSERT_M("It should be possible to find inserted stuff in a hashtable", 
+                           (v = hashtable_search(h, (void*)k)));
+               KT_ASSERT_M("The extracted element should be the same we inserted", 
+                           (v == &tstruct[i]));
+       }
+
+       KT_ASSERT_M("The total count of number of elements should be 10", 
+                   (10 == hashtable_count(h)));
+
+       // remove the 10 items
+       for (int i = 0; i < 10; i++) {
+               k = i;
+               KT_ASSERT_M("It should be possible to remove an existing element", 
+                           (v = hashtable_remove(h, (void*)k)));
+       }
+       // make sure they are all gone
+       for (int i = 0; i < 10; i++) {
+               k = i;
+
+               KT_ASSERT_M("An element should not remain in a hashtable after deletion", 
+                           !(v = hashtable_search(h, (void*)k)));
+       }
+
+       KT_ASSERT_M("The hashtable should be empty", 
+                   (0 == hashtable_count(h)));
+
+       hashtable_destroy(h);
+
+       return true;
+}
+
+/* Ghetto test, only tests one prod or consumer at a time */
+// TODO: Un-guetto test, add assertions.
+bool test_bcq(void)
+{
+       /* Tests a basic struct */
+       struct my_struct {
+               int x;
+               int y;
+       };
+       struct my_struct in_struct, out_struct;
+       
+       DEFINE_BCQ_TYPES(test, struct my_struct, 16);
+       struct test_bcq t_bcq;
+       bcq_init(&t_bcq, struct my_struct, 16);
+       
+       in_struct.x = 4;
+       in_struct.y = 5;
+       out_struct.x = 1;
+       out_struct.y = 2;
+       
+       bcq_enqueue(&t_bcq, &in_struct, 16, 5);
+       bcq_dequeue(&t_bcq, &out_struct, 16);
+       printk("out x %d. out y %d\n", out_struct.x, out_struct.y);
+       
+       /* Tests the BCQ a bit more, esp with overflow */
+       #define NR_ELEM_A_BCQ 8 /* NOTE: this must be a power of 2! */
+       DEFINE_BCQ_TYPES(my, int, NR_ELEM_A_BCQ);
+       struct my_bcq a_bcq;
+       bcq_init(&a_bcq, int, NR_ELEM_A_BCQ);
+       
+       int y = 2;
+       int output[100];
+       int retval[100];
+
+       /* Helpful debugger */
+       void print_a_bcq(struct my_bcq *bcq)
+       {
+               printk("A BCQ (made of ints): %p\n", bcq);
+               printk("\tprod_idx: %p\n", bcq->hdr.prod_idx);
+               printk("\tcons_pub_idx: %p\n", bcq->hdr.cons_pub_idx);
+               printk("\tcons_pvt_idx: %p\n", bcq->hdr.cons_pvt_idx);
+               for (int i = 0; i < NR_ELEM_A_BCQ; i++) {
+                       printk("Element %d, rdy_for_cons: %02p\n", i,
+                              bcq->wraps[i].rdy_for_cons);
+               }
+       }
+
+       /* Put in more than it can take */
+       for (int i = 0; i < 15; i++) {
+               y = i;
+               retval[i] = bcq_enqueue(&a_bcq, &y, NR_ELEM_A_BCQ, 10);
+               printk("enqueued: %d, had retval %d \n", y, retval[i]);
+       }
+       //print_a_bcq(&a_bcq);
+       
+       /* Try to dequeue more than we put in */
+       for (int i = 0; i < 15; i++) {
+               retval[i] = bcq_dequeue(&a_bcq, &output[i], NR_ELEM_A_BCQ);
+               printk("dequeued: %d with retval %d\n", output[i], retval[i]);
+       }
+       //print_a_bcq(&a_bcq);
+       
+       /* Put in some it should be able to take */
+       for (int i = 0; i < 3; i++) {
+               y = i;
+               retval[i] = bcq_enqueue(&a_bcq, &y, NR_ELEM_A_BCQ, 10);
+               printk("enqueued: %d, had retval %d \n", y, retval[i]);
+       }
+       
+       /* Take those, and then a couple extra */
+       for (int i = 0; i < 5; i++) {
+               retval[i] = bcq_dequeue(&a_bcq, &output[i], NR_ELEM_A_BCQ);
+               printk("dequeued: %d with retval %d\n", output[i], retval[i]);
+       }
+       
+       /* Try some one-for-one */
+       for (int i = 0; i < 5; i++) {
+               y = i;
+               retval[i] = bcq_enqueue(&a_bcq, &y, NR_ELEM_A_BCQ, 10);
+               printk("enqueued: %d, had retval %d \n", y, retval[i]);
+               retval[i] = bcq_dequeue(&a_bcq, &output[i], NR_ELEM_A_BCQ);
+               printk("dequeued: %d with retval %d\n", output[i], retval[i]);
+       }
+
+       return true;
+}
+
+/* Test a simple concurrent send and receive (one prod, one cons).  We spawn a
+ * process that will go into _M mode on another core, and we'll do the test from
+ * an alarm handler run on our core.  When we start up the process, we won't
+ * return so we need to defer the work with an alarm. */
+// TODO: Check if we can add more assertions.
+bool test_ucq(void)
+{
+       struct timer_chain *tchain = &per_cpu_info[core_id()].tchain;
+       struct alarm_waiter *waiter = kmalloc(sizeof(struct alarm_waiter), 0);
+
+       /* Alarm handler: what we want to do after the process is up */
+       void send_msgs(struct alarm_waiter *waiter)
+       {
+               struct timer_chain *tchain;
+               struct proc *old_proc, *p = waiter->data;
+               struct ucq *ucq = (struct ucq*)USTACKTOP;
+               struct event_msg msg;
+
+               printk("Running the alarm handler!\n");
+               printk("NR msg per page: %d\n", NR_MSG_PER_PAGE);
+               /* might not be mmaped yet, if not, abort.  We used to user_mem_check,
+                * but now we just touch it and PF. */
+               char touch = *(char*)ucq;
+               asm volatile ("" : : "r"(touch));
+               /* load their address space */
+               old_proc = switch_to(p);
+               /* So it's mmaped, see if it is ready (note that this is dangerous) */
+               if (!ucq->ucq_ready) {
+                       printk("Not ready yet\n");
+                       switch_back(p, old_proc);
+                       goto abort;
+               }
+               /* So it's ready, time to finally do the tests... */
+               printk("[kernel] Finally starting the tests... \n");
+               /* 1: Send a simple message */
+               printk("[kernel] #1 Sending simple message (7, deadbeef)\n");
+               msg.ev_type = 7;
+               msg.ev_arg2 = 0xdeadbeef;
+               send_ucq_msg(ucq, p, &msg);
+               printk("nr_pages: %d\n", atomic_read(&ucq->nr_extra_pgs));
+               /* 2: Send a bunch.  In a VM, this causes one swap, and then a bunch of
+                * mmaps. */
+               printk("[kernel] #2 \n");
+               for (int i = 0; i < 5000; i++) {
+                       msg.ev_type = i;
+                       send_ucq_msg(ucq, p, &msg);
+               }
+               printk("nr_pages: %d\n", atomic_read(&ucq->nr_extra_pgs));
+               printk("[kernel] #3 \n");
+               /* 3: make sure we chained pages (assuming 1k is enough) */
+               for (int i = 0; i < 1000; i++) {
+                       msg.ev_type = i;
+                       send_ucq_msg(ucq, p, &msg);
+               }
+               printk("nr_pages: %d\n", atomic_read(&ucq->nr_extra_pgs));
+               /* other things we could do:
+                *  - concurrent producers / consumers...  ugh.
+                *  - would require a kmsg to another core, instead of a local alarm
+                */
+               /* done, switch back and free things */
+               switch_back(p, old_proc);
+               proc_decref(p);
+               kfree(waiter); /* since it was kmalloc()d */
+               return;
+       abort:
+               tchain = &per_cpu_info[core_id()].tchain;
+               /* Set to run again */
+               set_awaiter_rel(waiter, 1000000);
+               set_alarm(tchain, waiter);
+       }
+       /* Set up a handler to run the real part of the test */
+       init_awaiter(waiter, send_msgs);
+       set_awaiter_rel(waiter, 1000000);       /* 1s should be long enough */
+       set_alarm(tchain, waiter);
+       /* Just spawn the program */
+       struct file *program;
+       program = do_file_open("/bin/ucq", 0, 0);
+       
+       KT_ASSERT_M("We should be able to find /bin/ucq", 
+                   program);
+
+       char *p_envp[] = {"LD_LIBRARY_PATH=/lib", 0};
+       struct proc *p = proc_create(program, 0, p_envp);
+       proc_wakeup(p);
+       /* instead of getting rid of the reference created in proc_create, we'll put
+        * it in the awaiter */
+       waiter->data = p;
+       kref_put(&program->f_kref);
+       /* Should never return from schedule (env_pop in there) also note you may
+        * not get the process you created, in the event there are others floating
+        * around that are runnable */
+       run_scheduler();
+       smp_idle();
+       
+       KT_ASSERT_M("We should never return from schedule",
+                   false);
+
+       return true;
+}
+
+/* rudimentary tests.  does the basics, create, merge, split, etc.  Feel free to
+ * add more, esp for the error conditions and finding free slots.  This is also
+ * a bit lazy with setting the caller's fields (perm, flags, etc). */
+// TODO: See if we could add more assertions, try to add more descriptive
+//       messages to assertions.
+bool test_vm_regions(void)
+{
+       #define MAX_VMR_TESTS 10
+       struct proc pr, *p = &pr;       /* too lazy to even create one */
+       int n = 0;
+       TAILQ_INIT(&p->vm_regions);
+
+       struct vmr_summary {
+               uintptr_t base; 
+               uintptr_t end; 
+       };
+       int check_vmrs(struct proc *p, struct vmr_summary *results, int len, int n)
+       {
+               int count = 0;
+               struct vm_region *vmr;
+               TAILQ_FOREACH(vmr, &p->vm_regions, vm_link) {
+                       if (count >= len) {
+                               printk("More vm_regions than expected\n");
+                               break;
+                       }
+                       if ((vmr->vm_base != results[count].base) ||
+                           (vmr->vm_end != results[count].end)) {
+                               printk("VM test case %d failed!\n", n);
+                               print_vmrs(p);
+                               return -1;
+                       }
+                       count++;
+               }
+               return count;
+       }
+       struct vm_region *vmrs[MAX_VMR_TESTS];
+       struct vmr_summary results[MAX_VMR_TESTS];
+
+       memset(results, 0, sizeof(results));
+       /* Make one */
+       vmrs[0] = create_vmr(p, 0x2000, 0x1000);
+       results[0].base = 0x2000;
+       results[0].end = 0x3000;
+       check_vmrs(p, results, 1, n++);
+       /* Grow it */
+       grow_vmr(vmrs[0], 0x4000);
+       results[0].base = 0x2000;
+       results[0].end = 0x4000;
+       check_vmrs(p, results, 1, n++);
+       /* Grow it poorly */
+       KT_ASSERT_M("It should pass bad grow test", 
+                   (-1 == grow_vmr(vmrs[0], 0x3000)));
+       check_vmrs(p, results, 1, n++);
+       /* Make another right next to it */
+       vmrs[1] = create_vmr(p, 0x4000, 0x1000);
+       results[1].base = 0x4000;
+       results[1].end = 0x5000;
+       check_vmrs(p, results, 2, n++);
+       /* try to grow through it */
+       KT_ASSERT_M("It should pass bad grow test", 
+                   (-1 == grow_vmr(vmrs[0], 0x5000)));
+       check_vmrs(p, results, 2, n++);
+       /* Merge them */
+       merge_vmr(vmrs[0], vmrs[1]);
+       results[0].end = 0x5000;
+       results[1].base = 0;
+       results[1].end = 0;
+       check_vmrs(p, results, 1, n++);
+       vmrs[1]= create_vmr(p, 0x6000, 0x4000);
+       results[1].base = 0x6000;
+       results[1].end = 0xa000;
+       check_vmrs(p, results, 2, n++);
+       /* try to merge unmergables (just testing ranges) */
+       KT_ASSERT_M("It should pass bad merge test", 
+                   (-1 == merge_vmr(vmrs[0], vmrs[1])));
+       check_vmrs(p, results, 2, n++);
+       vmrs[2] = split_vmr(vmrs[1], 0x8000);
+       results[1].end = 0x8000;
+       results[2].base = 0x8000;
+       results[2].end = 0xa000;
+       check_vmrs(p, results, 3, n++);
+       /* destroy one */
+       destroy_vmr(vmrs[1]);
+       results[1].base = 0x8000;
+       results[1].end = 0xa000;
+       check_vmrs(p, results, 2, n++);
+       /* shrink */
+       shrink_vmr(vmrs[2], 0x9000);
+       results[1].base = 0x8000;
+       results[1].end = 0x9000;
+       check_vmrs(p, results, 2, n++); /* 10 */
+       KT_ASSERT_M("We should be able to find the right vmr", 
+                   (vmrs[2] == find_vmr(p, 0x8500)));
+       KT_ASSERT_M("We should be able to find the right vmr", 
+                   (vmrs[2] == find_first_vmr(p, 0x8500)));
+       KT_ASSERT_M("We should be able to find the right vmr", 
+                   (vmrs[2] == find_first_vmr(p, 0x7500)));
+       KT_ASSERT_M("We shouldn't be able to find a vmr", 
+                   !(find_first_vmr(p, 0x9500)));
+       /* grow up to another */
+       grow_vmr(vmrs[0], 0x8000);
+       results[0].end = 0x8000;
+       check_vmrs(p, results, 2, n++);
+       vmrs[0]->vm_prot = 88;
+       vmrs[2]->vm_prot = 77;
+       /* should be unmergeable due to perms */
+       KT_ASSERT_M("It should pass bad merge test", 
+                   -1 == merge_vmr(vmrs[0], vmrs[2]));
+       check_vmrs(p, results, 2, n++);
+       /* should merge now */
+       vmrs[2]->vm_prot = 88;
+       merge_vmr(vmrs[0], vmrs[2]);
+       results[0].end = 0x9000;
+       check_vmrs(p, results, 1, n++);
+       destroy_vmr(vmrs[0]);
+       check_vmrs(p, results, 0, n++);
+       /* Check the automerge function */
+       vmrs[0] = create_vmr(p, 0x2000, 0x1000);
+       vmrs[1] = create_vmr(p, 0x3000, 0x1000);
+       vmrs[2] = create_vmr(p, 0x4000, 0x1000);
+       for (int i = 0; i < 3; i++) {
+               vmrs[i]->vm_prot = PROT_READ;
+               vmrs[i]->vm_flags = 0;
+               vmrs[i]->vm_file = 0; /* would like to test this, it's a pain for now */
+       }
+       vmrs[0] = merge_me(vmrs[1]);
+       results[0].base = 0x2000;
+       results[0].end = 0x5000;
+       check_vmrs(p, results, 1, n++);
+       destroy_vmr(vmrs[0]);
+       check_vmrs(p, results, 0, n++);
+       /* Check unfixed creation requests */
+       vmrs[0] = create_vmr(p, 0x0000, 0x1000);
+       vmrs[1] = create_vmr(p, 0x0000, 0x1000);
+       vmrs[2] = create_vmr(p, 0x0000, 0x1000);
+       results[0].base = 0x0000;
+       results[0].end  = 0x1000;
+       results[1].base = 0x1000;
+       results[1].end  = 0x2000;
+       results[2].base = 0x2000;
+       results[2].end  = 0x3000;
+       check_vmrs(p, results, 3, n++);
+
+       return true;
+}
+
+bool test_radix_tree(void)
+{
+       struct radix_tree real_tree = RADIX_INITIALIZER;
+       struct radix_tree *tree = &real_tree;
+       void *retval;
+
+       KT_ASSERT_M("It should be possible to insert at 0", 
+                   !radix_insert(tree, 0, (void*)0xdeadbeef, 0));
+       radix_delete(tree, 0);
+       KT_ASSERT_M("It should be possible to re-insert at 0", 
+                   !radix_insert(tree, 0, (void*)0xdeadbeef, 0));
+
+       KT_ASSERT_M("It should be possible to insert first", 
+                   !radix_insert(tree, 3, (void*)0xdeadbeef, 0));
+       radix_insert(tree, 4, (void*)0x04040404, 0);
+       KT_ASSERT((void*)0xdeadbeef == radix_lookup(tree, 3));
+       for (int i = 5; i < 100; i++)
+               if ((retval = radix_lookup(tree, i))) {
+                       printk("Extra item %p at slot %d in tree %p\n", retval, i,
+                              tree);
+                       print_radix_tree(tree);
+                       monitor(0);
+               }
+       KT_ASSERT_M("It should be possible to insert a two-tier", 
+                   !radix_insert(tree, 65, (void*)0xcafebabe, 0));
+       KT_ASSERT_M("It should not be possible to reinsert", 
+                   radix_insert(tree, 4, (void*)0x03030303, 0));
+       KT_ASSERT_M("It should be possible to insert a two-tier boundary", 
+                   !radix_insert(tree, 4095, (void*)0x4095, 0));
+       KT_ASSERT_M("It should be possible to insert a three-tier", 
+                   !radix_insert(tree, 4096, (void*)0x4096, 0));
+       //print_radix_tree(tree);
+       radix_delete(tree, 65);
+       radix_delete(tree, 3);
+       radix_delete(tree, 4);
+       radix_delete(tree, 4095);
+       radix_delete(tree, 4096);
+       //print_radix_tree(tree);
+
+       return true;
+}
+
+/* Assorted FS tests, which were hanging around in init.c */
+// TODO: remove all the print statements and try to convert most into assertions
+bool test_random_fs(void)
+{
+       int retval = do_symlink("/dir1/sym", "/bin/hello", S_IRWXU);
+       KT_ASSERT_M("symlink1 should be created successfully", 
+                   (!retval));
+       retval = do_symlink("/symdir", "/dir1/dir1-1", S_IRWXU);
+       KT_ASSERT_M("symlink1 should be created successfully", 
+                   (!retval));
+       retval = do_symlink("/dir1/test.txt", "/dir2/test2.txt", S_IRWXU);
+       KT_ASSERT_M("symlink2 should be created successfully", 
+                   (!retval));
+       retval = do_symlink("/dir1/dir1-1/up", "../../", S_IRWXU);
+       KT_ASSERT_M("symlink3 should be created successfully", 
+                   (!retval));
+       retval = do_symlink("/bin/hello-sym", "hello", S_IRWXU);
+       KT_ASSERT_M("symlink4 should be created successfully", 
+                   (!retval));
+
+       struct dentry *dentry;
+       struct nameidata nd_r = {0}, *nd = &nd_r;
+       retval = path_lookup("/dir1/sym", 0, nd);
+       KT_ASSERT_M("symlink lookup should work for an existing symlink", 
+                   (!retval)); 
+       char *symname = nd->dentry->d_inode->i_op->readlink(nd->dentry);
+       printk("Pathlookup got %s (sym)\n", nd->dentry->d_name.name);
+       if (!symname)
+               printk("symlink reading failed\n");
+       else
+               printk("Symname: %s (/bin/hello)\n", symname);
+       path_release(nd);
+       /* try with follow */
+       memset(nd, 0, sizeof(struct nameidata));
+       retval = path_lookup("/dir1/sym", LOOKUP_FOLLOW, nd);
+       
+       KT_ASSERT_M("symlink lookup should work for an existing symlink", 
+                   (!retval));
+       printk("Pathlookup got %s (hello)\n", nd->dentry->d_name.name);
+       path_release(nd);
+       
+       /* try with a directory */
+       memset(nd, 0, sizeof(struct nameidata));
+       retval = path_lookup("/symdir/f1-1.txt", 0, nd);
+       KT_ASSERT_M("symlink lookup should work for an existing symlink", 
+                   (!retval));
+       printk("Pathlookup got %s (f1-1.txt)\n", nd->dentry->d_name.name);
+       path_release(nd);
+       
+       /* try with a rel path */
+       printk("Try with a rel path\n");
+       memset(nd, 0, sizeof(struct nameidata));
+       retval = path_lookup("/symdir/up/hello.txt", 0, nd);
+       KT_ASSERT_M("symlink lookup should work for an existing symlink", 
+                   (!retval));
+       printk("Pathlookup got %s (hello.txt)\n", nd->dentry->d_name.name);
+       path_release(nd);
+       
+       printk("Try for an ELOOP\n");
+       memset(nd, 0, sizeof(struct nameidata));
+       retval = path_lookup("/symdir/up/symdir/up/symdir/up/symdir/up/hello.txt", 0, nd);
+       KT_ASSERT_M("symlink lookup should fail for a non existing symlink", 
+                   (retval));
+       path_release(nd);
+
+       return true;
+}
+
+/* Kernel message to restart our kthread */
+static void __test_up_sem(uint32_t srcid, long a0, long a1, long a2)
+{
+       struct semaphore *sem = (struct semaphore*)a0;
+       printk("[kmsg] Upping the sem to start the kthread, stacktop is %p\n",
+                  get_stack_top());
+       if (!sem_up(sem)) {
+               printk("[kmsg] Crap, the sem didn't have a kthread waiting!\n");
+               return;
+       }
+       printk("Kthread will restart when we handle the __launch RKM\n");
+}
+
+/* simple test - start one, do something else, and resume it.  For lack of a
+ * better infrastructure, we send ourselves a kmsg to run the kthread, which
+ * we'll handle in smp_idle (which you may have to manually call).  Note this
+ * doesn't test things like memory being leaked, or dealing with processes. */
+// TODO: Add assertions.
+bool test_kthreads(void)
+{
+       struct semaphore sem;
+       sem_init(&sem, 1);              /* set to 1 to test the unwind */
+       printk("We're a kthread!  Stacktop is %p.  Testing suspend, etc...\n",
+              get_stack_top());
+       /* So we have something that will wake us up.  Routine messages won't get
+        * serviced in the kernel right away. */
+       send_kernel_message(core_id(), __test_up_sem, (long)&sem, 0, 0,
+                           KMSG_ROUTINE);
+       /* Actually block (or try to) */
+       /* This one shouldn't block - but will test the unwind (if 1 above) */
+       printk("About to sleep, but should unwind (signal beat us)\n");
+       sem_down(&sem);
+       /* This one is for real, yo.  Run and tell that. */
+       printk("About to sleep for real\n");
+       sem_down(&sem);
+       printk("Kthread restarted!, Stacktop is %p.\n", get_stack_top());
+
+       return true;
+}
+
+/* Second player's kmsg */
+static void __test_kref_2(uint32_t srcid, long a0, long a1, long a2)
+{
+       struct kref *kref = (struct kref*)a0;
+       bool *done = (bool*)a1;
+       enable_irq();
+       for (int i = 0; i < 10000000; i++) {
+               kref_get(kref, 1);
+               set_core_timer(1, TRUE);
+               udelay(2);
+               kref_put(kref);
+       }
+       *done = TRUE;
+}
+
+/* Runs a simple test between core 0 (caller) and core 2 */
+// TODO: I believe we need more assertions.
+bool test_kref(void)
+{
+       struct kref local_kref;
+       bool done = FALSE;
+       
+       kref_init(&local_kref, fake_release, 1);
+       send_kernel_message(2, __test_kref_2, (long)&local_kref, (long)&done, 0,
+                           KMSG_ROUTINE);
+       for (int i = 0; i < 10000000; i++) {
+               kref_get(&local_kref, 1);
+               udelay(2);
+               kref_put(&local_kref);
+       }
+       while (!done)
+               cpu_relax();
+       KT_ASSERT(kref_refcnt(&local_kref) == 1);
+       printk("[TEST-KREF] Simple 2-core getting/putting passed.\n");
+
+       return true;
+}
+
+// TODO: Add more descriptive assertion messages.
+bool test_atomics(void)
+{
+       /* subtract_and_test */
+       atomic_t num;
+       /* Test subing to 0 */
+       atomic_init(&num, 1);
+       KT_ASSERT(atomic_sub_and_test(&num, 1) == 1);
+       atomic_init(&num, 2);
+       KT_ASSERT(atomic_sub_and_test(&num, 2) == 1);
+       /* Test not getting to 0 */
+       atomic_init(&num, 1);
+       KT_ASSERT(atomic_sub_and_test(&num, 0) == 0);
+       atomic_init(&num, 2);
+       KT_ASSERT(atomic_sub_and_test(&num, 1) == 0);
+       /* Test negatives */
+       atomic_init(&num, -1);
+       KT_ASSERT(atomic_sub_and_test(&num, 1) == 0);
+       atomic_init(&num, -1);
+       KT_ASSERT(atomic_sub_and_test(&num, -1) == 1);
+       /* Test larger nums */
+       atomic_init(&num, 265);
+       KT_ASSERT(atomic_sub_and_test(&num, 265) == 1);
+       atomic_init(&num, 265);
+       KT_ASSERT(atomic_sub_and_test(&num, 2) == 0);
+
+       /* CAS */
+       /* Simple test, make sure the bool retval of CAS handles failure */
+       bool test_cas_val(long init_val)
+       {
+               atomic_t actual_num;
+               long old_num;
+               int attempt;
+               atomic_init(&actual_num, init_val);
+               attempt = 0;
+               do {
+                       old_num = atomic_read(&actual_num);
+                       /* First time, try to fail */
+                       if (attempt == 0) 
+                               old_num++;
+                       attempt++;      
+               } while (!atomic_cas(&actual_num, old_num, old_num + 10));
+               if (atomic_read(&actual_num) != init_val + 10) {
+                       return false;
+               } else {
+                       return true;
+               }
+       }
+       KT_ASSERT_M("CAS test for 257 should be successful.",
+                   test_cas_val(257));
+       KT_ASSERT_M("CAS test for 1 should be successful.",
+                   test_cas_val(1));
+       return true;
+}
+
+/* Helper KMSG for test_abort.  Core 1 does this, while core 0 sends an IRQ. */
+static void __test_try_halt(uint32_t srcid, long a0, long a1, long a2)
+{
+       disable_irq();
+       /* wait 10 sec.  should have a bunch of ints pending */
+       udelay(10000000);
+       printk("Core 1 is about to halt\n");
+       cpu_halt();
+       printk("Returned from halting on core 1\n");
+}
+
+/* x86 test, making sure our cpu_halt() and handle_irq() work.  If you want to
+ * see it fail, you'll probably need to put a nop in the asm for cpu_halt(), and
+ * comment out abort_halt() in handle_irq(). */
+// TODO: Add assertions.
+bool test_abort_halt(void)
+{
+#ifdef CONFIG_X86
+       send_kernel_message(1, __test_try_halt, 0, 0, 0, KMSG_ROUTINE);
+       /* wait 1 sec, enough time to for core 1 to be in its KMSG */
+       udelay(1000000);
+       /* Send an IPI */
+       send_ipi(0x01, I_TESTING);
+       printk("Core 0 sent the IPI\n");
+#endif /* CONFIG_X86 */
+       return true;
+}
+
+/* Funcs and global vars for test_cv() */
+static struct cond_var local_cv;
+static atomic_t counter;
+static struct cond_var *cv = &local_cv;
+static volatile bool state = FALSE;            /* for test 3 */
+
+void __test_cv_signal(uint32_t srcid, long a0, long a1, long a2)
+{
+       if (atomic_read(&counter) % 4)
+               cv_signal(cv);
+       else
+               cv_broadcast(cv);
+       atomic_dec(&counter);
+}
+
+void __test_cv_waiter(uint32_t srcid, long a0, long a1, long a2)
+{
+       cv_lock(cv);
+       /* check state, etc */
+       cv_wait_and_unlock(cv);
+       atomic_dec(&counter);
+}
+
+void __test_cv_waiter_t3(uint32_t srcid, long a0, long a1, long a2)
+{
+       udelay(a0);
+       /* if state == false, we haven't seen the signal yet */
+       cv_lock(cv);
+       while (!state) {
+               cpu_relax();
+               cv_wait(cv);    /* unlocks and relocks */
+       }
+       cv_unlock(cv);
+       /* Make sure we are done, tell the controller we are done */
+       cmb();
+       assert(state);
+       atomic_dec(&counter);
+}
+
+// TODO: Add more assertions.
+bool test_cv(void)
+{
+       int nr_msgs;
+
+       cv_init(cv);
+       /* Test 0: signal without waiting */
+       cv_broadcast(cv);
+       cv_signal(cv);
+       kthread_yield();
+       printk("test_cv: signal without waiting complete\n");
+
+       /* Test 1: single / minimal shit */
+       nr_msgs = num_cpus - 1; /* not using cpu 0 */
+       atomic_init(&counter, nr_msgs);
+       for (int i = 1; i < num_cpus; i++)
+               send_kernel_message(i, __test_cv_waiter, 0, 0, 0, KMSG_ROUTINE);
+       udelay(1000000);
+       cv_signal(cv);
+       kthread_yield();
+       while (atomic_read(&counter) != nr_msgs - 1)
+               cpu_relax();
+       printk("test_cv: single signal complete\n");
+       cv_broadcast(cv);
+       /* broadcast probably woke up the waiters on our core.  since we want to
+        * spin on their completion, we need to yield for a bit. */
+       kthread_yield();
+       while (atomic_read(&counter))
+               cpu_relax();
+       printk("test_cv: broadcast signal complete\n");
+
+       /* Test 2: shitloads of waiters and signalers */
+       nr_msgs = 0x500;        /* any more than 0x20000 could go OOM */
+       atomic_init(&counter, nr_msgs);
+       for (int i = 0; i < nr_msgs; i++) {
+               int cpu = (i % (num_cpus - 1)) + 1;
+               if (atomic_read(&counter) % 5)
+                       send_kernel_message(cpu, __test_cv_waiter, 0, 0, 0, KMSG_ROUTINE);
+               else
+                       send_kernel_message(cpu, __test_cv_signal, 0, 0, 0, KMSG_ROUTINE);
+       }
+       kthread_yield();        /* run whatever messages we sent to ourselves */
+       while (atomic_read(&counter)) {
+               cpu_relax();
+               cv_broadcast(cv);
+               udelay(1000000);
+               kthread_yield();        /* run whatever messages we sent to ourselves */
+       }
+       KT_ASSERT(!cv->nr_waiters);
+       printk("test_cv: massive message storm complete\n");
+
+       /* Test 3: basic one signaller, one receiver.  we want to vary the amount of
+        * time the sender and receiver delays, starting with (1ms, 0ms) and ending
+        * with (0ms, 1ms).  At each extreme, such as with the sender waiting 1ms,
+        * the receiver/waiter should hit the "check and wait" point well before the
+        * sender/signaller hits the "change state and signal" point. */
+       for (int i = 0; i < 1000; i++) {
+               for (int j = 0; j < 10; j++) {  /* some extra chances at each point */
+                       state = FALSE;
+                       atomic_init(&counter, 1);       /* signal that the client is done */
+                       /* client waits for i usec */
+                       send_kernel_message(2, __test_cv_waiter_t3, i, 0, 0, KMSG_ROUTINE);
+                       cmb();
+                       udelay(1000 - i);       /* senders wait time: 1000..0 */
+                       state = TRUE;
+                       cv_signal(cv);
+                       /* signal might have unblocked a kthread, let it run */
+                       kthread_yield();
+                       /* they might not have run at all yet (in which case they lost the
+                        * race and don't need the signal).  but we need to wait til they're
+                        * done */
+                       while (atomic_read(&counter))
+                               cpu_relax();
+                       KT_ASSERT(!cv->nr_waiters);
+               }
+       }
+       printk("test_cv: single sender/receiver complete\n");
+
+       return true;
+}
+
+/* Based on a bug I noticed.  TODO: actual memset test... */
+bool test_memset(void)
+{
+       #define ARR_SZ 256
+       
+       void print_array(char *c, size_t len)
+       {
+               for (int i = 0; i < len; i++)
+                       printk("%04d: %02x\n", i, *c++);
+       }
+       
+       bool check_array(char *c, char x, size_t len)
+       {
+               for (int i = 0; i < len; i++) {
+                       #define ASSRT_SIZE 64
+                       char *assrt_msg = (char*) kmalloc(ASSRT_SIZE, 0);
+                       snprintf(assrt_msg, ASSRT_SIZE, 
+                                    "Char %d is %c (%02x), should be %c (%02x)", i, *c, *c,
+                                    x, x);
+                       KT_ASSERT_M(assrt_msg, (*c == x));
+                       c++;
+               }
+               return true;
+       }
+       
+       bool run_check(char *arr, int ch, size_t len)
+       {
+               char *c = arr;
+               for (int i = 0; i < ARR_SZ; i++)
+                       *c++ = 0x0;
+               memset(arr, ch, len - 4);
+               if (check_array(arr, ch, len - 4) &&
+                   check_array(arr + len - 4, 0x0, 4)) {
+                       return true;
+               } else {
+                       return false;
+               }
+       }
+
+       char bytes[ARR_SZ];
+
+       if (!run_check(bytes, 0xfe, 20) || !run_check(bytes, 0xc0fe, 20)) {
+               return false;
+       }
+
+       return true;
+}
+
+void __attribute__((noinline)) __longjmp_wrapper(struct jmpbuf* jb)
+{
+       asm ("");
+       printk("Starting: %s\n", __FUNCTION__);
+       longjmp(jb, 1);
+       // Should never get here
+       printk("Exiting: %s\n", __FUNCTION__); 
+}
+
+// TODO: Add assertions.
+bool test_setjmp()
+{
+       struct jmpbuf jb;
+       printk("Starting: %s\n", __FUNCTION__);
+       if (setjmp(&jb)) {
+         printk("After second setjmp return: %s\n", __FUNCTION__);
+    }
+    else {
+         printk("After first setjmp return: %s\n", __FUNCTION__);
+      __longjmp_wrapper(&jb);
+    }
+       printk("Exiting: %s\n", __FUNCTION__);
+
+       return true;
+}
+
+// TODO: add assertions.
+bool test_apipe(void)
+{
+       static struct atomic_pipe test_pipe;
+
+       struct some_struct {
+               long x;
+               int y;
+       };
+       /* Don't go too big, or you'll run off the stack */
+       #define MAX_BATCH 100
+
+       void __test_apipe_writer(uint32_t srcid, long a0, long a1, long a2)
+       {
+               int ret, count_todo;
+               int total = 0;
+               struct some_struct local_str[MAX_BATCH];
+               for (int i = 0; i < MAX_BATCH; i++) {
+                       local_str[i].x = 0xf00;
+                       local_str[i].y = 0xba5;
+               }
+               /* testing 0, and max out at 50. [0, ... 50] */
+               for (int i = 0; i < MAX_BATCH + 1; i++) {
+                       count_todo = i;
+                       while (count_todo) {
+                               ret = apipe_write(&test_pipe, &local_str, count_todo);
+                               /* Shouldn't break, based on the loop counters */
+                               if (!ret) {
+                                       printk("Writer breaking with %d left\n", count_todo);
+                                       break;
+                               }
+                               total += ret;
+                               count_todo -= ret;
+                       }
+               }
+               printk("Writer done, added %d elems\n", total);
+               apipe_close_writer(&test_pipe);
+       }
+
+       void __test_apipe_reader(uint32_t srcid, long a0, long a1, long a2)
+       {
+               int ret, count_todo;
+               int total = 0;
+               struct some_struct local_str[MAX_BATCH] = {{0}};
+               /* reversed loop compared to the writer [50, ... 0] */
+               for (int i = MAX_BATCH; i >= 0; i--) {
+                       count_todo = i;
+                       while (count_todo) {
+                               ret = apipe_read(&test_pipe, &local_str, count_todo);
+                               if (!ret) {
+                                       printk("Reader breaking with %d left\n", count_todo);
+                                       break;
+                               }
+                               total += ret;
+                               count_todo -= ret;
+                       }
+               }
+               printk("Reader done, took %d elems\n", total);
+               for (int i = 0; i < MAX_BATCH; i++) {
+                       assert(local_str[i].x == 0xf00);
+                       assert(local_str[i].y == 0xba5);
+               }
+               apipe_close_reader(&test_pipe);
+       }
+
+       void *pipe_buf = kpage_alloc_addr();
+       KT_ASSERT(pipe_buf);
+       apipe_init(&test_pipe, pipe_buf, PGSIZE, sizeof(struct some_struct));
+       printd("*ap_buf %p\n", test_pipe.ap_buf);
+       printd("ap_ring_sz %p\n", test_pipe.ap_ring_sz);
+       printd("ap_elem_sz %p\n", test_pipe.ap_elem_sz);
+       printd("ap_rd_off %p\n", test_pipe.ap_rd_off);
+       printd("ap_wr_off %p\n", test_pipe.ap_wr_off);
+       printd("ap_nr_readers %p\n", test_pipe.ap_nr_readers);
+       printd("ap_nr_writers %p\n", test_pipe.ap_nr_writers);
+       send_kernel_message(0, __test_apipe_writer, 0, 0, 0, KMSG_ROUTINE);
+       /* Once we start synchronizing with a kmsg / kthread that could be on a
+        * different core, we run the chance of being migrated when we block. */
+       __test_apipe_reader(0, 0, 0, 0);
+       /* Wait til the first test is done */
+       while (test_pipe.ap_nr_writers) {
+               kthread_yield();
+               cpu_relax();
+       }
+       /* Try cross core (though CV wake ups schedule on the waking core) */
+       apipe_open_reader(&test_pipe);
+       apipe_open_writer(&test_pipe);
+       send_kernel_message(1, __test_apipe_writer, 0, 0, 0, KMSG_ROUTINE);
+       __test_apipe_reader(0, 0, 0, 0);
+       /* We could be on core 1 now.  If we were called from core0, our caller
+        * might expect us to return while being on core 0 (like if we were kfunc'd
+        * from the monitor.  Be careful if you copy this code. */
+
+       return true;
+}
+
+static struct rwlock rwlock, *rwl = &rwlock;
+static atomic_t rwlock_counter;
+// TODO: Add assertions.
+bool test_rwlock(void)
+{
+       bool ret;
+       rwinit(rwl);
+       /* Basic: can i lock twice, recursively? */
+       rlock(rwl);
+       ret = canrlock(rwl);
+       KT_ASSERT(ret);
+       runlock(rwl);
+       runlock(rwl);
+       /* Other simply tests */
+       wlock(rwl);
+       wunlock(rwl);
+
+       /* Just some half-assed different operations */
+       void __test_rwlock(uint32_t srcid, long a0, long a1, long a2)
+       {
+               int rand = read_tsc() & 0xff;
+               for (int i = 0; i < 10000; i++) {
+                       switch ((rand * i) % 5) {
+                               case 0:
+                               case 1:
+                                       rlock(rwl);
+                                       runlock(rwl);
+                                       break;
+                               case 2:
+                               case 3:
+                                       if (canrlock(rwl))
+                                               runlock(rwl);
+                                       break;
+                               case 4:
+                                       wlock(rwl);
+                                       wunlock(rwl);
+                                       break;
+                       }
+               }
+               /* signal to allow core 0 to finish */
+               atomic_dec(&rwlock_counter);
+       }
+               
+       /* send 4 messages to each non core 0 */
+       atomic_init(&rwlock_counter, (num_cpus - 1) * 4);
+       for (int i = 1; i < num_cpus; i++)
+               for (int j = 0; j < 4; j++)
+                       send_kernel_message(i, __test_rwlock, 0, 0, 0, KMSG_ROUTINE);
+       while (atomic_read(&rwlock_counter))
+               cpu_relax();
+       printk("rwlock test complete\n");
+
+       return true;
+}
+
+/* Funcs and global vars for test_rv() */
+static struct rendez local_rv;
+static struct rendez *rv = &local_rv;
+/* reusing state and counter from test_cv... */
+
+static int __rendez_cond(void *arg)
+{
+       return *(bool*)arg;
+}
+
+void __test_rv_wakeup(uint32_t srcid, long a0, long a1, long a2)
+{
+       if (atomic_read(&counter) % 4)
+               cv_signal(cv);
+       else
+               cv_broadcast(cv);
+       atomic_dec(&counter);
+}
+
+void __test_rv_sleeper(uint32_t srcid, long a0, long a1, long a2)
+{
+       rendez_sleep(rv, __rendez_cond, (void*)&state);
+       atomic_dec(&counter);
+}
+
+void __test_rv_sleeper_timeout(uint32_t srcid, long a0, long a1, long a2)
+{
+       /* half-assed amount of time. */
+       rendez_sleep_timeout(rv, __rendez_cond, (void*)&state, a0);
+       atomic_dec(&counter);
+}
+
+// TODO: Add more assertions.
+bool test_rv(void)
+{
+       int nr_msgs;
+
+       rendez_init(rv);
+       /* Test 0: signal without waiting */
+       rendez_wakeup(rv);
+       kthread_yield();
+       printk("test_rv: wakeup without sleeping complete\n");
+
+       /* Test 1: a few sleepers */
+       nr_msgs = num_cpus - 1; /* not using cpu 0 */
+       atomic_init(&counter, nr_msgs);
+       state = FALSE;
+       for (int i = 1; i < num_cpus; i++)
+               send_kernel_message(i, __test_rv_sleeper, 0, 0, 0, KMSG_ROUTINE);
+       udelay(1000000);
+       cmb();
+       state = TRUE;
+       rendez_wakeup(rv);
+       /* broadcast probably woke up the waiters on our core.  since we want to
+        * spin on their completion, we need to yield for a bit. */
+       kthread_yield();
+       while (atomic_read(&counter))
+               cpu_relax();
+       printk("test_rv: bulk wakeup complete\n");
+
+       /* Test 2: different types of sleepers / timeouts */
+       state = FALSE;
+       nr_msgs = 0x500;        /* any more than 0x20000 could go OOM */
+       atomic_init(&counter, nr_msgs);
+       for (int i = 0; i < nr_msgs; i++) {
+               int cpu = (i % (num_cpus - 1)) + 1;
+               /* timeouts from 0ms ..5000ms (enough that they should wake via cond */
+               if (atomic_read(&counter) % 5)
+                       send_kernel_message(cpu, __test_rv_sleeper_timeout, i * 4, 0, 0,
+                                           KMSG_ROUTINE);
+               else
+                       send_kernel_message(cpu, __test_rv_sleeper, 0, 0, 0, KMSG_ROUTINE);
+       }
+       kthread_yield();        /* run whatever messages we sent to ourselves */
+       state = TRUE;
+       while (atomic_read(&counter)) {
+               cpu_relax();
+               rendez_wakeup(rv);
+               udelay(1000000);
+               kthread_yield();        /* run whatever messages we sent to ourselves */
+       }
+       KT_ASSERT(!rv->cv.nr_waiters);
+       printk("test_rv: lots of sleepers/timeouts complete\n");
+
+       return true;
+}
+
+/* Cheap test for the alarm internal management */
+// TODO: Add assertions.
+bool test_alarm(void)
+{
+       uint64_t now = tsc2usec(read_tsc());
+       struct alarm_waiter await1, await2;
+       struct timer_chain *tchain = &per_cpu_info[0].tchain;
+       void shouldnt_run(struct alarm_waiter *awaiter)
+       {
+               printk("Crap, %p ran!\n", awaiter);
+       }
+       void empty_run(struct alarm_waiter *awaiter)
+       {
+               printk("Yay, %p ran (hopefully twice)!\n", awaiter);
+       }
+       /* Test basic insert, move, remove */
+       init_awaiter(&await1, shouldnt_run);
+       set_awaiter_abs(&await1, now + 1000000000);
+       set_alarm(tchain, &await1);
+       reset_alarm_abs(tchain, &await1, now + 1000000000 - 50);
+       reset_alarm_abs(tchain, &await1, now + 1000000000 + 50);
+       unset_alarm(tchain, &await1);
+       /* Test insert of one that fired already */
+       init_awaiter(&await2, empty_run);
+       set_awaiter_rel(&await2, 1);
+       set_alarm(tchain, &await2);
+       enable_irq();
+       udelay(1000);
+       reset_alarm_abs(tchain, &await2, now + 10);
+       udelay(1000);
+       unset_alarm(tchain, &await2);
+
+       printk("%s complete\n", __FUNCTION__);
+
+       return true;
+}
+
+/* Linker function tests.  Keep them commented, etc. */
+#if 0
+linker_func_1(xme11)
+{
+       printk("xme11\n");
+}
+
+linker_func_1(xme12)
+{
+       printk("xme12\n");
+}
+
+linker_func_1(xme13)
+{
+       printk("xme13\n");
+}
+
+linker_func_1(xme14)
+{
+       printk("xme14\n");
+}
+
+linker_func_1(xme15)
+{
+       printk("xme15\n");
+}
+
+linker_func_2(xme21)
+{
+       printk("xme21\n");
+}
+
+linker_func_2(xme22)
+{
+       printk("xme22\n");
+}
+
+linker_func_2(xme23)
+{
+       printk("xme23\n");
+}
+
+linker_func_2(xme24)
+{
+       printk("xme24\n");
+}
+
+linker_func_2(xme25)
+{
+       printk("xme25\n");
+}
+
+linker_func_3(xme31)
+{
+       printk("xme31\n");
+}
+
+linker_func_3(xme32)
+{
+       printk("xme32\n");
+}
+
+linker_func_3(xme33)
+{
+       printk("xme33\n");
+}
+
+linker_func_3(xme34)
+{
+       printk("xme34\n");
+}
+
+linker_func_3(xme35)
+{
+       printk("xme35\n");
+}
+
+linker_func_4(xme41)
+{
+       printk("xme41\n");
+}
+
+linker_func_4(xme42)
+{
+       printk("xme42\n");
+}
+
+linker_func_4(xme43)
+{
+       printk("xme43\n");
+}
+
+linker_func_4(xme44)
+{
+       printk("xme44\n");
+}
+
+linker_func_4(xme45)
+{
+       printk("xme45\n");
+}
+#endif /* linker func tests */
diff --git a/kern/src/tests_pb_kernel.c b/kern/src/tests_pb_kernel.c
deleted file mode 100644 (file)
index 71be1e0..0000000
+++ /dev/null
@@ -1,2120 +0,0 @@
-/*
- * Postboot kernel tests: Tests to be ran after boot in kernel mode.
- * TODO: Some of the tests here may not necessarily be tests to be ran after
- *       boot. If that is the case, change them in
- */
-
-#ifdef __SHARC__
-#pragma nosharc
-#endif
-
-#include <arch/mmu.h>
-#include <arch/arch.h>
-#include <bitmask.h>
-#include <smp.h>
-
-#include <ros/memlayout.h>
-#include <ros/common.h>
-#include <ros/bcq.h>
-#include <ros/ucq.h>
-
-#include <atomic.h>
-#include <stdio.h>
-#include <assert.h>
-#include <string.h>
-#include <testing.h>
-#include <trap.h>
-#include <process.h>
-#include <syscall.h>
-#include <time.h>
-#include <kfs.h>
-#include <multiboot.h>
-#include <pmap.h>
-#include <page_alloc.h>
-#include <pmap.h>
-#include <slab.h>
-#include <kmalloc.h>
-#include <hashtable.h>
-#include <radix.h>
-#include <monitor.h>
-#include <kthread.h>
-#include <schedule.h>
-#include <umem.h>
-#include <ucq.h>
-#include <setjmp.h>
-
-#include <apipe.h>
-#include <rwlock.h>
-#include <rendez.h>
-
-#define l1 (available_caches.l1)
-#define l2 (available_caches.l2)
-#define l3 (available_caches.l3)
-
-#ifdef CONFIG_X86
-
-// TODO: Do test if possible inside this function, and add assertions.
-bool test_ipi_sending(void)
-{
-       int8_t state = 0;
-
-       register_irq(I_TESTING, test_hello_world_handler, NULL,
-                    MKBUS(BusIPI, 0, 0, 0));
-       enable_irqsave(&state);
-       cprintf("\nCORE 0 sending broadcast\n");
-       send_broadcast_ipi(I_TESTING);
-       udelay(3000000);
-       cprintf("\nCORE 0 sending all others\n");
-       send_all_others_ipi(I_TESTING);
-       udelay(3000000);
-       cprintf("\nCORE 0 sending self\n");
-       send_self_ipi(I_TESTING);
-       udelay(3000000);
-       cprintf("\nCORE 0 sending ipi to physical 1\n");
-       send_ipi(0x01, I_TESTING);
-       udelay(3000000);
-       cprintf("\nCORE 0 sending ipi to physical 2\n");
-       send_ipi(0x02, I_TESTING);
-       udelay(3000000);
-       cprintf("\nCORE 0 sending ipi to physical 3\n");
-       send_ipi(0x03, I_TESTING);
-       udelay(3000000);
-       cprintf("\nCORE 0 sending ipi to physical 15\n");
-       send_ipi(0x0f, I_TESTING);
-       udelay(3000000);
-       cprintf("\nCORE 0 sending ipi to logical 2\n");
-       send_group_ipi(0x02, I_TESTING);
-       udelay(3000000);
-       cprintf("\nCORE 0 sending ipi to logical 1\n");
-       send_group_ipi(0x01, I_TESTING);
-       udelay(3000000);
-       cprintf("\nDone!\n");
-       disable_irqsave(&state);
-
-       return true;
-}
-
-// TODO: Refactor to make it return and add assertions.
-// Note this never returns and will muck with any other timer work
-bool test_pic_reception(void)
-{
-       register_irq(IdtPIC + IrqCLOCK, test_hello_world_handler, NULL,
-                    MKBUS(BusISA, 0, 0, 0));
-       pit_set_timer(100,TIMER_RATEGEN); // totally arbitrary time
-       pic_unmask_irq(0, 0);
-       cprintf("PIC1 Mask = 0x%04x\n", inb(PIC1_DATA));
-       cprintf("PIC2 Mask = 0x%04x\n", inb(PIC2_DATA));
-       unmask_lapic_lvt(LAPIC_LVT_LINT0);
-       cprintf("Core %d's LINT0: 0x%08x\n", core_id(), read_mmreg32(LAPIC_LVT_LINT0));
-       enable_irq();
-       while(1);
-
-       return true;
-}
-
-// TODO: Add assertions.
-bool test_ioapic_pit_reroute(void) 
-{
-       register_irq(IdtPIC + IrqCLOCK, test_hello_world_handler, NULL,
-                    MKBUS(BusISA, 0, 0, 0));
-#ifdef CONFIG_ENABLE_MPTABLES
-#warning "not routing the irq"
-       //ioapic_route_irq(0, 3);       
-#endif
-
-       cprintf("Starting pit on core 3....\n");
-       udelay(3000000);
-       pit_set_timer(0xFFFE,TIMER_RATEGEN); // totally arbitrary time
-       
-       udelay(3000000);
-#ifdef CONFIG_ENABLE_MPTABLES
-#warning "NOT unrouting the irq"
-       //ioapic_unroute_irq(0);
-#endif
-       udelay(300000);
-       cprintf("Masked pit. Waiting before return...\n");
-       udelay(3000000);
-
-       return true;
-}
-
-#endif // CONFIG_X86
-
-// TODO: Assert printed info follows the standard (or whatever we want to test).
-bool test_print_info(void)
-{
-       cprintf("\nCORE 0 asking all cores to print info:\n");
-       smp_call_function_all(test_print_info_handler, NULL, 0);
-       cprintf("\nDone!\n");
-       return true;
-}
-
-// TODO: Add assertions. Possibly the way to go is to extract relevant info 
-//       from cache properties and make assertions on the colored pages lists 
-//       based on those.
-// TODO: The test was commented out. Figure out why was it like that and fix it.
-bool test_page_coloring(void) 
-{
-       /*
-       //Print the different cache properties of our machine
-       print_cache_properties("L1", l1);
-       cprintf("\n");
-       print_cache_properties("L2", l2);
-       cprintf("\n");
-       print_cache_properties("L3", l3);
-       cprintf("\n");
-
-       //Print some stats about our memory
-       cprintf("Max Address: %llu\n", MAX_VADDR);
-       cprintf("Num Pages: %u\n", npages);
-
-       //Declare a local variable for allocating pages 
-       page_t* page;
-
-       cprintf("Contents of the page free list:\n");
-       for(int i=0; i<llc_cache->num_colors; i++) {
-               cprintf("  COLOR %d:\n", i);
-               LIST_FOREACH(page, &colored_page_free_list[i], pg_link) {
-                       cprintf("    Page: %d\n", page2ppn(page));
-               }
-       }
-
-       //Run through and allocate all pages through l1_page_alloc
-       cprintf("Allocating from L1 page colors:\n");
-       for(int i=0; i<get_cache_num_page_colors(l1); i++) {
-               cprintf("  COLOR %d:\n", i);
-               while(colored_page_alloc(l1, &page, i) != -ENOMEM)
-                       cprintf("    Page: %d\n", page2ppn(page));
-       }
-
-       //Put all the pages back by reinitializing
-       page_init();
-       
-       //Run through and allocate all pages through l2_page_alloc
-       cprintf("Allocating from L2 page colors:\n");
-       for(int i=0; i<get_cache_num_page_colors(l2); i++) {
-               cprintf("  COLOR %d:\n", i);
-               while(colored_page_alloc(l2, &page, i) != -ENOMEM)
-                       cprintf("    Page: %d\n", page2ppn(page));
-       }
-
-       //Put all the pages back by reinitializing
-       page_init();
-       
-       //Run through and allocate all pages through l3_page_alloc
-       cprintf("Allocating from L3 page colors:\n");
-       for(int i=0; i<get_cache_num_page_colors(l3); i++) {
-               cprintf("  COLOR %d:\n", i);
-               while(colored_page_alloc(l3, &page, i) != -ENOMEM)
-                       cprintf("    Page: %d\n", page2ppn(page));
-       }
-       
-       //Put all the pages back by reinitializing
-       page_init();
-       
-       //Run through and allocate all pages through page_alloc
-       cprintf("Allocating from global allocator:\n");
-       while(upage_alloc(&page) != -ENOMEM)
-               cprintf("    Page: %d\n", page2ppn(page));
-       
-       if(colored_page_alloc(l2, &page, 0) != -ENOMEM)
-               cprintf("Should not get here, all pages should already be gone!\n");
-       cprintf("All pages gone for sure...\n");
-       
-       //Now lets put a few pages back using page_free..
-       cprintf("Reinserting pages via page_free and reallocating them...\n");
-       page_free(&pages[0]);
-       page_free(&pages[15]);
-       page_free(&pages[7]);
-       page_free(&pages[6]);
-       page_free(&pages[4]);
-
-       while(upage_alloc(&page) != -ENOMEM)
-               cprintf("Page: %d\n", page2ppn(page));  
-       
-       page_init();
-       */
-       return true;
-}
-
-// TODO: Add assertions.
-bool test_color_alloc(void) {
-       size_t checkpoint = 0;
-       uint8_t* colors_map = kmalloc(BYTES_FOR_BITMASK(llc_cache->num_colors), 0);
-       cache_color_alloc(l2, colors_map);
-       cache_color_alloc(l3, colors_map);
-       cache_color_alloc(l3, colors_map);
-       cache_color_alloc(l2, colors_map);
-       cache_color_free(llc_cache, colors_map);
-       cache_color_free(llc_cache, colors_map);
-       cache_color_free(llc_cache, colors_map);
-       cache_color_free(llc_cache, colors_map);
-       cache_color_free(llc_cache, colors_map);
-       cache_color_free(llc_cache, colors_map);
-       cache_color_free(llc_cache, colors_map);
-       cache_color_free(llc_cache, colors_map);
-       cache_color_free(llc_cache, colors_map);
-       cache_color_free(llc_cache, colors_map);
-       cache_color_free(llc_cache, colors_map);
-       cache_color_free(llc_cache, colors_map);
-       cache_color_free(llc_cache, colors_map);
-       cache_color_free(llc_cache, colors_map);
-       cache_color_free(llc_cache, colors_map);
-       cache_color_free(llc_cache, colors_map);
-       cache_color_free(l2, colors_map);
-       cache_color_free(llc_cache, colors_map);
-       cache_color_free(llc_cache, colors_map);
-
-print_cache_colors:
-       printk("L1 free colors, tot colors: %d\n", l1->num_colors);
-       PRINT_BITMASK(l1->free_colors_map, l1->num_colors);
-       printk("L2 free colors, tot colors: %d\n", l2->num_colors);
-       PRINT_BITMASK(l2->free_colors_map, l2->num_colors);
-       printk("L3 free colors, tot colors: %d\n", l3->num_colors);
-       PRINT_BITMASK(l3->free_colors_map, l3->num_colors);
-       printk("Process allocated colors\n");
-       PRINT_BITMASK(colors_map, llc_cache->num_colors);
-       printk("test_color_alloc() complete!\n");
-
-       return true;
-}
-
-barrier_t test_cpu_array;
-
-// TODO: Add assertions, try to do everything from within this same function.
-bool test_barrier(void)
-{
-       cprintf("Core 0 initializing barrier\n");
-       init_barrier(&test_cpu_array, num_cpus);
-       cprintf("Core 0 asking all cores to print ids, barrier, rinse, repeat\n");
-       smp_call_function_all(test_barrier_handler, NULL, 0);
-
-       return true;
-}
-
-// TODO: Maybe remove all the printing statements and instead use the 
-//       KT_ASSERT_M macro to include a message on assertions.
-bool test_interrupts_irqsave(void)
-{
-       int8_t state = 0;
-       printd("Testing Nesting Enabling first, turning ints off:\n");
-       disable_irq();
-       printd("Interrupts are: %x\n", irq_is_enabled());
-       KT_ASSERT(!irq_is_enabled());
-       printd("Enabling IRQSave\n");
-       enable_irqsave(&state);
-       printd("Interrupts are: %x\n", irq_is_enabled());
-       KT_ASSERT(irq_is_enabled());
-       printd("Enabling IRQSave Again\n");
-       enable_irqsave(&state);
-       printd("Interrupts are: %x\n", irq_is_enabled());
-       KT_ASSERT(irq_is_enabled());
-       printd("Disabling IRQSave Once\n");
-       disable_irqsave(&state);
-       printd("Interrupts are: %x\n", irq_is_enabled());
-       KT_ASSERT(irq_is_enabled());
-       printd("Disabling IRQSave Again\n");
-       disable_irqsave(&state);
-       printd("Interrupts are: %x\n", irq_is_enabled());
-       KT_ASSERT(!irq_is_enabled());
-       printd("Done.  Should have been 0, 200, 200, 200, 0\n");
-
-       printd("Testing Nesting Disabling first, turning ints on:\n");
-       state = 0;
-       enable_irq();
-       printd("Interrupts are: %x\n", irq_is_enabled());
-       KT_ASSERT(irq_is_enabled());
-       printd("Disabling IRQSave Once\n");
-       disable_irqsave(&state);
-       printd("Interrupts are: %x\n", irq_is_enabled());
-       KT_ASSERT(!irq_is_enabled());
-       printd("Disabling IRQSave Again\n");
-       disable_irqsave(&state);
-       printd("Interrupts are: %x\n", irq_is_enabled());
-       KT_ASSERT(!irq_is_enabled());
-       printd("Enabling IRQSave Once\n");
-       enable_irqsave(&state);
-       printd("Interrupts are: %x\n", irq_is_enabled());
-       KT_ASSERT(!irq_is_enabled());
-       printd("Enabling IRQSave Again\n");
-       enable_irqsave(&state);
-       printd("Interrupts are: %x\n", irq_is_enabled());
-       KT_ASSERT(irq_is_enabled());
-       printd("Done.  Should have been 200, 0, 0, 0, 200 \n");
-
-       state = 0;
-       disable_irq();
-       printd("Ints are off, enabling then disabling.\n");
-       enable_irqsave(&state);
-       printd("Interrupts are: %x\n", irq_is_enabled());
-       KT_ASSERT(irq_is_enabled());
-       disable_irqsave(&state);
-       printd("Interrupts are: %x\n", irq_is_enabled());
-       KT_ASSERT(!irq_is_enabled());
-       printd("Done.  Should have been 200, 0\n");
-
-       state = 0;
-       enable_irq();
-       printd("Ints are on, enabling then disabling.\n");
-       enable_irqsave(&state);
-       printd("Interrupts are: %x\n", irq_is_enabled());
-       KT_ASSERT(irq_is_enabled());
-       disable_irqsave(&state);
-       printd("Interrupts are: %x\n", irq_is_enabled());
-       KT_ASSERT(irq_is_enabled());
-       printd("Done.  Should have been 200, 200\n");
-
-       state = 0;
-       disable_irq();
-       printd("Ints are off, disabling then enabling.\n");
-       disable_irqsave(&state);
-       printd("Interrupts are: %x\n", irq_is_enabled());
-       KT_ASSERT(!irq_is_enabled());
-       enable_irqsave(&state);
-       printd("Interrupts are: %x\n", irq_is_enabled());
-       KT_ASSERT(!irq_is_enabled());
-       printd("Done.  Should have been 0, 0\n");
-
-       state = 0;
-       enable_irq();
-       printd("Ints are on, disabling then enabling.\n");
-       disable_irqsave(&state);
-       printd("Interrupts are: %x\n", irq_is_enabled());
-       KT_ASSERT(!irq_is_enabled());
-       enable_irqsave(&state);
-       printd("Interrupts are: %x\n", irq_is_enabled());
-       KT_ASSERT(irq_is_enabled());
-       printd("Done.  Should have been 0, 200\n");
-
-       disable_irq();
-       return true;
-}
-
-// TODO: Maybe remove PRINT_BITMASK statements and use KT_ASSERT_M instead
-//       somehow.
-bool test_bitmasks(void)
-{
-#define masksize 67
-       DECL_BITMASK(mask, masksize);
-       CLR_BITMASK(mask, masksize);
-//     PRINT_BITMASK(mask, masksize);
-       SET_BITMASK_BIT(mask, 0);
-       SET_BITMASK_BIT(mask, 11);
-       SET_BITMASK_BIT(mask, 17);
-       SET_BITMASK_BIT(mask, masksize-1);
-//     PRINT_BITMASK(mask, masksize);
-       DECL_BITMASK(mask2, masksize);
-       COPY_BITMASK(mask2, mask, masksize);
-//     printk("copy of original mask, should be the same as the prev\n");
-//     PRINT_BITMASK(mask2, masksize);
-       CLR_BITMASK_BIT(mask, 11);
-//     PRINT_BITMASK(mask, masksize);
-       KT_ASSERT_M("Bit 17 should be 1", 1 == GET_BITMASK_BIT(mask, 17));
-       KT_ASSERT_M("Bit 11 should be 0", 0 == GET_BITMASK_BIT(mask, 11));
-       FILL_BITMASK(mask, masksize);
-//     PRINT_BITMASK(mask, masksize);
-       KT_ASSERT_M("Bitmask should not be clear after calling FILL_BITMASK", 
-                   0 == BITMASK_IS_CLEAR(mask,masksize));
-       CLR_BITMASK(mask, masksize);
-//     PRINT_BITMASK(mask, masksize);
-       KT_ASSERT_M("Bitmask should be clear after calling CLR_BITMASK", 
-                   1 == BITMASK_IS_CLEAR(mask,masksize));
-       return true;
-}
-
-checklist_t *RO the_global_list;
-
-static void test_checklist_handler(struct hw_trapframe *hw_tf, void *data)
-{
-       udelay(1000000);
-       cprintf("down_checklist(%x,%d)\n", the_global_list, core_id());
-       down_checklist(the_global_list);
-}
-
-// TODO: Add assertions
-bool test_checklists(void)
-{
-       INIT_CHECKLIST(a_list, MAX_NUM_CPUS);
-       the_global_list = &a_list;
-       printk("Checklist Build, mask size: %d\n", sizeof(a_list.mask.bits));
-       printk("mask\n");
-       PRINT_BITMASK(a_list.mask.bits, a_list.mask.size);
-       SET_BITMASK_BIT(a_list.mask.bits, 11);
-       printk("Set bit 11\n");
-       PRINT_BITMASK(a_list.mask.bits, a_list.mask.size);
-
-       CLR_BITMASK(a_list.mask.bits, a_list.mask.size);
-       INIT_CHECKLIST_MASK(a_mask, MAX_NUM_CPUS);
-       FILL_BITMASK(a_mask.bits, num_cpus);
-       //CLR_BITMASK_BIT(a_mask.bits, core_id());
-       //SET_BITMASK_BIT(a_mask.bits, 1);
-       //printk("New mask (1, 17, 25):\n");
-       printk("Created new mask, filled up to num_cpus\n");
-       PRINT_BITMASK(a_mask.bits, a_mask.size);
-       printk("committing new mask\n");
-       commit_checklist_wait(&a_list, &a_mask);
-       printk("Old mask (copied onto):\n");
-       PRINT_BITMASK(a_list.mask.bits, a_list.mask.size);
-       //smp_call_function_single(1, test_checklist_handler, 0, 0);
-
-       smp_call_function_all(test_checklist_handler, NULL, 0);
-
-       printk("Waiting on checklist\n");
-       waiton_checklist(&a_list);
-       printk("Done Waiting!\n");
-
-       return true;
-}
-
-atomic_t a, b, c;
-
-static void test_incrementer_handler(struct hw_trapframe *tf, void *data)
-{
-       assert(data);
-       atomic_inc(data);
-}
-
-static void test_null_handler(struct hw_trapframe *tf, void *data)
-{
-       asm volatile("nop");
-}
-
-// TODO: Add assertions.
-bool test_smp_call_functions(void)
-{
-       int i;
-       atomic_init(&a, 0);
-       atomic_init(&b, 0);
-       atomic_init(&c, 0);
-       handler_wrapper_t *waiter0 = 0, *waiter1 = 0, *waiter2 = 0, *waiter3 = 0,
-                         *waiter4 = 0, *waiter5 = 0;
-       uint8_t me = core_id();
-       printk("\nCore %d: SMP Call Self (nowait):\n", me);
-       printk("---------------------\n");
-       smp_call_function_self(test_hello_world_handler, NULL, 0);
-       printk("\nCore %d: SMP Call Self (wait):\n", me);
-       printk("---------------------\n");
-       smp_call_function_self(test_hello_world_handler, NULL, &waiter0);
-       smp_call_wait(waiter0);
-       printk("\nCore %d: SMP Call All (nowait):\n", me);
-       printk("---------------------\n");
-       smp_call_function_all(test_hello_world_handler, NULL, 0);
-       printk("\nCore %d: SMP Call All (wait):\n", me);
-       printk("---------------------\n");
-       smp_call_function_all(test_hello_world_handler, NULL, &waiter0);
-       smp_call_wait(waiter0);
-       printk("\nCore %d: SMP Call All-Else Individually, in order (nowait):\n", me);
-       printk("---------------------\n");
-       for(i = 1; i < num_cpus; i++)
-               smp_call_function_single(i, test_hello_world_handler, NULL, 0);
-       printk("\nCore %d: SMP Call Self (wait):\n", me);
-       printk("---------------------\n");
-       smp_call_function_self(test_hello_world_handler, NULL, &waiter0);
-       smp_call_wait(waiter0);
-       printk("\nCore %d: SMP Call All-Else Individually, in order (wait):\n", me);
-       printk("---------------------\n");
-       for(i = 1; i < num_cpus; i++)
-       {
-               smp_call_function_single(i, test_hello_world_handler, NULL, &waiter0);
-               smp_call_wait(waiter0);
-       }
-       printk("\nTesting to see if any IPI-functions are dropped when not waiting:\n");
-       printk("A: %d, B: %d, C: %d (should be 0,0,0)\n", atomic_read(&a), atomic_read(&b), atomic_read(&c));
-       smp_call_function_all(test_incrementer_handler, &a, 0);
-       smp_call_function_all(test_incrementer_handler, &b, 0);
-       smp_call_function_all(test_incrementer_handler, &c, 0);
-       // if i can clobber a previous IPI, the interleaving might do it
-       smp_call_function_single(1 % num_cpus, test_incrementer_handler, &a, 0);
-       smp_call_function_single(2 % num_cpus, test_incrementer_handler, &b, 0);
-       smp_call_function_single(3 % num_cpus, test_incrementer_handler, &c, 0);
-       smp_call_function_single(4 % num_cpus, test_incrementer_handler, &a, 0);
-       smp_call_function_single(5 % num_cpus, test_incrementer_handler, &b, 0);
-       smp_call_function_single(6 % num_cpus, test_incrementer_handler, &c, 0);
-       smp_call_function_all(test_incrementer_handler, &a, 0);
-       smp_call_function_single(3 % num_cpus, test_incrementer_handler, &c, 0);
-       smp_call_function_all(test_incrementer_handler, &b, 0);
-       smp_call_function_single(1 % num_cpus, test_incrementer_handler, &a, 0);
-       smp_call_function_all(test_incrementer_handler, &c, 0);
-       smp_call_function_single(2 % num_cpus, test_incrementer_handler, &b, 0);
-       // wait, so we're sure the others finish before printing.
-       // without this, we could (and did) get 19,18,19, since the B_inc
-       // handler didn't finish yet
-       smp_call_function_self(test_null_handler, NULL, &waiter0);
-       // need to grab all 5 handlers (max), since the code moves to the next free.
-       smp_call_function_self(test_null_handler, NULL, &waiter1);
-       smp_call_function_self(test_null_handler, NULL, &waiter2);
-       smp_call_function_self(test_null_handler, NULL, &waiter3);
-       smp_call_function_self(test_null_handler, NULL, &waiter4);
-       smp_call_wait(waiter0);
-       smp_call_wait(waiter1);
-       smp_call_wait(waiter2);
-       smp_call_wait(waiter3);
-       smp_call_wait(waiter4);
-       printk("A: %d, B: %d, C: %d (should be 19,19,19)\n", atomic_read(&a), atomic_read(&b), atomic_read(&c));
-       printk("Attempting to deadlock by smp_calling with an outstanding wait:\n");
-       smp_call_function_self(test_null_handler, NULL, &waiter0);
-       printk("Sent one\n");
-       smp_call_function_self(test_null_handler, NULL, &waiter1);
-       printk("Sent two\n");
-       smp_call_wait(waiter0);
-       printk("Wait one\n");
-       smp_call_wait(waiter1);
-       printk("Wait two\n");
-       printk("\tMade it through!\n");
-       printk("Attempting to deadlock by smp_calling more than are available:\n");
-       printk("\tShould see an Insufficient message and a kernel warning.\n");
-       if (smp_call_function_self(test_null_handler, NULL, &waiter0))
-               printk("\tInsufficient handlers to call function (0)\n");
-       if (smp_call_function_self(test_null_handler, NULL, &waiter1))
-               printk("\tInsufficient handlers to call function (1)\n");
-       if (smp_call_function_self(test_null_handler, NULL, &waiter2))
-               printk("\tInsufficient handlers to call function (2)\n");
-       if (smp_call_function_self(test_null_handler, NULL, &waiter3))
-               printk("\tInsufficient handlers to call function (3)\n");
-       if (smp_call_function_self(test_null_handler, NULL, &waiter4))
-               printk("\tInsufficient handlers to call function (4)\n");
-       if (smp_call_function_self(test_null_handler, NULL, &waiter5))
-               printk("\tInsufficient handlers to call function (5)\n");
-       smp_call_wait(waiter0);
-       smp_call_wait(waiter1);
-       smp_call_wait(waiter2);
-       smp_call_wait(waiter3);
-       smp_call_wait(waiter4);
-       smp_call_wait(waiter5);
-       printk("\tMade it through!\n");
-
-       printk("Done\n");
-
-       return true;
-}
-
-#ifdef CONFIG_X86
-// TODO: Fix the KT_ASSERTs
-bool test_lapic_status_bit(void)
-{
-       register_irq(I_TESTING, test_incrementer_handler, &a,
-                    MKBUS(BusIPI, 0, 0, 0));
-       #define NUM_IPI 100000
-       atomic_set(&a,0);
-       printk("IPIs received (should be 0): %d\n", a);
-       // KT_ASSERT_M("IPIs received should be 0", (0 == a));
-       for(int i = 0; i < NUM_IPI; i++) {
-               send_ipi(7, I_TESTING);
-               lapic_wait_to_send();
-       }
-       // need to wait a bit to let those IPIs get there
-       udelay(5000000);
-       printk("IPIs received (should be %d): %d\n", a, NUM_IPI);
-       // KT_ASSERT_M("IPIs received should be 100000", (NUM_IPI == a));
-       // hopefully that handler never fires again.  leaving it registered for now.
-
-       return true;
-}
-#endif // CONFIG_X86
-
-/************************************************************/
-/* ISR Handler Functions */
-
-void test_hello_world_handler(struct hw_trapframe *hw_tf, void *data)
-{
-       int trapno;
-       #if defined(CONFIG_X86)
-       trapno = hw_tf->tf_trapno;
-       #else
-       trapno = 0;
-       #endif
-
-       cprintf("Incoming IRQ, ISR: %d on core %d with tf at %p\n",
-               trapno, core_id(), hw_tf);
-}
-
-spinlock_t print_info_lock = SPINLOCK_INITIALIZER_IRQSAVE;
-
-void test_print_info_handler(struct hw_trapframe *hw_tf, void *data)
-{
-       uint64_t tsc = read_tsc();
-
-       spin_lock_irqsave(&print_info_lock);
-       cprintf("----------------------------\n");
-       cprintf("This is Core %d\n", core_id());
-       cprintf("Timestamp = %lld\n", tsc);
-#ifdef CONFIG_X86
-       cprintf("Hardware core %d\n", hw_core_id());
-       cprintf("MTRR_DEF_TYPE = 0x%08x\n", read_msr(IA32_MTRR_DEF_TYPE));
-       cprintf("MTRR Phys0 Base = 0x%016llx, Mask = 0x%016llx\n",
-               read_msr(0x200), read_msr(0x201));
-       cprintf("MTRR Phys1 Base = 0x%016llx, Mask = 0x%016llx\n",
-               read_msr(0x202), read_msr(0x203));
-       cprintf("MTRR Phys2 Base = 0x%016llx, Mask = 0x%016llx\n",
-               read_msr(0x204), read_msr(0x205));
-       cprintf("MTRR Phys3 Base = 0x%016llx, Mask = 0x%016llx\n",
-               read_msr(0x206), read_msr(0x207));
-       cprintf("MTRR Phys4 Base = 0x%016llx, Mask = 0x%016llx\n",
-               read_msr(0x208), read_msr(0x209));
-       cprintf("MTRR Phys5 Base = 0x%016llx, Mask = 0x%016llx\n",
-               read_msr(0x20a), read_msr(0x20b));
-       cprintf("MTRR Phys6 Base = 0x%016llx, Mask = 0x%016llx\n",
-               read_msr(0x20c), read_msr(0x20d));
-       cprintf("MTRR Phys7 Base = 0x%016llx, Mask = 0x%016llx\n",
-               read_msr(0x20e), read_msr(0x20f));
-#endif // CONFIG_X86
-       cprintf("----------------------------\n");
-       spin_unlock_irqsave(&print_info_lock);
-}
-
-void test_barrier_handler(struct hw_trapframe *hw_tf, void *data)
-{
-       cprintf("Round 1: Core %d\n", core_id());
-       waiton_barrier(&test_cpu_array);
-       waiton_barrier(&test_cpu_array);
-       waiton_barrier(&test_cpu_array);
-       waiton_barrier(&test_cpu_array);
-       waiton_barrier(&test_cpu_array);
-       waiton_barrier(&test_cpu_array);
-       cprintf("Round 2: Core %d\n", core_id());
-       waiton_barrier(&test_cpu_array);
-       cprintf("Round 3: Core %d\n", core_id());
-       // uncomment to see it fucked up
-       //cprintf("Round 4: Core %d\n", core_id());
-}
-
-static void test_waiting_handler(struct hw_trapframe *hw_tf, void *data)
-{
-       atomic_dec(data);
-}
-
-#ifdef CONFIG_X86
-// TODO: Add assertions.
-bool test_pit(void)
-{
-       cprintf("Starting test for PIT now (10s)\n");
-       udelay_pit(10000000);
-       cprintf("End now\n");
-       cprintf("Starting test for TSC (if stable) now (10s)\n");
-       udelay(10000000);
-       cprintf("End now\n");
-
-       cprintf("Starting test for LAPIC (if stable) now (10s)\n");
-       enable_irq();
-       lapic_set_timer(10000000, FALSE);
-
-       atomic_t waiting;
-       atomic_init(&waiting, 1);
-       register_irq(I_TESTING, test_waiting_handler, &waiting,
-                    MKBUS(BusIPI, 0, 0, 0));
-       while(atomic_read(&waiting))
-               cpu_relax();
-       cprintf("End now\n");
-
-       return true;
-}
-
-// TODO: Add assertions.
-bool test_circ_buffer(void)
-{
-       int arr[5] = {0, 1, 2, 3, 4};
-
-       for (int i = 0; i < 5; i++) {
-               FOR_CIRC_BUFFER(i, 5, j)
-                       printk("Starting with current = %d, each value = %d\n", i, j);
-       }
-       
-       return true;
-}
-
-static void test_km_handler(uint32_t srcid, long a0, long a1, long a2)
-{
-       printk("Received KM on core %d from core %d: arg0= %p, arg1 = %p, "
-              "arg2 = %p\n", core_id(), srcid, a0, a1, a2);
-       return;
-}
-
-// TODO: Add assertions. Try to do everything inside this function.
-bool test_kernel_messages(void)
-{
-       printk("Testing Kernel Messages\n");
-       /* Testing sending multiples, sending different types, alternating, and
-        * precendence (the immediates should trump the others) */
-       printk("sending 5 IMMED to core 1, sending (#,deadbeef,0)\n");
-       for (int i = 0; i < 5; i++)
-               send_kernel_message(1, test_km_handler, (long)i, 0xdeadbeef, 0,
-                                   KMSG_IMMEDIATE);
-       udelay(5000000);
-       printk("sending 5 routine to core 1, sending (#,cafebabe,0)\n");
-       for (int i = 0; i < 5; i++)
-               send_kernel_message(1, test_km_handler, (long)i, 0xcafebabe, 0,
-                                   KMSG_ROUTINE);
-       udelay(5000000);
-       printk("sending 10 routine and 3 immediate to core 2\n");
-       for (int i = 0; i < 10; i++)
-               send_kernel_message(2, test_km_handler, (long)i, 0xcafebabe, 0,
-                                   KMSG_ROUTINE);
-       for (int i = 0; i < 3; i++)
-               send_kernel_message(2, test_km_handler, (long)i, 0xdeadbeef, 0,
-                                   KMSG_IMMEDIATE);
-       udelay(5000000);
-       printk("sending 5 ea alternating to core 2\n");
-       for (int i = 0; i < 5; i++) {
-               send_kernel_message(2, test_km_handler, (long)i, 0xdeadbeef, 0,
-                                   KMSG_IMMEDIATE);
-               send_kernel_message(2, test_km_handler, (long)i, 0xcafebabe, 0,
-                                   KMSG_ROUTINE);
-       }
-       udelay(5000000);
-       
-       return true;
-}
-#endif // CONFIG_X86
-static void test_single_cache(int iters, size_t size, int align, int flags,
-                              void (*ctor)(void *, size_t),
-                              void (*dtor)(void *, size_t))
-{
-       struct kmem_cache *test_cache;
-       void *objects[iters];
-       test_cache = kmem_cache_create("test_cache", size, align, flags, ctor, dtor);
-       printk("Testing Kmem Cache:\n");
-       print_kmem_cache(test_cache);
-       for (int i = 0; i < iters; i++) {
-               objects[i] = kmem_cache_alloc(test_cache, 0);
-               printk("Buffer %d addr = %p\n", i, objects[i]);
-       }
-       for (int i = 0; i < iters; i++) {
-               kmem_cache_free(test_cache, objects[i]);
-       }
-       kmem_cache_destroy(test_cache);
-       printk("\n\n\n\n");
-}
-
-void a_ctor(void *buf, size_t size)
-{
-       printk("constructin tests\n");
-}
-void a_dtor(void *buf, size_t size)
-{
-       printk("destructin tests\n");
-}
-
-// TODO: Make test_single_cache return something, and then add assertions here.
-bool test_slab(void)
-{
-       test_single_cache(10, 128, 512, 0, 0, 0);
-       test_single_cache(10, 128, 4, 0, a_ctor, a_dtor);
-       test_single_cache(10, 1024, 16, 0, 0, 0);
-
-       return true;
-}
-
-// TODO: Add assertions.
-bool test_kmalloc(void)
-{
-       printk("Testing Kmalloc\n");
-       void *bufs[NUM_KMALLOC_CACHES + 1];     
-       size_t size;
-       for (int i = 0; i < NUM_KMALLOC_CACHES + 1; i++){
-               size = (KMALLOC_SMALLEST << i) - sizeof(struct kmalloc_tag);
-               bufs[i] = kmalloc(size, 0);
-               printk("Size %d, Addr = %p\n", size, bufs[i]);
-       }
-       for (int i = 0; i < NUM_KMALLOC_CACHES; i++) {
-               printk("Freeing buffer %d\n", i);
-               kfree(bufs[i]);
-       }
-       printk("Testing a large kmalloc\n");
-       size = (KMALLOC_LARGEST << 2);
-       bufs[0] = kmalloc(size, 0);
-       printk("Size %d, Addr = %p\n", size, bufs[0]);
-       kfree(bufs[0]);
-
-       return true;
-}
-
-static size_t test_hash_fn_col(void *k)
-{
-       return (size_t)k % 2; // collisions in slots 0 and 1
-}
-
-bool test_hashtable(void)
-{
-       struct test {int x; int y;};
-       struct test tstruct[10];
-
-       struct hashtable *h;
-       uintptr_t k = 5;
-       struct test *v = &tstruct[0];
-
-       h = create_hashtable(32, __generic_hash, __generic_eq);
-       
-       // test inserting one item, then finding it again
-       KT_ASSERT_M("It should be possible to insert items to a hashtable", 
-                   hashtable_insert(h, (void*)k, v));
-       v = NULL;
-       KT_ASSERT_M("It should be possible to find inserted stuff in a hashtable", 
-                   (v = hashtable_search(h, (void*)k)));
-
-       KT_ASSERT_M("The extracted element should be the same we inserted", 
-                   (v == &tstruct[0]));
-
-       v = NULL;
-
-       KT_ASSERT_M("It should be possible to remove an existing element", 
-                   (v = hashtable_remove(h, (void*)k)));
-
-       KT_ASSERT_M("An element should not remain in a hashtable after deletion", 
-                   !(v = hashtable_search(h, (void*)k)));
-
-       /* Testing a bunch of items, insert, search, and removal */
-       for (int i = 0; i < 10; i++) {
-               k = i; // vary the key, we don't do KEY collisions
-               KT_ASSERT_M("It should be possible to insert elements to a hashtable", 
-                           (hashtable_insert(h, (void*)k, &tstruct[i])));
-       }
-       // read out the 10 items
-       for (int i = 0; i < 10; i++) {
-               k = i;
-               KT_ASSERT_M("It should be possible to find inserted stuff in a hashtable", 
-                           (v = hashtable_search(h, (void*)k)));
-               KT_ASSERT_M("The extracted element should be the same we inserted", 
-                           (v == &tstruct[i]));
-       }
-
-       KT_ASSERT_M("The total count of number of elements should be 10", 
-                   (10 == hashtable_count(h)));
-
-       // remove the 10 items
-       for (int i = 0; i < 10; i++) {
-               k = i;
-               KT_ASSERT_M("It should be possible to remove an existing element", 
-                           (v = hashtable_remove(h, (void*)k)));
-
-       }
-       // make sure they are all gone
-       for (int i = 0; i < 10; i++) {
-               k = i;
-               KT_ASSERT_M("An element should not remain in a hashtable after deletion", 
-                           !(v = hashtable_search(h, (void*)k)));
-       }
-
-       KT_ASSERT_M("The hashtable should be empty", 
-                   (0 == hashtable_count(h)));
-
-       hashtable_destroy(h);
-
-       // same test of a bunch of items, but with collisions.
-       /* Testing a bunch of items with collisions, etc. */
-       h = create_hashtable(32, test_hash_fn_col, __generic_eq);
-       // insert 10 items
-       for (int i = 0; i < 10; i++) {
-               k = i; // vary the key, we don't do KEY collisions
-
-               KT_ASSERT_M("It should be possible to insert elements to a hashtable", 
-                           (hashtable_insert(h, (void*)k, &tstruct[i])));
-       }
-       // read out the 10 items
-       for (int i = 0; i < 10; i++) {
-               k = i;
-               KT_ASSERT_M("It should be possible to find inserted stuff in a hashtable", 
-                           (v = hashtable_search(h, (void*)k)));
-               KT_ASSERT_M("The extracted element should be the same we inserted", 
-                           (v == &tstruct[i]));
-       }
-
-       KT_ASSERT_M("The total count of number of elements should be 10", 
-                   (10 == hashtable_count(h)));
-
-       // remove the 10 items
-       for (int i = 0; i < 10; i++) {
-               k = i;
-               KT_ASSERT_M("It should be possible to remove an existing element", 
-                           (v = hashtable_remove(h, (void*)k)));
-       }
-       // make sure they are all gone
-       for (int i = 0; i < 10; i++) {
-               k = i;
-
-               KT_ASSERT_M("An element should not remain in a hashtable after deletion", 
-                           !(v = hashtable_search(h, (void*)k)));
-       }
-
-       KT_ASSERT_M("The hashtable should be empty", 
-                   (0 == hashtable_count(h)));
-
-       hashtable_destroy(h);
-
-       return true;
-}
-
-/* Ghetto test, only tests one prod or consumer at a time */
-// TODO: Un-guetto test, add assertions.
-bool test_bcq(void)
-{
-       /* Tests a basic struct */
-       struct my_struct {
-               int x;
-               int y;
-       };
-       struct my_struct in_struct, out_struct;
-       
-       DEFINE_BCQ_TYPES(test, struct my_struct, 16);
-       struct test_bcq t_bcq;
-       bcq_init(&t_bcq, struct my_struct, 16);
-       
-       in_struct.x = 4;
-       in_struct.y = 5;
-       out_struct.x = 1;
-       out_struct.y = 2;
-       
-       bcq_enqueue(&t_bcq, &in_struct, 16, 5);
-       bcq_dequeue(&t_bcq, &out_struct, 16);
-       printk("out x %d. out y %d\n", out_struct.x, out_struct.y);
-       
-       /* Tests the BCQ a bit more, esp with overflow */
-       #define NR_ELEM_A_BCQ 8 /* NOTE: this must be a power of 2! */
-       DEFINE_BCQ_TYPES(my, int, NR_ELEM_A_BCQ);
-       struct my_bcq a_bcq;
-       bcq_init(&a_bcq, int, NR_ELEM_A_BCQ);
-       
-       int y = 2;
-       int output[100];
-       int retval[100];
-
-       /* Helpful debugger */
-       void print_a_bcq(struct my_bcq *bcq)
-       {
-               printk("A BCQ (made of ints): %p\n", bcq);
-               printk("\tprod_idx: %p\n", bcq->hdr.prod_idx);
-               printk("\tcons_pub_idx: %p\n", bcq->hdr.cons_pub_idx);
-               printk("\tcons_pvt_idx: %p\n", bcq->hdr.cons_pvt_idx);
-               for (int i = 0; i < NR_ELEM_A_BCQ; i++) {
-                       printk("Element %d, rdy_for_cons: %02p\n", i,
-                              bcq->wraps[i].rdy_for_cons);
-               }
-       }
-
-       /* Put in more than it can take */
-       for (int i = 0; i < 15; i++) {
-               y = i;
-               retval[i] = bcq_enqueue(&a_bcq, &y, NR_ELEM_A_BCQ, 10);
-               printk("enqueued: %d, had retval %d \n", y, retval[i]);
-       }
-       //print_a_bcq(&a_bcq);
-       
-       /* Try to dequeue more than we put in */
-       for (int i = 0; i < 15; i++) {
-               retval[i] = bcq_dequeue(&a_bcq, &output[i], NR_ELEM_A_BCQ);
-               printk("dequeued: %d with retval %d\n", output[i], retval[i]);
-       }
-       //print_a_bcq(&a_bcq);
-       
-       /* Put in some it should be able to take */
-       for (int i = 0; i < 3; i++) {
-               y = i;
-               retval[i] = bcq_enqueue(&a_bcq, &y, NR_ELEM_A_BCQ, 10);
-               printk("enqueued: %d, had retval %d \n", y, retval[i]);
-       }
-       
-       /* Take those, and then a couple extra */
-       for (int i = 0; i < 5; i++) {
-               retval[i] = bcq_dequeue(&a_bcq, &output[i], NR_ELEM_A_BCQ);
-               printk("dequeued: %d with retval %d\n", output[i], retval[i]);
-       }
-       
-       /* Try some one-for-one */
-       for (int i = 0; i < 5; i++) {
-               y = i;
-               retval[i] = bcq_enqueue(&a_bcq, &y, NR_ELEM_A_BCQ, 10);
-               printk("enqueued: %d, had retval %d \n", y, retval[i]);
-               retval[i] = bcq_dequeue(&a_bcq, &output[i], NR_ELEM_A_BCQ);
-               printk("dequeued: %d with retval %d\n", output[i], retval[i]);
-       }
-
-       return true;
-}
-
-/* Test a simple concurrent send and receive (one prod, one cons).  We spawn a
- * process that will go into _M mode on another core, and we'll do the test from
- * an alarm handler run on our core.  When we start up the process, we won't
- * return so we need to defer the work with an alarm. */
-// TODO: Check if we can add more assertions.
-bool test_ucq(void)
-{
-       struct timer_chain *tchain = &per_cpu_info[core_id()].tchain;
-       struct alarm_waiter *waiter = kmalloc(sizeof(struct alarm_waiter), 0);
-
-       /* Alarm handler: what we want to do after the process is up */
-       void send_msgs(struct alarm_waiter *waiter)
-       {
-               struct timer_chain *tchain;
-               struct proc *old_proc, *p = waiter->data;
-               struct ucq *ucq = (struct ucq*)USTACKTOP;
-               struct event_msg msg;
-
-               printk("Running the alarm handler!\n");
-               printk("NR msg per page: %d\n", NR_MSG_PER_PAGE);
-               /* might not be mmaped yet, if not, abort.  We used to user_mem_check,
-                * but now we just touch it and PF. */
-               char touch = *(char*)ucq;
-               asm volatile ("" : : "r"(touch));
-               /* load their address space */
-               old_proc = switch_to(p);
-               /* So it's mmaped, see if it is ready (note that this is dangerous) */
-               if (!ucq->ucq_ready) {
-                       printk("Not ready yet\n");
-                       switch_back(p, old_proc);
-                       goto abort;
-               }
-               /* So it's ready, time to finally do the tests... */
-               printk("[kernel] Finally starting the tests... \n");
-               /* 1: Send a simple message */
-               printk("[kernel] #1 Sending simple message (7, deadbeef)\n");
-               msg.ev_type = 7;
-               msg.ev_arg2 = 0xdeadbeef;
-               send_ucq_msg(ucq, p, &msg);
-               printk("nr_pages: %d\n", atomic_read(&ucq->nr_extra_pgs));
-               /* 2: Send a bunch.  In a VM, this causes one swap, and then a bunch of
-                * mmaps. */
-               printk("[kernel] #2 \n");
-               for (int i = 0; i < 5000; i++) {
-                       msg.ev_type = i;
-                       send_ucq_msg(ucq, p, &msg);
-               }
-               printk("nr_pages: %d\n", atomic_read(&ucq->nr_extra_pgs));
-               printk("[kernel] #3 \n");
-               /* 3: make sure we chained pages (assuming 1k is enough) */
-               for (int i = 0; i < 1000; i++) {
-                       msg.ev_type = i;
-                       send_ucq_msg(ucq, p, &msg);
-               }
-               printk("nr_pages: %d\n", atomic_read(&ucq->nr_extra_pgs));
-               /* other things we could do:
-                *  - concurrent producers / consumers...  ugh.
-                *  - would require a kmsg to another core, instead of a local alarm
-                */
-               /* done, switch back and free things */
-               switch_back(p, old_proc);
-               proc_decref(p);
-               kfree(waiter); /* since it was kmalloc()d */
-               return;
-       abort:
-               tchain = &per_cpu_info[core_id()].tchain;
-               /* Set to run again */
-               set_awaiter_rel(waiter, 1000000);
-               set_alarm(tchain, waiter);
-       }
-       /* Set up a handler to run the real part of the test */
-       init_awaiter(waiter, send_msgs);
-       set_awaiter_rel(waiter, 1000000);       /* 1s should be long enough */
-       set_alarm(tchain, waiter);
-       /* Just spawn the program */
-       struct file *program;
-       program = do_file_open("/bin/ucq", 0, 0);
-       
-       KT_ASSERT_M("We should be able to find /bin/ucq", 
-                   program);
-
-       char *p_envp[] = {"LD_LIBRARY_PATH=/lib", 0};
-       struct proc *p = proc_create(program, 0, p_envp);
-       proc_wakeup(p);
-       /* instead of getting rid of the reference created in proc_create, we'll put
-        * it in the awaiter */
-       waiter->data = p;
-       kref_put(&program->f_kref);
-       /* Should never return from schedule (env_pop in there) also note you may
-        * not get the process you created, in the event there are others floating
-        * around that are runnable */
-       run_scheduler();
-       smp_idle();
-       
-       KT_ASSERT_M("We should never return from schedule",
-                   false);
-
-       return true;
-}
-
-/* rudimentary tests.  does the basics, create, merge, split, etc.  Feel free to
- * add more, esp for the error conditions and finding free slots.  This is also
- * a bit lazy with setting the caller's fields (perm, flags, etc). */
-// TODO: See if we could add more assertions, try to add more descriptive
-//       messages to assertions.
-bool test_vm_regions(void)
-{
-       #define MAX_VMR_TESTS 10
-       struct proc pr, *p = &pr;       /* too lazy to even create one */
-       int n = 0;
-       TAILQ_INIT(&p->vm_regions);
-
-       struct vmr_summary {
-               uintptr_t base; 
-               uintptr_t end; 
-       };
-       int check_vmrs(struct proc *p, struct vmr_summary *results, int len, int n)
-       {
-               int count = 0;
-               struct vm_region *vmr;
-               TAILQ_FOREACH(vmr, &p->vm_regions, vm_link) {
-                       if (count >= len) {
-                               printk("More vm_regions than expected\n");
-                               break;
-                       }
-                       if ((vmr->vm_base != results[count].base) ||
-                           (vmr->vm_end != results[count].end)) {
-                               printk("VM test case %d failed!\n", n);
-                               print_vmrs(p);
-                               return -1;
-                       }
-                       count++;
-               }
-               return count;
-       }
-       struct vm_region *vmrs[MAX_VMR_TESTS];
-       struct vmr_summary results[MAX_VMR_TESTS];
-
-       memset(results, 0, sizeof(results));
-       /* Make one */
-       vmrs[0] = create_vmr(p, 0x2000, 0x1000);
-       results[0].base = 0x2000;
-       results[0].end = 0x3000;
-       check_vmrs(p, results, 1, n++);
-       /* Grow it */
-       grow_vmr(vmrs[0], 0x4000);
-       results[0].base = 0x2000;
-       results[0].end = 0x4000;
-       check_vmrs(p, results, 1, n++);
-       /* Grow it poorly */
-       KT_ASSERT_M("It should pass bad grow test", 
-                   (-1 == grow_vmr(vmrs[0], 0x3000)));
-       check_vmrs(p, results, 1, n++);
-       /* Make another right next to it */
-       vmrs[1] = create_vmr(p, 0x4000, 0x1000);
-       results[1].base = 0x4000;
-       results[1].end = 0x5000;
-       check_vmrs(p, results, 2, n++);
-       /* try to grow through it */
-       KT_ASSERT_M("It should pass bad grow test", 
-                   (-1 == grow_vmr(vmrs[0], 0x5000)));
-       check_vmrs(p, results, 2, n++);
-       /* Merge them */
-       merge_vmr(vmrs[0], vmrs[1]);
-       results[0].end = 0x5000;
-       results[1].base = 0;
-       results[1].end = 0;
-       check_vmrs(p, results, 1, n++);
-       vmrs[1]= create_vmr(p, 0x6000, 0x4000);
-       results[1].base = 0x6000;
-       results[1].end = 0xa000;
-       check_vmrs(p, results, 2, n++);
-       /* try to merge unmergables (just testing ranges) */
-       KT_ASSERT_M("It should pass bad merge test", 
-                   (-1 == merge_vmr(vmrs[0], vmrs[1])));
-       check_vmrs(p, results, 2, n++);
-       vmrs[2] = split_vmr(vmrs[1], 0x8000);
-       results[1].end = 0x8000;
-       results[2].base = 0x8000;
-       results[2].end = 0xa000;
-       check_vmrs(p, results, 3, n++);
-       /* destroy one */
-       destroy_vmr(vmrs[1]);
-       results[1].base = 0x8000;
-       results[1].end = 0xa000;
-       check_vmrs(p, results, 2, n++);
-       /* shrink */
-       shrink_vmr(vmrs[2], 0x9000);
-       results[1].base = 0x8000;
-       results[1].end = 0x9000;
-       check_vmrs(p, results, 2, n++); /* 10 */
-       KT_ASSERT_M("We should be able to find the right vmr", 
-                   (vmrs[2] == find_vmr(p, 0x8500)));
-       KT_ASSERT_M("We should be able to find the right vmr", 
-                   (vmrs[2] == find_first_vmr(p, 0x8500)));
-       KT_ASSERT_M("We should be able to find the right vmr", 
-                   (vmrs[2] == find_first_vmr(p, 0x7500)));
-       KT_ASSERT_M("We shouldn't be able to find a vmr", 
-                   !(find_first_vmr(p, 0x9500)));
-       /* grow up to another */
-       grow_vmr(vmrs[0], 0x8000);
-       results[0].end = 0x8000;
-       check_vmrs(p, results, 2, n++);
-       vmrs[0]->vm_prot = 88;
-       vmrs[2]->vm_prot = 77;
-       /* should be unmergeable due to perms */
-       KT_ASSERT_M("It should pass bad merge test", 
-                   -1 == merge_vmr(vmrs[0], vmrs[2]));
-       check_vmrs(p, results, 2, n++);
-       /* should merge now */
-       vmrs[2]->vm_prot = 88;
-       merge_vmr(vmrs[0], vmrs[2]);
-       results[0].end = 0x9000;
-       check_vmrs(p, results, 1, n++);
-       destroy_vmr(vmrs[0]);
-       check_vmrs(p, results, 0, n++);
-       /* Check the automerge function */
-       vmrs[0] = create_vmr(p, 0x2000, 0x1000);
-       vmrs[1] = create_vmr(p, 0x3000, 0x1000);
-       vmrs[2] = create_vmr(p, 0x4000, 0x1000);
-       for (int i = 0; i < 3; i++) {
-               vmrs[i]->vm_prot = PROT_READ;
-               vmrs[i]->vm_flags = 0;
-               vmrs[i]->vm_file = 0; /* would like to test this, it's a pain for now */
-       }
-       vmrs[0] = merge_me(vmrs[1]);
-       results[0].base = 0x2000;
-       results[0].end = 0x5000;
-       check_vmrs(p, results, 1, n++);
-       destroy_vmr(vmrs[0]);
-       check_vmrs(p, results, 0, n++);
-       /* Check unfixed creation requests */
-       vmrs[0] = create_vmr(p, 0x0000, 0x1000);
-       vmrs[1] = create_vmr(p, 0x0000, 0x1000);
-       vmrs[2] = create_vmr(p, 0x0000, 0x1000);
-       results[0].base = 0x0000;
-       results[0].end  = 0x1000;
-       results[1].base = 0x1000;
-       results[1].end  = 0x2000;
-       results[2].base = 0x2000;
-       results[2].end  = 0x3000;
-       check_vmrs(p, results, 3, n++);
-
-       return true;
-}
-
-bool test_radix_tree(void)
-{
-       struct radix_tree real_tree = RADIX_INITIALIZER;
-       struct radix_tree *tree = &real_tree;
-       void *retval;
-
-       KT_ASSERT_M("It should be possible to insert at 0", 
-                   !radix_insert(tree, 0, (void*)0xdeadbeef, 0));
-       radix_delete(tree, 0);
-       KT_ASSERT_M("It should be possible to re-insert at 0", 
-                   !radix_insert(tree, 0, (void*)0xdeadbeef, 0));
-
-       KT_ASSERT_M("It should be possible to insert first", 
-                   !radix_insert(tree, 3, (void*)0xdeadbeef, 0));
-       radix_insert(tree, 4, (void*)0x04040404, 0);
-       KT_ASSERT((void*)0xdeadbeef == radix_lookup(tree, 3));
-       for (int i = 5; i < 100; i++)
-               if ((retval = radix_lookup(tree, i))) {
-                       printk("Extra item %p at slot %d in tree %p\n", retval, i,
-                              tree);
-                       print_radix_tree(tree);
-                       monitor(0);
-               }
-       KT_ASSERT_M("It should be possible to insert a two-tier", 
-                   !radix_insert(tree, 65, (void*)0xcafebabe, 0));
-       KT_ASSERT_M("It should not be possible to reinsert", 
-                   radix_insert(tree, 4, (void*)0x03030303, 0));
-       KT_ASSERT_M("It should be possible to insert a two-tier boundary", 
-                   !radix_insert(tree, 4095, (void*)0x4095, 0));
-       KT_ASSERT_M("It should be possible to insert a three-tier", 
-                   !radix_insert(tree, 4096, (void*)0x4096, 0));
-       //print_radix_tree(tree);
-       radix_delete(tree, 65);
-       radix_delete(tree, 3);
-       radix_delete(tree, 4);
-       radix_delete(tree, 4095);
-       radix_delete(tree, 4096);
-       //print_radix_tree(tree);
-
-       return true;
-}
-
-/* Assorted FS tests, which were hanging around in init.c */
-// TODO: remove all the print statements and try to convert most into assertions
-bool test_random_fs(void)
-{
-       int retval = do_symlink("/dir1/sym", "/bin/hello", S_IRWXU);
-       KT_ASSERT_M("symlink1 should be created successfully", 
-                   (!retval));
-       retval = do_symlink("/symdir", "/dir1/dir1-1", S_IRWXU);
-       KT_ASSERT_M("symlink1 should be created successfully", 
-                   (!retval));
-       retval = do_symlink("/dir1/test.txt", "/dir2/test2.txt", S_IRWXU);
-       KT_ASSERT_M("symlink2 should be created successfully", 
-                   (!retval));
-       retval = do_symlink("/dir1/dir1-1/up", "../../", S_IRWXU);
-       KT_ASSERT_M("symlink3 should be created successfully", 
-                   (!retval));
-       retval = do_symlink("/bin/hello-sym", "hello", S_IRWXU);
-       KT_ASSERT_M("symlink4 should be created successfully", 
-                   (!retval));
-
-       struct dentry *dentry;
-       struct nameidata nd_r = {0}, *nd = &nd_r;
-       retval = path_lookup("/dir1/sym", 0, nd);
-       KT_ASSERT_M("symlink lookup should work for an existing symlink", 
-                   (!retval)); 
-       char *symname = nd->dentry->d_inode->i_op->readlink(nd->dentry);
-       printk("Pathlookup got %s (sym)\n", nd->dentry->d_name.name);
-       if (!symname)
-               printk("symlink reading failed\n");
-       else
-               printk("Symname: %s (/bin/hello)\n", symname);
-       path_release(nd);
-       /* try with follow */
-       memset(nd, 0, sizeof(struct nameidata));
-       retval = path_lookup("/dir1/sym", LOOKUP_FOLLOW, nd);
-       
-       KT_ASSERT_M("symlink lookup should work for an existing symlink", 
-                   (!retval));
-       printk("Pathlookup got %s (hello)\n", nd->dentry->d_name.name);
-       path_release(nd);
-       
-       /* try with a directory */
-       memset(nd, 0, sizeof(struct nameidata));
-       retval = path_lookup("/symdir/f1-1.txt", 0, nd);
-       KT_ASSERT_M("symlink lookup should work for an existing symlink", 
-                   (!retval));
-       printk("Pathlookup got %s (f1-1.txt)\n", nd->dentry->d_name.name);
-       path_release(nd);
-       
-       /* try with a rel path */
-       printk("Try with a rel path\n");
-       memset(nd, 0, sizeof(struct nameidata));
-       retval = path_lookup("/symdir/up/hello.txt", 0, nd);
-       KT_ASSERT_M("symlink lookup should work for an existing symlink", 
-                   (!retval));
-       printk("Pathlookup got %s (hello.txt)\n", nd->dentry->d_name.name);
-       path_release(nd);
-       
-       printk("Try for an ELOOP\n");
-       memset(nd, 0, sizeof(struct nameidata));
-       retval = path_lookup("/symdir/up/symdir/up/symdir/up/symdir/up/hello.txt", 0, nd);
-       KT_ASSERT_M("symlink lookup should fail for a non existing symlink", 
-                   (retval));
-       path_release(nd);
-
-       return true;
-}
-
-/* Kernel message to restart our kthread */
-static void __test_up_sem(uint32_t srcid, long a0, long a1, long a2)
-{
-       struct semaphore *sem = (struct semaphore*)a0;
-       printk("[kmsg] Upping the sem to start the kthread, stacktop is %p\n",
-                  get_stack_top());
-       if (!sem_up(sem)) {
-               printk("[kmsg] Crap, the sem didn't have a kthread waiting!\n");
-               return;
-       }
-       printk("Kthread will restart when we handle the __launch RKM\n");
-}
-
-/* simple test - start one, do something else, and resume it.  For lack of a
- * better infrastructure, we send ourselves a kmsg to run the kthread, which
- * we'll handle in smp_idle (which you may have to manually call).  Note this
- * doesn't test things like memory being leaked, or dealing with processes. */
-// TODO: Add assertions.
-bool test_kthreads(void)
-{
-       struct semaphore sem;
-       sem_init(&sem, 1);              /* set to 1 to test the unwind */
-       printk("We're a kthread!  Stacktop is %p.  Testing suspend, etc...\n",
-              get_stack_top());
-       /* So we have something that will wake us up.  Routine messages won't get
-        * serviced in the kernel right away. */
-       send_kernel_message(core_id(), __test_up_sem, (long)&sem, 0, 0,
-                           KMSG_ROUTINE);
-       /* Actually block (or try to) */
-       /* This one shouldn't block - but will test the unwind (if 1 above) */
-       printk("About to sleep, but should unwind (signal beat us)\n");
-       sem_down(&sem);
-       /* This one is for real, yo.  Run and tell that. */
-       printk("About to sleep for real\n");
-       sem_down(&sem);
-       printk("Kthread restarted!, Stacktop is %p.\n", get_stack_top());
-
-       return true;
-}
-
-/* Second player's kmsg */
-static void __test_kref_2(uint32_t srcid, long a0, long a1, long a2)
-{
-       struct kref *kref = (struct kref*)a0;
-       bool *done = (bool*)a1;
-       enable_irq();
-       for (int i = 0; i < 10000000; i++) {
-               kref_get(kref, 1);
-               set_core_timer(1, TRUE);
-               udelay(2);
-               kref_put(kref);
-       }
-       *done = TRUE;
-}
-
-/* Runs a simple test between core 0 (caller) and core 2 */
-// TODO: I believe we need more assertions.
-bool test_kref(void)
-{
-       struct kref local_kref;
-       bool done = FALSE;
-       
-       kref_init(&local_kref, fake_release, 1);
-       send_kernel_message(2, __test_kref_2, (long)&local_kref, (long)&done, 0,
-                           KMSG_ROUTINE);
-       for (int i = 0; i < 10000000; i++) {
-               kref_get(&local_kref, 1);
-               udelay(2);
-               kref_put(&local_kref);
-       }
-       while (!done)
-               cpu_relax();
-       KT_ASSERT(kref_refcnt(&local_kref) == 1);
-       printk("[TEST-KREF] Simple 2-core getting/putting passed.\n");
-
-       return true;
-}
-
-// TODO: Add more descriptive assertion messages.
-bool test_atomics(void)
-{
-       /* subtract_and_test */
-       atomic_t num;
-       /* Test subing to 0 */
-       atomic_init(&num, 1);
-       KT_ASSERT(atomic_sub_and_test(&num, 1) == 1);
-       atomic_init(&num, 2);
-       KT_ASSERT(atomic_sub_and_test(&num, 2) == 1);
-       /* Test not getting to 0 */
-       atomic_init(&num, 1);
-       KT_ASSERT(atomic_sub_and_test(&num, 0) == 0);
-       atomic_init(&num, 2);
-       KT_ASSERT(atomic_sub_and_test(&num, 1) == 0);
-       /* Test negatives */
-       atomic_init(&num, -1);
-       KT_ASSERT(atomic_sub_and_test(&num, 1) == 0);
-       atomic_init(&num, -1);
-       KT_ASSERT(atomic_sub_and_test(&num, -1) == 1);
-       /* Test larger nums */
-       atomic_init(&num, 265);
-       KT_ASSERT(atomic_sub_and_test(&num, 265) == 1);
-       atomic_init(&num, 265);
-       KT_ASSERT(atomic_sub_and_test(&num, 2) == 0);
-
-       /* CAS */
-       /* Simple test, make sure the bool retval of CAS handles failure */
-       bool test_cas_val(long init_val)
-       {
-               atomic_t actual_num;
-               long old_num;
-               int attempt;
-               atomic_init(&actual_num, init_val);
-               attempt = 0;
-               do {
-                       old_num = atomic_read(&actual_num);
-                       /* First time, try to fail */
-                       if (attempt == 0) 
-                               old_num++;
-                       attempt++;      
-               } while (!atomic_cas(&actual_num, old_num, old_num + 10));
-               if (atomic_read(&actual_num) != init_val + 10) {
-                       return false;
-               } else {
-                       return true;
-               }
-       }
-       KT_ASSERT_M("CAS test for 257 should be successful.",
-                   test_cas_val(257));
-       KT_ASSERT_M("CAS test for 1 should be successful.",
-                   test_cas_val(1));
-       return true;
-}
-
-/* Helper KMSG for test_abort.  Core 1 does this, while core 0 sends an IRQ. */
-static void __test_try_halt(uint32_t srcid, long a0, long a1, long a2)
-{
-       disable_irq();
-       /* wait 10 sec.  should have a bunch of ints pending */
-       udelay(10000000);
-       printk("Core 1 is about to halt\n");
-       cpu_halt();
-       printk("Returned from halting on core 1\n");
-}
-
-/* x86 test, making sure our cpu_halt() and handle_irq() work.  If you want to
- * see it fail, you'll probably need to put a nop in the asm for cpu_halt(), and
- * comment out abort_halt() in handle_irq(). */
-// TODO: Add assertions.
-bool test_abort_halt(void)
-{
-#ifdef CONFIG_X86
-       send_kernel_message(1, __test_try_halt, 0, 0, 0, KMSG_ROUTINE);
-       /* wait 1 sec, enough time to for core 1 to be in its KMSG */
-       udelay(1000000);
-       /* Send an IPI */
-       send_ipi(0x01, I_TESTING);
-       printk("Core 0 sent the IPI\n");
-#endif /* CONFIG_X86 */
-       return true;
-}
-
-/* Funcs and global vars for test_cv() */
-static struct cond_var local_cv;
-static atomic_t counter;
-static struct cond_var *cv = &local_cv;
-static volatile bool state = FALSE;            /* for test 3 */
-
-void __test_cv_signal(uint32_t srcid, long a0, long a1, long a2)
-{
-       if (atomic_read(&counter) % 4)
-               cv_signal(cv);
-       else
-               cv_broadcast(cv);
-       atomic_dec(&counter);
-}
-
-void __test_cv_waiter(uint32_t srcid, long a0, long a1, long a2)
-{
-       cv_lock(cv);
-       /* check state, etc */
-       cv_wait_and_unlock(cv);
-       atomic_dec(&counter);
-}
-
-void __test_cv_waiter_t3(uint32_t srcid, long a0, long a1, long a2)
-{
-       udelay(a0);
-       /* if state == false, we haven't seen the signal yet */
-       cv_lock(cv);
-       while (!state) {
-               cpu_relax();
-               cv_wait(cv);    /* unlocks and relocks */
-       }
-       cv_unlock(cv);
-       /* Make sure we are done, tell the controller we are done */
-       cmb();
-       assert(state);
-       atomic_dec(&counter);
-}
-
-// TODO: Add more assertions.
-bool test_cv(void)
-{
-       int nr_msgs;
-
-       cv_init(cv);
-       /* Test 0: signal without waiting */
-       cv_broadcast(cv);
-       cv_signal(cv);
-       kthread_yield();
-       printk("test_cv: signal without waiting complete\n");
-
-       /* Test 1: single / minimal shit */
-       nr_msgs = num_cpus - 1; /* not using cpu 0 */
-       atomic_init(&counter, nr_msgs);
-       for (int i = 1; i < num_cpus; i++)
-               send_kernel_message(i, __test_cv_waiter, 0, 0, 0, KMSG_ROUTINE);
-       udelay(1000000);
-       cv_signal(cv);
-       kthread_yield();
-       while (atomic_read(&counter) != nr_msgs - 1)
-               cpu_relax();
-       printk("test_cv: single signal complete\n");
-       cv_broadcast(cv);
-       /* broadcast probably woke up the waiters on our core.  since we want to
-        * spin on their completion, we need to yield for a bit. */
-       kthread_yield();
-       while (atomic_read(&counter))
-               cpu_relax();
-       printk("test_cv: broadcast signal complete\n");
-
-       /* Test 2: shitloads of waiters and signalers */
-       nr_msgs = 0x500;        /* any more than 0x20000 could go OOM */
-       atomic_init(&counter, nr_msgs);
-       for (int i = 0; i < nr_msgs; i++) {
-               int cpu = (i % (num_cpus - 1)) + 1;
-               if (atomic_read(&counter) % 5)
-                       send_kernel_message(cpu, __test_cv_waiter, 0, 0, 0, KMSG_ROUTINE);
-               else
-                       send_kernel_message(cpu, __test_cv_signal, 0, 0, 0, KMSG_ROUTINE);
-       }
-       kthread_yield();        /* run whatever messages we sent to ourselves */
-       while (atomic_read(&counter)) {
-               cpu_relax();
-               cv_broadcast(cv);
-               udelay(1000000);
-               kthread_yield();        /* run whatever messages we sent to ourselves */
-       }
-       KT_ASSERT(!cv->nr_waiters);
-       printk("test_cv: massive message storm complete\n");
-
-       /* Test 3: basic one signaller, one receiver.  we want to vary the amount of
-        * time the sender and receiver delays, starting with (1ms, 0ms) and ending
-        * with (0ms, 1ms).  At each extreme, such as with the sender waiting 1ms,
-        * the receiver/waiter should hit the "check and wait" point well before the
-        * sender/signaller hits the "change state and signal" point. */
-       for (int i = 0; i < 1000; i++) {
-               for (int j = 0; j < 10; j++) {  /* some extra chances at each point */
-                       state = FALSE;
-                       atomic_init(&counter, 1);       /* signal that the client is done */
-                       /* client waits for i usec */
-                       send_kernel_message(2, __test_cv_waiter_t3, i, 0, 0, KMSG_ROUTINE);
-                       cmb();
-                       udelay(1000 - i);       /* senders wait time: 1000..0 */
-                       state = TRUE;
-                       cv_signal(cv);
-                       /* signal might have unblocked a kthread, let it run */
-                       kthread_yield();
-                       /* they might not have run at all yet (in which case they lost the
-                        * race and don't need the signal).  but we need to wait til they're
-                        * done */
-                       while (atomic_read(&counter))
-                               cpu_relax();
-                       KT_ASSERT(!cv->nr_waiters);
-               }
-       }
-       printk("test_cv: single sender/receiver complete\n");
-
-       return true;
-}
-
-/* Based on a bug I noticed.  TODO: actual memset test... */
-bool test_memset(void)
-{
-       #define ARR_SZ 256
-       
-       void print_array(char *c, size_t len)
-       {
-               for (int i = 0; i < len; i++)
-                       printk("%04d: %02x\n", i, *c++);
-       }
-       
-       bool check_array(char *c, char x, size_t len)
-       {
-               for (int i = 0; i < len; i++) {
-                       #define ASSRT_SIZE 64
-                       char *assrt_msg = (char*) kmalloc(ASSRT_SIZE, 0);
-                       snprintf(assrt_msg, ASSRT_SIZE, 
-                                    "Char %d is %c (%02x), should be %c (%02x)", i, *c, *c,
-                                    x, x);
-                       KT_ASSERT_M(assrt_msg, (*c == x));
-                       c++;
-               }
-               return true;
-       }
-       
-       bool run_check(char *arr, int ch, size_t len)
-       {
-               char *c = arr;
-               for (int i = 0; i < ARR_SZ; i++)
-                       *c++ = 0x0;
-               memset(arr, ch, len - 4);
-               if (check_array(arr, ch, len - 4) &&
-                   check_array(arr + len - 4, 0x0, 4)) {
-                       return true;
-               } else {
-                       return false;
-               }
-       }
-
-       char bytes[ARR_SZ];
-
-       if (!run_check(bytes, 0xfe, 20) || !run_check(bytes, 0xc0fe, 20)) {
-               return false;
-       }
-
-       return true;
-}
-
-void __attribute__((noinline)) __longjmp_wrapper(struct jmpbuf* jb)
-{
-       asm ("");
-       printk("Starting: %s\n", __FUNCTION__);
-       longjmp(jb, 1);
-       // Should never get here
-       printk("Exiting: %s\n", __FUNCTION__); 
-}
-
-// TODO: Add assertions.
-bool test_setjmp()
-{
-       struct jmpbuf jb;
-       printk("Starting: %s\n", __FUNCTION__);
-       if (setjmp(&jb)) {
-         printk("After second setjmp return: %s\n", __FUNCTION__);
-    }
-    else {
-         printk("After first setjmp return: %s\n", __FUNCTION__);
-      __longjmp_wrapper(&jb);
-    }
-       printk("Exiting: %s\n", __FUNCTION__);
-
-       return true;
-}
-
-// TODO: add assertions.
-bool test_apipe(void)
-{
-       static struct atomic_pipe test_pipe;
-
-       struct some_struct {
-               long x;
-               int y;
-       };
-       /* Don't go too big, or you'll run off the stack */
-       #define MAX_BATCH 100
-
-       void __test_apipe_writer(uint32_t srcid, long a0, long a1, long a2)
-       {
-               int ret, count_todo;
-               int total = 0;
-               struct some_struct local_str[MAX_BATCH];
-               for (int i = 0; i < MAX_BATCH; i++) {
-                       local_str[i].x = 0xf00;
-                       local_str[i].y = 0xba5;
-               }
-               /* testing 0, and max out at 50. [0, ... 50] */
-               for (int i = 0; i < MAX_BATCH + 1; i++) {
-                       count_todo = i;
-                       while (count_todo) {
-                               ret = apipe_write(&test_pipe, &local_str, count_todo);
-                               /* Shouldn't break, based on the loop counters */
-                               if (!ret) {
-                                       printk("Writer breaking with %d left\n", count_todo);
-                                       break;
-                               }
-                               total += ret;
-                               count_todo -= ret;
-                       }
-               }
-               printk("Writer done, added %d elems\n", total);
-               apipe_close_writer(&test_pipe);
-       }
-
-       void __test_apipe_reader(uint32_t srcid, long a0, long a1, long a2)
-       {
-               int ret, count_todo;
-               int total = 0;
-               struct some_struct local_str[MAX_BATCH] = {{0}};
-               /* reversed loop compared to the writer [50, ... 0] */
-               for (int i = MAX_BATCH; i >= 0; i--) {
-                       count_todo = i;
-                       while (count_todo) {
-                               ret = apipe_read(&test_pipe, &local_str, count_todo);
-                               if (!ret) {
-                                       printk("Reader breaking with %d left\n", count_todo);
-                                       break;
-                               }
-                               total += ret;
-                               count_todo -= ret;
-                       }
-               }
-               printk("Reader done, took %d elems\n", total);
-               for (int i = 0; i < MAX_BATCH; i++) {
-                       assert(local_str[i].x == 0xf00);
-                       assert(local_str[i].y == 0xba5);
-               }
-               apipe_close_reader(&test_pipe);
-       }
-
-       void *pipe_buf = kpage_alloc_addr();
-       KT_ASSERT(pipe_buf);
-       apipe_init(&test_pipe, pipe_buf, PGSIZE, sizeof(struct some_struct));
-       printd("*ap_buf %p\n", test_pipe.ap_buf);
-       printd("ap_ring_sz %p\n", test_pipe.ap_ring_sz);
-       printd("ap_elem_sz %p\n", test_pipe.ap_elem_sz);
-       printd("ap_rd_off %p\n", test_pipe.ap_rd_off);
-       printd("ap_wr_off %p\n", test_pipe.ap_wr_off);
-       printd("ap_nr_readers %p\n", test_pipe.ap_nr_readers);
-       printd("ap_nr_writers %p\n", test_pipe.ap_nr_writers);
-       send_kernel_message(0, __test_apipe_writer, 0, 0, 0, KMSG_ROUTINE);
-       /* Once we start synchronizing with a kmsg / kthread that could be on a
-        * different core, we run the chance of being migrated when we block. */
-       __test_apipe_reader(0, 0, 0, 0);
-       /* Wait til the first test is done */
-       while (test_pipe.ap_nr_writers) {
-               kthread_yield();
-               cpu_relax();
-       }
-       /* Try cross core (though CV wake ups schedule on the waking core) */
-       apipe_open_reader(&test_pipe);
-       apipe_open_writer(&test_pipe);
-       send_kernel_message(1, __test_apipe_writer, 0, 0, 0, KMSG_ROUTINE);
-       __test_apipe_reader(0, 0, 0, 0);
-       /* We could be on core 1 now.  If we were called from core0, our caller
-        * might expect us to return while being on core 0 (like if we were kfunc'd
-        * from the monitor.  Be careful if you copy this code. */
-
-       return true;
-}
-
-static struct rwlock rwlock, *rwl = &rwlock;
-static atomic_t rwlock_counter;
-// TODO: Add assertions.
-bool test_rwlock(void)
-{
-       bool ret;
-       rwinit(rwl);
-       /* Basic: can i lock twice, recursively? */
-       rlock(rwl);
-       ret = canrlock(rwl);
-       KT_ASSERT(ret);
-       runlock(rwl);
-       runlock(rwl);
-       /* Other simply tests */
-       wlock(rwl);
-       wunlock(rwl);
-
-       /* Just some half-assed different operations */
-       void __test_rwlock(uint32_t srcid, long a0, long a1, long a2)
-       {
-               int rand = read_tsc() & 0xff;
-               for (int i = 0; i < 10000; i++) {
-                       switch ((rand * i) % 5) {
-                               case 0:
-                               case 1:
-                                       rlock(rwl);
-                                       runlock(rwl);
-                                       break;
-                               case 2:
-                               case 3:
-                                       if (canrlock(rwl))
-                                               runlock(rwl);
-                                       break;
-                               case 4:
-                                       wlock(rwl);
-                                       wunlock(rwl);
-                                       break;
-                       }
-               }
-               /* signal to allow core 0 to finish */
-               atomic_dec(&rwlock_counter);
-       }
-               
-       /* send 4 messages to each non core 0 */
-       atomic_init(&rwlock_counter, (num_cpus - 1) * 4);
-       for (int i = 1; i < num_cpus; i++)
-               for (int j = 0; j < 4; j++)
-                       send_kernel_message(i, __test_rwlock, 0, 0, 0, KMSG_ROUTINE);
-       while (atomic_read(&rwlock_counter))
-               cpu_relax();
-       printk("rwlock test complete\n");
-
-       return true;
-}
-
-/* Funcs and global vars for test_rv() */
-static struct rendez local_rv;
-static struct rendez *rv = &local_rv;
-/* reusing state and counter from test_cv... */
-
-static int __rendez_cond(void *arg)
-{
-       return *(bool*)arg;
-}
-
-void __test_rv_wakeup(uint32_t srcid, long a0, long a1, long a2)
-{
-       if (atomic_read(&counter) % 4)
-               cv_signal(cv);
-       else
-               cv_broadcast(cv);
-       atomic_dec(&counter);
-}
-
-void __test_rv_sleeper(uint32_t srcid, long a0, long a1, long a2)
-{
-       rendez_sleep(rv, __rendez_cond, (void*)&state);
-       atomic_dec(&counter);
-}
-
-void __test_rv_sleeper_timeout(uint32_t srcid, long a0, long a1, long a2)
-{
-       /* half-assed amount of time. */
-       rendez_sleep_timeout(rv, __rendez_cond, (void*)&state, a0);
-       atomic_dec(&counter);
-}
-
-// TODO: Add more assertions.
-bool test_rv(void)
-{
-       int nr_msgs;
-
-       rendez_init(rv);
-       /* Test 0: signal without waiting */
-       rendez_wakeup(rv);
-       kthread_yield();
-       printk("test_rv: wakeup without sleeping complete\n");
-
-       /* Test 1: a few sleepers */
-       nr_msgs = num_cpus - 1; /* not using cpu 0 */
-       atomic_init(&counter, nr_msgs);
-       state = FALSE;
-       for (int i = 1; i < num_cpus; i++)
-               send_kernel_message(i, __test_rv_sleeper, 0, 0, 0, KMSG_ROUTINE);
-       udelay(1000000);
-       cmb();
-       state = TRUE;
-       rendez_wakeup(rv);
-       /* broadcast probably woke up the waiters on our core.  since we want to
-        * spin on their completion, we need to yield for a bit. */
-       kthread_yield();
-       while (atomic_read(&counter))
-               cpu_relax();
-       printk("test_rv: bulk wakeup complete\n");
-
-       /* Test 2: different types of sleepers / timeouts */
-       state = FALSE;
-       nr_msgs = 0x500;        /* any more than 0x20000 could go OOM */
-       atomic_init(&counter, nr_msgs);
-       for (int i = 0; i < nr_msgs; i++) {
-               int cpu = (i % (num_cpus - 1)) + 1;
-               /* timeouts from 0ms ..5000ms (enough that they should wake via cond */
-               if (atomic_read(&counter) % 5)
-                       send_kernel_message(cpu, __test_rv_sleeper_timeout, i * 4, 0, 0,
-                                           KMSG_ROUTINE);
-               else
-                       send_kernel_message(cpu, __test_rv_sleeper, 0, 0, 0, KMSG_ROUTINE);
-       }
-       kthread_yield();        /* run whatever messages we sent to ourselves */
-       state = TRUE;
-       while (atomic_read(&counter)) {
-               cpu_relax();
-               rendez_wakeup(rv);
-               udelay(1000000);
-               kthread_yield();        /* run whatever messages we sent to ourselves */
-       }
-       KT_ASSERT(!rv->cv.nr_waiters);
-       printk("test_rv: lots of sleepers/timeouts complete\n");
-
-       return true;
-}
-
-/* Cheap test for the alarm internal management */
-// TODO: Add assertions.
-bool test_alarm(void)
-{
-       uint64_t now = tsc2usec(read_tsc());
-       struct alarm_waiter await1, await2;
-       struct timer_chain *tchain = &per_cpu_info[0].tchain;
-       void shouldnt_run(struct alarm_waiter *awaiter)
-       {
-               printk("Crap, %p ran!\n", awaiter);
-       }
-       void empty_run(struct alarm_waiter *awaiter)
-       {
-               printk("Yay, %p ran (hopefully twice)!\n", awaiter);
-       }
-       /* Test basic insert, move, remove */
-       init_awaiter(&await1, shouldnt_run);
-       set_awaiter_abs(&await1, now + 1000000000);
-       set_alarm(tchain, &await1);
-       reset_alarm_abs(tchain, &await1, now + 1000000000 - 50);
-       reset_alarm_abs(tchain, &await1, now + 1000000000 + 50);
-       unset_alarm(tchain, &await1);
-       /* Test insert of one that fired already */
-       init_awaiter(&await2, empty_run);
-       set_awaiter_rel(&await2, 1);
-       set_alarm(tchain, &await2);
-       enable_irq();
-       udelay(1000);
-       reset_alarm_abs(tchain, &await2, now + 10);
-       udelay(1000);
-       unset_alarm(tchain, &await2);
-
-       printk("%s complete\n", __FUNCTION__);
-
-       return true;
-}
-
-/* Linker function tests.  Keep them commented, etc. */
-#if 0
-linker_func_1(xme11)
-{
-       printk("xme11\n");
-}
-
-linker_func_1(xme12)
-{
-       printk("xme12\n");
-}
-
-linker_func_1(xme13)
-{
-       printk("xme13\n");
-}
-
-linker_func_1(xme14)
-{
-       printk("xme14\n");
-}
-
-linker_func_1(xme15)
-{
-       printk("xme15\n");
-}
-
-linker_func_2(xme21)
-{
-       printk("xme21\n");
-}
-
-linker_func_2(xme22)
-{
-       printk("xme22\n");
-}
-
-linker_func_2(xme23)
-{
-       printk("xme23\n");
-}
-
-linker_func_2(xme24)
-{
-       printk("xme24\n");
-}
-
-linker_func_2(xme25)
-{
-       printk("xme25\n");
-}
-
-linker_func_3(xme31)
-{
-       printk("xme31\n");
-}
-
-linker_func_3(xme32)
-{
-       printk("xme32\n");
-}
-
-linker_func_3(xme33)
-{
-       printk("xme33\n");
-}
-
-linker_func_3(xme34)
-{
-       printk("xme34\n");
-}
-
-linker_func_3(xme35)
-{
-       printk("xme35\n");
-}
-
-linker_func_4(xme41)
-{
-       printk("xme41\n");
-}
-
-linker_func_4(xme42)
-{
-       printk("xme42\n");
-}
-
-linker_func_4(xme43)
-{
-       printk("xme43\n");
-}
-
-linker_func_4(xme44)
-{
-       printk("xme44\n");
-}
-
-linker_func_4(xme45)
-{
-       printk("xme45\n");
-}
-#endif /* linker func tests */
index d570ccf..cb4f9d2 100644 (file)
@@ -48,14 +48,12 @@ $(OBJDIR)/$(TESTS_DIR)/%: $(TESTS_LDDEPENDS_CPP)
 all: $(TESTS_EXECS)
        @:
 
-fill-kfs: $(TESTS_EXECS)
+install: $(TESTS_EXECS)
        @mkdir -p $(FIRST_KFS_PATH)/bin
        $(Q)cp -uP $^ $(FIRST_KFS_PATH)/bin
-       @echo "User space tests installed to KFS"
 
-unfill-kfs:
+uninstall:
        $(Q)rm -rf $(addprefix $(FIRST_KFS_PATH)/bin/, $(notdir $(TESTS_EXECS)))
-       @echo "User space tests removed from KFS"
 
 clean:
        @echo + clean [TESTS]
index f8a443b..249187b 100755 (executable)
@@ -102,7 +102,7 @@ function build_config() {
        # Enable tests to run.
        # These don't take much to execute so we can run them always and just parse
        # results if needed.
-       echo "CONFIG_POSTBOOT_KERNEL_TESTING=y" >> .config
+       echo "CONFIG_KERNEL_POSTBOOT_TESTING=y" >> .config
        echo "CONFIG_USERSPACE_TESTING=y" >> .config
        # Set all config variables dependent on the above changes to their defaults
        # without prompting
@@ -174,7 +174,7 @@ function build_userspace() {
        make install-libs
 
        # Compile tests.
-       make tests
+       make utest
 
        # Fill memory with tests.
        make fill-kfs
@@ -202,12 +202,14 @@ function build_busybox() {
        fi
 
        # Build busybox and copy it into kfs
+       echo -e "Build busybox"
        cd $BUSYBOX_DIR
        make
        cp busybox_unstripped ../../kern/kfs/bin/busybox
        cd ../../
 
        # Recompile kernel to include busybox
+       echo -e "Recompile kernel to include busybox"
        make
 
        echo -e "[BUILD_BUSYBOX]: End\n"
@@ -222,9 +224,7 @@ function run_qemu() {
        make qemu > $AKAROS_OUTPUT_FILE &
        MAKE_PID=$!
 
-       # TODO: Rather than finishing after Kernel PB Tests, put a generic 
-       #       "C'est fini" statement somewhere and look for it
-       WAIT_RESULT=`$SCR_WAIT_UNTIL $AKAROS_OUTPUT_FILE END_KERNEL_POSTBOOT_TESTS \
+       WAIT_RESULT=`$SCR_WAIT_UNTIL $AKAROS_OUTPUT_FILE END_USERSPACE_TESTS \
            ${MAX_RUN_TIME:-100}`
 
        # Extract Qemu_launcher PID
@@ -234,8 +234,12 @@ function run_qemu() {
        # To kill qemu we need to send a USR1 signal to Qemu_launcher.
        kill -10 $QEMU_PID
 
+       # Then we wait....
        wait $MAKE_PID
 
+       # cat the output of the file so we can see it in the console log
+       cat $AKAROS_OUTPUT_FILE
+
        echo -e "[RUN_AKAROS_IN_QEMU]: End\n"
 
        # If the run was terminated via a timeout, then we finish with an error.
@@ -308,15 +312,8 @@ fi
 
 echo -e "\n[TEST_REPORTING]: Begin"
 
-TESTS_TO_RUN="KERNEL_POSTBOOT" # TODO(alfongj): Remove this when not needed.
-# for COMPONENT in "${AFFECTED_COMPONENTS_ARRAY[@]}"; 
-# do
-#      # TODO(alfongj): Add to tests to run the name of the test suites to be ran.
-#      # TESTS_TO_RUN="$TESTS_TO_RUN SOMETHING"
-# done
-
 # Generate test report
-$SCR_GEN_TEST_REPORTS $AKAROS_OUTPUT_FILE $TEST_OUTPUT_DIR $TESTS_TO_RUN
+$SCR_GEN_TEST_REPORTS $AKAROS_OUTPUT_FILE $TEST_OUTPUT_DIR 
 echo "Tests generated in $TEST_OUTPUT_DIR"
 
 echo -e "[TEST_REPORTING]: End\n"
index 2f58e55..5fd9b25 100755 (executable)
@@ -155,7 +155,7 @@ class TestParser() :
                return matchRes.group(1)
 
        def __extract_test_fail_msg(self, line) :
-               regex = r'^\s*FAILED\s*\[(?:[a-zA-Z_-]+)\](?:\(.*\))?\s+(.*)$'
+               regex = r'^\s*FAILED\s*\[(?:[a-zA-Z_-]+)\](?:\(.*?\))\s+(.*)$'
                matchRes = re.match(regex, line)
                return matchRes.group(1)
 
@@ -205,10 +205,15 @@ class TestParser() :
                return test_suite
 
 
-
-KERNEL_PB_TESTS_KEY = 'KERNEL_POSTBOOT'
-KERNEL_PB_TESTS_SUITE_NAME = 'KERNEL'
-KERNEL_PB_TESTS_CLASS_NAME = 'POSTBOOT'
+def extract_tests(path):
+       regex = r'^\s*<--\s*BEGIN_(.+_.+)_TESTS\s*-->\s*$'
+       f = open(path, 'r')
+       tests = []
+       for line in f:
+               matchRes = re.match(regex, line)
+               if matchRes:
+                       tests.append(matchRes.group(1))
+       return tests
 
 def save_report(dir, filename, report) :
        filepath = dir + '/' + filename + '_TESTS.xml'
@@ -221,16 +226,14 @@ def save_report(dir, filename, report) :
 def main() :
        akaros_output_file_path = sys.argv[1]
        test_output_dir = sys.argv[2]
-       tests_to_run = sys.argv[3].strip().split(' ')
+       tests = extract_tests(akaros_output_file_path)
 
-       # Kernel Postboot Tests
-       if KERNEL_PB_TESTS_KEY in tests_to_run :
+       # Parse, process, and save the test results
+       for test in tests :
+               suite_name, class_name = test.split('_')
                test_suite = TestParser(akaros_output_file_path, \
-                                       KERNEL_PB_TESTS_SUITE_NAME, \
-                                       KERNEL_PB_TESTS_CLASS_NAME).parse_test_suite()
+                                       suite_name, class_name).parse_test_suite()
                test_report_str = test_suite.generate_markup().__str__()
-               kernel_pb_tests_report = save_report(test_output_dir, \
-                                                    KERNEL_PB_TESTS_KEY, \
-                                                    test_report_str)
+               save_report(test_output_dir, test, test_report_str)
 
 main()
diff --git a/user/tests/Makefile b/user/tests/Makefile
deleted file mode 100644 (file)
index 0bcc62d..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-ARCH ?= none # catch bugs
-CFLAGS_USER += -g
-CXXFLAGS_USER += -g
-
-SRCDIR := 
-OBJDIR := $(SRCDIR)obj
-INCDIR = $(SRCDIR)include
-
-LDLIBS := -lpthread -lbenchutil -lm -liplib -lndb -lbsd
-
-SCRIPTS := $(wildcard $(SRCDIR)*.sh)
-SRCS_C := $(wildcard $(SRCDIR)*.c)
-SRCS_CPP := $(wildcard $(SRCDIR)*.cc)
-HEADERS := $(shell find $(INCDIR) -name *.h)
-
-EXECS_C = $(patsubst $(SRCDIR)%.c, $(OBJDIR)/%, $(SRCS_C))
-EXECS_CPP = $(patsubst $(SRCDIR)%.cc, $(OBJDIR)/%, $(SRCS_CPP))
-EXECS = $(EXECS_C) $(EXECS_CPP)
-
-STATIC := $(findstring static,$(CFLAGS_USER))
-$(OBJDIR)/%: $(SRCS_C) $(HEADERS)
-       @echo + cc [TESTS] $<
-       @mkdir -p $(@D)
-       $(Q)$(CC) $(CFLAGS_USER) -I$(INCDIR) -o $@ $< $(LDLIBS)
-       @if [ "$(STATIC)" != "static" ]; then \
-               $(OBJDUMP) -S $@ > $@.asm; \
-               $(NM) -n $@ > $@.sym; \
-       fi
-
-# Note that we don't disassemble CPPs by default, even if they aren't static.
-# The files are pretty large regardless (9MB for a simple stream test asm).
-$(OBJDIR)/%: $(SRCS_CPP) $(HEADERS)
-       @echo + cc [TESTS] $<
-       @mkdir -p $(@D)
-       $(Q)$(CPP) $(CXXFLAGS_USER) -I$(INCDIR) -o $@ $< $(LDLIBS)
-
-all: $(EXECS)
-
-install: $(EXECS) $(SCRIPTS)
-       @mkdir -p $(AKAROS_ROOT)/$(FIRST_KFS_PATH)/bin/tests/user
-       $(Q)cp -uP $^ $(AKAROS_ROOT)/$(FIRST_KFS_PATH)/bin/tests/user
-
-uninstall: $(EXECS)
-       $(Q)rm -rf $(AKAROS_ROOT)/$(FIRST_KFS_PATH)/bin/tests/user
-
-clean:
-       @echo + clean [TESTS]
-       $(Q)rm -rf $(OBJDIR)
-
-.PHONY: $(PHONY)
diff --git a/user/tests/example.c b/user/tests/example.c
deleted file mode 100644 (file)
index 87b7650..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#include <testing.h>
-
-TEST_SUITE("EXAMPLE");
-
-
-
-/* <--- Begin definition of test cases ---> */
-
-bool test_one(void) {
-       UT_ASSERT_M("One plus one should equal 2", 1+1 == 2);
-}
-
-bool test_two(void) {
-       UT_ASSERT_M("One minus one should equal 0", 1-1 == 0);
-}
-
-bool test_three(void) {
-       UT_ASSERT_M("One should equal 0", 1 == 0);
-}
-
-/* <--- End definition of test cases ---> */
-
-
-
-struct usertest usertests[] = {
-       U_TEST_REG(one),
-       U_TEST_REG(two),
-       U_TEST_REG(three) // This one will fail.
-};
-
-int main(int argc, char *argv[]) {
-       // Run test suite passing it all the args as whitelist of what tests to run.
-       RUN_TEST_SUITE(&argv[1], argc-1);
-}
-
diff --git a/user/tests/include/testing.h b/user/tests/include/testing.h
deleted file mode 100644 (file)
index 515cc4f..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-#ifndef TESTS_TESTING_H
-#define TESTS_TESTING_H
-
-/*
- * Header file with infrastructure needed for userspace unit tests:
- *  - Assertion functions.
- *  - Test structures.
- *  - Launcher functions for test suites.
- */
-
-#include <malloc.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <string.h>
-#include <timing.h>
-
-/* 
- * Macros for assertions. 
- * UT_ASSERT_M prints a message in case of failure, UT_ASSERT just asserts.
- */
-#define UT_ASSERT_M(message, test)                                               \
-       do {                                                                         \
-               if (!(test)) {                                                           \
-                       char prefix[] = "Assertion failed: ";                                \
-                       int msg_size = sizeof(prefix) + sizeof(message) - 1;                 \
-                       test_msg = (char*) malloc(msg_size);                                 \
-                       snprintf(test_msg, msg_size, "%s%s", prefix, message);               \
-                       return false;                                                        \
-               }                                                                        \
-       } while (0)
-
-#define UT_ASSERT(test)                                                          \
-       do {                                                                         \
-               if (!(test)) {                                                           \
-                       return false;                                                        \
-               }                                                                        \
-       } while (0)
-
-
-
-/*
- * Structs and macros for registering test cases.
- */
-struct usertest {
-       char name[256]; // Name of the test function.
-       bool (*func)(void); // Name of the test function, should be equal to 'name'.
-       bool enabled; // Whether or not to run the test.
-};
-
-/* Used for defining an userspace test structure entry inline. */
-#define U_TEST_REG(name) \
-       {"test_" #name, test_##name, true}
-
-
-
-/*
- * Creates all the runnable code for a test suite.
- */
-#define TEST_SUITE(__suite_name)                                                 \
-       char *test_msg;                                                              \
-       char suite_name[] = __suite_name;
-
-#define RUN_TEST_SUITE(whitelist, whitelist_len)                                 \
-       int num_tests = sizeof(usertests) / sizeof(struct usertest);                 \
-       testing_main(whitelist, whitelist_len, usertests, num_tests);
-
-/* Disables all the tests not passed through a whitelist. */
-static void apply_whitelist(char *whitelist[], int whitelist_len,
-                               struct usertest tests[], int num_tests) {
-       for (int i=0; i<num_tests; i++) {
-               struct usertest *test = &tests[i];
-               if (test->enabled) {
-                       for (int j = 1; j < whitelist_len; ++j) {
-                               test->enabled = false;
-                               if (strcmp(test->name, whitelist[j]) == 0) {
-                                       test->enabled = true;
-                                       break;
-                               }
-                       }
-               }
-       }
-}
-
-
-
-static int testing_main(char *whitelist[], int whitelist_len, 
-                           struct usertest tests[], int num_tests) {
-       extern char *test_msg, suite_name[];
-       printf("<-- BEGIN_USERSPACE_%s_TESTS -->\n", suite_name);
-
-       // If any arguments are passed, treat them as a whitelist of what tests
-       // to run (i.e., disable all the rest).
-       if (whitelist_len > 0) {
-               apply_whitelist(whitelist, whitelist_len, tests, num_tests);
-       }
-
-       // Run tests.
-       for (int i=0; i<num_tests; i++) {
-               struct usertest *test = &tests[i];
-               if (test->enabled) {
-                       uint64_t start = read_tsc();
-                       bool result = test->func();
-                       uint64_t end = read_tsc();
-                       uint64_t et_us = tsc2usec(end - start) % 1000000;
-                       uint64_t et_s = tsc2sec(end - start);
-
-                       if (result) {
-                               printf("\tPASSED   [%s](%llu.%06llus)\n", test->name, et_s, 
-                                      et_us);
-                       } else {
-                               printf("\tFAILED   [%s](%llu.%06llus)  %s\n", test->name, et_s, 
-                                      et_us, test_msg);
-                               free(test_msg);
-                       }
-               } else {
-                       printf("\tDISABLED [%s]\n", test->name);
-               }
-       }
-
-       printf("<-- END_USERSPACE_%s_TESTS -->\n", suite_name);
-}
-
-#endif // TESTS_TESTING_H
diff --git a/user/tests/runall.sh b/user/tests/runall.sh
deleted file mode 100644 (file)
index b881ecf..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-#!/bin/ash
-#
-# runall
-#
-# Runs all userspace tests
-TEST_DIR=/bin/tests/user
-
-# Run all test suites in test directory.
-for file in $TEST_DIR/*[!.sh]
-do
-       $file
-done
diff --git a/user/utest/Makefile b/user/utest/Makefile
new file mode 100644 (file)
index 0000000..301a9a0
--- /dev/null
@@ -0,0 +1,54 @@
+ARCH ?= none # catch bugs
+CFLAGS_USER += -g
+CXXFLAGS_USER += -g
+LIBNAME = utest 
+
+SRCDIR := 
+OBJDIR := $(SRCDIR)obj
+INCDIR = $(SRCDIR)include
+
+LDLIBS := -lpthread -lbenchutil -lm -liplib -lndb -lbsd
+
+uc = $(shell echo $(1) | tr a-z A-Z)
+
+LIBUCNAME := $(call uc, $(LIBNAME))
+SCRIPTS := $(wildcard $(SRCDIR)*.sh)
+SRCS_C := $(wildcard $(SRCDIR)*.c)
+SRCS_CPP := $(wildcard $(SRCDIR)*.cc)
+HEADERS := $(shell find $(INCDIR) -name *.h)
+
+EXECS_C = $(patsubst $(SRCDIR)%.c, $(OBJDIR)/%, $(SRCS_C))
+EXECS_CPP = $(patsubst $(SRCDIR)%.cc, $(OBJDIR)/%, $(SRCS_CPP))
+EXECS = $(EXECS_C) $(EXECS_CPP)
+
+STATIC := $(findstring static,$(CFLAGS_USER))
+$(OBJDIR)/%: $(SRCS_C) $(HEADERS)
+       @echo + cc [$(LIBUCNAME)] $<
+       @mkdir -p $(@D)
+       $(Q)$(CC) $(CFLAGS_USER) -I$(INCDIR) -o $@ $< $(LDLIBS)
+       @if [ "$(STATIC)" != "static" ]; then \
+               $(OBJDUMP) -S $@ > $@.asm; \
+               $(NM) -n $@ > $@.sym; \
+       fi
+
+# Note that we don't disassemble CPPs by default, even if they aren't static.
+# The files are pretty large regardless (9MB for a simple stream test asm).
+$(OBJDIR)/%: $(SRCS_CPP) $(HEADERS)
+       @echo + cc [$(LIBUCNAME)] $<
+       @mkdir -p $(@D)
+       $(Q)$(CPP) $(CXXFLAGS_USER) -I$(INCDIR) -o $@ $< $(LDLIBS)
+
+all: $(EXECS)
+
+install: $(EXECS) $(SCRIPTS)
+       @mkdir -p $(AKAROS_ROOT)/$(FIRST_KFS_PATH)/bin/tests/utest
+       $(Q)cp -uP $^ $(AKAROS_ROOT)/$(FIRST_KFS_PATH)/bin/tests/utest
+
+uninstall: $(EXECS)
+       $(Q)rm -rf $(AKAROS_ROOT)/$(FIRST_KFS_PATH)/bin/tests/utest
+
+clean:
+       @echo + clean [$(LIBUCNAME)]
+       $(Q)rm -rf $(OBJDIR)
+
+.PHONY: $(PHONY)
diff --git a/user/utest/example.c b/user/utest/example.c
new file mode 100644 (file)
index 0000000..9daf8d7
--- /dev/null
@@ -0,0 +1,34 @@
+#include <utest.h>
+
+TEST_SUITE("EXAMPLE");
+
+/* <--- Begin definition of test cases ---> */
+
+bool test_one(void) {
+       UT_ASSERT_M("One plus one should equal 2", 1+1 == 2);
+}
+
+bool test_two(void) {
+       UT_ASSERT_M("One minus one should equal 0", 1-1 == 0);
+}
+
+bool test_three(void) {
+       UT_ASSERT_M("1 should equal 1", 1 == 1);
+}
+
+/* <--- End definition of test cases ---> */
+
+struct utest utests[] = {
+       UTEST_REG(one),
+       UTEST_REG(two),
+       UTEST_REG(three) 
+};
+int num_utests = sizeof(utests) / sizeof(struct utest);
+
+int main(int argc, char *argv[]) {
+       // Run test suite passing it all the args as whitelist of what tests to run.
+       char **whitelist = &argv[1];
+       int whitelist_len = argc - 1;
+       RUN_TEST_SUITE(utests, num_utests, whitelist, whitelist_len);
+}
+
diff --git a/user/utest/include/utest.h b/user/utest/include/utest.h
new file mode 100644 (file)
index 0000000..10aa164
--- /dev/null
@@ -0,0 +1,104 @@
+#ifndef UTEST_UTEST_H
+#define UTEST_UTEST_H
+
+/*
+ * Header file with infrastructure needed for userspace unit tests:
+ *  - Assertion functions.
+ *  - Test structures.
+ *  - Launcher functions for test suites.
+ */
+
+#include <malloc.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+#include <timing.h>
+#include <execinfo.h>
+
+/* 
+ * Macros for assertions. 
+ */
+#define UT_ASSERT(test)                                                          \
+       UT_ASSERT_M("", test)
+
+#define UT_ASSERT_M(message, test)                                               \
+       do {                                                                         \
+               if (!(test)) {                                                           \
+                       char fmt[] = "Assertion failure in %s() at %s:%d: %s";               \
+                       sprintf(utest_msg, fmt, __FUNCTION__, __FILE__, __LINE__, message);  \
+                       return false;                                                        \
+               }                                                                        \
+       } while (0)
+
+/*
+ * Structs and macros for registering test cases.
+ */
+struct utest {
+       char name[256]; // Name of the test function.
+       bool (*func)(void); // Name of the test function, should be equal to 'name'.
+       bool enabled; // Whether or not to run the test.
+};
+
+/* Used for defining an userspace test structure entry inline. */
+#define UTEST_REG(name) \
+       {"test_" #name, test_##name, true}
+
+/*
+ * Creates all the runnable code for a test suite.
+ */
+#define TEST_SUITE(__suite_name)                                                 \
+       char utest_msg[1024];                                                        \
+       char suite_name[] = __suite_name;
+
+#define RUN_TEST_SUITE(utests, num_utests, whitelist, whitelist_len)             \
+       do {                                                                         \
+               if (whitelist_len > 0)                                                   \
+                       apply_whitelist(whitelist, whitelist_len, utests, num_utests);       \
+               run_utests(suite_name, utests, num_utests);                              \
+       } while (0)
+
+/* Disables all the tests not passed through a whitelist. */
+static void apply_whitelist(char *whitelist[], int whitelist_len,
+                               struct utest tests[], int num_tests) {
+       for (int i=0; i<num_tests; i++) {
+               struct utest *test = &tests[i];
+               if (test->enabled) {
+                       for (int j = 0; j < whitelist_len; ++j) {
+                               test->enabled = false;
+                               if (strcmp(test->name, whitelist[j]) == 0) {
+                                       test->enabled = true;
+                                       break;
+                               }
+                       }
+               }
+       }
+}
+
+static int run_utests(char *suite_name, struct utest tests[], int num_tests) {
+       extern char utest_msg[];
+       printf("<-- BEGIN_USERSPACE_%s_TESTS -->\n", suite_name);
+
+       for (int i=0; i<num_tests; i++) {
+               struct utest *test = &tests[i];
+               if (test->enabled) {
+                       uint64_t start = read_tsc();
+                       bool result = test->func();
+                       uint64_t end = read_tsc();
+                       uint64_t et_us = tsc2usec(end - start) % 1000000;
+                       uint64_t et_s = tsc2sec(end - start);
+
+                       char fmt[] = "\t%s   [%s](%llu.%06llus)   %s\n";
+                       if (result) {
+                               printf(fmt, "PASSED", test->name, et_s, et_us, "");
+                       } else {
+                               printf(fmt, "FAILED", test->name, et_s, et_us, utest_msg);
+                       }
+               } else {
+                       printf("\tDISABLED [%s]\n", test->name);
+               }
+       }
+
+       printf("<-- END_USERSPACE_%s_TESTS -->\n", suite_name);
+}
+
+#endif // UTEST_UTEST_H
diff --git a/user/utest/runall.sh b/user/utest/runall.sh
new file mode 100644 (file)
index 0000000..972df35
--- /dev/null
@@ -0,0 +1,14 @@
+#!/bin/ash
+#
+# runall
+#
+# Runs all userspace tests
+TEST_DIR=/bin/tests/utest
+
+# Run all test suites in test directory.
+echo "<-- BEGIN_USERSPACE_TESTS  -->"
+for file in $TEST_DIR/*[!.sh]
+do
+       $file
+done
+echo "<-- END_USERSPACE_TESTS  -->"