Loading...
/*
 * Copyright (c) 2025 Apple Inc. All rights reserved.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
 *
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. The rights granted to you under the License
 * may not be used to create, or enable the creation or redistribution of,
 * unlawful or unlicensed copies of an Apple operating system, or to
 * circumvent, violate, or enable the circumvention or violation of, any
 * terms of an Apple operating system software license agreement.
 *
 * Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this file.
 *
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
 */

#ifndef OS_X18_H
#define OS_X18_H

#if defined(__arm64__)

#include <stdbool.h>

#include <sys/cdefs.h>

#include <os/availability.h>

__BEGIN_DECLS

/*!
 * @function os_custom_x18_abi
 *
 * @abstract
 *
 * Switch thread into or out of custom ABI usage for the x18 register.
 *
 * This API comes with lots of caveats. Users of this API must take a
 * disproportionate amount of care, so it is strongly advised to only
 * use this API if absolutely required.
 *
 * Under normal operation, x18 is reserved for operating system usage,
 * and may therefore not be touched by any application code. The Apple
 * ARM64 Application Binary Interface codifies this by stating: "The
 * platforms reserve register x18. Don’t use this register."
 *
 * However, there are special situations, such as when implementing
 * compatibility layers for other ABIs, where custom usage x18 becomes
 * a necessity, notably when it is part of the ABI contract itself
 * (for example, used as a TSD base).
 *
 * This API enables per-thread use of x18 under such special
 * circumstances. To use it, application code must issue
 * `os_custom_x18_abi(true)` at the boundary between the regular macOS
 * application code and the code using the custom ABI. When in this
 * mode, x18 behaves like any other general purpose register for this
 * thread: It has no other semantics towards the operating system
 * other than holding arbitrary values, and it will get saved and
 * restored across context switches like any other GPR. When switching
 * back from the custom ABI code to macOS application code,
 * `os_custom_x18_abi(false)` must then be issued, in order to restore
 * the proper system-defined operating semantics for x18 again.
 *
 * Note that code running after `os_custom_x18_abi(true)` must not
 * call, directly or in the form of callbacks, into any macOS
 * library/framework code in the current thread, with the exception of
 * `os_custom_x18_abi() and `os_custom_x18_abi_get()` themselves.
 *
 * Great care must also be taken with signal handlers and other
 * asynchronous code entry points. These should either not call into
 * any macOS library/framework code (note that this includes POSIX
 * interfaces), or bracket such calls between
 * `os_custom_x18_abi(false)` and `os_custom_x18_abi(true)`, iff the
 * custom x18 ABI is enabled according to `os_custom_x18_abi_get()`.
 * Any other regular limitations for signal handler code calling into
 * OS functions apply as well. Unless the use of signals is absolutely
 * required, masking all signals before entering custom x18 ABI mode
 * avoids any complication with signal handlers.
 *
 * Also note that the operating system does not preserve any x18 value
 * from within the custom ABI code across `os_custom_x18_abi()`
 * calls. Effectively, calling `os_custom_x18_abi(false)` destroys
 * x18's value. In the likely case that the application code wishes to
 * preserve x18's content for the custom ABI code, the application
 * code must save and restore the affected thread's x18 value itself.
 *
 * `os_custom_x18_abi()` will, however, properly save and restore x18
 * for its system-defined operating semantics, meaning that
 * application code must not restore x18 in the other direction,
 * i.e. after switching back from custom ABI code to macOS code, nor
 * does it have to save the value before entering custom ABI code (the
 * application code may actually not have the proper information to do
 * so safely). In summary, application code is in charge of x18's
 * value on the "custom ABI side", while macOS itself is in charge of
 * the value on the "macOS side".
 *
 * @param custom true to switch the thread into custom ABI x18 usage,
 * false to switch back to regular macOS x18 semantics.
 *
 */

API_UNAVAILABLE(ios, tvos, watchos, bridgeos) API_AVAILABLE(macos(16.4))
extern
void os_custom_x18_abi(bool custom);

/*!
 * @function os_custom_x18_abi_get
 *
 * @abstract
 *
 * Returns whether custom x18 ABI mode is enabled.
 *
 * This can be used to determine if the custom x18 ABI needs temporary
 * disablement prior to calling into any macOS code, e.g. in signal handlers.
 *
 * @return `true` iff custom x18 ABI is enabled.
 */
API_UNAVAILABLE(ios, tvos, watchos, bridgeos) API_AVAILABLE(macos(16.4))
extern
bool os_custom_x18_abi_get(void);

__END_DECLS

#endif // defined(__arm64__)

#endif // OS_X18_H