L4Re - L4 Runtime Environment
This environment comprises a set of capabilities to initial L4Re objects that are required to bootstrap and run this application. These capabilities include:
During the bootstrapping of the application, the loader establishes data spaces for each individual region in the ELF binary. These include data spaces for the code and data sections, and a data space backed with RAM for the stack of the program's first thread.
One loader implementation is the
moe root task. Moe usually starts an init process that is responsible for coordinating the further boot process. The default init process is
ned, which implements a script-based configuration and startup of other processes. Ned uses Lua (http://www.lua.org) as its scripting language, see Ned Script example for more details.
The default L4Re init process (Ned) provides a Lua script based configuration of initial capabilities and application startup. Ned itself also has a set of initial objects available that can be used to create the environment for an application. The most important object is a kernel object factory that allows creation of kernel objects such as IPC gates (communication channels), tasks, threads, etc. Ned uses Lua tables (associative arrays) to represent sets of capabilities that shall be granted to application processes.
The L4 Lua package in Ned also has support functions to create application tasks, region-map objects, etc. to start an ELF binary in a new task. The package also contains Lua bindings for basic L4Re objects, for example, to generic factory objects, which are used to create kernel objects and also user-level objects provided by user-level servers.
In general, a connection between a client and a server is represented by a communication channel (IPC gate). That is available to the client and the server. You can see the simplest connection between a client and a server in the following example.
As you can see in the snippet, the first action is to create a new channel (IPC gate) using
loader:new_channel(). The capability to the gate is stored in the variable
svc. Then the binary
my_server is started in a new task, and full (
:full()) access to the IPC gate is granted to the server as initial object. The gate is accessible to the server application as "service" in the set of its initial capabilities. Virtually in parallel a second task, running the client application, is started and also given access to the IPC gate with less rights (
:m("rw"), note, this is essential). The server can now receive messages via the IPC gate and provide some service and the client can call operations on the IPC gate to communicate with the server.
Services that keep client specific state need to implement per-client server objects. Usually it is the responsibility of some authority (e.g., Ned) to request such an object from the service via a generic factory object that the service provides initially.
This example is quite similar to the first one, however, the difference is that Ned itself calls the create method on the factory object provided by the server and passes the returned capability of that request as "foo_service" to the client process.
svc:create(..)call blocks on the server. This means the script execution blocks until the my-service application handles the create request.