| // 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; | 
 | }; |