diff options
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/Makefile | 34 | ||||
| -rw-r--r-- | tests/common/arch/riscv64/syscall.h | 50 | ||||
| -rw-r--r-- | tests/common/printf.c | 583 | ||||
| -rw-r--r-- | tests/common/test.h | 324 | ||||
| -rw-r--r-- | tests/hello-world/init.c | 14 | ||||
| -rw-r--r-- | tests/hello-world/source.mk | 8 | ||||
| -rw-r--r-- | tests/noop/init.c | 13 | ||||
| -rw-r--r-- | tests/noop/source.mk | 8 |
8 files changed, 1034 insertions, 0 deletions
diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 0000000..2012107 --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,34 @@ +TESTS := + +ARCH ?= riscv64 +CROSS_COMPILE ?= $(ARCH)-unknown-elf- + +LLVM ?= 0 +COMPILER != [ "$(LLVM)" != "0" ] \ + && echo clang --target="$(CROSS_COMPILE)" \ + || echo $(CROSS_COMPILE)gcc + +OBFLAGS := -ffreestanding -nostdlib -std=c17 -g +INCLUDEFLAGS := -I ../include -I. +WARNFLAGS := -Wall -Wextra +COMPILE := $(COMPILER) $(WARNFLAGS) $(INCLUDEFLAGS) $(OBFLAGS) + +GEN_INITRD := cpio -H newc -o > +QEMU := qemu-system-$(ARCH) -machine virt -kernel ../kmi.bin \ + -serial stdio \ + -monitor none \ + -nographic \ + -no-reboot \ + -initrd + +COMMON := build/printf.o ../kmi.bin ../include/kmi/syscalls.h + +include noop/source.mk +include hello-world/source.mk + +.PHONY: check +check: $(TESTS) + +build/printf.o: common/printf.c + mkdir -p build + $(COMPILE) -c common/printf.c -o build/printf.o diff --git a/tests/common/arch/riscv64/syscall.h b/tests/common/arch/riscv64/syscall.h new file mode 100644 index 0000000..aafda82 --- /dev/null +++ b/tests/common/arch/riscv64/syscall.h @@ -0,0 +1,50 @@ +#ifndef KMI_TESTS_ARCH_RISCV64_SYSCALL_H +#define KMI_TESTS_ARCH_RISCV64_SYSCALL_H + +#include <kmi/syscalls.h> +#include <kmi/attrs.h> + +static inline struct sys_ret syscall(size_t n, + long arg0, long arg1, long arg2, long arg3, + long arg4, + long arg5) +{ + register long a0 __asm__ ("a0") = arg0; + register long a1 __asm__ ("a1") = arg1; + register long a2 __asm__ ("a2") = arg2; + register long a3 __asm__ ("a3") = arg3; + register long a4 __asm__ ("a4") = arg4; + register long a5 __asm__ ("a5") = arg5; + +#define OUTPUTS "+r" (a0), "=r" (a1), "=r" (a2), "=r" (a3), "=r" (a4), "=r" (a5) + + if (n == 1) + __asm__ volatile ("ecall" : OUTPUTS : "r" (a0)); + + else if (n == 2) + __asm__ volatile ("ecall" : OUTPUTS : "r" (a0), "r" (a1)); + + else if (n == 3) + __asm__ volatile ("ecall" : OUTPUTS : "r" (a0), "r" (a1), + "r" (a2)); + + else if (n == 4) + __asm__ volatile ("ecall" : OUTPUTS + : "r" (a0), "r" (a1), "r" (a2), "r" (a3)); + + else if (n == 5) + __asm__ volatile ("ecall" : OUTPUTS + : "r" (a0), "r" (a1), "r" (a2), "r" (a3), + "r" (a4)); + + else if (n == 6) + __asm__ volatile ("ecall" : OUTPUTS + : "r" (a0), "r" (a1), "r" (a2), "r" (a3), + "r" (a4), "r" (a5)); + +#undef OUTPUTS + + return (struct sys_ret){a0, a1, a2, a3, a4, a5}; +} + +#endif /* KMI_TESTS_ARCH_RISCV64_SYSCALL_H */ diff --git a/tests/common/printf.c b/tests/common/printf.c new file mode 100644 index 0000000..0ad084b --- /dev/null +++ b/tests/common/printf.c @@ -0,0 +1,583 @@ +#include <stdarg.h> +#include "test.h" + +/* Directly copied from src/debug.c, which was copied from + * https://github.com/mpaland/printf/blob/master/printf.c + */ + +/** Ask kernel to print out one character for us. Only works if kernel was + * compiled with DEBUG=1. */ +static void __putchar(char c) +{ + sys_putch(c); +} + +/** Printf formatting left align flag. */ +#define LEFT_FLAG (1 << 0) + +/** Printf formatting explicit sign flag. */ +#define SIGN_FLAG (1 << 1) + +/** Printf formatting hash sign flag. */ +#define HASH_FLAG (1 << 2) + +/** Printf formatting zero padding flag. */ +#define ZERO_FLAG (1 << 3) + +/** Printf formatting ' flag. */ +#define FMT_FLAG (1 << 4) + +/** Printf formatting space flag. */ +#define SPACE_FLAG (1 << 5) + +/** Printf formatting long specifier flag. */ +#define LONG_FLAG (1 << 6) + +/** Printf formatting long long specifier flag. */ +#define LLONG_FLAG (1 << 7) + +/** Printf formatting short flag. */ +#define SHORT_FLAG (1 << 8) + +/** Printf formatting char flag. */ +#define CHAR_FLAG (1 << 9) + +/** Printf precision flag. */ +#define PRECS_FLAG (1 << 11) + +/** Printf unsigned flag. */ +#define UNSIGN_FLAG (1 << 12) + +/** Printf width flag. */ +#define WIDTH_FLAG (1 << 13) + +/** Printf padding flag. */ +#define PAD_FLAG (1 << 14) + +/** Printf continue flag. */ +#define CONT 1 + +/** Printf stop flag. */ +#define STOP 0 + +/** + * Check if character is ASCII decimal digit. + * + * @param c Character to check. + * @return \c true if character is ASCII decimal digit, \c false otherwise. + */ +static bool __is_digit(char c) +{ + return (c >= '0') && (c <= '9'); +} + +/** + * Convert string to corresponding number (assuming int). + * + * @param s Number string. + * @return Corresponding number. + */ +static int __atoi(const char *s) +{ + unsigned int i = 0; + while (__is_digit(*s)) { + i = i * 10 + (unsigned int)(*(s++) - '0'); + } + + return i; +} + +/** + * Calculate signed char from value using type interpretation. + * + * @param x Type to interpret value as. + * @param value Value to interpret. + * @param base Base to interpret value in. + */ +#define handle_type(x, value, base) \ + c = (x)value % (x)base; \ + value = (x)value / (x)base; +/** + * Convert number to string length. + * + * @param value Number to print. + * @param base Base to print in. + * @param flags Flags to output. + * @param print Print number as well. + * @return Length of corresponding string. + */ +static size_t __integral_val(ssize_t value, size_t base, size_t flags, + bool print) +{ + /* assume ascii numbers, which is why 'signed char' is probably fine */ + size_t ret = 0; + signed char c = 0; + + + if (flags & UNSIGN_FLAG) { + /* signed values, only with i format */ + if (flags & LLONG_FLAG) { + handle_type(signed long long, value, base); + } else if (flags & LONG_FLAG) { + handle_type(signed long, value, base); + } else if (flags & SHORT_FLAG) { + handle_type(signed short, value, base); + } else if (flags & CHAR_FLAG) { + handle_type(signed char, value, base); + } else { + handle_type(signed int, value, base); + } + + /* convert negative results into actual characters */ + c = c < 0 ? -c : c; + + } else { + /* unsigned values, everything else */ + if (flags & LLONG_FLAG) { + handle_type(unsigned long long, value, base); + } else if (flags & LONG_FLAG) { + handle_type(unsigned long, value, base); + } else if (flags & SHORT_FLAG) { + handle_type(unsigned short, value, base); + } else if (flags & CHAR_FLAG) { + handle_type(unsigned char, value, base); + } else { + handle_type(unsigned int, value, base); + } + } + + if (base == 16) + c += c > 9 ? 'a' - 10 : '0'; + else + c += '0'; + + if (value != 0) + ret = __integral_val(value, base, flags, print); + + if (print) + __putchar(c); + + return ret + 1; +} + +/** + * Print out a string. + * + * @param s String to print out. + * @return Bytes printed. + */ +static size_t __puts(const char *s) +{ + size_t i = 0; + while (s[i]) { + __putchar(s[i++]); + } + + return i; +} + +/** + * Print prefix corresponding to \c base. + * + * @param base Base to integer. + * @return Length of prefix as string. + */ +static size_t __print_prefix(size_t base) +{ + switch (base) { + case 16: return __puts("0x"); + case 8: return __puts("0"); + case 2: return __puts("0b"); + default: break; + } + + return 0; +} + +/** + * Print padding. + * + * @param pad Number of characters to print. + * @param pad_char Character to use as padding. + * @return Number of characters printed. + */ +static size_t __print_padding(size_t pad, char pad_char) +{ + size_t i = 0; + for (; i < pad; ++i) { + __putchar(pad_char); + } + + return i; +} + +/** + * Print signed value. + * + * @param value Value to print. + * @param flags Flags to printing. + * @return Number of characters written. + */ +static size_t __print_sign(ssize_t value, size_t flags) +{ + if (flags & LLONG_FLAG) + value = (signed long long)value; + else if (flags & LONG_FLAG) + value = (signed long)value; + else if (flags & SHORT_FLAG) + value = (signed short)value; + else if (flags & CHAR_FLAG) + value = (signed char)value; + else + value = (signed int)value; + + if (value < 0) { + __putchar('-'); + return 1; + } else if (flags & SIGN_FLAG) { + __putchar('+'); + return 1; + } + + return 0; +} + +/** + * Length of integral value as string. + * + * @param value Value to convert to string. + * @param base Base to interpret value as. + * @param flags Formatting flags. + * @return \see __integral_val(). + */ +#define __integral_len(value, base, flags) __integral_val((value), (base), \ + (flags), false) + +/** + * Print integral value as string. + * + * @param value Value to convert to string. + * @param base Base to interpret value as. + * @param flags Formatting flags. + * @return \see __integral_val(). + */ +#define __integral_print(value, base, flags) __integral_val((value), (base), \ + (flags), true) + +/** + * Print integral value. + * + * @param value Value to print. + * @param base Base to print value in. + * @param flags Flags to printing. + * @param width Minimum width of printing. + * @return Number of characters written. + */ +static size_t __print_integral(ssize_t value, size_t base, size_t flags, + size_t width) +{ + size_t ret = 0; + size_t raw_len = __integral_len(value, base, flags); + ssize_t pad = (flags & PAD_FLAG) ? width - raw_len : 0; + + /* depending on which flags are set, the prefix, sign and right justify has to + * be ordereder differently. */ + if (flags & ZERO_FLAG) { + if (!(flags & UNSIGN_FLAG)) + ret += __print_sign(value, flags); + + if (flags & HASH_FLAG) + ret += __print_prefix(base); + + if (pad > 0 && !(flags & LEFT_FLAG)) + ret += __print_padding(pad, '0'); + + } else if (flags & SPACE_FLAG) { + if (pad > 0 && !(flags & LEFT_FLAG)) + ret += __print_padding(pad, ' '); + + if (flags & UNSIGN_FLAG) + ret += __print_sign(value, flags); + + if (flags & HASH_FLAG) + ret += __print_prefix(base); + } else { + if (!(flags & UNSIGN_FLAG)) + ret += __print_sign(value, flags); + + if (flags & HASH_FLAG) + ret += __print_prefix(base); + } + + /* print value itself */ + ret += __integral_print(value, base, flags); + + /* left-justify */ + if (flags & ZERO_FLAG) { + if (pad > 0 && (flags & LEFT_FLAG)) + ret += __print_padding(pad, '0'); + } else if (flags & SPACE_FLAG) { + if (pad > 0 && (flags & LEFT_FLAG)) + ret += __print_padding(pad, ' '); + } + + return ret; +} + +int printf(const char *fmt, ...) +{ + /* largely inspired by + * https://github.com/mpaland/printf/blob/master/printf.c + */ + + /* Note that X is binary formatting, because who uses uppercase hex? */ + + va_list vl; + va_start(vl, fmt); + + size_t chars_written = 0; + + while (*fmt) { + if (*fmt != '%') { + __putchar(*fmt++); + chars_written++; + continue; + } + + fmt++; + if (*fmt == '%') { + /* literal percent sign */ + __putchar('%'); + chars_written++; + fmt++; + continue; + } + + /* check flags */ + size_t flags = 0; + int a = STOP; + do { + switch (*fmt) { + case ' ': + flags |= SPACE_FLAG; + fmt++; + a = CONT; + break; + + case '-': + flags |= LEFT_FLAG; + fmt++; + a = CONT; + break; + + case '+': + flags |= SIGN_FLAG; + fmt++; + a = CONT; + break; + + case '#': + flags |= HASH_FLAG; + fmt++; + a = CONT; + break; + + case '0': + flags |= ZERO_FLAG; + fmt++; + a = CONT; + break; + + case '\'': + flags |= FMT_FLAG; + fmt++; + a = CONT; + break; + + default: + a = STOP; + break; + } + } while (a != STOP); + + /* check width */ + size_t width = 0; + if (__is_digit(*fmt)) { + width = __atoi(fmt++); + flags |= WIDTH_FLAG | PAD_FLAG | SPACE_FLAG; + } else if (*fmt == '*') { + int w = va_arg(vl, int); + if (w < 0) { + width = -w; + flags |= LEFT_FLAG; + } else { + width = w; + } + flags |= WIDTH_FLAG | PAD_FLAG | SPACE_FLAG; + fmt++; + } + + /* check precision */ + size_t precision = 0; + if (*fmt == '.') { + fmt++; + flags |= PRECS_FLAG | PAD_FLAG | ZERO_FLAG; + if (__is_digit(*fmt)) { + precision = __atoi(fmt++); + } else if (*fmt == '*') { + precision = va_arg(vl, int); + fmt++; + } + } + + /* check length */ + switch (*fmt) { + case 'l': + fmt++; + if (*fmt == 'l') { + flags |= LLONG_FLAG; + fmt++; + } else { + flags |= LONG_FLAG; + } + break; + + case 'h': + fmt++; + if (*fmt == 'h') { + flags |= CHAR_FLAG; + fmt++; + } else { + flags |= SHORT_FLAG; + } + break; + + case 'j': + fmt++; + if (sizeof(intmax_t) == sizeof(long)) + flags |= LONG_FLAG; + else + flags |= LLONG_FLAG; + break; + + case 'z': + fmt++; + if (sizeof(size_t) == sizeof(long)) + flags |= LONG_FLAG; + else + flags |= LLONG_FLAG; + break; + + case 't': + fmt++; + if (sizeof(ptrdiff_t) == sizeof(long)) + flags |= LONG_FLAG; + else + flags |= LLONG_FLAG; + break; + } + + /* read actual specifier */ + size_t base = 10; + size_t value = 0; + int i = -1; + const char *s = 0; + void *p = 0; + int *n = 0; + char c = 0; + + switch (*fmt) { + case 'd': + case 'i': + case 'u': + case 'x': + case 'X': + case 'o': + case 'b': + /* integer handling */ + switch (*fmt) { + case 'x': + base = 16; + break; + case 'X': + base = 2; + break; + case 'o': + base = 8; + break; + default: + base = 10; + break; + } + + if (base == 10) + flags &= ~HASH_FLAG; + + /* precision takes precedence */ + if (flags & PRECS_FLAG) + width = precision; + + /* formatting doesn't apply to decimal integers + * */ + if (*fmt != 'i' && *fmt != 'd') { + flags &= ~SIGN_FLAG; + flags |= UNSIGN_FLAG; + } + + if (flags & LLONG_FLAG) + value = va_arg(vl, long long); + else if (flags & LONG_FLAG) + value = va_arg(vl, long); + else + value = va_arg(vl, int); + + chars_written += + __print_integral(value, base, flags, width); + fmt++; + break; + + case 'c': + c = va_arg(vl, int); + __putchar(c); + chars_written++; + fmt++; + break; + + case 's': + s = va_arg(vl, const char *); + + if (flags & PRECS_FLAG) + i = precision; + + for (; *s && i--;) { + __putchar(*s++); + chars_written++; + } + fmt++; + break; + + case 'p': + p = va_arg(vl, void *); + flags |= UNSIGN_FLAG | HASH_FLAG; + + if (sizeof(void *) == sizeof(long)) + flags |= LONG_FLAG; + else + flags |= LLONG_FLAG; + + chars_written += + __print_integral((ssize_t)p, 16, flags, width); + fmt++; + break; + + case 'n': + n = va_arg(vl, int *); + *n = chars_written; + fmt++; + break; + } + } + + va_end(vl); + return chars_written; +} diff --git a/tests/common/test.h b/tests/common/test.h new file mode 100644 index 0000000..3b591e0 --- /dev/null +++ b/tests/common/test.h @@ -0,0 +1,324 @@ +#ifndef KMI_TESTS_H +#define KMI_TESTS_H + +#include <kmi/attrs.h> +#include <kmi/types.h> + +#if defined(__riscv) +# if __riscv_xlen == 64 +#include "arch/riscv64/syscall.h" +# endif +#endif + +#define syscall0(op) syscall(1, op, 0, 0, 0, 0, 0) +#define syscall1(op, a0) syscall(2, op, a0, 0, 0, 0, 0) +#define syscall2(op, a0, a1) syscall(3, op, a0, a1, 0, 0, 0) +#define syscall3(op, a0, a1, a2) syscall(4, op, a0, a1, a2, 0, 0) +#define syscall4(op, a0, a1, a2, a3) syscall(5, op, a0, a1, a2, a3, 0) +#define syscall5(op, a0, a1, a2, a3, a4) syscall(6, op, a0, a1, a2, a3, a4) + +#define UNUSED(x) (void)x +#define START(pid, tid, d0, d1, d2, d3)\ +void _start(sys_arg_t pid, sys_arg_t tid,\ + sys_arg_t d0, sys_arg_t d1, sys_arg_t d2, sys_arg_t d3) + +static inline void sys_noop() +{ + syscall0(SYS_NOOP); +} + +static inline void sys_putch(char c) +{ + syscall1(SYS_PUTCH, c); +} + +static inline void *sys_req_mem(size_t size, vmflags_t flags) +{ + struct sys_ret r = syscall2(SYS_REQ_MEM, size, flags); + if (r.s) + return NULL; + + return (void *)r.a0; +} + +static inline void *sys_req_fixmem(uintptr_t fixed, size_t size, vmflags_t flags) +{ + struct sys_ret r = syscall3(SYS_REQ_FIXMEM, fixed, size, flags); + if (r.s) + return NULL; + + return (void *)r.a0; +} + +static inline void *sys_req_pmem(uintptr_t addr, size_t size, vmflags_t flags) +{ + struct sys_ret r = syscall3(SYS_REQ_PMEM, addr, size, flags); + if (r.s) + return NULL; + + return (void *)r.a0; +} + +static inline void *sys_req_page(size_t size, vmflags_t flags, uintptr_t *addr, size_t *asize) +{ + struct sys_ret r = syscall2(SYS_REQ_PAGE, size, flags); + if (r.s) + return NULL; + + if (addr) + *addr = r.a1; + + if (asize) + *asize = r.a2; + + return (void *)r.a0; +} + +static inline void *sys_req_sharedmem(size_t size, vmflags_t flags) +{ + struct sys_ret r = syscall2(SYS_REQ_SHAREDMEM, size, flags); + if (r.s) + return NULL; + + return (void *)r.a0; +} + +static inline void *sys_ref_sharedmem(id_t tid, uintptr_t addr, vmflags_t flags) +{ + struct sys_ret r = syscall3(SYS_REF_SHAREDMEM, tid, addr, flags); + if (r.s) + return NULL; + + return (void *)r.a0; +} + +static inline void sys_free_mem(uintptr_t start) +{ + syscall1(SYS_FREE_MEM, start); +} + +static inline uint64_t sys_timebase() +{ + struct sys_ret r = syscall0(SYS_TIMEBASE); + if (r.s) + return 0; + +#if defined(_LP64) + return r.a0; +#else + return ((uint64_t)r.a1 << 32) | r.a0 +#endif +} + +static inline uint64_t sys_ticks() +{ + struct sys_ret r = syscall0(SYS_TICKS); + if (r.s) + return 0; + +#if defined(_LP64) + return r.a0; +#else + return ((uint64_t)r.a1 << 32) | r.a0; +#endif +} + +static inline id_t sys_req_rel_timer(uint64_t ticks) +{ + struct sys_ret r; +#if defined(_LP64) + r = syscall2(SYS_REQ_REL_TIMER, ticks >> 32, ticks); +#else + r = syscall1(SYS_REQ_REL_TIMER, ticks); +#endif + + if (r.s) + return -1; + + return r.a0; +} + +static inline id_t sys_req_abs_timer(uint64_t ticks) +{ + struct sys_ret r; +#if defined(_LP64) + r = syscall2(SYS_REQ_ABS_TIMER, ticks >> 32, ticks); +#else + r = syscall1(SYS_REQ_ABS_TIMER, ticks); +#endif + + if (r.s) + return -1; + + return r.a0; +} + +#define sys_ipc_req0(pid) syscall1(SYS_IPC_REQ, pid) +#define sys_ipc_req1(pid, d0) syscall2(SYS_IPC_REQ, pid, d0) +#define sys_ipc_req2(pid, d0, d1) syscall3(SYS_IPC_REQ, pid, d0, d1) +#define sys_ipc_req3(pid, d0, d1, d2) syscall4(SYS_IPC_REQ, pid, d0, d1, d2) +#define sys_ipc_req4(pid, d0, d1, d2, d3) syscall5(SYS_IPC_REQ, pid, d0, d1, d2, d3) + +#define sys_ipc_fwd0(pid) syscall1(SYS_IPC_FWD, pid) +#define sys_ipc_fwd1(pid, d0) syscall2(SYS_IPC_FWD, pid, d0) +#define sys_ipc_fwd2(pid, d0, d1) syscall3(SYS_IPC_FWD, pid, d0, d1) +#define sys_ipc_fwd3(pid, d0, d1, d2) syscall4(SYS_IPC_FWD, pid, d0, d1, d2) +#define sys_ipc_fwd4(pid, d0, d1, d2, d3) syscall5(SYS_IPC_FWD, pid, d0, d1, d2, d3) + +#define sys_ipc_kick0(pid) syscall1(SYS_IPC_KICK, pid) +#define sys_ipc_kick1(pid, d0) syscall2(SYS_IPC_KICK, pid, d0) +#define sys_ipc_kick2(pid, d0, d1) syscall3(SYS_IPC_KICK, pid, d0, d1) +#define sys_ipc_kick3(pid, d0, d1, d2) syscall4(SYS_IPC_KICK, pid, d0, d1, d2) +#define sys_ipc_kick4(pid, d0, d1, d2, d3) syscall5(SYS_IPC_KICK, pid, d0, d1, d2, d3) + +#define sys_ipc_resp0(pid) syscall1(SYS_IPC_RESP, pid) +#define sys_ipc_resp1(pid, d0) syscall2(SYS_IPC_RESP, pid, d0) +#define sys_ipc_resp2(pid, d0, d1) syscall3(SYS_IPC_RESP, pid, d0, d1) +#define sys_ipc_resp3(pid, d0, d1, d2) syscall4(SYS_IPC_RESP, pid, d0, d1, d2) +#define sys_ipc_resp4(pid, d0, d1, d2, d3) syscall5(SYS_IPC_RESP, pid, d0, d1, d2, d3) + +#define sys_ipc_ghost0(pid) syscall1(SYS_IPC_GHOST, pid) +#define sys_ipc_ghost1(pid, d0) syscall2(SYS_IPC_GHOST, pid, d0) +#define sys_ipc_ghost2(pid, d0, d1) syscall3(SYS_IPC_GHOST, pid, d0, d1) +#define sys_ipc_ghost3(pid, d0, d1, d2) syscall4(SYS_IPC_GHOST, pid, d0, d1, d2) +#define sys_ipc_ghost4(pid, d0, d1, d2, d3) syscall5(SYS_IPC_GHOST, pid, d0, d1, d2, d3) + +static inline enum sys_status sys_set_handler(id_t tid, id_t pid) +{ + struct sys_ret r = syscall2(SYS_SET_HANDLER, tid, pid); + return r.s; +} + +static inline enum sys_status sys_notify(id_t tid) +{ + struct sys_ret r = syscall1(SYS_NOTIFY, tid); + return r.s; +} + +static inline id_t sys_create(uintptr_t func, long d0, long d1, long d2, long d3) +{ + struct sys_ret r = syscall5(SYS_CREATE, func, d0, d1, d2, d3); + return r.s; +} + +/* note that negative IDs are error values */ +static inline id_t sys_fork(id_t *new_id) +{ + struct sys_ret r = syscall0(SYS_FORK); + if (new_id) + *new_id = r.a0; + + return r.s; +} + +static inline enum sys_status sys_exec(uintptr_t bin, uintptr_t interp) +{ + struct sys_ret r = syscall2(SYS_EXEC, bin, interp); + /* if we reach this point, something's gone wrong */ + return r.s; +} + +/* negative IDs mean errors */ +static inline id_t sys_spawn(uintptr_t bin, uintptr_t interp) +{ + struct sys_ret r = syscall2(SYS_EXEC, bin, interp); + return r.s; +} + +static inline enum sys_status sys_kill(id_t pid) +{ + struct sys_ret r = syscall1(SYS_KILL, pid); + return r.s; +} + +static inline enum sys_status sys_swap(id_t tid) +{ + struct sys_ret r = syscall1(SYS_SWAP, tid); + return r.s; +} + +static inline enum sys_status sys_conf_set(enum conf_param param, long arg) +{ + struct sys_ret r = syscall2(SYS_SET_CONF, param, arg); + return r.s; +} + +static inline long sys_conf_get(enum conf_param param, long arg) +{ + struct sys_ret r = syscall2(SYS_GET_CONF, param, arg); + return r.a0; +} + +static inline enum sys_status sys_set_cap(id_t tid, enum sys_cap cap) +{ + struct sys_ret r = syscall2(SYS_SET_CAP, tid, cap); + return r.s; +} + +static inline enum sys_status sys_get_cap(id_t tid, enum sys_cap *cap) +{ + struct sys_ret r = syscall1(SYS_GET_CAP, tid); + *cap = r.a0; + return r.s; +} + +static inline enum sys_status sys_clear_cap(id_t tid, enum sys_cap cap) +{ + struct sys_ret r = syscall2(SYS_CLEAR_CAP, tid, cap); + return r.s; +} + +static inline enum sys_status sys_poweroff(enum poweroff_type type) +{ + struct sys_ret r = syscall1(SYS_POWEROFF, type); + return r.s; +} + +static inline enum sys_status sys_sleep() +{ + struct sys_ret r = syscall0(SYS_SLEEP); + return r.s; +} + +/** note that negative IDs mean errors */ +static inline id_t sys_irq_req(long irq) +{ + struct sys_ret r = syscall1(SYS_IRQ_REQ, irq); + return r.s; +} + +static inline enum sys_status sys_free_irq(long irq) +{ + struct sys_ret r = syscall1(SYS_FREE_IRQ, irq); + return r.s; +} + +static inline enum sys_status sys_detach(id_t tid) +{ + struct sys_ret r = syscall1(SYS_DETACH, tid); + return r.s; +} + +static inline enum sys_status sys_exit() +{ + struct sys_ret r = syscall0(SYS_EXIT); + return r.s; +} + +int printf(const char *fmt, ...) __printf; + +#define error(x, ...)\ + printf("ERROR: " x # __VA_ARGS__) + +#define check(x, y, ...)\ + if (!(x)) {\ + error(y #__VA_ARGS__);\ + sys_poweroff(SYS_SHUTDOWN);\ + } + +static inline void ok() { + printf("OK\n"); + sys_poweroff(SYS_SHUTDOWN); +} + +#endif /* KMI_TESTS_H */ diff --git a/tests/hello-world/init.c b/tests/hello-world/init.c new file mode 100644 index 0000000..fc882ec --- /dev/null +++ b/tests/hello-world/init.c @@ -0,0 +1,14 @@ +#include <common/test.h> + +START(pid, tid, d0, d1, d2, d3) +{ + UNUSED(pid); + UNUSED(tid); + UNUSED(d0); + UNUSED(d1); + UNUSED(d2); + UNUSED(d3); + + printf("Hello, world!\n"); + ok(); +} diff --git a/tests/hello-world/source.mk b/tests/hello-world/source.mk new file mode 100644 index 0000000..203a42e --- /dev/null +++ b/tests/hello-world/source.mk @@ -0,0 +1,8 @@ +TESTS := $(TESTS) hello-world + +.PHONY: hello-world +hello-world: hello-world/init.c $(COMMON) + mkdir -p build/hello-world + $(COMPILE) hello-world/init.c build/printf.o -o build/hello-world/init + echo build/hello-world/init | $(GEN_INITRD) hello-world/initrd + $(QEMU) hello-world/initrd | grep 'Hello, world!' diff --git a/tests/noop/init.c b/tests/noop/init.c new file mode 100644 index 0000000..a7e66f8 --- /dev/null +++ b/tests/noop/init.c @@ -0,0 +1,13 @@ +#include <common/test.h> + +START(pid, tid, d0, d1, d2, d3) +{ + UNUSED(pid); + UNUSED(tid); + UNUSED(d0); + UNUSED(d1); + UNUSED(d2); + UNUSED(d3); + sys_noop(); + ok(); +} diff --git a/tests/noop/source.mk b/tests/noop/source.mk new file mode 100644 index 0000000..087ce9b --- /dev/null +++ b/tests/noop/source.mk @@ -0,0 +1,8 @@ +TESTS := $(TESTS) noop + +.PHONY: noop +noop: noop/init.c $(COMMON) + mkdir -p build/noop + $(COMPILE) noop/init.c build/printf.o -o build/noop/init + echo build/noop/init | $(GEN_INITRD) noop/initrd + $(QEMU) noop/initrd | grep 'OK' |
