Use a temp process for test_uaccess
[akaros.git] / kern / src / ktest / pb_ktests.c
index 5dfd003..a5de1ee 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>
@@ -875,6 +880,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, KMALLOC_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)
@@ -2085,6 +2167,212 @@ bool test_u16pool(void)
        return FALSE;
 }
 
+bool test_uaccess(void)
+{
+       char buf[128] = { 0 };
+       char buf2[128] = { 0 };
+       struct proc *tmp;
+       int err;
+       static const size_t mmap_size = 4096;
+       void *addr;
+
+       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);
+
+       addr = mmap(tmp, 0, mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, -1, 0);
+
+       KT_ASSERT_M("Mmap failed", addr != MAP_FAILED);
+
+       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);
+
+       munmap(tmp, (uintptr_t) addr, mmap_size);
+
+
+       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);
+
+       proc_decref(tmp);
+       return TRUE;
+}
+
+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),
@@ -2106,6 +2394,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),
@@ -2124,6 +2413,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)