genode/doc/release_notes/12-05.txt
Norman Feske 98211db63d doc: move release notes to sub directory
This keeps the doc/ directory tidy and neat.
2020-11-27 09:19:09 +01:00

1030 lines
51 KiB
Plaintext

===============================================
Release notes for the Genode OS Framework 12.05
===============================================
Genode Labs
The best way to characterize version 12.05 of the Genode OS Framework is to
dub it as feature release. Among the numerous additions of new functionality
are a new USB stack, media replay capabilities, and the ability to run the GNU
tool chain including GCC, G++, Binutils, and GNU Make directly on Genode. That
said, the current release is not short of architectural improvements either.
The highlights are the introduction of Genode's file-system infrastructure and
a new concept for the dynamic adjustment of the system's behaviour at runtime.
The release follows the rough plan we laid out in our
[https://genode.org/about/road-map - road map]. One planned road-map item was
revisiting our base of device drivers as we realized that some important
drivers were not on par with our requirements, the USB stack being the most
important example. Our prior existing solution was originally ported from Linux
2.6.20. It is needless to say that this version is severely limited when it comes
to the use of modern hardware. Instead of continuing to walk the path of the
existing solution, we took the chance to fundamentally re-approach the problem
of porting a complex driver subsystem from the Linux kernel. We are happy to
have found a new methodology that promises to become a much more sustainable
solution for Genode. The rationale behind the new development is described in
detail in section [Re-approaching the Linux device-driver environment].
The second major road-map item refers to the Noux runtime environment, which
enables us to run a growing number of unmodified GNU programs natively on
Genode. The abilities of Noux have taken a giant leap forward. The two most
significant improvements are the support of stacked file systems and networking
support. With those in place, we have become able to run most parts of the
Genode tool chain including GCC, G++, Binutils, and GNU Make via Noux. Thanks
to the added networking support, we are able to use basic networking tools such
as netcat as well.
The third topic according to the road map is file-system support. Version 12.05
contains the groundwork for this domain. The foundation is the new file-system
session interface. A first implementation of this interface is available in the
form of an in-memory file system. To enable the use of Genode's file-system
facilities by applications, we added support to the C runtime as well as to
Noux.
In addition to the features planned according to our road map, there are many
new functionalities and improvements. To name a few: By enhancing the existing
configuration concept described in section [System reconfiguration at runtime],
we principally enable components to respond to configuration adjustments
on-the-fly, which clears the way for elegantly solving many problems typical
for general-purpose computing. The port of libav accompanied with profound
changes of our version of libSDL enables us to replay media data. The Fiasco.OC
base platform has received a lot of attention to fully leverage the kernel's
capability concept. Last but not least, the port of Lua interpreter allows for
using this popular scripting language on Genode.
The release of version 12.05 is accompanied with a slightly updated road map.
The persistent storage topic has been traded for our media player because the
former one naturally builds upon the just recently added file-system interface.
Furthermore, we decided to defer the live CD until July as we realized that we
first need to overhaul low-level components such as USB before the new live
system can be expected to work as intended. Also, some of the scenarios we want
to present depend on framework features just introduced with the current release,
in particular the file-system infrastructure and the media capabilities.
Re-approaching the Linux device-driver environment
##################################################
User-level device drivers are a never-ending quest for microkernel-based
systems. The two most extreme approaches are the development of a custom driver
base developed from scratch, or the use of a virtualized OS as donor of
device-drivers. An example of the former approach is the HelenOS project, which
aspires to conduct the development of all needed device drivers within the
project. The latter approach also known as device-driver OS is domesticated by
NUL (NOVA userland) for networking drivers and the L4Re (Fiasco.OC userland).
For Genode, neither of both extremes seems to be viable. For the sake of
argumentation, let's consider USB support as an example. We deem the
development of a new USB stack from scratch as a far too elaborative
undertaking, in particular when looking at the functionality we desire. The
feature set of HelenOS's custom-built USB stack is quite illustrative. It
supports HID and USB storage, yet no high-speed devices, nor even more
sophisticated features such as USB 3.0. On the other hand, using the
device-driver OS approach just for providing USB support is unfortunate when
considering that even the most basic devices such as keyboard and mouse depend
on a working USB stack. We would pull in a complete OS kernel (donor kernel)
just for the sake of handling user input. Furthermore device drivers do not
come for free even when using an unmodified donor kernel. Integrating the
donor kernel with the remaining Genode system requires glue code interacting
with the donor kernel. This code would translate driver API calls to Genode
RPC interfaces. Even more importantly for us, the use of a device-driver OS
requires a base platform with support for virtualization. But there is no
virtualization solution that works across all of Genode's base platforms. Quite
the contrary. We experience that each virtualization solution such as L4Linux,
OKLinux, or Vancouver, is largely tied to a particular kernel (Fiasco.OC, OKL4,
or NOVA respectively). Therefore the device-driver OS approach defeats Genode's
inter-kernel portability. Even if we had a portable virtualization solution at
hand, we still would have the problem that for providing the device-driver
service, we need to trust the donor kernel to a certain degree. If the driver
uses DMA, the whole donor kernel must be trusted not to misuse DMA. Even though
IOMMUs are apparently able to relief the problem, they are far from being a
magic bullet for solving it.
Fortunately, there is a middle-ground to walk on namely porting device drivers
from a "donor OS". We have come a long way to bring the porting work of device
drivers to (a certain level of) perfection. The current release bears the fruit
of our latest achievement in this respect. Let us summarize the long-winded
travel through device-driver porting land that we had so far:
The naive way is to identify the driver code in the source code of the donor
OS, copying it over and massaging it until it works well in the new
environment. There are two fundamental problems with this way of porting.
First, there is a high likelihood to insert new bugs in the process of
modifying the imported 3rd-party code. But more importantly, each update of the
driver to a new version requires the developer to revisit the modifications.
In many cases, the rationale behind certain changes gets lost over time. The
consequence is that updating drivers becomes a largely dissatisfying kind of
work for which there is always a good excuse to not take it on.
To limit the trouble of maintaining 3rd-party drivers, the number-one rule
is to not modify 3rd-party driver code. The much better alternative is
to embed the unmodified driver into a so-called device-driver environment.
(DDE). From the driver's perspective, a DDE looks identical to the
donor OS. But the DDE makes the driver talk to custom glue code instead of
interacting with the donor OS kernel. This raises the question of how to
create a maintainable DDE. The first attempts to create a DDE for Linux
device drivers came down to a mix of reimplementing some of the Linux
APIs, taking some other portions of the Linux kernel as is, and modifying
some Linux headers to a certain degree. Each of those categories has its
own set of problems. By reimplementing Linux APIs, one risks to introduce bugs
by not implementing the exact behaviour as the Linux kernel. Because most Linux
APIs have no clear specification other than the kernel code, it is sometimes
hard to capture all semantic details. The problem of introducing bugs can be
alleviated by reusing original code wherever possible. For example, instead of
providing custom memory allocators, it is tempting to just reuse the Linux slab
implementation. The downside of reusing existing code is, however, that such
code tends to depend on further kernel code. Pulling-in the transitive
dependencies leads to more dependencies etc. The temptation of just continuing
to add more and more unmodified kernel code into the DDE can easily go out of
hand. One way to cut out such undesired dependencies is to slightly modify
(parts of) the kernel code. Unfortunately, the category of slightly modified
code usually turns out to become an ongoing maintenance burden. The bottom line
is that finding the right mix of reimplementation, slight modification, and
reuse is a matter of sure instinct of the DDE developer.
Another way to put it is defining the problem as the search in an optimization
space for the economically most sensible solution. The optimization criterion we
set out to maximize is the ratio of feature code (the actual driver, no DDE nor
glue) to the number of lines of code that must be manually maintained. To give
the order of magnitude of the code we speak of, the traditional Linux DDE
including the support for NIC, USB, and sound is comprised of more than 350.000
lines of code. The portion of modified or custom written code (code that must be
manually maintained) is more than 40.000 lines of code. Given this complexity,
we found us hesitant to update the code to newer kernel versions. The
engineering labour of such an update is significant yet not much of a rewarding
work. Apart from the burden of managing a piece of software that complex, our
confidence in the classical Linux DDE approach slipped further with each
debugging session that involved Linux DDE. In our experience, Linux DDE still
significantly deviates from the semantics of the Linux kernel but in subtle
ways. Often problems go unnoticed until a driver uses a kernel API in a
slightly unusual way. For example, a driver calling 'udelay()' from the interrupt
handler. The sheer complexity of the code base can make tracking down such issues
a painful experience. This is further amplified by the existence of certain
invariants provided by the Linux kernel but absent in the Linux DDE. One
particular source of trouble is the control flow in the event of an interrupt.
Within the Linux kernel, the interrupt handler can make the assumption that no
code of the interrupted CPU can be executed until the interrupt handler returns.
In contrast, Linux DDE models interrupts as independent threads and assumes that
all code is multi-processor safe. Consequently the control flows of the driver
executed in the Linux kernel and the same driver executed in Linux DDE differs
in subtle ways, leading to the worst of all bugs namely race conditions.
While our focus shifted away from the classical Linux DDE, we discovered the
beauty of creating extremely tight device-driver environments. In contrast to
the Linux DDE, which tried to be useful for a large range of driver classes on
the cost of becoming complex, we created new slim DDEs for single drivers or a
strictly outlined class of drivers. One example is the DDE for iPXE networking
drivers. The iPXE boot loader covers most of today's commodity network cards.
The drivers of iPXE are actually Linux drivers adapted to be executed in an
environment as minimalistic as a boot loader. It turns out that a DDE of less
than 1.000 lines of code paves the way towards using a rich base of networking
drivers (more than 100.000 lines of driver code) on Genode. A similarly
positive experience was made for the Intel GEM driver ported from the Linux
kernel. The 18.000 lines of driver code require a DDE of less than 3.000 lines
of code to reuse the driver on Genode.
These success stories motivated us to proceed going into this direction
when revisiting our USB driver. Our goal was to replace the aging USB driver,
which was based on the original Linux DDE by a new driver conducted via an
USB-specific but onion-skin tight DDE. As a general rule, we forbid ourself to
modify 3rd-party code. To completely remove race conditions from the picture,
we furthermore decided to run the entire driver stack including the handling
of client requests with a single physical thread only. This thread manages
multiple pseudo-thread contexts using cooperative scheduling.
The result is more than convincing for us. With a DDE of less than 4.000 lines
of code, we have become able to use the unmodified Linux-3.2 USB stack, which
comprises more than 60.000 lines of code. Only 3 lines had to be modified. In
contrast to Linux DDE, the 4.000 lines of custom-written DDE code are relatively
easy to comprehend. For most of the functions provided by the DDE, the
implemented semantics are a rigid subset of the original functionality as found
in the Linux kernel. Apparently the knowledge of function usage patterns in a
particular driver allows for vast simplifications. Given our self-imposed rule
to not modify 3rd-party code, we expect that future updates to new Linux kernel
versions will pose much less of a burden.
With our current approach of creating rigidly tailored DDEs, we are convinced
to have found a healthy balance between the manual effort needed to create and
maintain a base of ported device drivers and the utility those driver provide
to our system.
System reconfiguration at runtime
#################################
By addressing more and more concerns of general-purpose computing, we are
forced to push the boundaries of the framework beyond the limited scope of
special-purpose OSes. The biggest challenge is the accommodation of highly
dynamic workload. With respect to managing physical resources, the framework
was designed from the ground up with those requirements in mind. So there is a
strong basement to build upon. However, another aspect of dynamic systems is
the adaptation of the behaviour of components at runtime. This aspect used to
be an underdeveloped spot of the Genode system. With the API improvements of
the current release, we supplement the existing Genode concepts with profound
support for dynamic policies.
To give a few examples of such dynamic policies: We expect the audio mixer to
immediately respond to adjusted volume settings. The calibration of pointer
devices might be adapted on-the-fly by the user. We want to change the color
scheme of the GUI without the need to restart the GUI server. Screen
resolutions or the size of text terminals shouldn't be fixed at the start time
but changeable. Also policies such as the assignment of devices to subsystems
are subject to decisions taken at run time rather than at system-integration
time. Of course, each of those problems could be addressed individually by
adding dedicated RPC interfaces to components that support run-time
adjustments. For example, a touchscreen device driver could sport an RPC
interface for allowing the modification of calibration parameters.
But the information supplied via such configuration interfaces tends to have
a high overlap with configuration information passed to components via
Genode's configuration mechanism, which ultimately leads to uncertainty
about whether to supply such information via the configuration mechanism
or via RPC. The RPC approach also raises the question of how to initialize
dynamic configuration arguments such that the component can operate before
being explicitly configured via RPC. In the best case, a component would
accept both, a static configuration supplied via the existing configuration
mechanism and a dynamic configuration interface exposed via RPC. Obviously,
this spoils the principle of functional orthogonality, making the component
hard to test and maintain. In the worst case, a component may drop the
possibility for static configuration altogether and just rely on configuration
parameters provided via RPC. This way, we introduce a mandatory dependency
of the component from a corresponding configuration component.
There must be a better solution. Fortunately, there is. The key is to turn the
once static configuration mechanism into a dynamic facility. The configuration
mechanism uses the ROM session interface as underlying mechanism. When a
process requests a ROM module called "config" by opening a ROM session at its
parent, the parent hands out the configuration data of the respective subsystem
via a pseudo ROM dataspace. The process can then attach this dataspace to its
local address space to access the configuration information. This information
is typically expressed as XML, which makes the mechanism powerful enough to
handle arbitrarily structured configuration data. Until now, most components
used to request the 'config' dataspace only once at their start time. Once
obtained, the policy remained in effect for the whole lifetime of the
component. We can turn this static mode of operation into a dynamic one by
letting the component query for a "config" ROM module not only once but
repeatedly during its lifetime. Each time, the program requests its
configuration, the parent may hand out a dataspace with updated information.
The code for parsing the "config" data in the configured component is already
there. The only change is that the code is executed not once but multiple
times. Of course, having each component poll for configuration changes at their
parent at regular intervals won't scale too well. Components should obtain a
new config dataspace only if there is an actual change. To enable the parent to
notify the component of such changes, we enhanced the ROM session interface
with a signalling mechanism. The client (in our case this is the child process)
can register a signal handler that will get notified each time the ROM module
changes. On the reception of such a signal, it can re-evaluate the
configuration information.
Of course, the configuration file handled by the init process remains to be
static because init is meant to handle the static portions of the system only.
But dynamic config files can be used in three different ways already: First,
requests for config files can be routed to arbitrary ROM services instead of
the immediate parent. The remote ROM service may support the dynamic update of
ROM modules and provide the signalling. An example for such a dynamic policy
component can be found at 'os/run/dynamic_config.run'. In structure, this
scenario corresponds to the approach of having a dedicated policy component
define the runtime policy of a server. But in contrast to the native approach,
the 'dynamic_config.run' scenario solves the initialization problem by letting
the configured component use the policy provider as a service. The second way
of employing dynamic configurations is to run a service as a child subsystem
using the 'Slave' API. An example for this scenario is provided by
'os/run/dynamic_config_slave.run'. The third variety is the use of the loader
service to instantiate subsystems. The ROM modules of such subsystems can not
only be defined by the client of the loader but can be updated at any time
using dynamic ROM sessions. An example for the latter variant can be found at
'os/run/dynamic_config_loader.run'.
Base framework
##############
Support for dynamic ROM sessions
================================
As outlined in section [System reconfiguration at runtime], the usefulness of
the ROM session interface has just taken a giant leap with the introduction of
the following tiny function:
! void sigh(Signal_context_capability sigh);
This function allows a ROM session client to register for events referring to
the session's ROM module. At first sight, it might be counter intuitive to
expect events originating from such sessions because the most prominent
provider of the ROM service is core, which exports static binary data loaded at
boot time to higher-level components. Naturally, such boot-time modules never
change. But ROM sessions are used elsewhere, in particular by parent processes
for supplying read-only information to child subsystems. For instance, shared
libraries, executable binaries, and configuration data are passed to child
subsystems as ROM modules. But in contrast to core's ROM modules, this
information may be dynamic in nature. For example, the configuration of the
audio mixer may change at any time during the lifetime of the mixer. Also
executable binaries may change in the event of system updates. Enabling the
system to respond to such changes is crucial the use of Genode as
general-purpose OS.
For existing users of the ROM session interface, there is nothing to consider.
API compatibility is maintained. However, by installing a signal handler using
the 'sigh()' function, the client will receive a notification each time the
data changes at the server. From the client's perspective, the original data
contained in the currently used dataspace remains unchanged until the client
calls 'dataspace()' the next time. This way, the update of the ROM module at
the client side is transactional. There is no inconsistent intermediate state.
Misc
====
:Support for non-executable memory mappings:
Via the newly added 'executable' flag of 'Rm_session::attach()', clients of the
RM service become able to express whether they want a mapping to be executable
or not. This allows dataspaces to be mapped as non-executable by default and as
executable only if needed.
:Support for process-local pseudo capabilities:
On some platforms, in particular Linux, we used process-local pseudo capabilities
as helpers to implement the Genode API. In contrast to a normal capability,
which refers to an object accessible via RPC, a pseudo capability is not
more than a glorified pointer. The uses of local pseudo capabilities are
normally constrained to special cases in platform-dependent code. They do not
exist at API level.
However, our observation of the need for such a utility for platforms other
than Linux prompted us to generalize the local capabilities. The result has
been incorporated into the platform-independent 'base' repository as part of
the 'Native_capability_tpl' interface. At API level, this change is transparent.
Low-level OS infrastructure
###########################
Loader
======
The original loader service was primarily motivated by the browser-plugin
scenario presented on our live CD. But since the initial version, we envisioned
this component to become the generic mechanism of choice for scenarios where
subsystems are to be created and removed dynamically at runtime. The current
release introduces a largely revised loader-session interface and a new
implementation of the loader component. The new version widens the application
scope of the service and, at the same time, reduces its implementation
complexity.
The complexity reduction is achieved by removing the original limitation of
supplying the new sub system as a single binary blob only. The server used to
implement heuristics and functionality for dealing with different kinds of
blobs such as ELF images or TAR archives. This has been replaced by a
session-local ROM service, which can be equipped with an arbitrary number of
ROM modules supplied by the loader's client prior starting a new subsystem.
Even though the TAR support has been removed, a separate instance of the
'tar_rom' service can be used within the subsystem to provide the formerly
built-in functionality.
The new loader component is best illustrated by two examples. The traditional
loader example at 'os/run/loader.run' shows how the loader intercepts the
nitpicker session of the loaded subsystem. The corresponding source code
can be found at 'os/src/test/loader/'. The second example at
'os/run/dynamic_config_loader.run' shows how the concept of dynamic ROM
sessions can be combined with the loader. As demonstrated by this example,
ROM images used by the loaded subsystem can be updated at runtime by the
client of the loader session.
New file-system infrastructure
==============================
The current release introduces Genode's file-system session interface, provides
a first implementation of this interface in the form of an in-memory file
system, and enables the libc to use the new file-system facility.
The new interface resides in 'os/include/file_system_session/'. It uses
synchronous RPC calls for functions referring to directory and meta-data
handling. For transferring payload from/to files, the packet-stream interface
is used. We envision that the asynchronous design of the packet-stream
interface fits well with the block-session interface and thereby allows for
hiding I/O latencies when performing subsequent requests in an asynchronous
way.
[image file_system_stack]
Compared to Unix-like file-system APIs, Genode's file-system session interface
is much simpler. In particular, it does not support per-file permissions. On
Genode, we facilitate binding policy (such as write-permission) as sessions
rather than individual file objects.
In-memory file system
~~~~~~~~~~~~~~~~~~~~~
As reference implementation of the new interface, a new 'ram_fs' service can be
found at 'os/src/server/ram_fs'. It stores sparse files in memory. At startup
time, 'ram_fs' is able to populate the file-system with directories, ROM
modules, and inline data as specified in its configuration.
Access to the file system can be tailored for each session depending on the
session's label. By default, no permissions are granted to any session.
To selectively permit access to (a part of) the file system, at least one
policy must be defined.
The following configuration illustrates the way of how to express policy.
! <config>
! <!-- preload RAM file system -->
! <content>
! <dir name="tmp">
! <rom name="init" as="blubb" />
! </dir>
! <dir name="home">
! <dir name="user">
! <inline name=".vimrc">
! set hidden
! </inline>
! </dir>
! </dir>
! </content>
! <!-- constrain sessions according to their labels -->
! <policy label="noux -> root" root="/" />
! <policy label="noux -> home" root="/home/user" writeable="yes" />
! <policy label="noux -> tmp" root="/tmp" writeable="yes" />
! </config>
The '<content>' sub node of the '<config>' node provides a way to pre-populate
the file system with directories and files. Note that '<dir>' nodes can be
arbitrarily nested. Files can be loaded from the ROM service. By adding the
optional 'as' attribute to a '<rom>' node, the file name can be defined
independently from the ROM module name. In addition to creating files from
ROM modules, files can be created from data specified directly as part of the
configuration using '<inline>' nodes. The content of such nodes is used as
file content as is.
Session-specific access-control policy is expressed via one or more '<policy>'
nodes. At session-creation time, each policy node is matched against the label
of the new session. If the label of a policy node matches, the defined policy
is applied. If multiple policies match, the one with the longest 'label'
attribute (the most specific one) is selected.
A policy node may contain the following attributes. The mandatory 'root'
attribute defines the view port of the session onto the file system. The
optional 'writeable' attribute grants the permission to modify the file system.
To illustrate the use of the 'ram_fs' component, refer to the
'libports/run/libc_fs.run' script.
:Limitations:
The current state should be regarded as work in progress. In particular, the
error handling and the life-time management of file-system nodes will need
further attention. Functionality-wise, the support for truncating files and
symbolic-link handling are not yet implemented.
Furthermore, there is much room for optimization, in particular for the
handling of directory entries. Currently, we communicate only one directory
entry at a time, which is suboptimal when traversing large trees. However, we
decided to focus on functionality first and defer optimizations (such as
batching directory entries) to a later stage of development.
The current implementation does not handle file modification times at all,
which may be a severe limitation for tools that depend on this information such
as GNU Make.
File-system plugin for the C runtime
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To enable libc-using programs to access the new file-system interface, there is
a new libc plugin at 'libports/src/lib/libc_fs'. Using this plugin, files
stored on a native Genode file system can be accessed using the traditional
POSIX file API.
To see how the three parts described above fit together, the test case at
'libports/run/libc_fs' can be taken as reference. It reuses the original
'libc_ffat' test to exercise several file operations on a RAM file-system using
the libc API.
C Runtime
=========
:POSIX threads and semaphores:
The new 'pthread' library implements a subset of the POSIX thread and semaphore
API. We plan to extend it as needed. Currently, it is used as support for the
libSDL-based 'avplay' program.
:Separate setjmp/longjmp into own library:
The setjmp/longjmp facility comes with the libc but it is fairly free-standing
code, which is useful not only for libc-using programs but also for raw
Genode components, in particular the new USB stack. Therefore, we separated
the setjmp/longjmp code into a separate 'libc-setjmp' library. Even though
the library is prefixed with 'libc' it does not depend on the remaining
parts of the C runtime.
:Misc:
* Implementation of '_nanosleep()'
* Let 'mmap()' return aligned anonymous memory
Program argument handling
=========================
The main-function arguments of Genode programs were never used by genuine
Genode components because the Genode's configuration concept is the most
adequate and consistent way of passing parameters to components.
But most components ported from other systems and not specifically developed
for Genode, expect configuration arguments passed via the argc-argv interface.
One way to reuse such components is to change their way of handling arguments
by the means of patching 3rd-party source code. In some cases (for example
for the Vancouver VMM), this is the preferred way because manual adaptation
work is required anyway.
On the other hand, there are 3rd-party applications that would be nice to
reuse as is without any manual patching work, for example the libSDL-based
'avplay' or the muPDF application. To ease the integration of such
programs into Genode setups, we added the new 'config_args' library. At the
startup of the program, this library inspects the config node for arguments and
fills the argv structure to be passed to the 'main()' function.
The configuration syntax looks as follows:
! <config>
! <arg value="...">
! <arg value="...">
! ...
! </config>
The 'value' attribute of the first '<arg>' node becomes 'argv[0]' and so on.
DDE Kit
=======
We added the API call 'dde_kit_timer_schedule_absolute' to the DDE Kit
interface. Traditionally, DDE Kit timers used to be disposed after a single
use. But we learned that there exist use cases for reusing a single timer
object for multiple subsequent timeouts. The 'schedule_absolute' function
accommodates those scenarios.
LOG-to-Terminal adapter
=======================
The new LOG-to-terminal component to be found at 'os/src/server/terminal_log'
provides the LOG service by writing each LOG-output request prefixed by the
session-label to a terminal-session. It thereby enables the routing of LOG
output to different kinds of terminal sessions such as UART drivers, the
graphical terminal, or the TCP terminal. The 'gems/run/terminal_log.run'
script demonstrates the usage of the new component.
Optimized blitting on ARM platforms
===================================
The blitting library employed by nitpicker and other GUI applications used to
come in the form of two implementations. The generic version implemented the
copying operation via Genode's 'memcpy' function, which conducts a simple
byte-wise copy at relatively poor performance. In practice, the generic fall
back was expected to not being used much as there is an assembly-optimized
implementation for x86 machines. Because there wasn't an ARM-specific
implementation available yet, ARM platforms suffered under the poor performance
of the generic fall-back implementation. To bring the blitting up to speed on
such platforms, we supplemented the blitting library with an ARM-specific
optimized version.
Libraries and applications
##########################
New and updated libraries
=========================
:Qoost:
Qoost is a small library developed by Genode Labs for making the development
of Qt4-based applications, in particular applications using QWidgets, more
enjoyable. The library is currently used by the new Qt4-based video player
example at 'qt4/src/app/qt_avplay'.
:Update of zlib to version 1.2.7:
Zlib as been updated because the previous version mysteriously disappeared
from the official zlib mirrors.
:Video codecs via libav:
The [https://libav.org - libav project] is one successor of the popular
[https://ffmpeg.org/ - FFmpeg] library, which is a comprehensive solution
for video and audio decoding, conversion, and streaming. The version
0.8.2 of libav has been incorporated into the libports repository.
Lua for script-based testing
============================
The current release of Genode includes initial support for the Lua programming
language, a clean scripting language with excellent portability capabilities -
just ANSI C. Lua comes with a tiny runtime implementation, which recommends it
as base for test scripting or rapid prototyping in Genode.
Currently, the Lua libraries are accompanied by a small test program
'test-moon', which utilizes the C++ variant of the Lua runtime. The test shows
an exemplary integration of Genode interfaces to print the RAM quota and sleep
for several seconds. The simplicity of the application shows the potential of
this approach.
In the future, essential Genode interfaces could be made available to Lua
scripts as libraries or classes and 'test-moon' could be extended to a
versatile test tool, which loads and runs test scripts configured with
Genode's config mechanism. Test results can be aggregated, printed, and
analyzed at runtime by scripts.
:[https://lua.org/]: Lua programming language
libSDL
======
Motivated by our work on media replay capabilities, we enhanced the port
of libSDL with support for timer, thread, and audio-related functions.
:SDL timer support:
Basic support for SDL timers and delay functions has been added.
:SDL thread support:
Thanks to the minimal support for pthreads added by the means of the new
'pthread' library, we are able to activate the SDL thread API. The most common
threading and synchronization primitives work but not all features are
supported. We will complement the coverage of support as needed.
:SDL audio support:
The new libSDL audio back end enables the use of Genode's audio-session
interface from SDL applications. This way, SDL programs can be combined
with audio drivers as well as with the mixer component.
The audio volume (in percent) can be configured in the config file of the
SDL application:
! <config>
! <sdl_audio_volume value="100"/>
! </config>
Note that the SDL audio back end does respond to configuration changes at
run time. By supplying the config dynamically rather than via a static
file, the audio volume may get updated while the SDL application is running.
GDB monitor
===========
We refined the GDB monitor to facilitate its use for debugging ever more
sophisticated scenarios.
One of those scenarios is executing the Noux environment within GDB. To execute
a meaningful Noux scenario, we need a way to pass configuration data through
the GDB monitor to the debugging target. This feature has been implemented by
adding a new '<config>' subnode to the '<target>' node at the GDB monitor
configuration.
Furthermore, we discovered a limitation of the built-in memory-preservation
policy of the GDB monitor. In general, GDB monitor passes all RAM quota to the
debugging target, leaving only a hard-coded quantum of resources for itself.
However, the amount of RAM actually required by the monitor depends on the
behaviour of the debugging target. Each time, the target requests a ROM module,
GDB monitor creates a shadow copy of the ROM module in order to be able to
modify its content. Of course, the shadow copies consume memory, for which GDB
monitor is accounted for. No hard-coded RAM-preservation policy will be able to
cover all usage scenarios. Therefore, we decided to let the user express this
policy explicitly via the GDB monitor configuration. The amount of RAM that GDB
monitor should preserve for itself must be provided via the new 'resource' node
of the GDB monitor configuration. For example,
! <start name="gdb_monitor">
! <resource name="RAM" quantum="1G"/>
! <config>
! <target name="noux">
! <preserve name="RAM" quantum="2M"/>
! ...
! </config>
! </start>
Media player based on libav
===========================
The current release features the initial version of a natively running media
player. It consists of the following pieces.
:libav: is a framework library for decoding, converting and streaming audio
and video data. The libav library has been incorporated into the 'libports'
repository.
:avplay: is an example application, which showcases the use of libav
using libSDL to integrate with a host OS. Thanks to our port of libSDL
to Genode, we are able to use the 'avplay' application without modification.
When used on Genode, 'avplay' uses a framebuffer session, an input session, a
timer session, and an audio-out session as back ends. Thereby we are able to
integrate 'avplay' seamlessly with existing components that provide these
interfaces, in particular the audio mixer, framebuffer and input drivers, but
also the nitpicker GUI server.
:qt_avplay: is a Qt4 front end to 'avplay'. It spawns an instance of 'avplay'
as a slave process.
[image media_player]
The unmodified 'avplay' embedded in Qt4-based GUI.
The media file was downloaded from
https://www.youtube.com/watch?v=CbtAP3kUCxs.
The latter part is particularly interesting because it makes creative use of
Genode's unique service virtualization facilities. The 'qt_avplay' program
(GUI) starts 'avplay' (aka the codec) as a separate child process. When
started, the codec requests a framebuffer session from the GUI. The GUI, in
turn, creates a separate session to the nitpicker GUI server specifically for
displaying the codec's output on screen and hands out the buffer returned by
nitpicker to the codec. However, the GUI retains the privilege to control the
way how the buffer is displayed on screen. By using the 'QNitpickerViewWidget',
the GUI is thereby able to embed the codec's view seamlessly into the Qt4 GUI
as a widget. But both the GUI and the codec have completely independent data
paths to the GUI server. So the operation of the codec does not depend on
proper and timely operation of the GUI. Vice versa, the GUI process cannot be
compromised by the codec because the codec is sandboxed in a separate process.
The GUI interacts with the codec by virtualizing the input session interface
used by the codec. I.e., when the user clicks on the play or pause button, the
GUI submits artificial keyboard events with key codes interpreted by the
'avplay' program.
Besides the separation of the codec from the GUI, the 'qt_avplay' example is
interesting because it makes use of Genode's new dynamic configuration
facility. The SDL audio back end used by the codec repeatedly evaluates its
configuration during runtime. This configuration includes a volume prescale
factor. Via the dynamic configuration mechanism, the parent (the GUI) is able
to update the value of the volume prescale factor at any time and thereby
influence the behaviour of the codec.
[image media_effects]
Furthermore, the concept of running 'avplay' as a slave of the GUI clears the
way to even more sophisticated features such as the transparent addition of
video post-processing steps in the form of individual components. Instead of
connecting the codec directly with the nitpicker session, the GUI may decide to
route the framebuffer-session request to another slave (aka "effect plugin").
The effect plugin is a component that requests a framebuffer session at its
parent (the GUI) in order to provide a framebuffer service itself (to the GUI).
Each time, its client invokes the 'refresh()' function, the effect plugin
transforms pixels targeting its own framebuffer session. By routing the
framebuffer session between the codec, one or more instances of effect plugins,
and the nitpicker GUI server, any number of effect plugins can be chained
together to form a pipe of video-processing components. All this flexibility
comes with no addition to the Genode API. It is merely the result of composing
plain Genode components.
Terminal
========
Our custom terminal emulator that is hosted within the 'gems' repository has
been enhanced to support tab characters as well as the escape sequences needed
to use 'ls --color=auto'.
Device drivers
##############
USB
===
The new 'dde_linux' repository will host device drivers ported from the Linux
kernel. In contrast to the original 'linux_drivers' repository, 'dde_linux'
does not contain any 3rd-party source code. To download the Linux kernel source
code and extract the drivers, execute the 'make prepare' rule of the top-level
Makefile. The initial version of the 'dde_linux' repository comes with a USB
driver. The porting methodology follows the path of the Intel GEM port. Instead
of attempting to provide a generic Linux environment that works across drivers,
each driver comes with a specially tailored DDE.
The DDE consists of Genode-specific implementations of Linux API functions as
declared in 'lx_emul.h'. Most of these functions are dummies that must merely
be provided to resolve dependencies at the linking stage. They are called by
unused code-paths.
As of now, the USB driver supports UHCI and EHCI on the x86_32 platform. It
exposes USB HID devices and USB storage devices via Genode's input-session
and block-session respectively.
The HID driver supports keyboard and mouse. A run script can be found under
'dde_linux/run/usb_hid.run'. Configuration snippet:
!<start name="usb_drv">
! <resource name="RAM" quantum="3M"/>
! <provides><service name="Input"/></provides>
! <config>
! <hid/>
! </config>
!</start>
Note that we observed that certain 1.0 versions of Qemu do not generate mouse
interrupts. The mouse driver should work correctly on Qemu 1.0.93 and above.
The USB storage driver supports one USB storage device. Hot plugging has not
been tested. A run script can be found under 'dde_linux/run/usb_storage.run'.
Configuration snippet:
!<start name="usb_drv">
! <resource name="RAM" quantum="2M"/>
! <provides> <service name="Block"/> </provides>
! <config><storage /></config>
!</start>
Noux
####
Running GCC, binutils, coreutils natively on Genode
===================================================
We introduced support for stacked file systems alongside new glue code for
accessing File-system implementations provided via Genode's new
file-system-session Interface. Using stacked file systems, an arbitrary number
of file systems (such as TAR archives or file systems implemented as separate
Genode Components) can be composed to form one merged virtual file system.
An example is given via the 'ports/run/noux_bash.run' script. This run script
creates a virtual file system out of multiple TAR archives each containing the
content of a particular GNU package. In addition, one 'ram_fs' is mounted,
which enables Noux to perform write operations. This way, the shell output can
be redirected to a file, or files can be saved in VIM.
With the implementation of stacked file systems and the writeable RAM file
system in place, we are ready to greatly extend the range of GNU packages that
run (almost) unmodified on Genode. For us, the most important achievement is
the new ability to run binutils, the GNU compiler collection, and GNU Make. To
see Noux executing 'gcc' and 'readelf', please give the
'ports/run/noux_tool_chain.run' script a try.
Executing binutils and GCC has been successfully tested on OKL4, L4/Fiasco,
and L4ka::Pistachio. Fiasco.OC, NOVA, Linux, and Codezero are not yet
supported.
Networking support
==================
We desire to use a wide range of Unix networking tools such as wget, lynx, ssh,
and netcat on Genode. For this reason, the second focus of our Noux-related
developments is the added support for networking. The Noux syscall interface
has been extended with system calls for 'socket', 'getsockopt', 'setsockopt',
'accept', 'bind', 'getpeername', 'listen', 'send', 'sendto', 'recv',
'shutdown', 'connect', and 'getaddrinfo'. Within Noux, those system calls
are translated to calls to the libc and the libc-lwip plugin. This design
principally enables us to easily replace the TCP/IP stack in the future if
needed.
To experiment with the new networking support of Noux, you may use the
'ports/run/noux_net_netcat.run' as a good starting point. The test communicates
a message between two instances of netcat one running on the host system and
one running within the Noux runtime in qemu.
Platform support
################
Fiasco.OC microkernel
=====================
Releasing kernel resources
~~~~~~~~~~~~~~~~~~~~~~~~~~
By now, the Fiasco.OC base platform was still lacking proper handling of
kernel resources especially the tracking and releasing of capability selectors.
With release 12.02 we introduced a capability map for Fiasco.OC to circumvent
the usage of more than one kernel-selector for the same capability (please,
refer to the release notes 12.02 for further details).
With the current release we turned the capability class of the Fiasco.OC base
platform into a smart-pointer-like object which releases the corresponding entry
from the capability map whenever it detects that a capability gets unused.
Thereby leaking of kernel resources in terms of capability selectors gets
eliminated.
While reworking the capability handling of the Fiasco.OC base platform the
following problems were solved:
* A patch for the 'l4_task_cap_equal' syscall in Fiasco.OC was added, that
fixes some false positives, meaning: when comparing two capability selectors
that referenced the same kernel object including the same, rights false
was returned.
* There existed a race-condition when inserting a new capability into the
capability map
* Due to the re-usage of capability ids it was possible that a newly received
capability was exceptionally freed when actually an old entry should be
removed from the capability map
* At some points in the generic code base capabilities were copied in a way
that circumvented tracking by overloading assignment operators respectively
copy constructors effectively breaking the smart pointer semantic
Basic PandaBoard support
~~~~~~~~~~~~~~~~~~~~~~~~
With the current release we introduce basic support to build Genode/Fiasco.OC
for the popular PandaBoard OMAP4 platform. Although most needed drivers are
still lacking, it is at least possible to see core, init, and other
applications via serial line running on the PandaBoard.
Kernel debugger
~~~~~~~~~~~~~~~
The Fiasco.OC kernel debugger's object name buffer was too limited for most
Genode scenarios incorporating more than just a handful of threads. That
complicated debugging sometimes. An additional kernel patch extends the name
buffer.
Linux
=====
Using the chroot mechanism
~~~~~~~~~~~~~~~~~~~~~~~~~~
When used as component framework on Linux, Genode tries to preserve as many
native Linux features as possible. In some instances, those features go
surprisingly well with Genode. One particular feature is Linux' 'chroot'
mechanism, which is a popular way to execute Linux processes in a jailed
environment. When using Genode, the reliance on a file system is naturally
reduced to a minimum because the framework comes with abstractions vastly
different from a classical file system, namely capability-based naming of
resources. Still, the file system is there and can be exploited. In theory,
segregating different parts of Genode into different 'chroot' environments can
improve the situation. In practice, the use of such platform-specific solutions
raises the question of how to integrate the solution in way that is coherent
with the rest of the framework.
The new chroot component at 'os/src/app/chroot' makes the use of the chroot
mechanism within Genode scenarios an almost seamless experience. The component
behaves identical to Genode's init process except for the fact that its
subsystem is constrained to a configurable chroot path. The chroot path is
specified using a '<root>' node of the chroot configuration:
! <root path="chroot_path" />
The remaining part of the configuration is identical to the configuration of
init. In fact, under the hood, the chroot component is barely more than a
trampoline mechanism for spawning the actual init binary after taking all
precautions needed to setup the chroot environment.
To see how to deploy the new facility, please refer to the run script at
'os/run/chroot.run'. The run script uses POSIX file capabilities to allow the
use of the 'chroot' component under the account of a normal user. However, for
granting the needed capabilities, the run script will ask for root permission.
Non-executable mappings
~~~~~~~~~~~~~~~~~~~~~~~
Up to now, the Genode API provided no way to devise the use of non-executable
memory mappings. There is only the distinction between read-only and
read-writable dataspaces. This limitation becomes a severe limitation when
combining Genode with PaX. This prompted us to introduce the executable flag
to the 'Rm_session::attach()' function using non-executable as the default. So
far, Linux is the only platform that evaluates this flag. Only if set, the
'mmap' syscall will enable 'MAP_EXECUTABLE'. This is actually a rare exception.
The flag is set by the dynamic linker only. For hybrid Linux/Genode programs
(that do use the Linux 'ld-linux.so' instead of Genode's dynamic linker) the
executable flag is never set.
OKL4
====
The hard-coded dependency on a '/usr/bin/python2' binary spawned a bit of
confusion (or at least an inconvenience) among Genode users. So we introduced
simple heuristics for determining the actually installed python-2 version
during the 'make prepare' procedure and use the best match.
Build system and tools
######################
:Support proper shadowing of target.mk files:
The build system overlays multiple source trees (repositories) such that they
can shadow libraries and include search paths. We have extended the shadowing
concept to build targets. Furthermore, the change of the build system
streamlines the build stage for generating library dependencies, reducing the
processing time of this stage by 10-20 percent.
:Explicitly use qemu-system-i386 rather than qemu:
Up to now, the run tool used the plain 'qemu' binary for all (non-Linux)
x86_32 platforms and resorted to 'qemu-system-*' variants for x86_64 and
ARM platforms. To remove this inconsistency, the run tool has been changed
to always use the specific 'qemu-system-*' binary.