From e813641e2fef0fba5a2de9e5a44fd00ab95a86d0 Mon Sep 17 00:00:00 2001 From: Luca Dariz Date: Thu, 11 Jan 2024 22:08:57 +0100 Subject: add basic user-space tests with qemu * configure.ac: move test fragment to have USER32 * tests/Makefrag.am: add user tests * tests/README: add basic info on how to run and debug user tests * tests/configfrag.ac: allow the test compiler/flags to be autoconfigured or customized * tests/grub.cfg.single.template: add minimal grub config to boot a module * tests/include/device/cons.h: add a simplified version of device/cons.h usable for tests * tests/include/kern/printf.h: symlink to kern/printf.h * tests/include/mach/mig_support.h: add basic version for user-space tests * tests/include/syscalls.h: add prototypes for syscalls used in tests. * tests/include/testlib.h: add definitions for common test functionalities * tests/include/util/atoi.h: symlink to util/atoi.h * tests/run-qemu.sh.template: add a simple qemu test runner * tests/start.S: add arch-specific entry point * tests/syscalls.S: generate syscalls entry points * tests/test-hello.c: add basic smoke test * tests/testlib.c: add the minimal functionality to run a user-space executable and reboot the system, and some test helpers. * tests/user-qemu.mk: add rules to build simple user-space test modules, including generating mig stubs. The tests reuse some kernel code (like printf(), mach_atoi(), mem*(), str*() functions) so we can use the freestanding environment and not depend on glibc. Message-ID: <20240111210907.419689-1-luca@orpolo.org> --- tests/testlib.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 tests/testlib.c (limited to 'tests/testlib.c') diff --git a/tests/testlib.c b/tests/testlib.c new file mode 100644 index 00000000..2eaeb591 --- /dev/null +++ b/tests/testlib.c @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2024 Free Software Foundation + * + * This program is free software ; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation ; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY ; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the program ; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include + + +static int argc = 0; +static char *argv_unknown[] = {"unknown", "m1", "123", "456"}; +static char **argv = argv_unknown; +static char **envp = NULL; +static int envc = 0; + +static mach_port_t host_priv_port = 1; +static mach_port_t device_master_port = 2; + +void cnputc(char c, vm_offset_t cookie) +{ + char buf[2] = {c, 0}; + mach_print(buf); +} + +mach_port_t host_priv(void) +{ + return host_priv_port; +} + +mach_port_t device_priv(void) +{ + return device_master_port; +} + +void halt() +{ + int ret = host_reboot(host_priv_port, 0); + ASSERT_RET(ret, "host_reboot() failed!"); + while (1) + ; +} + +int msleep(uint32_t timeout) +{ + mach_port_t recv = mach_reply_port(); + return mach_msg(NULL, MACH_RCV_MSG|MACH_RCV_TIMEOUT|MACH_RCV_INTERRUPT, + 0, 0, recv, timeout, MACH_PORT_NULL); +} + +const char* e2s(int err) +{ + const char* s = e2s_gnumach(err); + if (s != NULL) + return s; + else + switch (err) + { + default: return "unknown"; + } +} + +/* + * Minimal _start() for test modules, we just take the arguments from the + * kernel, call main() and reboot. As in glibc, we expect the argument pointer + * as a first asrgument. + */ +void __attribute__((used, retain)) +c_start(void **argptr) +{ + intptr_t* argcptr = (intptr_t*)argptr; + argc = argcptr[0]; + argv = (char **) &argcptr[1]; + envp = &argv[argc + 1]; + envc = 0; + + while (envp[envc]) + ++envc; + + mach_atoi(argv[1], &host_priv_port); + mach_atoi(argv[2], &device_master_port); + + printf("started %s", argv[0]); + for (int i=1; i