/*
 * Copyright (c) 2017, Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */


#ifndef ZEPHYR_INCLUDE_SYSCALL_H_
#define ZEPHYR_INCLUDE_SYSCALL_H_

#include <syscall_list.h>
#include <zephyr/arch/syscall.h>
#include <stdbool.h>

#ifndef _ASMLANGUAGE
#include <zephyr/types.h>
#include <zephyr/linker/sections.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
 * System Call Declaration macros
 *
 * These macros are used in public header files to declare system calls.
 * They generate inline functions which have different implementations
 * depending on the current compilation context:
 *
 * - Kernel-only code, or CONFIG_USERSPACE disabled, these inlines will
 *   directly call the implementation
 * - User-only code, these inlines will marshal parameters and elevate
 *   privileges
 * - Mixed or indeterminate code, these inlines will do a runtime check
 *   to determine what course of action is needed.
 *
 * All system calls require a verifier function and an implementation
 * function.  These must follow a naming convention. For a system call
 * named k_foo():
 *
 * - The handler function will be named z_vrfy_k_foo(). Handler
 *   functions have the same type signature as the wrapped call,
 *   verify arguments passed up from userspace, and call the
 *   implementation function. See documentation for that typedef for
 *   more information.  - The implementation function will be named
 *   z_impl_k_foo(). This is the actual implementation of the system
 *   call.
 */

/**
 * @typedef _k_syscall_handler_t
 * @brief System call handler function type
 *
 * These are kernel-side skeleton functions for system calls. They are
 * necessary to sanitize the arguments passed into the system call:
 *
 * - Any kernel object or device pointers are validated with _SYSCALL_IS_OBJ()
 * - Any memory buffers passed in are checked to ensure that the calling thread
 *   actually has access to them
 * - Many kernel calls do no sanity checking of parameters other than
 *   assertions. The handler must check all of these conditions using
 *   _SYSCALL_ASSERT()
 * - If the system call has more than 6 arguments, then arg6 will be a pointer
 *   to some struct containing arguments 6+. The struct itself needs to be
 *   validated like any other buffer passed in from userspace, and its members
 *   individually validated (if necessary) and then passed to the real
 *   implementation like normal arguments
 *
 * Even if the system call implementation has no return value, these always
 * return something, even 0, to prevent register leakage to userspace.
 *
 * Once everything has been validated, the real implementation will be executed.
 *
 * @param arg1 system call argument 1
 * @param arg2 system call argument 2
 * @param arg3 system call argument 3
 * @param arg4 system call argument 4
 * @param arg5 system call argument 5
 * @param arg6 system call argument 6
 * @param ssf System call stack frame pointer. Used to generate kernel oops
 *            via _arch_syscall_oops_at(). Contents are arch-specific.
 * @return system call return value, or 0 if the system call implementation
 *         return void
 *
 */
typedef uintptr_t (*_k_syscall_handler_t)(uintptr_t arg1, uintptr_t arg2,
					  uintptr_t arg3, uintptr_t arg4,
					  uintptr_t arg5, uintptr_t arg6,
					  void *ssf);

/* True if a syscall function must trap to the kernel, usually a
 * compile-time decision.
 */
static ALWAYS_INLINE bool z_syscall_trap(void)
{
	bool ret = false;
#ifdef CONFIG_USERSPACE
#if defined(__ZEPHYR_SUPERVISOR__)
	ret = false;
#elif defined(__ZEPHYR_USER__)
	ret = true;
#else
	ret = arch_is_user_context();
#endif
#endif
	return ret;
}

/**
 * Indicate whether the CPU is currently in user mode
 *
 * @return true if the CPU is currently running with user permissions
 */
__pinned_func
static inline bool k_is_user_context(void)
{
#ifdef CONFIG_USERSPACE
	return arch_is_user_context();
#else
	return false;
#endif
}

#ifdef __cplusplus
}
#endif

#endif /* _ASMLANGUAGE */

#endif
