blob: 43b37d3e601623b2841737bfc785046634a36aee [file]
// Copyright 2019 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.
library zx;
type ExceptionContext = struct {
// TODO
};
@transport("Syscall")
closed protocol Thread {
/// ## Summary
///
/// Terminate the current running thread.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
///
/// [[noreturn]] void zx_thread_exit(void);
/// ```
///
/// ## Description
///
/// `zx_thread_exit()` causes the currently running thread to cease
/// running and exit.
///
/// The signal `ZX_THREAD_TERMINATED` will be asserted on the thread
/// object upon exit and may be observed via [`zx_object_wait_one()`]
/// or [`zx_object_wait_many()`] on a handle to the thread.
///
/// ## Rights
///
/// TODO(https://fxbug.dev/42107318)
///
/// ## Return value
///
/// `zx_thread_exit()` does not return.
///
/// ## See also
///
/// - [`zx_handle_close()`]
/// - [`zx_handle_duplicate()`]
/// - [`zx_object_wait_async()`]
/// - [`zx_object_wait_many()`]
/// - [`zx_object_wait_one()`]
/// - [`zx_thread_create()`]
/// - [`zx_thread_start()`]
///
/// [`zx_handle_close()`]: handle_close.md
/// [`zx_handle_duplicate()`]: handle_duplicate.md
/// [`zx_object_wait_async()`]: object_wait_async.md
/// [`zx_object_wait_many()`]: object_wait_many.md
/// [`zx_object_wait_one()`]: object_wait_one.md
/// [`zx_thread_create()`]: thread_create.md
/// [`zx_thread_start()`]: thread_start.md
@noreturn
strict Exit();
/// ## Summary
///
/// Create a thread.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
///
/// zx_status_t zx_thread_create(zx_handle_t process,
/// const char* name,
/// size_t name_size,
/// uint32_t options,
/// zx_handle_t* out);
/// ```
///
/// ## Description
///
/// `zx_thread_create()` creates a thread within the specified process.
///
/// Upon success a handle for the new thread is returned. The thread
/// will not start executing until [`zx_thread_start()`] is called.
///
/// *name* is silently truncated to a maximum of `ZX_MAX_NAME_LEN-1` characters.
///
/// Thread handles may be waited on and will assert the signal
/// `ZX_THREAD_TERMINATED` when the thread stops executing (due to
/// [`zx_thread_exit()`] being called).
///
/// *process* is the controlling [process object](/docs/reference/kernel_objects/process.md) for the
/// new thread, which will become a child of that process.
///
/// For thread lifecycle details see [thread object](/docs/reference/kernel_objects/thread.md).
///
/// ## Rights
///
/// *process* must be of type `ZX_OBJ_TYPE_PROCESS` and have `ZX_RIGHT_MANAGE_THREAD`.
///
/// ## Return value
///
/// On success, `zx_thread_create()` returns `ZX_OK` and a handle (via *out*)
/// to the new thread. In the event of failure, a negative error value is
/// returned.
///
/// ## Errors
///
/// `ZX_ERR_BAD_HANDLE` *process* is not a valid handle.
///
/// `ZX_ERR_WRONG_TYPE` *process* is not a process handle.
///
/// `ZX_ERR_ACCESS_DENIED` *process* does not have the `ZX_RIGHT_MANAGE_THREAD` right.
///
/// `ZX_ERR_INVALID_ARGS` *name* or *out* was an invalid pointer, or *options* was
/// non-zero.
///
/// `ZX_ERR_NO_MEMORY` Failure due to lack of memory.
/// There is no good way for userspace to handle this (unlikely) error.
/// In a future build this error will no longer occur.
///
/// ## See also
///
/// - [`zx_handle_close()`]
/// - [`zx_handle_duplicate()`]
/// - [`zx_object_wait_async()`]
/// - [`zx_object_wait_many()`]
/// - [`zx_object_wait_one()`]
/// - [`zx_thread_exit()`]
/// - [`zx_thread_start()`]
///
/// [`zx_handle_close()`]: handle_close.md
/// [`zx_handle_duplicate()`]: handle_duplicate.md
/// [`zx_object_wait_async()`]: object_wait_async.md
/// [`zx_object_wait_many()`]: object_wait_many.md
/// [`zx_object_wait_one()`]: object_wait_one.md
/// [`zx_thread_exit()`]: thread_exit.md
/// [`zx_thread_start()`]: thread_start.md
strict Create(resource struct {
process Handle:PROCESS;
name vector<uchar>:MAX_NAME_LEN;
options uint32;
}) -> (resource struct {
out Handle:THREAD;
}) error Status;
/// ## Summary
///
/// Start execution on a thread.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
///
/// zx_status_t zx_thread_start_regs(zx_handle_t handle,
/// uint64_t pc,
/// uint64_t sp,
/// uint64_t arg1,
/// uint64_t arg2,
/// uint64_t tp,
/// uint64_t abi_reg);
/// zx_status_t zx_thread_start(zx_handle_t handle,
/// zx_vaddr_t pc,
/// zx_vaddr_t sp,
/// uintptr_t arg1,
/// uintptr_t arg2);
/// ```
///
/// ## Description
///
/// _**TODO(https://fxbug.dev/478347581):** The new signature with *tp* and
/// *abi_reg* arguments is the preferred ABI in Fucshia API level 31 and
/// later. This will eventually be renamed to `zx_thread_start` when
/// API levels before 31 are no longer supported. The older signature
/// behaves exactly the same, with zero used for the new arguments._
///
/// `zx_thread_start()` causes a thread to begin execution. Its initial
/// registers are set as follows:
///
/// * The program counter is set to the *pc* argument.
/// * The stack pointer is set to the *sp* argument.
/// * The first two argument registers in the machine's C calling
/// convention are set to *arg1* and *arg2*, respectively.
/// * The machine's thread pointer register is set to the *tp* argument.
/// * The register used by the machine ABI for the shadow call stack
/// pointer is set to *abi_reg*. On x86 where there is no shadow call
/// stack ABI, this value goes into the `r15` register.
/// * All other general registers are zero.
/// * All floating-point and/or vector registers are in the machine's
/// initial state (usually mostly zero).
///
/// Each register value given must be some value that it's possible for
/// normal code to get into that register somehow. If not, the call fails
/// with `ZX_ERR_INVALID_ARGS`. For example, the PC on some machines can
/// only be set to a "canonical" address: it doesn't have to be a _valid_
/// address--it can be something that will cause a fault when the thread
/// actually executes at that PC, just like a normal jump instruction would
/// set the PC and then fault; but it cannot be a "noncanonical" address,
/// where a jump instruction _itself_ would fault without changing the PC.
/// Similarly, the stack pointer might need to be a pointer with valid
/// machine-required alignment (even if not an _actually valid_ address);
/// or the thread pointer might need to be a canonical address. For all
/// these registers on all machines, zero is always a valid argument value.
///
/// When the last handle to a thread is closed, the thread is destroyed.
///
/// Thread handles may be waited on and will assert the signal
/// `ZX_THREAD_TERMINATED` when the thread stops executing (due to
/// [`zx_thread_exit()`] being called).
///
/// *pc* shall point to a function that must call [`zx_thread_exit()`] or
/// [`zx_futex_wake_handle_close_thread_exit()`] or
/// [`zx_vmar_unmap_handle_close_thread_exit()`] before reaching the last instruction.
/// Below is an example:
///
/// ```c
/// [[noreturn]] void thread_entry(uint64_t arg1, uint64_t arg2) {
/// // do work here.
/// zx_thread_exit();
/// }
/// ```
///
/// Failing to call one of the exit functions before reaching the end of
/// the function will cause an architecture / toolchain specific exception.
///
/// ## Rights
///
/// *handle* must be of type `ZX_OBJ_TYPE_THREAD` and have `ZX_RIGHT_MANAGE_THREAD`.
///
/// ## Return value
///
/// `zx_thread_start()` returns `ZX_OK` on success.
/// In the event of failure, a negative error value is returned.
///
/// ## Errors
///
/// `ZX_ERR_BAD_HANDLE` *thread* is not a valid handle.
///
/// `ZX_ERR_WRONG_TYPE` *thread* is not a thread handle.
///
/// `ZX_ERR_ACCESS_DENIED` The handle *thread* lacks `ZX_RIGHT_WRITE`.
///
/// `ZX_ERR_BAD_STATE` *thread* is not ready to run or the process *thread*
/// is part of is no longer alive.
///
/// `ZX_ERR_INVALID_ARGS` One of the register values is impossible for the
/// machine to use.
///
/// ## See also
///
/// - [`zx_futex_wake_handle_close_thread_exit()`]
/// - [`zx_handle_close()`]
/// - [`zx_handle_duplicate()`]
/// - [`zx_object_wait_async()`]
/// - [`zx_object_wait_many()`]
/// - [`zx_object_wait_one()`]
/// - [`zx_thread_create()`]
/// - [`zx_thread_exit()`]
/// - [`zx_vmar_unmap_handle_close_thread_exit()`]
///
/// [`zx_futex_wake_handle_close_thread_exit()`]: futex_wake_handle_close_thread_exit.md
/// [`zx_handle_close()`]: handle_close.md
/// [`zx_handle_duplicate()`]: handle_duplicate.md
/// [`zx_object_wait_async()`]: object_wait_async.md
/// [`zx_object_wait_many()`]: object_wait_many.md
/// [`zx_object_wait_one()`]: object_wait_one.md
/// [`zx_thread_create()`]: thread_create.md
/// [`zx_thread_exit()`]: thread_exit.md
/// [`zx_vmar_unmap_handle_close_thread_exit()`]: vmar_unmap_handle_close_thread_exit.md
// TODO(https://fxbug.dev/478347581): The new signature now called
// StartRegs will be renamed back to Start after API levels <= 30 are
// retired, with StartRegs left as an alias until all later API levels that
// still had the old Start signature are retired.
@vdsocall
strict Start(resource struct {
handle Handle:THREAD;
thread_entry Vaddr;
stack Vaddr;
arg1 uintptr64;
arg2 uintptr64;
}) -> () error Status;
strict StartRegs(resource struct {
handle Handle:THREAD;
pc uint64;
sp uint64;
arg1 uint64;
arg2 uint64;
tp uint64;
abi_reg uint64;
}) -> () error Status;
/// ## Summary
///
/// Read one aspect of thread state.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
///
/// zx_status_t zx_thread_read_state(zx_handle_t handle,
/// uint32_t kind,
/// void* buffer,
/// size_t buffer_size);
/// ```
///
/// ## Description
///
/// `zx_thread_read_state()` reads one aspect of state of the thread. The thread
/// state may only be read when the thread is halted for an exception or the thread
/// is suspended.
///
/// The thread state is highly processor specific. See the structures in
/// zircon/syscalls/debug.h for the contents of the structures on each platform.
///
/// ## STATES
///
/// ### ZX_THREAD_STATE_GENERAL_REGS
///
/// The buffer must point to a `zx_thread_state_general_regs_t` structure that
/// contains the general registers for the current architecture.
///
/// ### ZX_THREAD_STATE_FP_REGS
///
/// The buffer must point to a `zx_thread_state_fp_regs_t` structure. On 64-bit
/// ARM platforms, float point state is in the vector registers and this structure
/// is empty.
///
/// ### ZX_THREAD_STATE_VECTOR_REGS
///
/// The buffer must point to a `zx_thread_state_vector_regs_t` structure.
///
/// ### ZX_THREAD_STATE_DEBUG_REGS
///
/// The buffer must point to a `zx_thread_state_debug_regs_t` structure. All input
/// fields will be ignored and overwritten with the actual values for the thread.
///
/// ### ZX_THREAD_STATE_SINGLE_STEP
///
/// The buffer must point to a `zx_thread_state_single_step_t` value, which
/// may contain either 0 (normal running), or 1 (single stepping enabled).
///
/// ## Rights
///
/// *handle* must be of type `ZX_OBJ_TYPE_THREAD` and have `ZX_RIGHT_READ`.
///
/// ## Return value
///
/// `zx_thread_read_state()` returns `ZX_OK` on success.
/// In the event of failure, a negative error value is returned.
///
/// ## Errors
///
/// `ZX_ERR_BAD_HANDLE` *handle* is not a valid handle.
///
/// `ZX_ERR_WRONG_TYPE` *handle* is not that of a thread.
///
/// `ZX_ERR_ACCESS_DENIED` *handle* lacks `ZX_RIGHT_READ`.
///
/// `ZX_ERR_INVALID_ARGS` *kind* is not valid or *buffer* is an invalid pointer.
///
/// `ZX_ERR_NO_MEMORY` Failure due to lack of memory.
/// There is no good way for userspace to handle this (unlikely) error.
/// In a future build this error will no longer occur.
///
/// `ZX_ERR_BUFFER_TOO_SMALL` The buffer length *buffer_size* is too small to
/// hold the data required by *kind*.
///
/// `ZX_ERR_BAD_STATE` The thread is not stopped at a point where state
/// is available. The thread state may only be read when the thread is stopped due
/// to an exception.
///
/// `ZX_ERR_NOT_SUPPORTED` *kind* is not supported.
/// This can happen, for example, when trying to read a register set that
/// is not supported by the hardware the program is currently running on.
///
/// ## See also
///
/// [thread_write_state](thread_write_state.md).
strict ReadState(resource struct {
handle Handle:THREAD;
kind uint32;
}) -> (struct {
@voidptr
buffer vector<byte>:MAX;
}) error Status;
/// ## Summary
///
/// Write one aspect of thread state.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
///
/// zx_status_t zx_thread_write_state(zx_handle_t handle,
/// uint32_t kind,
/// const void* buffer,
/// size_t buffer_size);
/// ```
///
/// ## Description
///
/// `zx_thread_write_state()` writes one aspect of state of the thread. The thread
/// state may only be written when the thread is halted for an exception or the
/// thread is suspended.
///
/// The thread state is highly processor specific. See the structures in
/// zircon/syscalls/debug.h for the contents of the structures on each platform.
///
/// To use the `zx_thread_write_state()` function with the `ZX_THREAD_STATE_DEBUG_REGS`
/// flag, you must specify `kernel.enable-serial-syscalls=true` on the kernel command line.
/// Otherwise, the function returns `ZX_ERR_NOT_SUPPORTED`.
///
/// ## STATES
///
/// See [`zx_thread_read_state()`] for the list of available states
/// and their corresponding values.
///
/// ### ZX_THREAD_STATE_DEBUG_REGS
///
/// #### ARM
///
/// ARM has a variable amount of debug breakpoints and watchpoints. For this
/// architecture, `zx_thread_state_debug_regs_t` is big enough to hold the maximum
/// amount of breakpoints possible. But in most cases a given CPU implementation
/// holds a lesser amount, meaning that the upper values beyond the limit are not
/// used.
///
/// The kernel will write all the available registers in the hardware independent of
/// the given breakpoint/watchpoint count value. This means that all the correct
/// state must be set for the call.
///
/// You can get the current state of the registers by calling
/// [`zx_thread_read_state()`](thread_read_state.md#zx_thread_state_debug_regs).
///
/// #### ARM Debug Hardware Debug Registers
///
/// ARM debug registers are highly configurable via their DBGBCR<n> registers.
/// However, Zircon limits that functionality to _Unlinked Address Matching_ HW
/// breakpoints. This means that HW breakpoints will only issue exceptions upon
/// exception on the given address in the corresponding DBGBVR register.
///
/// Because of this, all the values within DBGBCR will be ignored except for the E
/// bit, which is used to determine whether that particular breakpoint is activated
/// or not. Said in another way, in order to activate a HW breakpoint, all that is
/// needed is to set the correct address in DBGBVR and write 1 to DBGBCR.
///
/// ## Rights
///
/// *handle* must be of type `ZX_OBJ_TYPE_THREAD` and have `ZX_RIGHT_WRITE`.
///
/// ## Return value
///
/// `zx_thread_write_state()` returns `ZX_OK` on success.
/// In the event of failure, a negative error value is returned.
///
/// ## Errors
///
/// `ZX_ERR_BAD_HANDLE` *handle* is not a valid handle.
///
/// `ZX_ERR_WRONG_TYPE` *handle* is not that of a thread.
///
/// `ZX_ERR_ACCESS_DENIED` *handle* lacks `ZX_RIGHT_WRITE`.
///
/// `ZX_ERR_INVALID_ARGS` *kind* is not valid, *buffer* is an invalid pointer,
/// *buffer_size* doesn't match the size of the structure expected for *kind* or
/// the given values to set are not valid.
///
/// `ZX_ERR_NO_MEMORY` Failure due to lack of memory.
/// There is no good way for userspace to handle this (unlikely) error.
/// In a future build this error will no longer occur.
///
/// `ZX_ERR_BAD_STATE` The thread is not stopped at a point where state
/// is available. The thread state may only be read when the thread is stopped due
/// to an exception.
///
/// `ZX_ERR_NOT_SUPPORTED` *kind* is not supported.
/// This can happen, for example, when trying to read a register set that
/// is not supported by the hardware the program is currently running on,
/// or when using the `ZX_THREAD_STATE_DEBUG_REGS` kind without specifying
/// `kernel.enable-serial-syscalls=true` on the kernel command line.
///
/// #### ARM
///
/// `ZX_ERR_INVALID_ARGS` If the address provided to a DBGBVR register is not
/// valid (ie. not addressable from userspace). Also if any value is set for a HW
/// breakpoint beyond the number provided by the platform (see above for
/// information about retrieving that number).
///
/// ## See also
///
/// - [`zx_thread_read_state()`]
///
/// [`zx_thread_read_state()`]: thread_read_state.md
strict WriteState(resource struct {
handle Handle:THREAD;
kind uint32;
@voidptr
buffer vector<byte>:MAX;
}) -> () error Status;
/// ## Summary
///
/// Raise a user-generated exception.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
///
/// zx_status_t zx_thread_raise_exception(uint32_t options,
/// zx_excp_type_t type,
/// const zx_exception_context_t* context);
/// ```
///
/// ## Description
///
/// `zx_thread_raise_exception()` raises a user-generated exception. The exception
/// will be delivered to the exception channels associated with the current thread.
///
/// Currently, the *options* argument must be `ZX_EXCEPTION_TARGET_JOB_DEBUGGER`,
/// which causes the exception to be delivered to the job debugger exception channels.
/// In the future, *options* may be expanded to enable targeting other types of
/// exception channels.
///
/// The the *type* argument must be be `ZX_EXCP_USER`. In the future, *type* may be
/// expanded to enable raising other types of exceptions.
///
/// The `arch` field in `zx_exception_context_t` is ignored. Instead, use the
/// `synth_code` and `synth_data` fields to communicate information about the exception.
/// Codes less than `ZX_EXCP_USER_CODE_USER0` are reserved for system-defined purposes.
/// Applications may use codes greater than or equal to `ZX_EXCP_USER_CODE_USER0` for
/// their own purposes.
///
/// ## Return value
///
/// `zx_thread_raise_exception()` returns `ZX_OK` on success.
/// In the event of failure, a negative error value is returned.
///
/// ## Errors
///
/// `ZX_ERR_INVALID_ARGS` *options* is a value other than
/// `ZX_EXCEPTION_TARGET_JOB_DEBUGGER`, *type* is a value other than
/// *ZX_EXCP_USER*, or *context* is an invalid pointer.
///
/// `ZX_ERR_NO_MEMORY` Failure due to lack of memory.
/// There is no good way for userspace to handle this (unlikely) error.
/// In a future build this error will no longer occur.
///
/// ## See also
///
/// - [`zx_task_create_exception_channel()`]
///
/// [`zx_task_create_exception_channel()`]: task_create_exception_channel.md
strict RaiseException(struct {
options uint32;
type uint32;
context ExceptionContext;
}) -> () error Status;
/// ## Summary
///
/// Register a restartable sequence for a thread.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
///
/// zx_status_t zx_thread_set_rseq(zx_handle_t vmo, uint64_t offset, uint64_t size);
///
/// ## Description
///
/// `zx_thread_set_rseq()` registers a restartable sequence for the current thread. The
/// restartable sequence is defined by a `zx_rseq_t` structure in the VMO starting at
/// *offset* and of length *size*.
///
/// Zircon will keep the `cpu_id` field in the `zx_rseq_t` structure up to date with the
/// current CPU ID of the thread. If the thread is migrated to a different CPU while the
/// instruction pointer is in the restartable sequence defined by the `start_ip` and
/// `post_commit_offset` fields, the thread will resume execution at the address
/// specified by the `abort_ip` field.
///
/// Userspace should use volatile reads and writes to access the `zx_rseq_t` structure because
/// the kernel may modify the `cpu_id` field at any time, and the `start_ip`,
/// `post_commit_offset`, and `abort_ip` fields may be read by the kernel at any time.
///
/// At most one restartable sequence may be registered at a time. If the thread is already
/// has a restartable sequence registered, `zx_thread_set_rseq()` will return
/// `ZX_ERR_ALREADY_EXISTS`.
///
/// The *offset* must be 0 mod `alignof(zx_rseq_t)` and the region of size `sizeof(zx_rseq_t)`
/// starting at *offset* must not span a page boundary.
///
/// To unregister a restartable sequence, call `zx_thread_set_rseq()` with `ZX_HANDLE_INVALID`
/// for the *vmo* argument.
///
/// ## Return value
///
/// `zx_thread_set_rseq()` returns `ZX_OK` on success.
/// In the event of failure, a negative error value is returned.
///
/// ## Errors
///
/// `ZX_ERR_INVALID_ARGS` *offset* is not a multiple of `alignof(zx_rseq_t)`,
/// *size* is not `sizeof(zx_rseq_t)`, or the region of memory defined by
/// *offset* and *size* spans a page boundary.
///
/// `ZX_ERR_INVALID_ARGS` *vmo* is not directly writable, has been
/// marked as uncached, or is backed by a user pager.
///
/// `ZX_ERR_ALREADY_EXISTS` The thread already has a restartable sequence registered.
///
/// `ZX_ERR_BAD_HANDLE` *vmo* is neither a valid handle nor `ZX_HANDLE_INVALID`.
///
/// `ZX_ERR_WRONG_TYPE` *vmo* is not a VMO.
///
/// `ZX_ERR_ACCESS_DENIED` *vmo* is missing `ZX_RIGHT_READ`, `ZX_RIGHT_WRITE`, or
/// `ZX_RIGHT_DUPLICATE`.
strict SetRseq(resource struct {
vmo Handle:VMO;
offset uint64;
size uint64;
}) -> () error Status;
/// ## Summary
///
/// Yield the CPU of the current thread back to the scheduler.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
///
/// zx_status_t zx_thread_legacy_yield(uint32_t options);
/// ```
///
/// ## Description
///
/// `zx_thread_legacy_yield()` causes the calling thread to yield the CPU back to the scheduler.
///
/// Yield may result in other threads with similar importance running ahead of the current thread,
/// however, the exact behavior is unspecified.
///
/// `options` must be zero.
///
/// ## Rights
///
/// TODO(https://fxbug.dev/42107318)
///
/// ## Return value
///
/// `zx_thread_legacy_yield(uint32_t options)` will always return `ZX_OK` for zero `options`.
/// Any other `options` value, will result in `ZX_ERR_INVALID_ARGS`.
///
/// ## See also
///
/// - [`zx_nanosleep()`]
///
/// [`zx_nanosleep()`]: nanosleep.md
strict LegacyYield(resource struct {
options uint32;
}) -> () error Status;
};