blob: ad0e125ad9152de823271746691e36dc80aebfec [file] [log] [blame] [edit]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stdint.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <time.h>
// The macros allow to call syscall with a random number of argument, and ensure
// that the correct number of arguments are present and that they are casted to
// the correct type.
#define _syscall(number, arg1, arg2, arg3, arg4, ...) \
_syscall4(number, (intptr_t)(arg1), (intptr_t)(arg2), (intptr_t)(arg3), (intptr_t)(arg4))
#define syscall(number, ...) _syscall(number, __VA_ARGS__, 0, 0, 0, 0)
namespace {
intptr_t handle_error(intptr_t return_value) {
if (return_value < 0) {
// The return value contains the error number. Just drop it for now.
return_value = -1;
}
return return_value;
}
// Generic syscall with 4 arguments.
intptr_t _syscall4(intptr_t syscall_number, intptr_t arg1, intptr_t arg2, intptr_t arg3,
intptr_t arg4) {
intptr_t ret;
#if defined(__x86_64__)
register intptr_t r10 asm("r10") = arg4;
__asm__ volatile("syscall;"
: "=a"(ret)
: "a"(syscall_number), "D"(arg1), "S"(arg2), "d"(arg3), "r"(r10)
: "rcx", "r11", "memory");
#elif defined(__aarch64__)
register intptr_t x0 asm("x0") = arg1;
register intptr_t x1 asm("x1") = arg2;
register intptr_t x2 asm("x2") = arg3;
register intptr_t x3 asm("x3") = arg4;
register intptr_t number asm("x8") = syscall_number;
__asm__ volatile("svc #0"
: "=r"(ret)
: "0"(x0), "r"(x1), "r"(x2), "r"(x3), "r"(number)
: "memory");
#elif defined(__riscv) && __riscv_xlen == 64
register intptr_t a0 asm("a0") = arg1;
register intptr_t a1 asm("a1") = arg2;
register intptr_t a2 asm("a2") = arg3;
register intptr_t a3 asm("a3") = arg4;
register intptr_t number asm("a7") = syscall_number;
__asm__ volatile("ecall"
: "=r"(ret)
: "r"(a0), "r"(a1), "r"(a2), "r"(a3), "r"(number)
: "memory");
#endif
return handle_error(ret);
}
void sleep(int count) {
struct timespec ts = {.tv_sec = count, .tv_nsec = 0};
syscall(__NR_nanosleep, &ts, 0);
}
pid_t wait4(pid_t pid, int *wstatus, int options, struct rusage *rusage) {
return static_cast<pid_t>(syscall(__NR_wait4, pid, wstatus, options, rusage));
}
void main() {
for (;;) {
if (wait4(-1, nullptr, 0, nullptr) == -1) {
sleep(1);
}
}
}
} // namespace
extern "C" {
#if defined(__x86_64__)
__attribute__((force_align_arg_pointer))
#endif
void _start() {
main();
syscall(__NR_exit_group, 0);
__builtin_unreachable();
}
}