blob: 9441adee273c267a66c22e4ac23a59b027ef2278 [file] [log] [blame]
// 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;
// port_packet_t::type ZX_PKT_TYPE_USER.
type PacketUser = strict union {
1: u64 array<uint64, 4>;
2: u32 array<uint32, 8>;
3: u16 array<uint16, 16>;
4: c8 array<int8, 32>;
};
// port_packet_t::type ZX_PKT_TYPE_SIGNAL_ONE.
type PacketSignal = struct {
trigger Signals;
observed Signals;
count uint64;
reserved0 uint64;
reserved1 uint64;
};
type PacketException = struct {
pid uint64;
tid uint64;
reserved0 uint64;
reserved1 uint64;
};
type PacketGuestBell = struct {
addr Gpaddr;
reserved0 uint64;
reserved1 uint64;
reserved2 uint64;
};
// TODO(scottmg): Arch-specific definition.
type PacketGuestMem = struct {
addr Gpaddr;
//#if __aarch64__
//uint8_t access_size;
//bool sign_extend;
//uint8_t xt;
//bool read;
//uint64_t data;
//uint64_t reserved;
//#elif __x86_64__
//// NOTE: x86 instructions are guaranteed to be 15 bytes or fewer.
//#define X86_MAX_INST_LEN 15u
//uint8_t inst_len;
//uint8_t inst_buf[X86_MAX_INST_LEN];
//// This is the default operand size as determined by the CS and EFER register (Volume 3,
//// Section 5.2.1). If operating in 64-bit mode then near branches and all instructions, except
//// far branches, that implicitly reference the RSP will actually have a default operand size of
//// 64-bits (Volume 2, Section 2.2.1.7), and not the 32-bits that will be given here.
//uint8_t default_operand_size;
//uint8_t reserved[7];
//#endif
};
type PacketGuestIo = struct {
port uint16;
access_size uint8;
input bool;
// TODO(scottmg): Unnamed union.
//union {
// uint8_t u8;
// uint16_t u16;
// uint32_t u32;
// uint8_t data[4];
//};
reserved0 uint64;
reserved1 uint64;
reserved2 uint64;
};
type PacketGuestVcpu = struct {
// TODO(scottmg): Unnamed union.
//union {
// struct {
// uint64_t mask;
// uint8_t vector;
// } interrupt;
// struct {
// uint64_t id;
// zx_gpaddr_t entry;
// } startup;
//};
type uint8;
reserved uint64;
};
type PacketInterrupt = struct {
timestamp Time;
reserved0 uint64;
reserved1 uint64;
reserved2 uint64;
};
type PacketPageRequest = struct {
command uint16;
flags uint16;
reserved0 uint32;
offset uint64;
length uint64;
reserved1 uint64;
};
type PortPacket = struct {
key uint64;
type uint32;
status Status;
// TODO(scottmg): Unnamed union.
// union {
user PacketUser;
signal PacketSignal;
exception PacketException;
guest_bell PacketGuestBell;
guest_mem PacketGuestMem;
guest_io PacketGuestIo;
guest_vcpu PacketGuestVcpu;
interrupt PacketInterrupt;
page_request PacketPageRequest;
// };
};
@transport("Syscall")
closed protocol Port {
/// ## Summary
///
/// Create an IO port.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
///
/// zx_status_t zx_port_create(uint32_t options, zx_handle_t* out);
/// ```
///
/// ## Description
///
/// `zx_port_create()` creates a port: a waitable object that can be used to read
/// packets queued by kernel or by user-mode.
///
/// If you need this port to be bound to an interrupt, pass `ZX_PORT_BIND_TO_INTERRUPT` to *options*,
/// otherwise it should be `0`.
///
/// In the case where a port is bound to an interrupt, the interrupt packets are delivered via a
/// dedicated queue on ports and are higher priority than other non-interrupt packets.
///
/// The returned handle will have:
///
/// * `ZX_RIGHT_TRANSFER`: allowing them to be sent to another process through [`zx_channel_write()`].
/// * `ZX_RIGHT_WRITE`: allowing packets to be *queued*.
/// * `ZX_RIGHT_READ`: allowing packets to be *read*.
/// * `ZX_RIGHT_DUPLICATE`: allowing them to be *duplicated*.
///
/// ## Rights
///
/// Caller job policy must allow `ZX_POL_NEW_PORT`.
///
/// ## Return value
///
/// `zx_port_create()` returns `ZX_OK` and a valid IO port handle via *out* on
/// success. In the event of failure, an error value is returned.
///
/// ## Errors
///
/// `ZX_ERR_INVALID_ARGS` *options* has an invalid value, or *out* is an
/// invalid pointer or NULL.
///
/// `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 builds this error will no longer occur.
///
/// ## See also
///
/// - [`zx_handle_close()`]
/// - [`zx_handle_duplicate()`]
/// - [`zx_handle_replace()`]
/// - [`zx_object_wait_async()`]
/// - [`zx_port_queue()`]
/// - [`zx_port_wait()`]
///
/// [`zx_channel_write()`]: channel_write.md
/// [`zx_handle_close()`]: handle_close.md
/// [`zx_handle_duplicate()`]: handle_duplicate.md
/// [`zx_handle_replace()`]: handle_replace.md
/// [`zx_object_wait_async()`]: object_wait_async.md
/// [`zx_port_queue()`]: port_queue.md
/// [`zx_port_wait()`]: port_wait.md
strict Create(struct {
options uint32;
}) -> (resource struct {
out Handle:PORT;
}) error Status;
/// ## Summary
///
/// Queue a packet to a port.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
/// #include <zircon/syscalls/port.h>
///
/// zx_status_t zx_port_queue(zx_handle_t handle, const zx_port_packet_t* packet);
/// ```
///
/// ## Description
///
/// `zx_port_queue()` queues a user *packet* to the port specified by *handle*.
///
/// User packets are drained by [`zx_port_wait()`]. Failure to drain packets in a
/// timely fashion can cause excessive kernel memory to be used, which might generate
/// an exception. See [ipc limits](/docs/concepts/kernel/ipc_limits.md) for details.
///
/// ```
/// typedef struct zx_port_packet {
/// uint64_t key;
/// uint32_t type;
/// zx_status_t status;
/// union {
/// zx_packet_user_t user;
/// zx_packet_signal_t signal;
/// };
/// } zx_port_packet_t;
///
/// ```
///
/// In *packet* *type* should be `ZX_PKT_TYPE_USER` and only the `user`
/// union element is considered valid:
///
/// ```
/// typedef union zx_packet_user {
/// uint64_t u64[4];
/// uint32_t u32[8];
/// uint16_t u16[16];
/// uint8_t c8[32];
/// } zx_packet_user_t;
///
/// ```
///
/// ## Rights
///
/// *handle* must be of type `ZX_OBJ_TYPE_PORT` and have `ZX_RIGHT_WRITE`.
///
/// ## Return value
///
/// `zx_port_queue()` returns `ZX_OK` on successful queue of a packet.
///
/// ## Errors
///
/// `ZX_ERR_BAD_HANDLE` *handle* isn't a valid handle
///
/// `ZX_ERR_INVALID_ARGS` *packet* is an invalid pointer.
///
/// `ZX_ERR_WRONG_TYPE` *handle* is not a port handle.
///
/// `ZX_ERR_ACCESS_DENIED` *handle* does not have `ZX_RIGHT_WRITE`.
///
/// ## See also
///
/// - [`zx_port_create()`]
/// - [`zx_port_wait()`]
///
/// [`zx_port_create()`]: port_create.md
/// [`zx_port_wait()`]: port_wait.md
strict Queue(resource struct {
handle Handle:PORT;
packet PortPacket;
}) -> () error Status;
/// ## Summary
///
/// Wait for a packet arrival in a port.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
/// #include <zircon/syscalls/port.h>
///
/// zx_status_t zx_port_wait(zx_handle_t handle,
/// zx_time_t deadline,
/// zx_port_packet_t* packet);
/// ```
///
/// ## Description
///
/// `zx_port_wait()` is a blocking syscall, which causes the caller to wait until at least
/// one packet is available.
///
/// Upon return, if successful *packet* will contain the earliest (in FIFO order)
/// available packet data.
///
/// The *deadline* indicates when to stop waiting for a packet (with respect to
/// `ZX_CLOCK_MONOTONIC`) and will be automatically adjusted according to the job's
/// [timer slack] policy. If no packet has arrived by the deadline,
/// `ZX_ERR_TIMED_OUT` is returned. The value `ZX_TIME_INFINITE` will result in
/// waiting forever. A value in the past will result in an immediate timeout,
/// unless a packet is already available for reading.
///
/// Unlike [`zx_object_wait_one()`] and [`zx_object_wait_many()`] only one
/// waiting thread is released (per available packet), which makes ports
/// amenable to be serviced by thread pools.
///
/// There are two classes of packets: packets queued by userspace with [`zx_port_queue()`]
/// and packets queued by the kernel when objects a port is registered with change state. In both
/// cases the packet is always of type `zx_port_packet_t`:
///
/// ```
/// struct zx_port_packet_t {
/// uint64_t key;
/// uint32_t type;
/// zx_status_t status;
/// union {
/// zx_packet_user_t user;
/// zx_packet_signal_t signal;
/// zx_packet_guest_bell_t guest_bell;
/// zx_packet_guest_mem_t guest_mem;
/// zx_packet_guest_io_t guest_io;
/// zx_packet_guest_vcpu_t guest_vcpu;
/// zx_packet_interrupt_t interrupt;
/// zx_packet_page_request_t page_request;
/// };
/// };
/// ```
///
/// In the case of packets generated via [`zx_port_queue()`], *type* will be set to
/// `ZX_PKT_TYPE_USER`, and the caller of [`zx_port_queue()`] controls all other values in the
/// `zx_port_packet_t` structure. Access to the packet data is provided by the *user* member, with
/// type `zx_packet_user_t`:
///
/// ```
/// typedef union zx_packet_user {
/// uint64_t u64[4];
/// uint32_t u32[8];
/// uint16_t u16[16];
/// uint8_t c8[32];
/// } zx_packet_user_t;
/// ```
///
/// For packets generated by the kernel, type can be one of the following values:
///
/// `ZX_PKT_TYPE_SIGNAL_ONE` - generated by objects registered via
/// [`zx_object_wait_async()`].
///
/// `ZX_PKT_TYPE_GUEST_BELL`, `ZX_PKT_TYPE_GUEST_MEM`, `ZX_PKT_TYPE_GUEST_IO`,
/// or `ZX_PKT_TYPE_GUEST_VCPU` - generated by objects registered via [`zx_guest_set_trap()`].
///
/// `ZX_PKT_TYPE_INTERRUPT` - generated by objects registered via [`zx_interrupt_bind()`].
///
/// `ZX_PKT_TYPE_PAGE_REQUEST` - generated by objects registered via [`zx_pager_create_vmo()`].
///
/// All kernel queued packets will have *status* set to `ZX_OK` and *key* set to the
/// value provided to the registration syscall. For details on how to interpret the union, see
/// the corresponding registration syscall.
///
/// ## Rights
///
/// *handle* must be of type `ZX_OBJ_TYPE_PORT` and have `ZX_RIGHT_READ`.
///
/// ## Return value
///
/// `zx_port_wait()` returns `ZX_OK` on successful packet dequeuing.
///
/// ## Errors
///
/// `ZX_ERR_BAD_HANDLE` *handle* is not a valid handle.
///
/// `ZX_ERR_INVALID_ARGS` *packet* isn't a valid pointer
///
/// `ZX_ERR_ACCESS_DENIED` *handle* does not have `ZX_RIGHT_READ` and may
/// not be waited upon.
///
/// `ZX_ERR_TIMED_OUT` *deadline* passed and no packet was available.
///
/// ## See also
///
/// - [timer slack]
/// - [`zx_object_wait_async()`]
/// - [`zx_port_create()`]
/// - [`zx_port_queue()`]
///
/// [timer slack]: /docs/concepts/kernel/timer_slack.md
/// [`zx_guest_set_trap()`]: guest_set_trap.md
/// [`zx_interrupt_bind()`]: interrupt_bind.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_pager_create_vmo()`]: pager_create_vmo.md
/// [`zx_port_create()`]: port_create.md
/// [`zx_port_queue()`]: port_queue.md
@blocking
strict Wait(resource struct {
handle Handle:PORT;
deadline Time;
}) -> (struct {
packet PortPacket;
}) error Status;
/// ## Summary
///
/// Cancels async port notifications on an object.
///
/// ## Declaration
///
/// ```c
/// #include <zircon/syscalls.h>
///
/// zx_status_t zx_port_cancel(zx_handle_t handle,
/// zx_handle_t source,
/// uint64_t key);
/// ```
///
/// ## Description
///
/// `zx_port_cancel()` is a non-blocking syscall that cancels
/// all pending [`zx_object_wait_async()`] operations made with *source* and *key*.
///
/// When this call succeeds no new packets from the object pointed by
/// *source* with *key* will be delivered to *handle*, and pending queued
/// packets that match *source* and *key* are removed from the port.
///
/// ## Rights
///
/// *handle* must be of type `ZX_OBJ_TYPE_PORT` and have `ZX_RIGHT_WRITE`.
///
/// ## Return value
///
/// `zx_port_cancel()` returns `ZX_OK` if cancellation succeeded and
/// either queued packets were removed or pending [`zx_object_wait_async()`] were
/// canceled.
///
/// ## Errors
///
/// `ZX_ERR_BAD_HANDLE` *source* or *handle* is not a valid handle.
///
/// `ZX_ERR_WRONG_TYPE` *handle* is not a port handle.
///
/// `ZX_ERR_ACCESS_DENIED` *source* or *handle* does not have `ZX_RIGHT_WRITE`.
///
/// `ZX_ERR_NOT_SUPPORTED` *source* is a handle that cannot be waited on.
///
/// `ZX_ERR_NOT_FOUND` if either no pending packets or pending
/// [`zx_object_wait_async()`] calls with *source* and *key* were found.
///
/// ## See also
///
/// - [`zx_port_wait()`]
///
/// [`zx_object_wait_async()`]: object_wait_async.md
/// [`zx_port_wait()`]: port_wait.md
strict Cancel(resource struct {
handle Handle:PORT;
source Handle;
key uint64;
}) -> () error Status;
};