Add a simple LKL test applications that starts the kernel and performs
simple tests that minimally exercise the LKL API.

Signed-off-by: Octavian Purdila <octavian.purd...@intel.com>
---
 tools/lkl/.gitignore    |   1 +
 tools/lkl/Makefile      |   7 +-
 tools/lkl/tests/boot.c  | 488 ++++++++++++++++++++++++++++++++++++++++++++++++
 tools/lkl/tests/boot.sh |  10 +
 4 files changed, 504 insertions(+), 2 deletions(-)
 create mode 100644 tools/lkl/tests/boot.c
 create mode 100755 tools/lkl/tests/boot.sh

diff --git a/tools/lkl/.gitignore b/tools/lkl/.gitignore
index e69de29..7c456f2 100644
--- a/tools/lkl/.gitignore
+++ b/tools/lkl/.gitignore
@@ -0,0 +1 @@
+test/boot
diff --git a/tools/lkl/Makefile b/tools/lkl/Makefile
index cf97d27..1ae4481 100644
--- a/tools/lkl/Makefile
+++ b/tools/lkl/Makefile
@@ -7,14 +7,17 @@ LD=$(CROSS_COMPILE)ld
 endif
 
 lib_source = $(filter-out %-host.c,$(wildcard lib/*.c))
+source = $(wildcard tests/*.c)
 ifneq (,$(filter $(shell $(LD) -r -print-output-format),elf64-x86-64 
elf32-i386))
 lib_source += lib/posix-host.c
 LDFLAGS += -lpthread -lrt
 endif
 
 lib_objs = $(patsubst %.c,%.o, $(lib_source)) lib/lkl.o
+objs = $(patsubst %.c,%.o, $(source))
+execs = $(patsubst %.c,%, $(source))
 
-all: lib/liblkl.a
+all: lib/liblkl.a $(execs)
 
 lib/liblkl.a: $(lib_objs)
        $(AR) -rc $@ $^
@@ -31,4 +34,4 @@ $(objs): lib/lkl.o
 $(execs): lib/liblkl.a
 
 clean:
-       -rm -rf include/lkl/ lib/liblkl.a $(lib_objs)
+       -rm -rf include/lkl/ lib/liblkl.a $(lib_objs) $(objs) $(execs)
diff --git a/tools/lkl/tests/boot.c b/tools/lkl/tests/boot.c
new file mode 100644
index 0000000..f5945aa
--- /dev/null
+++ b/tools/lkl/tests/boot.c
@@ -0,0 +1,488 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <lkl.h>
+#include <lkl_host.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+static struct cl_args {
+       int printk;
+       const char *disk_filename;
+} cla;
+
+static struct cl_option {
+       const char *long_name;
+       char short_name;
+       const char *help;
+       int has_arg;
+} options[] = {
+       {"enable-printk", 'p', "show Linux printks", 0},
+       {"disk-file", 'd', "disk file to use", 1},
+       {0},
+};
+
+static int parse_opt(int key, char *arg)
+{
+       switch (key) {
+       case 'p':
+               cla.printk = 1;
+               break;
+       case 'd':
+               cla.disk_filename = arg;
+               break;
+       default:
+               return -1;
+       }
+
+       return 0;
+}
+
+void printk(const char *str, int len)
+{
+       if (cla.printk)
+               write(STDOUT_FILENO, str, len);
+}
+
+#define TEST(name) do_test(#name, test_##name)
+
+static void do_test(char *name, int (*fn)(char *, int))
+{
+       char str[60];
+       int result;
+
+       result = fn(str, sizeof(str));
+       printf("%-20s %s [%s]\n", name, result ? "passed" : "failed", str);
+}
+
+#define sleep_ns 87654321
+
+int test_nanosleep(char *str, int len)
+{
+       struct lkl_timespec ts = {
+               .tv_sec = 0,
+               .tv_nsec = sleep_ns,
+       };
+       struct timespec start, stop;
+       long delta;
+       long ret;
+
+       clock_gettime(CLOCK_MONOTONIC, &start);
+       ret = lkl_sys_nanosleep(&ts, NULL);
+       clock_gettime(CLOCK_MONOTONIC, &stop);
+
+       delta = (stop.tv_sec - start.tv_sec) +
+               (stop.tv_nsec - start.tv_nsec);
+
+       snprintf(str, len, "%ld", delta);
+
+       if (ret == 0 && delta > sleep_ns * 0.9 && delta < sleep_ns * 1.1)
+               return 1;
+
+       return 0;
+}
+
+int test_getpid(char *str, int len)
+{
+       long ret;
+
+       ret = lkl_sys_getpid();
+
+       snprintf(str, len, "%ld", ret);
+
+       if (ret == 1)
+               return 1;
+
+       return 0;
+}
+
+#define access_rights 0721
+
+int test_creat(char *str, int len)
+{
+       long ret;
+
+       ret = lkl_sys_creat("/file", access_rights);
+
+       snprintf(str, len, "%ld", ret);
+
+       if (ret == 0)
+               return 1;
+
+       return 0;
+}
+
+int test_close(char *str, int len)
+{
+       long ret;
+
+       ret = lkl_sys_close(0);
+
+       snprintf(str, len, "%ld", ret);
+
+       if (ret == 0)
+               return 1;
+
+       return 0;
+}
+
+int test_failopen(char *str, int len)
+{
+       long ret;
+
+       ret = lkl_sys_open("/file2", 0, 0);
+
+       snprintf(str, len, "%ld", ret);
+
+       if (ret == -LKL_ENOENT)
+               return 1;
+
+       return 0;
+}
+
+int test_umask(char *str, int len)
+{
+       long ret, ret2;
+
+       ret = lkl_sys_umask(0777);
+
+       ret2 = lkl_sys_umask(0);
+
+       snprintf(str, len, "%lo %lo", ret, ret2);
+
+       if (ret > 0 && ret2 == 0777)
+               return 1;
+
+       return 0;
+}
+
+int test_open(char *str, int len)
+{
+       long ret;
+
+       ret = lkl_sys_open("/file", LKL_O_RDWR, 0);
+
+       snprintf(str, len, "%ld", ret);
+
+       if (ret == 0)
+               return 1;
+
+       return 0;
+}
+
+static const char write_test[] = "test";
+
+int test_write(char *str, int len)
+{
+       long ret;
+
+       ret = lkl_sys_write(0, write_test, sizeof(write_test));
+
+       snprintf(str, len, "%ld", ret);
+
+       if (ret == sizeof(write_test))
+               return 1;
+
+       return 0;
+}
+
+int test_lseek(char *str, int len)
+{
+       long ret;
+       __lkl__kernel_loff_t res;
+
+       ret = lkl_sys_lseek(0, 0, &res, LKL_SEEK_SET);
+
+       snprintf(str, len, "%ld %lld", ret, res);
+
+       if (ret == 0)
+               return 1;
+
+       return 0;
+}
+
+int test_read(char *str, int len)
+{
+       char buf[10] = { 0, };
+       long ret;
+
+       ret = lkl_sys_read(0, buf, sizeof(buf));
+
+       snprintf(str, len, "%ld %s", ret, buf);
+
+       if (ret == sizeof(write_test) && strcmp(write_test, buf) == 0)
+               return 1;
+
+       return 0;
+}
+
+int test_fstat64(char *str, int len)
+{
+       struct lkl_stat64 stat;
+       long ret;
+
+       ret = lkl_sys_fstat64(0, &stat);
+
+       snprintf(str, len, "%ld %o %lld", ret, stat.st_mode, stat.st_size);
+
+       if (ret == 0 && stat.st_size == sizeof(write_test) &&
+           stat.st_mode == (access_rights | LKL_S_IFREG))
+               return 1;
+
+       return 0;
+}
+
+int test_mkdir(char *str, int len)
+{
+       long ret;
+
+       ret = lkl_sys_mkdir("/mnt", access_rights);
+
+       snprintf(str, len, "%ld", ret);
+
+       if (ret == 0)
+               return 1;
+
+       return 0;
+}
+
+int test_stat64(char *str, int len)
+{
+       struct lkl_stat64 stat;
+       long ret;
+
+       ret = lkl_sys_stat64("/mnt", &stat);
+
+       snprintf(str, len, "%ld %o", ret, stat.st_mode);
+
+       if (ret == 0 && stat.st_mode == (access_rights | LKL_S_IFDIR))
+               return 1;
+
+       return 0;
+}
+
+static const char *tmp_file;
+static union lkl_disk_backstore bs;
+static int disk_id = -1;
+
+int test_disk_add(char *str, int len)
+{
+       bs.fd = open(cla.disk_filename, O_RDWR);
+       if (bs.fd < 0)
+               goto out_unlink;
+
+       disk_id = lkl_disk_add(bs);
+       if (disk_id < 0)
+               goto out_close;
+
+       goto out;
+
+out_close:
+       close(bs.fd);
+out_unlink:
+       unlink(cla.disk_filename);
+
+out:
+       snprintf(str, len, "%x %d", bs.fd, disk_id);
+
+       if (disk_id >= 0)
+               return 1;
+
+       return 0;
+}
+
+static char mnt_point[32];
+
+static int test_mount(char *str, int len)
+{
+       long ret;
+
+       ret = lkl_mount_dev(disk_id, "ext4", 0, NULL, mnt_point,
+                           sizeof(mnt_point));
+
+       snprintf(str, len, "%ld", ret);
+
+       if (ret == 0)
+               return 1;
+
+       return 0;
+}
+
+static int test_chdir(char *str, int len)
+{
+       long ret;
+
+       ret = lkl_sys_chdir(mnt_point);
+
+       snprintf(str, len, "%ld", ret);
+
+       if (ret == 0)
+               return 1;
+
+       return 0;
+}
+
+static int dir_fd;
+
+static int test_opendir(char *str, int len)
+{
+       dir_fd = lkl_sys_open(".", LKL_O_RDONLY | LKL_O_DIRECTORY, 0);
+
+       snprintf(str, len, "%d", dir_fd);
+
+       if (dir_fd > 0)
+               return 1;
+
+       return 0;
+}
+
+static int test_getdents64(char *str, int len)
+{
+       long ret;
+       char buf[1024], *pos;
+       struct lkl_dirent64 *de;
+       int wr;
+
+       ret = lkl_sys_getdents64(dir_fd, buf, sizeof(buf));
+
+       wr = snprintf(str, len, "%d ", dir_fd);
+       str += wr;
+       len -= wr;
+
+       if (ret < 0)
+               return 0;
+
+       for (pos = buf; pos - buf < ret; pos += de->d_reclen) {
+               de = (struct lkl_dirent64 *)pos;
+
+               wr = snprintf(str, len, "%s ", de->d_name);
+               str += wr;
+               len -= wr;
+       }
+
+       return 1;
+}
+
+static int test_umount(char *str, int len)
+{
+       long ret, ret2, ret3;
+
+       ret = lkl_sys_close(dir_fd);
+
+       ret2 = lkl_sys_chdir("/");
+
+       ret3 = lkl_umount_dev(disk_id, 0, 1000);
+
+       snprintf(str, len, "%ld %ld %ld", ret, ret2, ret3);
+
+       if (!ret && !ret2 && !ret3)
+               return 1;
+
+       return 0;
+}
+
+static struct cl_option *find_short_opt(char name)
+{
+       struct cl_option *opt;
+
+       for (opt = options; opt->short_name != 0; opt++) {
+               if (opt->short_name == name)
+                       return opt;
+       }
+
+       return NULL;
+}
+
+static struct cl_option *find_long_opt(const char *name)
+{
+       struct cl_option *opt;
+
+       for (opt = options; opt->long_name; opt++) {
+               if (strcmp(opt->long_name, name) == 0)
+                       return opt;
+       }
+
+       return NULL;
+}
+
+static void print_help(void)
+{
+       struct cl_option *opt;
+
+       printf("usage:\n");
+       for (opt = options; opt->long_name; opt++)
+               printf("-%c, --%-20s %s\n", opt->short_name, opt->long_name,
+                      opt->help);
+}
+
+static int parse_opts(int argc, char **argv)
+{
+       int i;
+
+       for (i = 1; i < argc; i++) {
+               struct cl_option *opt = NULL;
+
+               if (argv[i][0] == '-') {
+                       if (argv[i][1] != '-')
+                               opt = find_short_opt(argv[i][1]);
+                       else
+                               opt = find_long_opt(&argv[i][2]);
+               }
+
+               if (!opt) {
+                       print_help();
+                       return -1;
+               }
+
+               if (parse_opt(opt->short_name, argv[i + 1]) < 0) {
+                       print_help();
+                       return -1;
+               }
+
+               if (opt->has_arg)
+                       i++;
+       }
+
+       return 0;
+}
+
+int main(int argc, char **argv)
+{
+       if (parse_opts(argc, argv) < 0)
+               return -1;
+
+       lkl_host_ops.print = printk;
+
+       TEST(disk_add);
+
+       lkl_start_kernel(&lkl_host_ops, 10 * 1024 * 1024, "");
+
+       TEST(getpid);
+       TEST(umask);
+       TEST(creat);
+       TEST(close);
+       TEST(failopen);
+       TEST(open);
+       TEST(write);
+       TEST(lseek);
+       TEST(read);
+       TEST(fstat64);
+       TEST(mkdir);
+       TEST(stat64);
+       TEST(nanosleep);
+       TEST(mount);
+       TEST(chdir);
+       TEST(opendir);
+       TEST(getdents64);
+       TEST(umount);
+
+       lkl_sys_halt();
+
+       close(bs.fd);
+       unlink(tmp_file);
+
+       return 0;
+}
diff --git a/tools/lkl/tests/boot.sh b/tools/lkl/tests/boot.sh
new file mode 100755
index 0000000..3fb7b1f
--- /dev/null
+++ b/tools/lkl/tests/boot.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+file=`mktemp`
+dd if=/dev/zero of=$file bs=1024 count=10240
+
+yes | mkfs.ext4 -q $file
+
+./boot -d $file $@
+
+rm $file
-- 
2.1.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to