slab: Add an arena pointer to the interface
[akaros.git] / kern / src / ktest / pb_ktests.c
index 11d4dc0..3be4a78 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <arch/mmu.h>
 #include <arch/arch.h>
+#include <arch/uaccess.h>
 #include <bitmask.h>
 #include <smp.h>
 
@@ -24,6 +25,7 @@
 #include <syscall.h>
 #include <time.h>
 #include <kfs.h>
+#include <mm.h>
 #include <multiboot.h>
 #include <pmap.h>
 #include <page_alloc.h>
 #include <kmalloc.h>
 #include <hashtable.h>
 #include <radix.h>
+#include <circular_buffer.h>
 #include <monitor.h>
 #include <kthread.h>
 #include <schedule.h>
 #include <umem.h>
+#include <init.h>
 #include <ucq.h>
 #include <setjmp.h>
+#include <sort.h>
 
 #include <apipe.h>
 #include <rwlock.h>
 
 KTEST_SUITE("POSTBOOT")
 
-#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.
@@ -105,8 +106,9 @@ bool test_pic_reception(void)
        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));
+       unmask_lapic_lvt(MSR_LAPIC_LVT_LINT0);
+       printk("Core %d's LINT0: 0x%08x\n", core_id(),
+              apicrget(MSR_LAPIC_LVT_TIMER));
        enable_irq();
        while(1);
 
@@ -115,150 +117,20 @@ bool test_pic_reception(void)
 
 #endif // CONFIG_X86
 
-// 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);
+       init_barrier(&test_cpu_array, num_cores);
        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 
+// 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)
 {
@@ -379,16 +251,16 @@ bool test_bitmasks(void)
        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", 
+       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", 
+       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;
+checklist_t *the_global_list;
 
 static void test_checklist_handler(struct hw_trapframe *hw_tf, void *data)
 {
@@ -400,7 +272,7 @@ static void test_checklist_handler(struct hw_trapframe *hw_tf, void *data)
 // TODO: Add assertions
 bool test_checklists(void)
 {
-       INIT_CHECKLIST(a_list, MAX_NUM_CPUS);
+       INIT_CHECKLIST(a_list, MAX_NUM_CORES);
        the_global_list = &a_list;
        printk("Checklist Build, mask size: %d\n", sizeof(a_list.mask.bits));
        printk("mask\n");
@@ -410,12 +282,12 @@ bool test_checklists(void)
        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);
+       INIT_CHECKLIST_MASK(a_mask, MAX_NUM_CORES);
+       FILL_BITMASK(a_mask.bits, num_cores);
        //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");
+       printk("Created new mask, filled up to num_cores\n");
        PRINT_BITMASK(a_mask.bits, a_mask.size);
        printk("committing new mask\n");
        commit_checklist_wait(&a_list, &a_mask);
@@ -471,7 +343,7 @@ bool test_smp_call_functions(void)
        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++)
+       for(i = 1; i < num_cores; i++)
                smp_call_function_single(i, test_hello_world_handler, NULL, 0);
        printk("\nCore %d: SMP Call Self (wait):\n", me);
        printk("---------------------\n");
@@ -479,7 +351,7 @@ bool test_smp_call_functions(void)
        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++)
+       for(i = 1; i < num_cores; i++)
        {
                smp_call_function_single(i, test_hello_world_handler, NULL, &waiter0);
                smp_call_wait(waiter0);
@@ -490,18 +362,18 @@ bool test_smp_call_functions(void)
        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_single(1 % num_cores, test_incrementer_handler, &a, 0);
+       smp_call_function_single(2 % num_cores, test_incrementer_handler, &b, 0);
+       smp_call_function_single(3 % num_cores, test_incrementer_handler, &c, 0);
+       smp_call_function_single(4 % num_cores, test_incrementer_handler, &a, 0);
+       smp_call_function_single(5 % num_cores, test_incrementer_handler, &b, 0);
+       smp_call_function_single(6 % num_cores, 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_single(3 % num_cores, 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_single(1 % num_cores, 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);
+       smp_call_function_single(2 % num_cores, 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
@@ -566,7 +438,6 @@ bool test_lapic_status_bit(void)
        // 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);
@@ -650,7 +521,7 @@ bool test_circ_buffer(void)
                FOR_CIRC_BUFFER(i, 5, j)
                        printk("Starting with current = %d, each value = %d\n", i, j);
        }
-       
+
        return true;
 }
 
@@ -693,7 +564,7 @@ bool test_kernel_messages(void)
                                    KMSG_ROUTINE);
        }
        udelay(5000000);
-       
+
        return true;
 }
 #endif // CONFIG_X86
@@ -703,7 +574,8 @@ static void test_single_cache(int iters, size_t size, int align, int flags,
 {
        struct kmem_cache *test_cache;
        void *objects[iters];
-       test_cache = kmem_cache_create("test_cache", size, align, flags, ctor, dtor);
+       test_cache = kmem_cache_create("test_cache", size, align, flags,
+                                      NULL, ctor, dtor);
        printk("Testing Kmem Cache:\n");
        print_kmem_cache(test_cache);
        for (int i = 0; i < iters; i++) {
@@ -740,7 +612,7 @@ bool test_slab(void)
 bool test_kmalloc(void)
 {
        printk("Testing Kmalloc\n");
-       void *bufs[NUM_KMALLOC_CACHES + 1];     
+       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);
@@ -775,58 +647,58 @@ bool test_hashtable(void)
        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", 
+       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", 
+       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", 
+       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", 
+       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", 
+       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", 
+               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", 
+               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", 
+               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", 
+       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", 
+               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", 
+               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", 
+       KT_ASSERT_M("The hashtable should be empty",
                    (0 == hashtable_count(h)));
 
        hashtable_destroy(h);
@@ -838,36 +710,36 @@ bool test_hashtable(void)
        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", 
+               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", 
+               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", 
+               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", 
+       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", 
+               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", 
+               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", 
+       KT_ASSERT_M("The hashtable should be empty",
                    (0 == hashtable_count(h)));
 
        hashtable_destroy(h);
@@ -875,6 +747,83 @@ bool test_hashtable(void)
        return true;
 }
 
+bool test_circular_buffer(void)
+{
+       static const size_t cbsize = 4096;
+       struct circular_buffer cb;
+       char *bigbuf;
+       size_t csize, off, cnum, mxsize;
+       char buf[256];
+
+       KT_ASSERT_M("Failed to build the circular buffer",
+                               circular_buffer_init(&cb, cbsize, NULL));
+
+       for (size_t i = 0; i < 8 * cbsize; i++) {
+               size_t len = snprintf(buf, sizeof(buf), "%lu\n", i);
+
+               KT_ASSERT_M("Circular buffer write failed",
+                                       circular_buffer_write(&cb, buf, len) == len);
+       }
+       cnum = off = 0;
+       while ((csize = circular_buffer_read(&cb, buf, sizeof(buf), off)) != 0) {
+               char *top = buf + csize;
+               char *ptr = buf;
+               char *pnl;
+
+               while ((pnl = memchr(ptr, '\n', top - ptr)) != NULL) {
+                       size_t num;
+
+                       *pnl = 0;
+                       num = strtoul(ptr, NULL, 10);
+                       KT_ASSERT_M("Numbers should be ascending", num >= cnum);
+                       cnum = num;
+                       ptr = pnl + 1;
+               }
+
+               off += ptr - buf;
+       }
+
+       for (size_t i = 0; i < (cbsize / sizeof(buf) + 1); i++) {
+               memset(buf, (int) i, sizeof(buf));
+
+               KT_ASSERT_M("Circular buffer write failed",
+                                       circular_buffer_write(&cb, buf,
+                                                                                 sizeof(buf)) == sizeof(buf));
+       }
+       cnum = off = 0;
+       while ((csize = circular_buffer_read(&cb, buf, sizeof(buf), off)) != 0) {
+               size_t num = buf[0];
+
+               KT_ASSERT_M("Invalid record read size", csize == sizeof(buf));
+
+               if (off != 0)
+                       KT_ASSERT_M("Invalid record sequence number",
+                                               num == ((cnum + 1) % 256));
+               cnum = num;
+               off += csize;
+       }
+
+       bigbuf = kzmalloc(cbsize, MEM_WAIT);
+       KT_ASSERT(bigbuf != NULL);
+
+       mxsize = circular_buffer_max_write_size(&cb);
+       KT_ASSERT_M("Circular buffer max write failed",
+                               circular_buffer_write(&cb, bigbuf, mxsize) == mxsize);
+
+       memset(bigbuf, 17, cbsize);
+       csize = circular_buffer_read(&cb, bigbuf, mxsize, 0);
+       KT_ASSERT_M("Invalid max record read size", csize == mxsize);
+
+       for (size_t i = 0; i < csize; i++)
+               KT_ASSERT_M("Invalid max record value", bigbuf[i] == 0);
+
+       kfree(bigbuf);
+
+       circular_buffer_destroy(&cb);
+
+       return TRUE;
+}
+
 /* Ghetto test, only tests one prod or consumer at a time */
 // TODO: Un-guetto test, add assertions.
 bool test_bcq(void)
@@ -885,26 +834,26 @@ bool test_bcq(void)
                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];
@@ -929,27 +878,27 @@ bool test_bcq(void)
                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;
@@ -976,7 +925,8 @@ bool test_ucq(void)
        void send_msgs(struct alarm_waiter *waiter)
        {
                struct timer_chain *tchain;
-               struct proc *old_proc, *p = waiter->data;
+               struct proc *p = waiter->data;
+               uintptr_t old_proc;
                struct ucq *ucq = (struct ucq*)USTACKTOP;
                struct event_msg msg;
 
@@ -1038,9 +988,9 @@ bool test_ucq(void)
        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 = do_file_open("/bin/ucq", O_READ, 0);
+
+       KT_ASSERT_M("We should be able to find /bin/ucq",
                    program);
 
        struct proc *p = proc_create(program, NULL, NULL);
@@ -1054,7 +1004,7 @@ bool test_ucq(void)
         * around that are runnable */
        run_scheduler();
        smp_idle();
-       
+
        KT_ASSERT_M("We should never return from schedule",
                    false);
 
@@ -1074,8 +1024,8 @@ bool test_vm_regions(void)
        TAILQ_INIT(&p->vm_regions);
 
        struct vmr_summary {
-               uintptr_t base; 
-               uintptr_t end; 
+               uintptr_t base;
+               uintptr_t end;
        };
        int check_vmrs(struct proc *p, struct vmr_summary *results, int len, int n)
        {
@@ -1111,7 +1061,7 @@ bool test_vm_regions(void)
        results[0].end = 0x4000;
        check_vmrs(p, results, 1, n++);
        /* Grow it poorly */
-       KT_ASSERT_M("It should pass bad grow test", 
+       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 */
@@ -1120,7 +1070,7 @@ bool test_vm_regions(void)
        results[1].end = 0x5000;
        check_vmrs(p, results, 2, n++);
        /* try to grow through it */
-       KT_ASSERT_M("It should pass bad grow test", 
+       KT_ASSERT_M("It should pass bad grow test",
                    (-1 == grow_vmr(vmrs[0], 0x5000)));
        check_vmrs(p, results, 2, n++);
        /* Merge them */
@@ -1134,7 +1084,7 @@ bool test_vm_regions(void)
        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", 
+       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);
@@ -1152,13 +1102,13 @@ bool test_vm_regions(void)
        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", 
+       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", 
+       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", 
+       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", 
+       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);
@@ -1167,7 +1117,7 @@ bool test_vm_regions(void)
        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", 
+       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 */
@@ -1213,13 +1163,13 @@ bool test_radix_tree(void)
        struct radix_tree *tree = &real_tree;
        void *retval;
 
-       KT_ASSERT_M("It should be possible to insert at 0", 
+       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", 
+       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", 
+       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));
@@ -1230,13 +1180,13 @@ bool test_radix_tree(void)
                        print_radix_tree(tree);
                        monitor(0);
                }
-       KT_ASSERT_M("It should be possible to insert a two-tier", 
+       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", 
+       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", 
+       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", 
+       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);
@@ -1254,26 +1204,26 @@ bool test_radix_tree(void)
 bool test_random_fs(void)
 {
        int retval = do_symlink("/dir1/sym", "/bin/hello", S_IRWXU);
-       KT_ASSERT_M("symlink1 should be created successfully", 
+       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", 
+       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", 
+       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", 
+       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", 
+       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)); 
+       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)
@@ -1284,33 +1234,33 @@ bool test_random_fs(void)
        /* 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", 
+
+       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", 
+       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", 
+       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", 
+       KT_ASSERT_M("symlink lookup should fail for a non existing symlink",
                    (retval));
        path_release(nd);
 
@@ -1337,8 +1287,7 @@ static void __test_up_sem(uint32_t srcid, long a0, long a1, long a2)
 // TODO: Add assertions.
 bool test_kthreads(void)
 {
-       struct semaphore sem;
-       sem_init(&sem, 1);              /* set to 1 to test the unwind */
+       struct semaphore sem = SEMAPHORE_INITIALIZER(sem, 1);
        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
@@ -1378,7 +1327,7 @@ 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);
@@ -1433,9 +1382,9 @@ bool test_atomics(void)
                do {
                        old_num = atomic_read(&actual_num);
                        /* First time, try to fail */
-                       if (attempt == 0) 
+                       if (attempt == 0)
                                old_num++;
-                       attempt++;      
+                       attempt++;
                } while (!atomic_cas(&actual_num, old_num, old_num + 10));
                if (atomic_read(&actual_num) != init_val + 10) {
                        return false;
@@ -1530,9 +1479,9 @@ bool test_cv(void)
        printk("test_cv: signal without waiting complete\n");
 
        /* Test 1: single / minimal shit */
-       nr_msgs = num_cpus - 1; /* not using cpu 0 */
+       nr_msgs = num_cores - 1; /* not using cpu 0 */
        atomic_init(&counter, nr_msgs);
-       for (int i = 1; i < num_cpus; i++)
+       for (int i = 1; i < num_cores; i++)
                send_kernel_message(i, __test_cv_waiter, 0, 0, 0, KMSG_ROUTINE);
        udelay(1000000);
        cv_signal(cv);
@@ -1552,7 +1501,7 @@ bool test_cv(void)
        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;
+               int cpu = (i % (num_cores - 1)) + 1;
                if (atomic_read(&counter) % 5)
                        send_kernel_message(cpu, __test_cv_waiter, 0, 0, 0, KMSG_ROUTINE);
                else
@@ -1602,19 +1551,19 @@ bool test_cv(void)
 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, 
+                       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));
@@ -1622,7 +1571,7 @@ bool test_memset(void)
                }
                return true;
        }
-       
+
        bool run_check(char *arr, int ch, size_t len)
        {
                char *c = arr;
@@ -1652,7 +1601,7 @@ void __attribute__((noinline)) __longjmp_wrapper(struct jmpbuf* jb)
        printk("Starting: %s\n", __FUNCTION__);
        longjmp(jb, 1);
        // Should never get here
-       printk("Exiting: %s\n", __FUNCTION__); 
+       printk("Exiting: %s\n", __FUNCTION__);
 }
 
 // TODO: Add assertions.
@@ -1810,10 +1759,10 @@ bool test_rwlock(void)
                /* 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++)
+       atomic_init(&rwlock_counter, (num_cores - 1) * 4);
+       for (int i = 1; i < num_cores; i++)
                for (int j = 0; j < 4; j++)
                        send_kernel_message(i, __test_rwlock, 0, 0, 0, KMSG_ROUTINE);
        while (atomic_read(&rwlock_counter))
@@ -1867,10 +1816,10 @@ bool test_rv(void)
        printk("test_rv: wakeup without sleeping complete\n");
 
        /* Test 1: a few sleepers */
-       nr_msgs = num_cpus - 1; /* not using cpu 0 */
+       nr_msgs = num_cores - 1; /* not using cpu 0 */
        atomic_init(&counter, nr_msgs);
        state = FALSE;
-       for (int i = 1; i < num_cpus; i++)
+       for (int i = 1; i < num_cores; i++)
                send_kernel_message(i, __test_rv_sleeper, 0, 0, 0, KMSG_ROUTINE);
        udelay(1000000);
        cmb();
@@ -1888,10 +1837,10 @@ bool test_rv(void)
        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;
+               int cpu = (i % (num_cores - 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,
+                       send_kernel_message(cpu, __test_rv_sleeper_timeout, i * 4000, 0, 0,
                                            KMSG_ROUTINE);
                else
                        send_kernel_message(cpu, __test_rv_sleeper, 0, 0, 0, KMSG_ROUTINE);
@@ -2009,7 +1958,7 @@ bool test_u16pool(void)
        int numalloc;
        KT_ASSERT(id);
 
-       t = kzmalloc(sizeof(int) * (AMT + 1), KMALLOC_WAIT);
+       t = kzmalloc(sizeof(int) * (AMT + 1), MEM_WAIT);
        for (x = 0; x < 1024; x++) {
                KT_ASSERT_M("Should be empty", id->tos == 0);
                for (i = 0; i < id->size; i++) {
@@ -2086,6 +2035,227 @@ bool test_u16pool(void)
        return FALSE;
 }
 
+static bool uaccess_mapped(void *addr, char *buf, char *buf2)
+{
+       KT_ASSERT_M(
+               "Copy to user (u8) to mapped address should not fail",
+               copy_to_user(addr, buf, 1) == 0);
+       KT_ASSERT_M(
+               "Copy to user (u16) to mapped address should not fail",
+               copy_to_user(addr, buf, 2) == 0);
+       KT_ASSERT_M(
+               "Copy to user (u32) to mapped address should not fail",
+               copy_to_user(addr, buf, 4) == 0);
+       KT_ASSERT_M(
+               "Copy to user (u64) to mapped address should not fail",
+               copy_to_user(addr, buf, 8) == 0);
+       KT_ASSERT_M(
+               "Copy to user (mem) to mapped address should not fail",
+               copy_to_user(addr, buf, sizeof(buf)) == 0);
+
+       KT_ASSERT_M(
+               "Copy from user (u8) to mapped address should not fail",
+               copy_from_user(buf, addr, 1) == 0);
+       KT_ASSERT_M(
+               "Copy from user (u16) to mapped address should not fail",
+               copy_from_user(buf, addr, 2) == 0);
+       KT_ASSERT_M(
+               "Copy from user (u32) to mapped address should not fail",
+               copy_from_user(buf, addr, 4) == 0);
+       KT_ASSERT_M(
+               "Copy from user (u64) to mapped address should not fail",
+               copy_from_user(buf, addr, 8) == 0);
+       KT_ASSERT_M(
+               "Copy from user (mem) to mapped address should not fail",
+               copy_from_user(buf, addr, sizeof(buf)) == 0);
+
+       KT_ASSERT_M(
+               "String copy to user to mapped address should not fail",
+               strcpy_to_user(current, addr, "Akaros") == 0);
+       KT_ASSERT_M(
+               "String copy from user to mapped address should not fail",
+               strcpy_from_user(current, buf, addr) == 0);
+       KT_ASSERT_M("The copied string content should be matching",
+                               memcmp(buf, "Akaros", 7) == 0);
+
+       return TRUE;
+}
+
+static bool uaccess_unmapped(void *addr, char *buf, char *buf2)
+{
+       KT_ASSERT_M("Copy to user (u8) to not mapped address should fail",
+                               copy_to_user(addr, buf, 1) == -EFAULT);
+       KT_ASSERT_M("Copy to user (u16) to not mapped address should fail",
+                               copy_to_user(addr, buf, 2) == -EFAULT);
+       KT_ASSERT_M("Copy to user (u32) to not mapped address should fail",
+                               copy_to_user(addr, buf, 4) == -EFAULT);
+       KT_ASSERT_M("Copy to user (u64) to not mapped address should fail",
+                               copy_to_user(addr, buf, 8) == -EFAULT);
+       KT_ASSERT_M("Copy to user (mem) to not mapped address should fail",
+                               copy_to_user(addr, buf, sizeof(buf)) == -EFAULT);
+
+       KT_ASSERT_M("Copy from user (u8) to not mapped address should fail",
+                               copy_from_user(buf, addr, 1) == -EFAULT);
+       KT_ASSERT_M("Copy from user (u16) to not mapped address should fail",
+                               copy_from_user(buf, addr, 2) == -EFAULT);
+       KT_ASSERT_M("Copy from user (u32) to not mapped address should fail",
+                               copy_from_user(buf, addr, 4) == -EFAULT);
+       KT_ASSERT_M("Copy from user (u64) to not mapped address should fail",
+                               copy_from_user(buf, addr, 8) == -EFAULT);
+       KT_ASSERT_M("Copy from user (mem) to not mapped address should fail",
+                               copy_from_user(buf, addr, sizeof(buf)) == -EFAULT);
+
+       KT_ASSERT_M(
+               "String copy to user to not mapped address should fail",
+               strcpy_to_user(NULL, addr, "Akaros") == -EFAULT);
+       KT_ASSERT_M(
+               "String copy from user to not mapped address should fail",
+               strcpy_from_user(NULL, buf, addr) == -EFAULT);
+
+       KT_ASSERT_M("Copy from user with kernel side source pointer should fail",
+                               copy_from_user(buf, buf2, sizeof(buf)) == -EFAULT);
+       KT_ASSERT_M("Copy to user with kernel side source pointer should fail",
+                               copy_to_user(buf, buf2, sizeof(buf)) == -EFAULT);
+
+       return TRUE;
+}
+
+bool test_uaccess(void)
+{
+       char buf[128] = { 0 };
+       char buf2[128] = { 0 };
+       struct proc *tmp;
+       uintptr_t switch_tmp;
+       int err;
+       static const size_t mmap_size = 4096;
+       void *addr;
+       bool passed = FALSE;
+
+       err = proc_alloc(&tmp, 0, 0);
+       KT_ASSERT_M("Failed to alloc a temp proc", err == 0);
+       /* Tell everyone we're ready in case some ops don't work on PROC_CREATED */
+       __proc_set_state(tmp, PROC_RUNNABLE_S);
+       switch_tmp = switch_to(tmp);
+       addr = mmap(tmp, 0, mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, -1, 0);
+       if (addr == MAP_FAILED)
+               goto out;
+       passed = uaccess_mapped(addr, buf, buf2);
+       munmap(tmp, (uintptr_t) addr, mmap_size);
+       if (!passed)
+               goto out;
+       passed = uaccess_unmapped(addr, buf, buf2);
+out:
+       switch_back(tmp, switch_tmp);
+       proc_decref(tmp);
+       return passed;
+}
+
+bool test_sort(void)
+{
+       int cmp_longs_asc(const void *p1, const void *p2)
+       {
+               const long v1 = *(const long *) p1;
+               const long v2 = *(const long *) p2;
+
+               return v1 < v2 ? -1 : (v1 > v2 ? 1 : 0);
+       }
+
+       int cmp_longs_desc(const void *p1, const void *p2)
+       {
+               const long v1 = *(const long *) p1;
+               const long v2 = *(const long *) p2;
+
+               return v1 < v2 ? 1 : (v1 > v2 ? -1 : 0);
+       }
+
+       size_t i;
+       long long_set_1[] = {
+               -9, 11, 0, 23, 123, -99, 3, 11, 23, -999, 872, 17, 21
+       };
+       long long_set_2[] = {
+               31, 77, -1, 2, 0, 64, 11, 19, 69, 111, -89, 17, 21, 44, 77
+       };
+
+       sort(long_set_1, ARRAY_SIZE(long_set_1), sizeof(long), cmp_longs_asc);
+       for (i = 1; i < ARRAY_SIZE(long_set_1); i++)
+               KT_ASSERT(long_set_1[i - 1] <= long_set_1[i]);
+
+       sort(long_set_2, ARRAY_SIZE(long_set_2), sizeof(long), cmp_longs_desc);
+       for (i = 1; i < ARRAY_SIZE(long_set_2); i++)
+               KT_ASSERT(long_set_2[i - 1] >= long_set_2[i]);
+
+       return TRUE;
+}
+
+bool test_cmdline_parse(void)
+{
+       static const char *fake_cmdline =
+               "kernel -root=/foo -simple -num=123 -quoted='abc \\'' -dup=311 "
+               "-dup='akaros' -empty='' -inner=-outer -outer=-inner=xyz";
+       const char *opt;
+       char param[128];
+
+       /* Note that the get_boot_option() API should be passed NULL the first time
+        * it is called, in normal cases, and should be passed the value returned by
+        * previous call to get_boot_option(), in case multiple options with same
+        * name have to be fetched.
+        */
+       opt = get_boot_option(fake_cmdline, "-root", param, sizeof(param));
+       KT_ASSERT_M("Unable to parse -root option", opt);
+       KT_ASSERT_M("Invalid -root option value", strcmp(param, "/foo") == 0);
+
+       opt = get_boot_option(fake_cmdline, "-root", NULL, 0);
+       KT_ASSERT_M("Unable to parse -root option when param not provided", opt);
+
+       opt = get_boot_option(fake_cmdline, "-simple", param, sizeof(param));
+       KT_ASSERT_M("Unable to parse -simple option", opt);
+       KT_ASSERT_M("Invalid -simple option value", strcmp(param, "") == 0);
+
+       opt = get_boot_option(fake_cmdline, "-num", param, sizeof(param));
+       KT_ASSERT_M("Unable to parse -num option", opt);
+       KT_ASSERT_M("Invalid -num option value", strcmp(param, "123") == 0);
+
+       opt = get_boot_option(fake_cmdline, "-quoted", param, sizeof(param));
+       KT_ASSERT_M("Unable to parse -quoted option", opt);
+       KT_ASSERT_M("Invalid -quoted option value", strcmp(param, "abc '") == 0);
+
+       opt = get_boot_option(fake_cmdline, "-dup", param, sizeof(param));
+       KT_ASSERT_M("Unable to parse -dup option", opt);
+       KT_ASSERT_M("Invalid -dup option first value", strcmp(param, "311") == 0);
+
+       opt = get_boot_option(opt, "-dup", param, sizeof(param));
+       KT_ASSERT_M("Unable to parse -dup option", opt);
+       KT_ASSERT_M("Invalid -dup option second value",
+                               strcmp(param, "akaros") == 0);
+
+       opt = get_boot_option(fake_cmdline, "-inner", param, sizeof(param));
+       KT_ASSERT_M("Unable to parse -inner option", opt);
+       KT_ASSERT_M("Invalid -inner option value", strcmp(param, "-outer") == 0);
+
+       opt = get_boot_option(opt, "-inner", param, sizeof(param));
+       KT_ASSERT_M("Should not be parsing -inner as value", !opt);
+
+       opt = get_boot_option(fake_cmdline, "-outer", param, sizeof(param));
+       KT_ASSERT_M("Unable to parse -outer option", opt);
+       KT_ASSERT_M("Invalid -outer option value",
+                               strcmp(param, "-inner=xyz") == 0);
+
+       opt = get_boot_option(fake_cmdline, "-missing", param, sizeof(param));
+       KT_ASSERT_M("Should not be parsing -missing option", !opt);
+
+       opt = get_boot_option(fake_cmdline, "-inne", NULL, 0);
+       KT_ASSERT_M("Should not be parsing -inne option", !opt);
+
+       opt = get_boot_option(fake_cmdline, "-outera", NULL, 0);
+       KT_ASSERT_M("Should not be parsing -outera option", !opt);
+
+       opt = get_boot_option(fake_cmdline, "-empty", param, sizeof(param));
+       KT_ASSERT_M("Unable to parse -empty option", opt);
+       KT_ASSERT_M("Invalid -empty option value", strcmp(param, "") == 0);
+
+       return TRUE;
+}
+
 static struct ktest ktests[] = {
 #ifdef CONFIG_X86
        KTEST_REG(ipi_sending,        CONFIG_TEST_ipi_sending),
@@ -2095,10 +2265,6 @@ static struct ktest ktests[] = {
        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(barrier,            CONFIG_TEST_barrier),
        KTEST_REG(interrupts_irqsave, CONFIG_TEST_interrupts_irqsave),
        KTEST_REG(bitmasks,           CONFIG_TEST_bitmasks),
@@ -2107,6 +2273,7 @@ static struct ktest ktests[] = {
        KTEST_REG(slab,               CONFIG_TEST_slab),
        KTEST_REG(kmalloc,            CONFIG_TEST_kmalloc),
        KTEST_REG(hashtable,          CONFIG_TEST_hashtable),
+       KTEST_REG(circular_buffer,    CONFIG_TEST_circular_buffer),
        KTEST_REG(bcq,                CONFIG_TEST_bcq),
        KTEST_REG(ucq,                CONFIG_TEST_ucq),
        KTEST_REG(vm_regions,         CONFIG_TEST_vm_regions),
@@ -2125,6 +2292,9 @@ static struct ktest ktests[] = {
        KTEST_REG(alarm,              CONFIG_TEST_alarm),
        KTEST_REG(kmalloc_incref,     CONFIG_TEST_kmalloc_incref),
        KTEST_REG(u16pool,            CONFIG_TEST_u16pool),
+       KTEST_REG(uaccess,            CONFIG_TEST_uaccess),
+       KTEST_REG(sort,               CONFIG_TEST_sort),
+       KTEST_REG(cmdline_parse,      CONFIG_TEST_cmdline_parse),
 };
 static int num_ktests = sizeof(ktests) / sizeof(struct ktest);
 linker_func_1(register_pb_ktests)