Base API

Core services

Physical memory

The RAM service provides access to physical memory. Each RAM session corresponds to a memory pool with a bounded quota. From this pool, the RAM-session client can allocate memory blocks in the form of dataspaces.

Read-only memory modules

The ROM service provides access to boot-time present binary files such as files loaded by the boot loader or files contained in a non-volatile ROM area. Each ROM session corresponds to an open file. The file's content is made available to the client as a read-only dataspace.

Address-space-layout managment

The region-manager (RM) service manages address-space layouts. A RM session corresponds to an address space layout into which dataspaces can be placed. Hence, a RM session populated with dataspaces provides a generic abstraction for a physical page table referencing memory pages.

Protection domains

The protection-domain (PD) service enables the creation of address spaces that are isolated from each other. Each PD session corresponds to a protection domain. The PD services is rarely used by applications directly. Instead, Genode's process-creation framework uses this service internally.

CPU

The CPU service provides a facility for creating and managing threads. A CPU session corresponds to a CPU time allocator from which multiple threads can be allocated.

Communication endpoints

The capability (CAP) service enables the creation of globally unique object identities (capabilities). Once allocated from a CAP session, a capability can be associated with a local object. A capability can be passed to another protection domain via an inter-process communication (IPC) call whereby the receiving protection domain obtains the right to send messages to the associated object.

Device access

Interrupts

The IRQ service enables user-level device drivers to serve device interrupts. Each IRQ session corresponds to an associated interrupt line.

Memory-mapped I/O

The IO_MEM service enables user-level device drivers to obtain memory-mapped device resources as dataspaces. Each IO_MEM session corresponds to the reservation of a physical address range for which a dataspace is provided to the client. The user-level device driver can make the device resource visible in its address space by attaching the dataspace to its own RM session.

Port I/O

The IO_PORT service provides access to device IO-ports via an RPC interface. Each IO_PORT session corresponds to the access right to a port range.

Debug output

For low-level debugging, core provides a simple LOG service, which enables clients to print textual messages. In the LOG output, each message is tagged with the label of the corresponding client.

Runtime environment

Initial execution environment

A process is a composition of a protection domain (PD session), a memory pool (RAM session), an address-space layout (RM session), and a CPU session from which the main thread is created. These sessions form the environment of the process, which is represented by the Env class:

In addition to the process' initial sessions, the environment contains the heap of the process. The heap can be used for anonymous memory allocation and is front end for allocating RAM dataspaces from the process' RAM session and attaching these dataspaces to the process' RM session. By default, the process environment holds one initial LOG session used as standard text-output facility. For debugging purposes, there exists a printf front end for writing text to the initial LOG session.

Interaction with the outside world

At creation time, the only communication partner of a process is its immediate parent process, which provides the following interface:

Data types and structures

Basic data types

Genode provides common integer types in its namespace. Integer types that can be derived from built-in compiler types are defined in:

In addition, there exist definitions for fixed-width integer types. For 32-bit platforms, those are defined in:

Genode facilitates the use of exceptions to signal errors but it uses exception types only as textual expression of error code and for grouping errors. Normally, exceptions do not carry payload. For code consistency, exception types should inherit from the Exception base class.

For parsing structured text such as argument strings or XML, Genode provides simple tokenizing support via the Token class.

Structured data types

Most book-keeping tasks in Genode rely in single-connected lists, which use the List template.

For use cases where associative arrays are needed such as allocators and object pools, Genode relies on AVL trees. Furthermore, there exists a specialized version of the AVL tree for managing pools of strings. Because the List data type inserts new list elements at the list head, it cannot be used for implementing wait queues requiring first-in-first-out semantics. For such use cases, there exists a dedicated Fifo template.

Argument strings

Genode uses comma-separated sequences of tag=value assignments for specifying session-construction arguments. The Arg_string provides an interface for extracting individual values from argument strings and for argument-string manipulation.

Allocators

All allocators implement the generic Allocator interface. Allocators that operate on address ranges supplement the plain Allocator by implementing the more specific Range_allocator interface.

The Slab allocator is tailored for allocating small fixed-size memory blocks from a big chunk of memory. For the common use case of using slab allocation for a certain type rather than for a known byte-size, there exists a typed slab allocator as a front-end of Slab. In contrast to the rather limited slab allocators, Allocator_avl allows for arbitrary allocations from a list of address regions. It implements a best-fit allocation strategy, supports arbitrary alignments, and allocations at specified addresses. For safely using range allocators from multiple threads, synchronized versions of range-allocator implementations can be constructed with the help of the following template:

Inter-process communication

Remote procedure calls

Capability representation

Inter-process communication on Genode is based on capabilities. A capability is a system-wide unique object identity that can be passed between processes. On kernels with support for local names, a capability may have a different name in each process but still refer to the same object. The representation of a capability as a communication endpoint depends on the underlying kernel.

On Linux, a capability is a tuple of a port number and a globally unique object ID:

A plain capability is an untyped reference to a remote object of any type. To facilitate the type-safe use of RPC interfaces at the C++ language level, there exists a template for creating specialized capability types. By convention, each RPC interface introduces a corresponding capability type to be used for invoking the interface.

RPC marshalling and message transfer

Genode provides mechanisms for implementing remote procedure calls (RPC). The interaction between the client (the caller) and the server (callee) consists of the following steps:

  1. Client marshals arguments to form a message. The first part of the message is a function opcode.

  2. Client sends message via the kernel to the server and blocks for the result.

  3. Server dispatches request according to the opcode stored in the message.

  4. Server unmarshalls function arguments,

  5. Server executes the function,

  6. Server marshals the produced results.

  7. Server sends result message to the client.

  8. Client unmarshals results.

When following this scheme, both communication partners require a receive buffer and a send buffer. Because the message buffer contains the payload copied by the underlying kernel, the message buffer is platform dependent.

On Linux, the message buffer gets transfered via read and write. Therefore, it is just a plain memory buffer:

On L4/Fiasco and L4ka::Pistachio, the message buffer gets transfered via an optimized kernel IPC call, which requires a special message-buffer layouts:

The message buffer has no public interface but it is operated on via the Ipc_marshaller and Ipc_unmarshaller classes, which provide stream operators for inserting and extracting data to/from a message buffer. The role of the client and server are modelled by the classes Ipc_client and Ipc_server.

Note: The stream operators are missing in the documentation.

Asynchronous notifications

Inter-process communication via remote procedure calls requires both communication partners to operate in a synchronous fashion. The signalling framework complements the synchronous RPC mode of communication with an interface for issuing and receiving asynchronous notifications.

It defines interfaces for signal transmitters and signal receivers. A signal receiver can receive signals from multiple sources, whereas the sources of incoming signals are distinguishable. One or multiple threads can either poll or block for incoming signals. Each signal receiver is addressable via a capability. The signal transmitter provides fire-and-forget semantics for submitting signals to exactly one signal receiver. Signals are communicated in a reliable fashion, which means that the exact number of signals submitted to a signal transmitter is communicated to the corresponding signal receiver. Signals serve as raw notifications and cannot carry any payload.

Shared memory

Genode supports shared memory between multiple processes using dataspaces. Dataspaces are memory containers as provided by core's RAM, IO_MEM, or ROM services. Each dataspace is referenced by a capability that can be passed among multiple processes. Each process with the capability to a dataspace can access the dataspace's content by attaching the dataspace to its RM session. In addition to be used as arguments for RM-session calls, dataspaces provide the following interface:

Client-server framework

Server-object handling

The server-object framework extends Genode's RPC mechanism with the abstraction of a remotely invokable object (server object).

To be able to handle incoming remote object calls, the class of a local object must be inherited from Server_object and provide a dispatch function that matches the remotely accessible object interface. A server object becomes remotely accessible after registering it at an Server_entrypoint. A server entrypoint is a pool (Object_pool) of an arbitrary number of server objects of arbitrary types and it uses the processing time and stack provided by a Server_activation to process incoming object requests.

Server sessions

In the Genode architecture, servers provide their services over session-based communication channels. Each service type is represented as a server object implementing the root interface. The server announces its service type by providing the service name and the capability of the service's root interface (announce function of the parent interface). Via the capability to the root interface, the parent is then able to create and destroy sessions.

Because defining root interfaces for services follows a recurring pattern, there exists a default template that implements the standard behaviour of the root interface (Root_component).

Connecting to services

The interaction of a client with a server involves the definition of session-construction arguments, the request of the session creation via its parent, the initialization of the matching RPC-client stub code with the received session capability, the actual use of the session interface, and the closure of the session. The Connection template provides a way to greatly simplify the handling of session arguments, session creation, and destruction on the client side. By implementing a service-specific connection class inherited from Connection, session arguments become plain constructor arguments, session functions can be called directly on the Connection object, and the session gets properly closed when destructing the Connection.

Threads and synchronization

Threads

On Genode, a thread is created by constructing an object of a class inherited from Thread. The new thread starts execution at the entry member function. With this design, each thread runs in the context of its object and can access context-specific information by accessing its member variables. Threads use a statically allocated stack, which is dimensioned as specified via a template argument.

There exists no timed sleep function in the Genode base framework. Timed sleep is rather be provided by a server implementing a timer-device driver. However, the special case of infinite blocking is covered by the following base API function. Genode allows all blocking operations of threads to be canceled via a cancel_blocking mechanism provided by core's CPU service. The cancellation of a blocking operation is reflected at the API level by a raised exception of the type Blocking_canceled.

Synchronization

For mutual exclusive execution of critical sections, there exists a simple lock interface providing lock and unlock semantics. The lock comes in two flavours. Cancelable locks can be unblocked by force via core's cancel-blocking mechanism. In contrast, a non-cancelable lock (Lock) does not reflect the cancellation of its blocking operation at the API level but transparently re-enters its blocking state after a cancellation.

For the use case of using locks for protecting critical sections, the Lock_guard provides a convenient mechanism for the automated unlocking of a lock when leaving a variable scope. Alongside lock-based mutual exclusion of entering critical sections, organizing threads in a producer-consumer relationship is a common design pattern for thread synchronization. The Semaphore interface enables the implementation of this synchronization scheme.

Child management

Child policy

For processes that manage a number of child processes, each child process is represented by an instance of the Child class. This instance contains the policy to be applied to the child (for example how session requests are routed to services) and contains the child's execution environment including the RAM session holding the child's memory quota.

The Service_pool classes support the management of services announced by children or provided locally, and the synchronization of service requests with service announcements.

Process creation

Utilities

Basic functions for handling strings and integers

ELF binary parser

Format-string handling

Document Actions