| // Copyright 2022 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. |
| @available(added=HEAD) |
| library fuchsia.starnix.binder; |
| |
| using zx; |
| using fuchsia.io; |
| using fuchsia.posix; |
| using fuchsia.unknown; |
| |
| const MAX_PATH_LENGTH uint64 = 4095; |
| const MAX_REQUEST_COUNT uint64 = 16; |
| const MAX_FILE_HANDLE_COUNT uint64 = 16; |
| const MAX_IOCTL_WRITE_COUNT uint64 = 16; |
| const MAX_WRITE_BYTES uint64 = 32768; |
| |
| alias Fd = int32; |
| |
| /// The flags associated with an opened file. |
| type FileFlags = flexible bits : uint64 { |
| // Permissions |
| /// The owner can read the file. |
| RIGHT_READABLE = 0b1; |
| /// The owner can write to fhe file. |
| RIGHT_WRITABLE = 0b10; |
| // Skipping bits for exec and suid bits and for group and other mode if |
| // they are needed in the future. |
| |
| // File type |
| /// The file is a directory. |
| DIRECTORY = 0b1000000000000; |
| }; |
| |
| /// The representation of an open file that can be transferred between the |
| /// binder device driver and the client. |
| type FileHandle = resource table { |
| /// The handle connecting to the file protocol. If not present, the file |
| /// should behave as it is was a null file: all read must succeed with empty |
| /// content and all write must succeed. See `fdio_fd_create_null()`. |
| 1: file zx.Handle; |
| |
| /// The flags associated with the opened file. |
| 3: flags FileFlags; |
| |
| /// Optional. The file descriptor to help with translation between processes. |
| 4: fd Fd; |
| }; |
| |
| /// Protocol that gives the binder driver access to the client process' |
| /// resources. |
| open protocol ProcessAccessor { |
| /// Writes the contents of `content` to `address` in the process memory, |
| /// using the vmo content size to determine the number of bytes to write. |
| flexible WriteMemory(resource struct { |
| address uint64; |
| content zx.Handle:VMO; |
| }) -> () error fuchsia.posix.Errno; |
| |
| /// Writes the contents of `bytes` to `address` in the process memory. |
| /// `WriteBytes` is functionally equivalent to `WriteMemory`, but is |
| /// optimized for small writes of less than `MAX_WRITE_BYTES`. |
| flexible WriteBytes(resource struct { |
| address uint64; |
| bytes vector<uint8>:MAX_WRITE_BYTES; |
| }) -> () error fuchsia.posix.Errno; |
| |
| /// Execute the given `request` and returns the associated `response`. Any |
| /// failure will interrupt further processing and fail this operation and |
| /// the associated errno will be then returned. |
| /// The implementator of this protocol should handle these requests as best |
| /// it can so that a failure doesn't have visible side-effects. |
| flexible FileRequest(@generated_name("FileRequest") resource table { |
| /// The list of file descriptor the client must close. |
| 1: close_requests vector<Fd>:MAX_REQUEST_COUNT; |
| /// The list of file descriptor the client must duplicate and transfer to |
| /// the binder driver. |
| 2: get_requests vector<Fd>:MAX_REQUEST_COUNT; |
| /// The list of open file the client must add to its fd table, returning |
| /// the new minted file descriptors. |
| 3: add_requests vector<FileHandle>:MAX_REQUEST_COUNT; |
| }) -> (@generated_name("FileResponse") resource table { |
| // (No ordinal 1 since there is no response for the close operation.) |
| /// The list of open file retriever for the `get_requests`. |
| 2: get_responses vector<FileHandle>:MAX_REQUEST_COUNT; |
| /// The list of file descriptors minted for the `add_requests`. |
| 3: add_responses vector<Fd>:MAX_REQUEST_COUNT; |
| }) error fuchsia.posix.Errno; |
| }; |
| |
| /// Give access to the binder nodes. |
| @discoverable |
| open protocol DevBinder { |
| /// Open the binder device node. |
| flexible Open(resource table { |
| /// The path to the binder device in the starnix process. |
| /// Mandatory |
| 1: path vector<uint8>:MAX_PATH_LENGTH; |
| |
| /// The service giving the binder driver access to the resources of the client process. |
| 2: process_accessor client_end:ProcessAccessor; |
| |
| /// The handle to the process that will use the binder driver. It is |
| /// used by the driver to read the data sent to the driver. |
| /// Mandatory |
| 3: process zx.Handle:PROCESS; |
| |
| /// The request to the Binder protocol implementation. |
| /// Mandatory |
| 4: binder server_end:Binder; |
| }); |
| |
| /// Close the binder device node, previously opened with `Open`. The handle |
| /// is passed back to the service so that it can identify the device being |
| /// closed. |
| flexible Close(resource table { |
| /// The Binder protocol opened previously. |
| 1: binder client_end:Binder; |
| }); |
| }; |
| |
| |
| /// Protocol that allows a binder server to request changes to the container's power state. |
| @discoverable |
| open protocol ContainerPowerController { |
| /// This requests that the container wakes up to service requests. |
| flexible Wake(resource table { |
| /// (Optional): This represents a wake lease that the binder server has. |
| /// The container will ensure that this wake lease will be kept alive until |
| /// The container takes its wake lease. |
| 1: power_baton zx.Handle; |
| |
| /// (Optional): This creates a wake lock associated with this event pair. |
| /// The container will not go back to sleep until the other end of this event pair has been |
| /// closed. |
| /// If this does not exist, then the container can sleep when it chooses after handling the |
| /// Wake call. |
| /// |
| /// The container will signal the pair of wake_lock with USER_0 when the lock has been created |
| /// in the kernel. |
| 2: wake_lock zx.Handle:EVENTPAIR; |
| }); |
| |
| /// Registers an eventpair that will be signaled when the container is suspended or resumed. |
| /// The signals are ASLEEP(USER_1) and AWAKE(USER_0). |
| /// |
| /// The kernel returns AWAKE upon initial registration of the eventpair. |
| flexible RegisterWakeWatcher(resource table { |
| 1: watcher zx.Handle:EVENTPAIR; |
| }) -> (); |
| }; |
| |
| /// Protocol that allows Starnix to control binder servers and clients in other |
| /// Fuchsia components. |
| @discoverable |
| open protocol RemoteController { |
| /// Called by the Starnix kernel when it requires the remote Fuchsia |
| /// component to start servicing the binder protocol. |
| flexible Start(resource table { |
| 1: dev_binder client_end:DevBinder; |
| 2: lutex_controller client_end:LutexController; |
| 3: container_power_controller client_end:ContainerPowerController; |
| }); |
| }; |
| |
| /// Protocol that allows a Fuchsia component to interact with the Linux futexes |
| /// of a process running inside starnix. |
| @discoverable |
| open protocol LutexController { |
| /// FUTEX_WAIT_BITSET command |
| flexible WaitBitset(@generated_name("WaitBitsetRequest") resource table { |
| /// The vmo containing the shared address of the futex. |
| /// Mandatory |
| 1: vmo zx.Handle:VMO; |
| /// The offset in the vmo where the shared address of the futex is. |
| /// Mandatory |
| 2: offset uint64; |
| /// The expected value of the futex. |
| /// Mandatory |
| 3: value uint32; |
| /// The bit mask. |
| /// Optional. If not present, as mask with all bits present will be used. |
| 4: mask uint32; |
| /// The deadline for the wait operation. |
| /// Optional. If not present, the operation can block indefinitely. |
| 5: deadline zx.Time; |
| }) -> () error fuchsia.posix.Errno; |
| |
| /// FUTEX_WAKE_BITSET command |
| flexible WakeBitset(@generated_name("WakeBitsetRequest") resource table { |
| /// The vmo containing the shared address of the futex. |
| /// Mandatory |
| 1: vmo zx.Handle:VMO; |
| /// The offset in the vmo where the shared address of the futex is. |
| /// Mandatory |
| 2: offset uint64; |
| /// Maximum number of waiter to wake. |
| /// Mandatory |
| 3: count uint32; |
| /// The bit mask. |
| /// Optional. If not present, as mask with all bits present will be used. |
| 4: mask uint32; |
| }) -> (@generated_name("WakeResponse") resource table { |
| /// The number of waiters that were woken up. |
| 1: count uint64; |
| }) error fuchsia.posix.Errno; |
| }; |
| |
| /// The location and size of writes required after a call to an ioctl. |
| type IoctlWrite = struct { |
| /// Address in the process to write to. |
| address uint64; |
| /// Offset into the VMO from where to read. |
| offset uint64; |
| /// Length of the write within the VMO. |
| length uint64; |
| }; |
| |
| /// An opened connection to a binder driver. |
| open protocol Binder { |
| /// Set the VMO to used as a share resource between the driver and the |
| /// client. `mapped_address` is the address where the vmo is mapped in the |
| /// client address space. |
| flexible SetVmo(resource struct { |
| vmo zx.Handle:VMO; |
| mapped_address uint64; |
| }); |
| /// Processes a Binder ioctl. This message returns writes for the calling thread |
| /// that must be processed to correctly handle the ioctl. |
| flexible Ioctl(resource struct { |
| /// Thread ID for the thread calling the ioctl. |
| tid zx.Koid; |
| /// The ioctl being called. |
| request uint32; |
| /// Optional argument for the ioctl. |
| arg uint64; |
| /// The VMO to return writes for this ioctl through. |
| vmo zx.Handle:VMO; |
| /// The files being transfered by the ioctl. |
| files vector<FileHandle>:MAX_FILE_HANDLE_COUNT; |
| }) -> (struct { |
| ioctl_writes vector<IoctlWrite>:MAX_IOCTL_WRITE_COUNT; |
| }) error fuchsia.posix.Errno; |
| }; |
| |
| // The maximum number of handles that is allowed for read/write operations. |
| const MAX_HANDLE_COUNT uint64 = 8; |
| |
| /// The flags when reading from an unix domain socket |
| type ReadFlags = flexible bits : uint64 { |
| /// When set, the data must not be removed from the queue and the next read |
| /// must resend the same data. |
| PEEK = 0b1; |
| }; |
| |
| /// A Unix Domain Socket |
| /// |
| /// This protocol is used to implement a unix domain socket in a Fuchsia |
| /// Component that will be able to communicate with a socket in Starnix. That |
| /// socket will be able to transmit file descriptors. |
| @discoverable |
| open protocol UnixDomainSocket { |
| compose fuchsia.unknown.Cloneable; |
| compose fuchsia.unknown.Closeable; |
| compose fuchsia.unknown.Queryable; |
| |
| /// Returns an EventPair that will allow Starnix to wait on the socket. This event must use: |
| /// - `fio.FileSignal.READABLE` to signal that a message is available. |
| /// - `fio.FileSignal.WRITABLE` to signal that it can accept a new message. |
| /// - `ZX_EVENTPAIR_PEER_CLOSED` to signal that it is closed. |
| flexible GetEvent(table {}) -> (resource table { |
| 1: event zx.Handle:<EVENTPAIR, zx.Rights.TRANSFER | zx.Rights.SIGNAL | zx.Rights.WAIT>; |
| }) error zx.Status; |
| |
| /// Read a message from the socket. |
| flexible Read(table { |
| 1: count uint64; |
| 2: flags ReadFlags; |
| }) -> (resource table { |
| 1: data fuchsia.io.Transfer; |
| 2: data_original_length uint64; |
| 3: handles vector<zx.Handle>:MAX_HANDLE_COUNT; |
| }) error zx.Status; |
| |
| /// Write a message to the socket. |
| flexible Write(resource table { |
| 1: data fuchsia.io.Transfer; |
| 2: handles vector<zx.Handle>:MAX_HANDLE_COUNT; |
| }) -> (table { |
| 1: actual_count uint64; |
| }) error zx.Status; |
| }; |