aboutsummaryrefslogtreecommitdiff
path: root/tests/common
diff options
context:
space:
mode:
Diffstat (limited to 'tests/common')
-rw-r--r--tests/common/arch/riscv64/syscall.h50
-rw-r--r--tests/common/printf.c583
-rw-r--r--tests/common/test.h324
3 files changed, 957 insertions, 0 deletions
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 */