|  | .. _syscalls: | 
|  |  | 
|  | System Calls | 
|  | ############ | 
|  | User threads run with a reduced set of privileges than supervisor threads: | 
|  | certain CPU instructions may not be used, and they have access to only a | 
|  | limited part of the memory map. System calls (may) allow user threads to | 
|  | perform operations not directly available to them. | 
|  |  | 
|  | When defining system calls, it is very important to ensure that access to the | 
|  | API's private data is done exclusively through system call interfaces. | 
|  | Private kernel data should never be made available to user mode threads | 
|  | directly. For example, the ``k_queue`` APIs were intentionally not made | 
|  | available as they store bookkeeping information about the queue directly | 
|  | in the queue buffers which are visible from user mode. | 
|  |  | 
|  | APIs that allow the user to register callback functions that run in | 
|  | supervisor mode should never be exposed as system calls. Reserve these | 
|  | for supervisor-mode access only. | 
|  |  | 
|  | This section describes how to declare new system calls and discusses a few | 
|  | implementation details relevant to them. | 
|  |  | 
|  | Components | 
|  | ********** | 
|  |  | 
|  | All system calls have the following components: | 
|  |  | 
|  | * A **C prototype** prefixed with :c:macro:`__syscall` for the API. It | 
|  | will be declared in some header under ``include/`` or in another | 
|  | ``SYSCALL_INCLUDE_DIRS`` directory. This prototype is never implemented | 
|  | manually, instead it gets created by the :ref:`gen_syscalls.py` script. | 
|  | What gets generated is an inline function which either calls the | 
|  | implementation function directly (if called from supervisor mode) or goes | 
|  | through privilege elevation and validation steps (if called from user | 
|  | mode). | 
|  |  | 
|  | * An **implementation function**, which is the real implementation of the | 
|  | system call. The implementation function may assume that all parameters | 
|  | passed in have been validated if it was invoked from user mode. | 
|  |  | 
|  | * A **verification function**, which wraps the implementation function | 
|  | and does validation of all the arguments passed in. | 
|  |  | 
|  | * An **unmarshalling function**, which is an automatically generated | 
|  | handler that must be included by user source code. | 
|  |  | 
|  | C Prototype | 
|  | *********** | 
|  |  | 
|  | The C prototype represents how the API is invoked from either user or | 
|  | supervisor mode. For example, to initialize a semaphore: | 
|  |  | 
|  | .. code-block:: c | 
|  |  | 
|  | __syscall void k_sem_init(struct k_sem *sem, unsigned int initial_count, | 
|  | unsigned int limit); | 
|  |  | 
|  | The :c:macro:`__syscall` attribute is very special. To the C compiler, it | 
|  | simply expands to 'static inline'. However to the post-build | 
|  | :ref:`parse_syscalls.py` script, it indicates that this API is a system call. | 
|  | The :ref:`parse_syscalls.py` script does some parsing of the function prototype, | 
|  | to determine the data types of its return value and arguments, and has some | 
|  | limitations: | 
|  |  | 
|  | * Array arguments must be passed in as pointers, not arrays. For example, | 
|  | ``int foo[]`` or ``int foo[12]`` is not allowed, but should instead be | 
|  | expressed as ``int *foo``. | 
|  |  | 
|  | * Function pointers horribly confuse the limited parser. The workaround is | 
|  | to typedef them first, and then express in the argument list in terms | 
|  | of that typedef. | 
|  |  | 
|  | * :c:macro:`__syscall` must be the first thing in the prototype. | 
|  |  | 
|  | The preprocessor is intentionally not used when determining the set of system | 
|  | calls to generate. However, any generated system calls that don't actually have | 
|  | a verification function defined (because the related feature is not enabled in | 
|  | the kernel configuration) will instead point to a special verification for | 
|  | unimplemented system calls. Data type definitions for APIs should not have | 
|  | conditional visibility to the compiler. | 
|  |  | 
|  | Any header file that declares system calls must include a special generated | 
|  | header at the very bottom of the header file. This header follows the | 
|  | naming convention ``syscalls/<name of header file>``. For example, at the | 
|  | bottom of ``include/sensor.h``: | 
|  |  | 
|  | .. code-block:: c | 
|  |  | 
|  | #include <syscalls/sensor.h> | 
|  |  | 
|  | C prototype functions must be declared in one of the directories | 
|  | listed in the CMake variable ``SYSCALL_INCLUDE_DIRS``. This list | 
|  | always contains ``${ZEPHYR_BASE}/include``, but will also contain | 
|  | ``APPLICATION_SOURCE_DIR`` when ``CONFIG_APPLICATION_DEFINED_SYSCALL`` | 
|  | is set, or ``${ZEPHYR_BASE}/subsys/testsuite/ztest/include`` when | 
|  | ``CONFIG_ZTEST`` is set. Additional paths can be added to the list | 
|  | through the CMake command line or in CMake code that is run before | 
|  | ``${ZEPHYR_BASE}/cmake/app/boilerplate.cmake`` is run. | 
|  |  | 
|  | Invocation Context | 
|  | ================== | 
|  |  | 
|  | Source code that uses system call APIs can be made more efficient if it is | 
|  | known that all the code inside a particular C file runs exclusively in | 
|  | user mode, or exclusively in supervisor mode. The system will look for | 
|  | the definition of macros :c:macro:`__ZEPHYR_SUPERVISOR__` or | 
|  | :c:macro:`__ZEPHYR_USER__`, typically these will be added to the compiler | 
|  | flags in the build system for the related files. | 
|  |  | 
|  | * If :option:`CONFIG_USERSPACE` is not enabled, all APIs just directly call | 
|  | the implementation function. | 
|  |  | 
|  | * Otherwise, the default case is to make a runtime check to see if the | 
|  | processor is currently running in user mode, and either make the system call | 
|  | or directly call the implementation function as appropriate. | 
|  |  | 
|  | * If :c:macro:`__ZEPHYR_SUPERVISOR__` is defined, then it is assumed that | 
|  | all the code runs in supervisor mode and all APIs just directly call the | 
|  | implementation function. If the code was actually running in user mode, | 
|  | there will be a CPU exception as soon as it tries to do something it isn't | 
|  | allowed to do. | 
|  |  | 
|  | * If :c:macro:`__ZEPHYR_USER__` is defined, then it is assumed that all the | 
|  | code runs in user mode and system calls are unconditionally made. | 
|  |  | 
|  | Implementation Details | 
|  | ====================== | 
|  |  | 
|  | Declaring an API with :c:macro:`__syscall` causes some code to be generated in | 
|  | C and header files by the :ref:`gen_syscalls.py` script, all of which can be found in | 
|  | the project out directory under ``include/generated/``: | 
|  |  | 
|  | * The system call is added to the enumerated type of system call IDs, | 
|  | which is expressed in ``include/generated/syscall_list.h``. It is the name | 
|  | of the API in uppercase, prefixed with ``K_SYSCALL_``. | 
|  |  | 
|  | * An entry for the system call is created in the dispatch table | 
|  | ``_k_syscall_table``, expressed in ``include/generated/syscall_dispatch.c`` | 
|  |  | 
|  | * A weak verification function is declared, which is just an alias of the | 
|  | 'unimplemented system call' verifier. This is necessary since the real | 
|  | verification function may or may not be built depending on the kernel | 
|  | configuration. For example, if a user thread makes a sensor subsystem | 
|  | API call, but the sensor subsystem is not enabled, the weak verifier | 
|  | will be invoked instead. | 
|  |  | 
|  | * An unmarshalling function is defined in ``include/generated/<name>_mrsh.c`` | 
|  |  | 
|  | The body of the API is created in the generated system header. Using the | 
|  | example of :c:func:`k_sem_init()`, this API is declared in | 
|  | ``include/kernel.h``. At the bottom of ``include/kernel.h`` is:: | 
|  |  | 
|  | #include <syscalls/kernel.h> | 
|  |  | 
|  | Inside this header is the body of :c:func:`k_sem_init()`:: | 
|  |  | 
|  | static inline void k_sem_init(struct k_sem * sem, unsigned int initial_count, unsigned int limit) | 
|  | { | 
|  | #ifdef CONFIG_USERSPACE | 
|  | if (z_syscall_trap()) { | 
|  | arch_syscall_invoke3(*(uintptr_t *)&sem, *(uintptr_t *)&initial_count, *(uintptr_t *)&limit, K_SYSCALL_K_SEM_INIT); | 
|  | return; | 
|  | } | 
|  | compiler_barrier(); | 
|  | #endif | 
|  | z_impl_k_sem_init(sem, initial_count, limit); | 
|  | } | 
|  |  | 
|  | This generates an inline function that takes three arguments with void | 
|  | return value. Depending on context it will either directly call the | 
|  | implementation function or go through a system call elevation. A | 
|  | prototype for the implementation function is also automatically generated. | 
|  |  | 
|  | The final layer is the invocation of the system call itself. All architectures | 
|  | implementing system calls must implement the seven inline functions | 
|  | :c:func:`_arch_syscall_invoke0` through :c:func:`_arch_syscall_invoke6`. These | 
|  | functions marshal arguments into designated CPU registers and perform the | 
|  | necessary privilege elevation. Parameters of API inline function, before being | 
|  | passed as arguments to system call, are C casted to ``uintptr_t`` which matches | 
|  | size of register. | 
|  | Exception to above is passing 64-bit parameters on 32-bit systems, in which case | 
|  | 64-bit parameters are split into lower and higher part and passed as two consecutive | 
|  | arguments. | 
|  | There is always a ``uintptr_t`` type return value, which may be neglected if | 
|  | not needed. | 
|  |  | 
|  | .. figure:: syscall_flow.png | 
|  | :alt: System Call execution flow | 
|  | :width: 80% | 
|  | :align: center | 
|  |  | 
|  | System Call execution flow | 
|  |  | 
|  | Some system calls may have more than six arguments, but number of arguments | 
|  | passed via registers is limited to six for all architectures. | 
|  | Additional arguments will need to be passed in an array in the source memory | 
|  | space, which needs to be treated as untrusted memory in the verification | 
|  | function. This code (packing, unpacking and validation) is generated | 
|  | automatically as needed in the stub above and in the unmarshalling function. | 
|  |  | 
|  | System calls return ``uintptr_t`` type value that is C casted, by wrapper, to | 
|  | a return type of API prototype declaration. This means that 64-bit value may | 
|  | not be directly returned, from a system call to its wrapper, on 32-bit systems. | 
|  | To solve the problem the automatically generated wrapper function defines 64-bit | 
|  | intermediate variable, which is considered **untrusted** buffer, on its stack | 
|  | and passes pointer to that variable to the system call, as a final argument. | 
|  | Upon return from the system call the value written to that buffer will be | 
|  | returned by the wrapper function. | 
|  | The problem does not exist on 64-bit systems which are able to return 64-bit | 
|  | values directly. | 
|  |  | 
|  | Implementation Function | 
|  | *********************** | 
|  |  | 
|  | The implementation function is what actually does the work for the API. | 
|  | Zephyr normally does little to no error checking of arguments, or does this | 
|  | kind of checking with assertions. When writing the implementation function, | 
|  | validation of any parameters is optional and should be done with assertions. | 
|  |  | 
|  | All implementation functions must follow the naming convention, which is the | 
|  | name of the API prefixed with ``z_impl_``. Implementation functions may be | 
|  | declared in the same header as the API as a static inline function or | 
|  | declared in some C file. There is no prototype needed for implementation | 
|  | functions, these are automatically generated. | 
|  |  | 
|  | Verification Function | 
|  | ********************* | 
|  |  | 
|  | The verification function runs on the kernel side when a user thread makes | 
|  | a system call. When the user thread makes a software interrupt to elevate to | 
|  | supervisor mode, the common system call entry point uses the system call ID | 
|  | provided by the user to look up the appropriate unmarshalling function for that | 
|  | system call and jump into it. This in turn calls the verification function. | 
|  |  | 
|  | Verification and unmarshalling functions only run when system call APIs are | 
|  | invoked from user mode. If an API is invoked from supervisor mode, the | 
|  | implementation is simply called and there is no software trap. | 
|  |  | 
|  | The purpose of the verification function is to validate all the arguments | 
|  | passed in.  This includes: | 
|  |  | 
|  | * Any kernel object pointers provided. For example, the semaphore APIs must | 
|  | ensure that the semaphore object passed in is a valid semaphore and that | 
|  | the calling thread has permission on it. | 
|  |  | 
|  | * Any memory buffers passed in from user mode. Checks must be made that the | 
|  | calling thread has read or write permissions on the provided buffer. | 
|  |  | 
|  | * Any other arguments that have a limited range of valid values. | 
|  |  | 
|  | Verification functions involve a great deal of boilerplate code which has been | 
|  | made simpler by some macros in :zephyr_file:`include/syscall_handler.h`. | 
|  | Verification functions should be declared using these macros. | 
|  |  | 
|  | Argument Validation | 
|  | =================== | 
|  |  | 
|  | Several macros exist to validate arguments: | 
|  |  | 
|  | * :c:macro:`Z_SYSCALL_OBJ()` Checks a memory address to assert that it is | 
|  | a valid kernel object of the expected type, that the calling thread | 
|  | has permissions on it, and that the object is initialized. | 
|  |  | 
|  | * :c:macro:`Z_SYSCALL_OBJ_INIT()` is the same as | 
|  | :c:macro:`Z_SYSCALL_OBJ()`, except that the provided object may be | 
|  | uninitialized. This is useful for verifiers of object init functions. | 
|  |  | 
|  | * :c:macro:`Z_SYSCALL_OBJ_NEVER_INIT()` is the same as | 
|  | :c:macro:`Z_SYSCALL_OBJ()`, except that the provided object must be | 
|  | uninitialized. This is not used very often, currently only for | 
|  | :c:func:`k_thread_create()`. | 
|  |  | 
|  | * :c:macro:`Z_SYSCALL_MEMORY_READ()` validates a memory buffer of a particular | 
|  | size. The calling thread must have read permissions on the entire buffer. | 
|  |  | 
|  | * :c:macro:`Z_SYSCALL_MEMORY_WRITE()` is the same as | 
|  | :c:macro:`Z_SYSCALL_MEMORY_READ()` but the calling thread must additionally | 
|  | have write permissions. | 
|  |  | 
|  | * :c:macro:`Z_SYSCALL_MEMORY_ARRAY_READ()` validates an array whose total size | 
|  | is expressed as separate arguments for the number of elements and the | 
|  | element size. This macro correctly accounts for multiplication overflow | 
|  | when computing the total size. The calling thread must have read permissions | 
|  | on the total size. | 
|  |  | 
|  | * :c:macro:`Z_SYSCALL_MEMORY_ARRAY_WRITE()` is the same as | 
|  | :c:macro:`Z_SYSCALL_MEMORY_ARRAY_READ()` but the calling thread must | 
|  | additionally have write permissions. | 
|  |  | 
|  | * :c:macro:`Z_SYSCALL_VERIFY_MSG()` does a runtime check of some boolean | 
|  | expression which must evaluate to true otherwise the check will fail. | 
|  | A variant :c:macro:`Z_SYSCALL_VERIFY` exists which does not take | 
|  | a message parameter, instead printing the expression tested if it | 
|  | fails. The latter should only be used for the most obvious of tests. | 
|  |  | 
|  | * :c:macro:`Z_SYSCALL_DRIVER_OP()` checks at runtime if a driver | 
|  | instance is capable of performing a particular operation.  While this | 
|  | macro can be used by itself, it's mostly a building block for macros | 
|  | that are automatically generated for every driver subsystem.  For | 
|  | instance, to validate the GPIO driver, one could use the | 
|  | :c:macro:`Z_SYSCALL_DRIVER_GPIO()` macro. | 
|  |  | 
|  | * :c:macro:`Z_SYSCALL_SPECIFIC_DRIVER()` is a runtime check to verify that | 
|  | a provided pointer is a valid instance of a specific device driver, that | 
|  | the calling thread has permissions on it, and that the driver has been | 
|  | initialized. It does this by checking the API structure pointer that | 
|  | is stored within the driver instance and ensuring that it matches the | 
|  | provided value, which should be the address of the specific driver's | 
|  | API structure. | 
|  |  | 
|  | If any check fails, the macros will return a nonzero value. The macro | 
|  | :c:macro:`Z_OOPS()` can be used to induce a kernel oops which will kill the | 
|  | calling thread. This is done instead of returning some error condition to | 
|  | keep the APIs the same when calling from supervisor mode. | 
|  |  | 
|  | Verifier Definition | 
|  | =================== | 
|  |  | 
|  | All system calls are dispatched to a verifier function with a prefixed | 
|  | ``z_vrfy_`` name based on the system call.  They have exactly the same | 
|  | return type and argument types as the wrapped system call.  Their job | 
|  | is to execute the system call (generally by calling the implementation | 
|  | function) after having validated all arguments. | 
|  |  | 
|  | The verifier is itself invoked by an automatically generated | 
|  | unmarshaller function which takes care of unpacking the register | 
|  | arguments from the architecture layer and casting them to the correct | 
|  | type.  This is defined in a header file that must be included from | 
|  | user code, generally somewhere after the definition of the verifier in | 
|  | a translation unit (so that it can be inlined). | 
|  |  | 
|  | For example: | 
|  |  | 
|  | .. code-block:: c | 
|  |  | 
|  | static int z_vrfy_k_sem_take(struct k_sem *sem, int32_t timeout) | 
|  | { | 
|  | Z_OOPS(Z_SYSCALL_OBJ(sem, K_OBJ_SEM)); | 
|  | return z_impl_k_sem_take(sem, timeout); | 
|  | } | 
|  | #include <syscalls/k_sem_take_mrsh.c> | 
|  |  | 
|  |  | 
|  | Verification Memory Access Policies | 
|  | =================================== | 
|  |  | 
|  | Parameters passed to system calls by reference require special handling, | 
|  | because the value of these parameters can be changed at any time by any | 
|  | user thread that has access to the memory that parameter points to. If the | 
|  | kernel makes any logical decisions based on the contents of this memory, this | 
|  | can open up the kernel to attacks even if checking is done. This is a class | 
|  | of exploits known as TOCTOU (Time Of Check to Time Of Use). | 
|  |  | 
|  | The proper procedure to mitigate these attacks is to make a copies in the | 
|  | verification function, and only perform parameter checks on the copies, which | 
|  | user threads will never have access to. The implementation functions get passed | 
|  | the copy and not the original data sent by the user. The | 
|  | :c:func:`z_user_to_copy()` and :c:func:`z_user_from_copy()` APIs exist for | 
|  | this purpose. | 
|  |  | 
|  | There is one exception in place, with respect to large data buffers which are | 
|  | only used to provide a memory area that is either only written to, or whose | 
|  | contents are never used for any validation or control flow. Further | 
|  | discussion of this later in this section. | 
|  |  | 
|  | As a first example, consider a parameter which is used as an output parameter | 
|  | for some integral value: | 
|  |  | 
|  |  | 
|  | .. code-block:: c | 
|  |  | 
|  | int z_vrfy_some_syscall(int *out_param) | 
|  | { | 
|  | int local_out_param; | 
|  | int ret; | 
|  |  | 
|  | ret = z_impl_some_syscall(&local_out_param); | 
|  | Z_OOPS(z_user_to_copy(out_param, &local_out_param, sizeof(*out_param))); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | Here we have allocated ``local_out_param`` on the stack, passed its address to | 
|  | the implementation function, and then used :c:func:`z_user_to_copy()` to fill | 
|  | in the memory passed in by the caller. | 
|  |  | 
|  | It might be tempting to do something more concise: | 
|  |  | 
|  | .. code-block:: c | 
|  |  | 
|  | int z_vrfy_some_syscall(int *out_param) | 
|  | { | 
|  | Z_OOPS(Z_SYSCALL_MEMORY_WRITE(out_param, sizeof(*out_param))); | 
|  | return z_impl_some_syscall(out_param); | 
|  | } | 
|  |  | 
|  | However, this is unsafe if the implementation ever does any reads to this | 
|  | memory as part of its logic. For example, it could be used to store some | 
|  | counter value, and this could be meddled with by user threads that have access | 
|  | to its memory. It is by far safest for small integral values to do the copying | 
|  | as shown in the first example. | 
|  |  | 
|  | Some parameters may be input/output. For instance, it's not uncommon to see APIs | 
|  | which pass in a pointer to some ``size_t`` which is a maximum allowable size, | 
|  | which is then updated by the implementation to reflect the actual number of | 
|  | bytes processed. This too should use a stack copy: | 
|  |  | 
|  | .. code-block:: c | 
|  |  | 
|  | int z_vrfy_in_out_syscall(size_t *size_ptr) | 
|  | { | 
|  | size_t size; | 
|  | int ret; | 
|  |  | 
|  | Z_OOPS(z_user_from_copy(&size, size_ptr, sizeof(size)); | 
|  | ret = z_impl_in_out_syscall(&size); | 
|  | *size_ptr = size; | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | Many system calls pass in structures or even linked data structures. All should | 
|  | be copied. Typically this is done by allocating copies on the stack: | 
|  |  | 
|  | .. code-block:: c | 
|  |  | 
|  | struct bar { | 
|  | ... | 
|  | }; | 
|  |  | 
|  | struct foo { | 
|  | ... | 
|  | struct bar *bar_left; | 
|  | struct bar *bar_right; | 
|  | }; | 
|  |  | 
|  | int z_vrfy_must_alloc(struct foo *foo) | 
|  | { | 
|  | int ret; | 
|  | struct foo foo_copy; | 
|  | struct bar bar_right_copy; | 
|  | struct bar bar_left_copy; | 
|  |  | 
|  | Z_OOPS(z_user_from_copy(&foo_copy, foo, sizeof(*foo))); | 
|  | Z_OOPS(z_user_from_copy(&bar_right_copy, foo_copy.bar_right, | 
|  | sizeof(struct bar))); | 
|  | foo_copy.bar_right = &bar_right_copy; | 
|  | Z_OOPS(z_user_from_copy(&bar_left_copy, foo_copy.bar_left, | 
|  | sizeof(struct bar))); | 
|  | foo_copy.bar_left = &bar_left_copy; | 
|  |  | 
|  | return z_impl_must_alloc(&foo_copy); | 
|  | } | 
|  |  | 
|  | In some cases the amount of data isn't known at compile time or may be too | 
|  | large to allocate on the stack. In this scenario, it may be necessary to draw | 
|  | memory from the caller's resource pool via :c:func:`z_thread_malloc()`. This | 
|  | should always be considered last resort. Functional safety programming | 
|  | guidelines heavily discourage usage of heap and the fact that a resource pool is | 
|  | used must be clearly documented. Any issues with allocation must be | 
|  | reported, to a caller, with returning the ``-ENOMEM`` . The ``Z_OOPS()`` | 
|  | should never be used to verify if resource allocation has been successful. | 
|  |  | 
|  | .. code-block:: c | 
|  |  | 
|  | struct bar { | 
|  | ... | 
|  | }; | 
|  |  | 
|  | struct foo { | 
|  | size_t count; | 
|  | struct bar *bar_list; /* array of struct bar of size count */ | 
|  | }; | 
|  |  | 
|  | int z_vrfy_must_alloc(struct foo *foo) | 
|  | { | 
|  | int ret; | 
|  | struct foo foo_copy; | 
|  | struct bar *bar_list_copy; | 
|  | size_t bar_list_bytes; | 
|  |  | 
|  | /* Safely copy foo into foo_copy */ | 
|  | Z_OOPS(z_user_from_copy(&foo_copy, foo, sizeof(*foo))); | 
|  |  | 
|  | /* Bounds check the count member, in the copy we made */ | 
|  | if (foo_copy.count > 32) { | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | /* Allocate RAM for the bar_list, replace the pointer in | 
|  | * foo_copy */ | 
|  | bar_list_bytes = foo_copy.count * sizeof(struct_bar); | 
|  | bar_list_copy = z_thread_malloc(bar_list_bytes); | 
|  | if (bar_list_copy == NULL) { | 
|  | return -ENOMEM; | 
|  | } | 
|  | Z_OOPS(z_user_from_copy(bar_list_copy, foo_copy.bar_list, | 
|  | bar_list_bytes)); | 
|  | foo_copy.bar_list = bar_list_copy; | 
|  |  | 
|  | ret = z_impl_must_alloc(&foo_copy); | 
|  |  | 
|  | /* All done with the memory, free it and return */ | 
|  | k_free(foo_copy.bar_list_copy); | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | Finally, we must consider large data buffers. These represent areas of user | 
|  | memory which either have data copied out of, or copied into. It is permitted | 
|  | to pass these pointers to the implementation function directly. The caller's | 
|  | access to the buffer still must be validated with ``Z_SYSCALL_MEMORY`` APIs. | 
|  | The following constraints need to be met: | 
|  |  | 
|  | * If the buffer is used by the implementation function to write data, such | 
|  | as data captured from some MMIO region, the implementation function must | 
|  | only write this data, and never read it. | 
|  |  | 
|  | * If the buffer is used by the implementation function to read data, such | 
|  | as a block of memory to write to some hardware destination, this data | 
|  | must be read without any processing. No conditional logic can be implemented | 
|  | due to the data buffer's contents. If such logic is required a copy must be | 
|  | made. | 
|  |  | 
|  | * The buffer must only be used synchronously with the call. The implementation | 
|  | must not ever save the buffer address and use it asynchronously, such as | 
|  | when an interrupt fires. | 
|  |  | 
|  | .. code-block:: c | 
|  |  | 
|  | int z_vrfy_get_data_from_kernel(void *buf, size_t size) | 
|  | { | 
|  | Z_OOPS(Z_SYSCALL_MEMORY_WRITE(buf, size)); | 
|  | return z_impl_get_data_from_kernel(buf, size); | 
|  | } | 
|  |  | 
|  | Verification Return Value Policies | 
|  | ================================== | 
|  |  | 
|  | When verifying system calls, it's important to note which kinds of verification | 
|  | failures should propagate a return value to the caller, and which should | 
|  | simply invoke :c:macro:`Z_OOPS()` which kills the calling thread. The current | 
|  | conventions are as follows: | 
|  |  | 
|  | #. For system calls that are defined but not compiled, invocations of these | 
|  | missing system calls are routed to :c:func:`handler_no_syscall()` which | 
|  | invokes :c:macro:`Z_OOPS()`. | 
|  |  | 
|  | #. Any invalid access to memory found by the set of ``Z_SYSCALL_MEMORY`` APIs, | 
|  | :c:func:`z_user_from_copy()`, :c:func:`z_user_to_copy()` | 
|  | should trigger a :c:macro:`Z_OOPS`. This happens when the caller doesn't have | 
|  | appropriate permissions on the memory buffer or some size calculation | 
|  | overflowed. | 
|  |  | 
|  | #. Most system calls take kernel object pointers as an argument, checked either | 
|  | with one of the ``Z_SYSCALL_OBJ`` functions,  ``Z_SYSCALL_DRIVER_nnnnn``, or | 
|  | manually using :c:func:`z_object_validate()`. These can fail for a variety | 
|  | of reasons: missing driver API, bad kernel object pointer, wrong kernel | 
|  | object type, or improper initialization state. These issues should always | 
|  | invoke :c:macro:`Z_OOPS()`. | 
|  |  | 
|  | #. Any error resulting from a failed memory heap allocation, often from | 
|  | invoking :c:func:`z_thread_malloc()`, should propagate ``-ENOMEM`` to the | 
|  | caller. | 
|  |  | 
|  | #. General parameter checks should be done in the implementation function, | 
|  | in most cases using ``CHECKIF()``. | 
|  |  | 
|  | * The behavior of ``CHECKIF()`` depends on the kernel configuration, but if | 
|  | user mode is enabled, :option:`CONFIG_RUNTIME_ERROR_CHECKS` is enforced, | 
|  | which guarantees that these checks will be made and a return value | 
|  | propagated. | 
|  |  | 
|  | #. It is totally forbidden for any kind of kernel mode callback function to | 
|  | be registered from user mode. APIs which simply install callbacks shall not | 
|  | be exposed as system calls. Some driver subsystem APIs may take optional | 
|  | function callback pointers. User mode verification functions for these APIs | 
|  | must enforce that these are NULL and should invoke :c:macro:`Z_OOPS()` if | 
|  | not. | 
|  |  | 
|  | #. Some parameter checks are enforced only from user mode. These should be | 
|  | checked in the verification function and propagate a return value to the | 
|  | caller if possible. | 
|  |  | 
|  | There are some known exceptions to these policies currently in Zephyr: | 
|  |  | 
|  | * :c:func:`k_thread_join()` and :c:func:`k_thread_abort()` are no-ops if | 
|  | the thread object isn't initialized. This is because for threads, the | 
|  | initialization bit pulls double-duty to indicate whether a thread is | 
|  | running, cleared upon exit. See #23030. | 
|  |  | 
|  | * :c:func:`k_thread_create()` invokes :c:macro:`Z_OOPS()` for parameter | 
|  | checks, due to a great deal of existing code ignoring the return value. | 
|  | This will also be addressed by #23030. | 
|  |  | 
|  | * :c:func:`k_thread_abort()` invokes :c:macro:`Z_OOPS()` if an essential | 
|  | thread is aborted, as the function has no return value. | 
|  |  | 
|  | * Various system calls related to logging invoke :c:macro:`Z_OOPS()` | 
|  | when bad parameters are passed in as they do not propagate errors. | 
|  |  | 
|  | Configuration Options | 
|  | ********************* | 
|  |  | 
|  | Related configuration options: | 
|  |  | 
|  | * :option:`CONFIG_USERSPACE` | 
|  |  | 
|  | APIs | 
|  | **** | 
|  |  | 
|  | Helper macros for creating system call verification functions are provided in | 
|  | :zephyr_file:`include/syscall_handler.h`: | 
|  |  | 
|  | * :c:macro:`Z_SYSCALL_OBJ()` | 
|  | * :c:macro:`Z_SYSCALL_OBJ_INIT()` | 
|  | * :c:macro:`Z_SYSCALL_OBJ_NEVER_INIT()` | 
|  | * :c:macro:`Z_OOPS()` | 
|  | * :c:macro:`Z_SYSCALL_MEMORY_READ()` | 
|  | * :c:macro:`Z_SYSCALL_MEMORY_WRITE()` | 
|  | * :c:macro:`Z_SYSCALL_MEMORY_ARRAY_READ()` | 
|  | * :c:macro:`Z_SYSCALL_MEMORY_ARRAY_WRITE()` | 
|  | * :c:macro:`Z_SYSCALL_VERIFY_MSG()` | 
|  | * :c:macro:`Z_SYSCALL_VERIFY` | 
|  |  | 
|  | Functions for invoking system calls are defined in | 
|  | :zephyr_file:`include/syscall.h`: | 
|  |  | 
|  | * :c:func:`_arch_syscall_invoke0` | 
|  | * :c:func:`_arch_syscall_invoke1` | 
|  | * :c:func:`_arch_syscall_invoke2` | 
|  | * :c:func:`_arch_syscall_invoke3` | 
|  | * :c:func:`_arch_syscall_invoke4` | 
|  | * :c:func:`_arch_syscall_invoke5` | 
|  | * :c:func:`_arch_syscall_invoke6` |