From e8a1df103cc28419dd7d4439c0b1d1739d110f78 Mon Sep 17 00:00:00 2001 From: Kimplul Date: Tue, 9 Jul 2024 22:12:27 +0300 Subject: start working on tests + Current setup will likely not last long, just a stopgap until I figure out how I want to build each testcase etc. Probably dir based, but I'll probably add some scripts that generate the build rules for each test case (or binary?). Also, should probably put ouput files in a build directory and keep the source clean, but again, good enough for now. Will have to start implementing more extensive tests, and probably come up with some way to compare textual output etc. --- tests/Makefile | 34 +++ tests/common/arch/riscv64/syscall.h | 50 ++++ tests/common/printf.c | 583 ++++++++++++++++++++++++++++++++++++ tests/common/test.h | 324 ++++++++++++++++++++ tests/hello-world/init.c | 14 + tests/hello-world/source.mk | 8 + tests/noop/init.c | 13 + tests/noop/source.mk | 8 + 8 files changed, 1034 insertions(+) create mode 100644 tests/Makefile create mode 100644 tests/common/arch/riscv64/syscall.h create mode 100644 tests/common/printf.c create mode 100644 tests/common/test.h create mode 100644 tests/hello-world/init.c create mode 100644 tests/hello-world/source.mk create mode 100644 tests/noop/init.c create mode 100644 tests/noop/source.mk (limited to 'tests') 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 +#include + +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 +#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 +#include + +#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 + +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 + +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' -- cgit v1.3