// Copyright 2017 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. #ifndef ZIRCON_FIDL_H_ #define ZIRCON_FIDL_H_ #include <assert.h> #include <stdalign.h> #include <stdint.h> #include <zircon/compiler.h> #include <zircon/types.h> __BEGIN_CDECLS // Fidl data types have a representation in a wire format. This wire // format is shared by all language bindings, including C11 and C++14. // // The C bindings also define a representation of fidl data types. For // a given type, the size and alignment of all parts of the type agree // with the wire format's representation. The C representation differs // in the representation of pointers to out-of-line allocations. On // the wire, allocations are encoded as either present or not. In C, // they are actual pointers. The C representation also places any // transferred handle types (including requests) inline. The wire // format tracks handles separately, just like the underlying channel // transport does. // // Turning the wire format into the C format is called decoding. // // Turning the C format into the wire format is called encoding. // // The formats are designed to allow for in-place coding, assuming all // out-of-line allocations placed are in traversal order (defined // below) with natural alignment. // Bounds. // Various fidl types, such as strings and vectors, may be bounded. If // no explicit bound is given, then FIDL_MAX_SIZE is implied. #define FIDL_MAX_SIZE UINT32_MAX // Out of line allocations. // The fidl wire format represents potential out-of-line allocations // (corresponding to actual pointer types in the C format) as // uintptr_t. For allocations that are actually present and that will // be patched up with pointers during decoding, the FIDL_ALLOC_PRESENT // value is used. For non-present nullable allocations, the // FIDL_ALLOC_ABSENT value is used. #define FIDL_ALLOC_PRESENT ((uintptr_t)UINTPTR_MAX) #define FIDL_ALLOC_ABSENT ((uintptr_t)0) // Out of line allocations are all 8 byte aligned. #define FIDL_ALIGNMENT ((size_t)8) #define FIDL_ALIGN(a) (((a) + 7) & ~7) #define FIDL_ALIGNDECL alignas(FIDL_ALIGNMENT) // An opaque struct representing the encoding of a particular fidl // type. typedef struct fidl_type fidl_type_t; // Primitive types. // Both on the wire and once deserialized, primitive fidl types // correspond directly to C types. There is no intermediate layer of // typedefs. For instance, fidl's float64 is generated as double. // All primitive types are non-nullable. // All primitive types are naturally sized and aligned on the wire. // fidl C Meaning. // --------------------------------------------- // bool bool A boolean. // int8 int8_t An 8 bit signed integer. // int16 int16_t A 16 bit signed integer. // int32 int32_t A 32 bit signed integer. // int64 int64_t A 64 bit signed integer. // uint8 uint8_t An 8 bit unsigned integer. // uint16 uint16_t A 16 bit unsigned integer. // uint32 uint32_t A 32 bit unsigned integer. // uint64 uint64_t A 64 bit unsigned integer. // float32 float A 32 bit IEEE-754 float. // float64 double A 64 bit IEEE-754 float. // Enums. // Fidl enums have an undering integer type (one of int8, int16, // int32, int64, uint8, uint16, uint32, or uint64). The wire format of // an enum and the C format of an enum are the same as the // corresponding primitive type. // String types. // Fidl strings are variable-length UTF-8 strings. Strings can be // nullable (string?) or nonnullable (string); if nullable, the null // string is distinct from the empty string. Strings can be bounded to // a fixed byte length (e.g. string:40? is a nullable string of at // most 40 bytes). // Strings are not guaranteed to be nul terminated. Strings can // contain embedded nuls throughout their length. // The fidl wire format dictates that strings are valid UTF-8. It is // up to clients to provide well-formed UTF-8 and servers to check for // it. Message encoding and decoding can, but does not by default, // perform this check. // All deserialized string types are represented by the fidl_string_t // structure. This structure consists of a size (in bytes) and a // pointer to an out-of-line allocation of uint8_t, guaranteed to be // at least as long as the length. // The bound on a string type is not present in the serialized format, // but is checked as part of validation. typedef struct fidl_string { // Number of UTF-8 code units (bytes), must be 0 if |data| is null. uint64_t size; // Pointer to UTF-8 code units (bytes) or null char* data; } fidl_string_t; // When encoded, an absent nullable string is represented as a // fidl_string_t with size 0 and FIDL_ALLOC_ABSENT data, with no // out-of-line allocation associated with it. A present string // (nullable or not) is represented as a fidl_string_t with some size // and with data equal to FIDL_ALLOC_PRESENT, which the decoding // process replaces with an actual pointer to the next out-of-line // allocation. // All string types: // fidl C Meaning // ----------------------------------------------------------------- // string fidl_string_t A string of arbitrary length. // string? fidl_string_t An optional string of arbitrary length. // string:N fidl_string_t A string up to N bytes long. // string:N? fidl_string_t An optional string up to N bytes long. // Arrays. // On the wire, an array of N objects of type T (array<T, N>) is // represented the same as N contiguous Ts. Equivalently, it is // represented the same as a nonnullable struct containing N fields // all of type T. // In C, this is just represented as a C array of the corresponding C // type. // Vector types. // Fidl vectors are variable-length arrays of a given type T. Vectors // can be nullable (vector<T>?) or nonnullable (vector<T>); if // nullable, the null vector is distinct from the empty // vector. Vectors can be bounded to a fixed element length // (e.g. vector<T>:40? is a nullable vector of at most 40 Ts). // All deserialized vector types are represented by the fidl_vector_t // structure. This structure consists of a count and a pointer to the // bytes. // The bound on a vector type is not present in the serialized format, // but is checked as part of validation. typedef struct fidl_vector { // Number of elements, must be 0 if |data| is null. uint64_t count; // Pointer to element data or null. void* data; } fidl_vector_t; // When encoded, an absent nullable vector is represented as a // fidl_vector_t with size 0 and FIDL_ALLOC_ABSENT data, with no // out-of-line allocation associated with it. A present vector // (nullable or not) is represented as a fidl_vector_t with some size // and with data equal to FIDL_ALLOC_PRESENT, which the decoding // process replaces with an actual pointer to the next out-of-line // allocation. // All vector types: // fidl C Meaning // -------------------------------------------------------------------------- // vector<T> fidl_vector_t A vector of T, of arbitrary length. // vector<T>? fidl_vector_t An optional vector of T, of arbitrary length. // vector<T>:N fidl_vector_t A vector of T, up to N elements. // vector<T>:N? fidl_vector_t An optional vector of T, up to N elements. // Handle types. // Handle types are encoded directly. Just like primitive types, there // is no fidl-specific handle type. Generated fidl structures simply // mention zx_handle_t. // Handle types are either nullable (handle?), or not (handle); and // either explicitly typed (e.g. handle<Channel> or handle<Job>), or // not. // All fidl handle types, regardless of subtype, are represented as // zx_handle_t. The encoding tables do know the handle subtypes, // however, for clients which wish to perform explicit checking. // The following are the possible handle subtypes. // process // thread // vmo // channel // event // port // interrupt // iomap // pci // log // socket // resource // eventpair // job // vmar // fifo // hypervisor // guest // timer // All handle types are 4 byte sized and aligned on the wire. // When encoded, absent nullable handles are represented as // FIDL_HANDLE_ABSENT. Present handles, whether nullable or not, are // represented as FIDL_HANDLE_PRESENT, which the decoding process will // overwrite with the next handle value in the channel message. #define FIDL_HANDLE_ABSENT ((zx_handle_t)ZX_HANDLE_INVALID) #define FIDL_HANDLE_PRESENT ((zx_handle_t)UINT32_MAX) // fidl C Meaning // ------------------------------------------------------------------ // handle zx_handle_t Any valid handle. // handle? zx_handle_t Any valid handle, or ZX_HANDLE_INVALID. // handle<T> zx_handle_t Any valid T handle. // handle<T>? zx_handle_t Any valid T handle, or ZX_HANDLE_INVALID. // Unions. // Fidl unions are a tagged sum type. The tag is a 4 bytes. For every // union type, the fidl compiler generates an enum representing the // different variants of the enum. This is followed, in C and on the // wire, by large enough and aligned enough storage for all members of // the union. // Unions may be nullable. Nullable unions are represented as a // pointer to an out of line allocation of tag-and-member. As with // other out-of-line allocations, ones present on the wire take the // value FIDL_ALLOC_PRESENT and those that are not are represented by // FIDL_ALLOC_NULL. Nonnullable unions are represented inline as a // tag-and-member. // For each fidl union type, a corresponding C type is generated. They // are all structs consisting of a fidl_union_tag_t discriminant, // followed by an anonymous union of all the union members. typedef uint32_t fidl_union_tag_t; // fidl C Meaning // -------------------------------------------------------------------- // union foo {...} struct union_foo { An inline union. // fidl_union_tag_t tag; // union {...}; // } // // union foo {...}? struct union_foo* A pointer to a // union_foo, or else // FIDL_ALLOC_ABSENT. // Messages. // All fidl messages share a common 16 byte header. typedef struct fidl_message_header { zx_txid_t txid; // This reserved word is used by Epitaphs to represent an error value. uint32_t reserved0; uint32_t flags; uint32_t ordinal; } fidl_message_header_t; // Messages which do not have a response use zero as a special // transaction id. #define FIDL_TXID_NO_RESPONSE 0ul // The system reserves the high half of the ordinal space. #define FIDL_ORD_SYSTEM_MASK 0x80000000ul // A FIDL message. typedef struct fidl_msg { // The bytes of the message. // // The bytes of the message might be in the encoded or decoded form. // Functions that take a |fidl_msg_t| as an argument should document whether // the expect encoded or decoded messages. // // See |num_bytes| for the number of bytes in the message. void* bytes; // The handles of the message. // // See |num_bytes| for the number of bytes in the message. zx_handle_t* handles; // The number of bytes in |bytes|. uint32_t num_bytes; // The number of handles in |handles|. uint32_t num_handles; } fidl_msg_t; // An outstanding FIDL transaction. typedef struct fidl_txn fidl_txn_t; struct fidl_txn { // Replies to the outstanding request and complete the FIDL transaction. // // Pass the |fidl_txn_t| object itself as the first parameter. The |msg| // should already be encoded. This function always consumes any handles // present in |msg|. // // Call |reply| only once for each |txn| object. After |reply| returns, the // |txn| object is considered invalid and might have been freed or reused // for another purpose. zx_status_t (*reply)(fidl_txn_t* txn, const fidl_msg_t* msg); }; // An epitaph is a message that a server sends just prior to closing the // connection. It provides an indication of why the connection is being closed. // Epitaphs are defined in the FIDL wire format specification. Once sent down // the wire, the channel should be closed. typedef struct fidl_epitaph { FIDL_ALIGNDECL // The error associated with this epitaph is stored in the reserved word of // the message header. System errors must be constants of type zx_status_t, // which are all negative. Positive numbers should be used for application // errors. A value of ZX_OK indicates no error. fidl_message_header_t hdr; } fidl_epitaph_t; // This ordinal value is reserved for Epitaphs. #define FIDL_EPITAPH_ORDINAL 0xFFFFFFFF // Assumptions. // Ensure that FIDL_ALIGNMENT is sufficient. static_assert(alignof(bool) <= FIDL_ALIGNMENT, ""); static_assert(alignof(int8_t) <= FIDL_ALIGNMENT, ""); static_assert(alignof(int16_t) <= FIDL_ALIGNMENT, ""); static_assert(alignof(int32_t) <= FIDL_ALIGNMENT, ""); static_assert(alignof(int64_t) <= FIDL_ALIGNMENT, ""); static_assert(alignof(uint8_t) <= FIDL_ALIGNMENT, ""); static_assert(alignof(uint16_t) <= FIDL_ALIGNMENT, ""); static_assert(alignof(uint32_t) <= FIDL_ALIGNMENT, ""); static_assert(alignof(uint64_t) <= FIDL_ALIGNMENT, ""); static_assert(alignof(float) <= FIDL_ALIGNMENT, ""); static_assert(alignof(double) <= FIDL_ALIGNMENT, ""); static_assert(alignof(void*) <= FIDL_ALIGNMENT, ""); static_assert(alignof(fidl_union_tag_t) <= FIDL_ALIGNMENT, ""); static_assert(alignof(fidl_message_header_t) <= FIDL_ALIGNMENT, ""); __END_CDECLS #endif // ZIRCON_FIDL_H_