| // 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; |
| timestamp Time; |
| 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 InstantBoot; |
| reserved0 uint64; |
| reserved1 uint64; |
| reserved2 uint64; |
| }; |
| |
| type PacketPageRequest = struct { |
| command uint16; |
| flags uint16; |
| reserved0 uint32; |
| offset uint64; |
| length uint64; |
| reserved1 uint64; |
| }; |
| |
| @next |
| type PacketProcessorPowerLevelTransitionRequest = struct { |
| /// Request targeting the provided power domain. |
| domain_id uint32; |
| |
| // Options applying to this transition. |
| options uint32; |
| |
| // Control Interface ID provided in the energy model. |
| control_argument uint64; |
| |
| // Control Interface Argument provided in the energy model. |
| control_interface uint64; |
| |
| reserved 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; |
| processor_power_level_transition PacketProcessorPowerLevelTransitionRequest; |
| // }; |
| }; |
| |
| @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. |
| /// |
| /// ```c |
| /// 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: |
| /// |
| /// ```c |
| /// 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_instant_mono_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`: |
| /// |
| /// ```c |
| /// 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`: |
| /// |
| /// ```c |
| /// 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 InstantMono; |
| }) -> (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; |
| |
| /// ## Summary |
| /// |
| /// Cancels all async port notifications matching a key. |
| /// |
| /// ## Declaration |
| /// |
| /// ```c |
| /// #include <zircon/syscalls.h> |
| /// |
| /// zx_status_t zx_port_cancel_key(zx_handle_t handle, |
| /// uint32_t options, |
| /// uint64_t key); |
| /// ``` |
| /// |
| /// ## Description |
| /// |
| /// `zx_port_cancel_key()` is a non-blocking syscall that cancels all |
| /// pending [`zx_object_wait_async()`] operations on this port registered |
| /// with *key*. |
| /// |
| /// When this call succeeds no new packets from operations registered with |
| /// *key* will be delivered to *handle*, and pending queued packets that |
| /// *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_key()` 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` *handle* is not a valid handle. |
| /// |
| /// `ZX_ERR_WRONG_TYPE` *handle* is not a port handle. |
| /// |
| /// `ZX_ERR_INVALID_ARGS` *options* has an invalid value. |
| /// |
| /// `ZX_ERR_ACCESS_DENIED` *handle* does not have `ZX_RIGHT_WRITE`. |
| /// |
| /// `ZX_ERR_NOT_FOUND` if either no pending packets or pending |
| /// [`zx_object_wait_async()`] calls matching *key* were found. |
| /// |
| /// ## See also |
| /// |
| /// - [`zx_port_wait()`] |
| /// |
| /// [`zx_object_wait_async()`]: object_wait_async.md |
| /// [`zx_port_wait()`]: port_wait.md |
| // TODO(https://fxbug.dev/339884866): This API was introduced in API level |
| // 20 but our versioning tooling does not yet support availability |
| // annotations for vDSO entry points. Enable this annotation once it's |
| // supported. |
| // @available(added=20) |
| strict CancelKey(resource struct { |
| handle Handle:PORT; |
| options uint32; |
| key uint64; |
| }) -> () error Status; |
| }; |