genode/doc/release_notes/11-11.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

1009 lines
49 KiB
Plaintext

===============================================
Release notes for the Genode OS Framework 11.11
===============================================
Genode Labs
Each Genode release is themed with a predominating topic. Version 11.08 aimed
at blurring the lines between the use of different base platforms whereas the
predecessor re-addressed inter-process communication. With the current release,
we explore the various approaches to virtualization using Genode. At the first
sight, this topic sounds like riding a dead horse because virtualization is
widely regarded as commodity by now. However, because Genode has virtualization
built right in the heart of its architecture, this topic gets a quite different
spin. As described in Section [A Plethora of Levels of Virtualization], the
version 11.11 contains the results of our exploration work about faithful
virtualization, paravirtualization, OS-level virtualization, and
application-level virtualization. The latter category is particularly unique to
Genode's architecture.
Besides elaborating on virtualization, the version 11.11 comes with new
features such as support for user-level debugging by the means of the GNU
debugger and the ability to run complex interactive UNIX applications on Genode
(i.e., VIM). Furthermore, we improved device-driver support, specifically for
ARM platforms. Apart from working on features, we had been busy with
optimizing several aspects of the framework, improvements ranging from improved
build-system performance, over reduced kernel-memory footprint for NOVA, to a
new IPC implementation for Linux.
For regular Genode developers, one of the most significant changes is the new
tool chain based on GCC 4.6.1. The background story about the tool-chain update
and its implications is described in Section [New tool chain based on GCC
4.6.1].
A Plethora of Levels of Virtualization
######################################
Virtualization has become a commodity feature universally expected from modern
operating systems. The motivations behind employing virtualization techniques
roughly fall into two categories: the re-use of existing software and
sandboxing untrusted code. The latter category is particularly related to
the Genode architecture. The Genode process tree is essentially a tree of
nested sandboxes where each node is able to impose policy on its children.
This immediately raises the question of where Genode's design could take us
when combined with existing virtualization techniques. To explore the
possible inter-relationships between Genode and virtualization, we conducted
a series of experiments. We found that Genode's recursive architecture
paves the way to far more flexible techniques than those we know from existing
solutions.
Faithful x86 PC Virtualization enabled by the Vancouver VMM
===========================================================
Most commonly, the term virtualization refers to faithful virtualization where
an unmodified guest OS is executed on a virtual hardware platform. Examples of
such virtual machines are VMware, VirtualBox, KVM, and Xen - naming only those
that make use of hardware virtualization capabilities. Those established
technologies have an impressive track record on the first of both categories
mentioned above - software re-use. However, when it comes to sandboxing
properties, we find that another virtual machine monitor (VMM) implementation
outshines these established solutions, namely the Vancouver virtual machine
monitor executed on top of the NOVA hypervisor. Combined, NOVA and Vancouver
are able to slash the complexity of the trusted computing base (TCB) for
isolating virtual machines to a tiny fraction compared to the established
products. The key is the poly-instantiation of the relatively complex virtual
machine monitor with each virtual machine. Each VMM is executed within a
dedicated protection domain. So a problem in one VM can only affect its
respective Guest OS but not any other VM. By executing the VMM outside of the
hypervisor, the hypervisor's complexity is dramatically smaller than
traditional hypervisors. Hence, the authors of NOVA coined the term
microhypervisor.
The NOVA virtualization architecture is detailed in the paper
[https://os.inf.tu-dresden.de/papers_ps/steinberg_eurosys2010.pdf - NOVA: A Microhypervisor-Based Secure Virtualization Architecture]
by Udo Steinberg and Bernhard Kauer.
Since February 2010, NOVA is one of the supported base platforms of Genode. But
until now, Vancouver has been tied to a specialized user land that comes with
NOVA. For the current Genode release, we took the chance to adopt this
technology for Genode.
[image vancouver]
The Vancouver virtual machine monitor executed as Genode
component
On Genode, the Vancouver VMM is executed as a normal Genode process.
Consequently, any number of VMM instances can be started either statically via
the init process or dynamically. By bringing Vancouver to Genode we are able to
combine the high performance and secure design of Vancouver with the
flexibility of Genode's component architecture. By combining Genode's session
routing concept with resource multiplexers, virtual machines can be connected
to one another as well as to Genode components.
That said, the current stage of development is still highly experimental.
But it clearly shows the feasibility of performing faithful virtualization
naturally integrated with a Genode-based system. For more technical details
about the porting work, please refer to Section
[Vancouver virtual machine monitor];
Android paravirtualized
=======================
Since 2009, Genode embraced the concept of paravirtualization for executing
unmodified Linux applications by the means of the OKLinux kernel. This special
variant of the Linux kernel is modified to run on top of the OKL4 microkernel.
With the added support for the Fiasco.OC kernel as base platform, the use of
L4Linux as another paravirtualized Linux variant became feasible. L4Linux has a
long history reaching back to times long before the term paravirtualization was
eventually coined. In contrast to faithful virtualization, paravirtualization
devises modifications of the kernel of the Guest OS but preserves binary
compatibility of the Guest's user-level software. The proponents of this
approach cite two advantages over faithful virtualization: better performance
and independence from virtualization-hardware support. For example, L4Linux is
available on ARM platforms with no virtualization support.
L4Linux is the base of L4Android, a project that combines the Android software
stack with L4Linux. With the current release, we have integrated L4Android with
Genode.
:[https://l4android.org]:
L4Android project website
[image l4android]
Android, a Linux distribution, and a process tree of Genode
components running side by side
As illustrated in the figure above, multiple Linux instances of both types
Android and plain Linux can be executed as nodes of the Genode process tree.
For their integration with the Genode environment, we extended the L4Linux
kernel with custom stub drivers that make Genode's session interfaces
available as virtual devices. These virtual devices include NIC, UART,
framebuffer, block, keyboard, and pointer devices. Our work on L4Linux is
explained in more detail in Section [L4Linux / L4Android].
OS-level Virtualization using the Noux runtime environment
==========================================================
Noux is our take on OS-level virtualization. The goal is to be able to use the
wealth of command-line-based UNIX software (in particular GNU) on Genode
without the overhead of running and maintaining a complete guest OS, and
without changing the original source code of the UNIX programs. This work is
primarily motivated by our ongoing mission to use Genode as development
environment.
[image noux]
The Noux runtime environment for UNIX software. The program is linked
against a custom libc plugin that directs system calls over an RPC
interface to the Noux server. The RPC interface resembles a
traditional UNIX system-call API.
The Noux approach is to provide the traditional UNIX system call interface as
an RPC service, which is at the same time the parent of the UNIX process(es) to
execute. The UNIX process is linked against the libc with a special back end
(libc plugin) that maps libc functionality to Noux RPC calls. This way, the
integration of the UNIX program with Noux is completely transparent to the
program. Because Noux plays the rule of a UNIX kernel, it has to implement
typical UNIX functionality such as a virtual file system (VFS). But in contrast
to a real kernel, it does not comprise any device drivers and protocol stacks.
As file system, we currently use TAR archives that Noux obtains from core's ROM
service. The content of such a TAR archive is exposed to the UNIX program as
file system.
One of the most prevalent pieces of UNIX software we spend the most of the day
with is VIM. Hence, we set the goal for this release to execute VIM via Noux on
Genode. This particular program is interesting for several technical reasons as
well. First, in contrast to most command-line tools such as coreutils, it is
interactive and implements its event loop via the 'select' system. This
provided us with the incentive to implement 'select' in Noux. Second, with far
more than 100,000 lines of code, VIM is not a toy but a highly complex and
advanced UNIX tool. Third, its user interface is based on ncurses, which
requires a fairly complete terminal emulator. Consequently, conducting the
development of Noux implied working with and understanding several components
in parallel including Noux itself, the libc, the Noux libc plugin, ncurses,
VIM, and the terminal emulator. Our undertaking was successful. We are now able
to run VIM without modifications and manual porting work on Genode.
The novelty of Noux compared to other OS-level virtualization approaches such
OpenVZ and FreeBSD jails lies in the degree of isolation it provides and the
simplicity of implementation. Noux instances are isolated from each other
by microkernel mechanisms. Therefore the isolation between two instances does
not depend on a relatively large kernel but on an extremely small trusted
computing base of less than 35,000 lines of code. At the same time, the
implementation turned out to be strikingly simple. Thanks to the existing APIs
provided by the Genode framework, the Noux server is implemented in less than
2,000 lines of code. We are thrilled to learn that this low amount of code
suffices to bring complex UNIX software such as VIM to life.
For more technical details about our work on this topic, please refer to
the Sections [Noux] and [Framebuffer-based virtual terminal and ncurses].
GDB debugging via application-level virtualization
==================================================
The work described in the previous sections was motivated with the desire to
re-use existing software on Genode. This section explores a creative use
of sandboxing facilitating the Genode architecture.
User-level debugging is a feature that we get repeatedly asked about. Until
now, the answer was pretty long-winded because we use different debugging
facilities on different kernels. However, none of those facilities are
comparable to the convenient debugging tools we know from commodity OSes.
For a long time, we were hesitant to build in debugging support into Genode
because we were afraid to subvert the security of Genode by adding special
debug interfaces short-circuiting security policies. Furthermore, none
of the microkernels we love so dearly featured support for user-level
debugging. So we deferred the topic. Until now. With GDB monitor, we have
found an approach to user-level debugging that is not only completely in
line with Genode's architecture but capitalizes it. Instead of adding
special debugging interfaces to low-level components such as the kernel
and core, we use an approach that we call application-level virtualization.
[image no_gdb]
A Genode process uses low-level services provided by core as well as a
higher-level service implemented as separate process component.
Each Genode process interacts with several low-level services provided by
Genode's core, in particular the RAM service for allocating memory, the CPU
service to create and run threads, and the RM service to manage the virtual
address space of the process. However, the process does not contact core
directly for those services but requests them via its chain of parents (i.e,
the init process). This gives us the opportunity to route session requests for
those services to alternative implementations.
[image gdb]
GDB monitor transparently intercepts the interaction of a Genode process with
its environment. By virtualizing fundamental core services, GDB monitor
exercises full control over the debugging target. GDB monitor, in turn,
utilizes a separate service component to establish a terminal connection with
a remote GDB.
When running a Genode process as debugging target, we place an intermediate
component called GDB monitor between the process and its parent. Because
GDB monitor is now the parent of the debugging target, all session requests
including those for core services are issued at GDB monitor. Instead of routing
those session requests further down the tree towards core, GDB monitor
provides a local implementation of these specific services and can thereby
observe and intercept all interactions between the process and core. In
particular, GDB monitor gains access to all memory objects allocated from the
debugging target's RAM session, it knows about the address space layout, and
becomes aware of all threads created by the debugging target. Because, GDB
monitor does possess the actual capabilitiy to the debugging target's CPU
session, it can execute control over those threads, i.e., pausing them or
enabling single-stepping. By combining the information about the debugging
target's address space layout and the access to its memory objects, GDB monitor
is even able to transparently change arbitrary memory in the debugging target,
for example, inserting breakpoint instructions into its text segment.
Thanks to application-level virtualization, the once deemed complicated problem
of user-level debugging has become straight forward to address. The solution
fits perfectly into the Genode concept, maintains its security, and does not
require special-purpose debugging hooks in the foundation of the operating
system.
To get a more complete picture about our work on GDB monitor, please read on at
Section [GDB monitor].
Base framework, low-level OS infrastructure
###########################################
Handling CPU exceptions at user level
=====================================
To support user-level policies of handling CPU exceptions such as division by
zero or breakpoint instructions, we have added support for reflecting such
exceptions to the CPU session interface. The owner of a CPU session
capability can register a signal handler for each individual thread allocated
from the session. This handler gets notified on the occurrence of an exception
caused by the respective thread similar to how page faults are reflected to
RM sessions. The CPU exception handling support has been implemented on the
Fiasco.OC and OKL4 base platforms.
Remote access to thread state
=============================
Closely related to the new support for handling CPU exceptions, we have
extended the information that can be gathered for threads of a CPU session to
general-purpose register state and the type of the last exception caused by the
thread. Furthermore, the CPU session interface has been extended to allow the
pausing and resumption of threads as well as single-stepping through CPU
instructions (on x86 and ARM).
All those additions are subject to capability-based security so that only the
one who possesses both a CPU-session capability and a thread capability can
access the thread state. This way, the extension of the CPU session interface
opens up a lot of new possibilities (especially regarding debugging facilities)
without affecting the security of the overall system.
Improved signaling latency
==========================
During the time span of the last two years, we have observed a steadily growing
number of use cases for Genode's signaling framework. Originally used only for
low-frequent notifications, the API has become fundamental to important Genode
mechanisms such as the data-flow protocol employed by the packet-stream
interface, the on-demand fault handling performed by dataspace managers, and
CPU exception handling. This observation provided us with the incentive to
improve the latency of delivering signals by placing signal delivery into a
dedicated thread within core.
Optimization for large memory-mapping sizes
===========================================
Some kernels, in particular NOVA, are optimized to deal with flexible mapping
sizes that are independent of physical page sizes. The internal representation
of memory mapping independent on page sizes can greatly reduce the memory
footprint needed to keep track memory mappings, but only if large mappings are
used. In practice, mapping sizes are constrained by their sizes and their
alignment in both physical and virtual address spaces. To facilitate the use of
large mappings with NOVA, we have optimized core for the use of large mappings.
Core tries to size-align memory objects in both physical memory and virtual
memory (core-local as well as within normal user processes). This optimization
is completely transparent to the Genode API but positively affects the
page-fault overhead throughout the system, most noticeably the NPT-fault
overhead of the Vancouver VMM.
Standard C++ library
====================
To accommodate users of the standard C++ library, we used to host the 'stdcxx'
library to the 'libc' repository. Apparently, there are use cases for 'stdcxx'
without Genode's C library, in particular for hybrid Linux/Genode programs that
are linked against the host's glibc anyway. So we decided to move the 'stdcxx'
to the base repository. So if you are needing 'stdcxx' but are not using
Genode's libc, enabling the 'base' repository in your build configuration
suffices.
Terminal-session interface
==========================
We revised the terminal session interface by adding a simple startup-protocol
for establishing terminal connections: At session-creation time, the terminal
session may not be ready to use. For example, a TCP terminal session needs an
established TCP connection first. However, we do not want the session-creation
to be blocked on the server side because this would render the server's
entry point unavailable for all other clients until the TCP connection is
ready. Instead, we deliver a 'connected' signal to the client emitted when the
session becomes ready to use. The Terminal::Connection waits for this signal
at construction time. Furthermore, we extended the terminal session interface
with the new 'avail()' and 'size()' functions. The 'avail()' function can be
used to query for the availability of new characters. The 'size()' function
returns the size of the terminal (number of rows and columns).
Dynamic linker
==============
The dynamic linker underwent several changes in its memory management. Since
the original FreeBSD implementation heavily relies on UNIX-like 'mmap'
semantics, which up to this point was poorly emulated using Genode primitives,
we abandoned this emulation completely. In the current setup the linker
utilizes Genode's managed-dataspace concept in order to handle the loading of
binaries and shared libraries and thus implements the required memory
management correctly.
Also the linker has been adapted to Genode's new GCC 4.6.1 tool chain, which
introduced new relocation types on the ARM platform.
Libraries and applications
##########################
C runtime
=========
We have updated our FreeBSD-based C library to version 8.2.0 and thereby
changed the way how the libc is integrated with Genode. Instead of hosting
the 3rd-party code as part of the Genode source tree in the form of the 'libc'
repository, the libc has now become part of the 'libports' repository. This
repository does not contain the actual 3rd-party source code but only the
rules of how to download and integrate the code. These steps are fully
automated via the 'libports/Makefile'. Prior using the libc, please make sure
to prepare the 'libc' package within the 'libports' repository:
! cd <genode-dir>/libports
! make prepare PKG=libc
Vancouver virtual machine monitor
=================================
Vancouver is a virtual machine monitor specifically developed for the use with
the NOVA hypervisor. It virtualizes a 32-bit x86 PC hardware including various
peripherals.
The official project website is [https://hypervisor.org]. Vancouver relies
on hardware virtualization support such as VMX (Intel) or SVM (AMD).
With the current release, we have added the first version of our port of
Vancouver to Genode to the 'ports' repository. To download the Vancouver
source code, simply issue the following command from within the 'ports'
repository:
! make prepare PKG=vancouver
The glue code between Vancouver and Genode is located at 'ports/src/vancouver/'.
At the current stage, the port is not practically usable but it demonstrates
well the general way of how the VMM code is meant to interact with Genode.
In contrast to the original Vancouver, which obtains its configuration from
command-line arguments, the Genode version reads the virtual machine
description as XML data supplied via Genode's config mechanism. For each
component declared within the '<machine>' node in the config XML file, a new
instance of a respective device model or host driver is instantiated. An
example virtual machine configuration looks like this:
! <machine>
! <mem start="0x0" end="0xa0000"/>
! <mem start="0x100000" end="0x2000000"/>
! <nullio io_base="0x80" />
! <pic io_base="0x20" elcr_base="0x4d0"/>
! <pic io_base="0xa0" irq="2" elcr_base="0x4d1"/>
! <pit io_base="0x40" irq="0"/>
! <scp io_port_a="0x92" io_port_b="0x61"/>
! <kbc io_base="0x60" irq_kbd="1" irq_aux="12"/>
! <keyb ps2_port="0" host_keyboard="0x10000"/>
! <mouse ps2_port="1" host_mouse="0x10001"/>
! <rtc io_base="0x70" irq="8"/>
! <serial io_base="0x3f8" irq="0x4" host_serial="0x4711"/>
! <hostsink host_dev="0x4712" buffer="80"/>
! <vga io_base="0x03c0"/>
! <vbios_disk/>
! <vbios_keyboard/>
! <vbios_mem/>
! <vbios_time/>
! <vbios_reset/>
! <vbios_multiboot/>
! <msi/>
! <ioapic/>
! <pcihostbridge bus_num="0" bus_count="0x10" io_base="0xcf8"
! mem_base="0xe0000000"/>
! <pmtimer io_port="0x8000"/>
! <vcpu/> <halifax/> <vbios/> <lapic/>
! </machine>
The virtual BIOS of Vancouver has built-in support for loading an OS from
multiboot modules. On Genode, the list of boot modules is supplied with
the '<multiboot>' node:
! <multiboot>
! <rom name="bootstrap"/>
! <rom name="fiasco"/>
! <rom name="sigma0.foc"/>
! <rom name="core.foc"/>
! </multiboot>
This configuration tells Vancouver to fetch the declared boot modules from
Genode's ROM service.
For the current version, we decided to support SVM-based hardware only
for the mere reason that it is well supported by recent Qemu versions. At the
time of the release, the SVM exit conditions CPUID, IOIO, MSR, NPT, INVALID,
STARTUP are handled. Of those conditions, the handling of NPT (nested page
table) faults was the most challenging part because of the tight interplay
between the NOVA hypervisor and the VMM at this point.
With this code in place, Vancouver is already able to boot unmodified
L4ka::Pistachio or Fiasco.OC kernels. Both kernels print diagnostic output over
the virtual comport and finally wait for the first timer interrupt.
Even though the current version has no practical use yet, it is a great
starting point to dive deeper into the topic of faithful virtualization with
Genode. For a quick example of running Vancouver, please refer to the
run script at 'ports/run/vancouver.run'.
We want to thank Bernhard Kauer and Udo Steinberg for having been extremely
responsive to our questions, making the realization of this first version
possible at a much shorter time frame than we expected.
TCP terminal
============
The new TCP terminal located at 'gems/src/server/tcp_terminal' is a service
that provides Genode's terminal-session interface via individual TCP
connections. It supports multiple clients. The TCP port to be used for each
client is defined as session policy in the config node of the TCP terminal
server:
! <config>
! <policy label="client" port="8181"/>
! <policy label="another_client" port="8282"/>
! </config>
For an example of how to use the TCP terminal, please refer to the run script
at 'gems/run/tcp_terminal.run'.
Framebuffer-based virtual terminal and ncurses
==============================================
We significantly advanced the implementation of our custom terminal emulator to
be found at 'gems/src/server/terminal'. The new version supports all terminal
capabilities needed to display and interact with ncurses-based applications
(e.g., VIM) including support for function keys, colors, key repeat, and
multiple keyboard layouts. The us-english keyboard layout is used by default.
The German keyboard layout can be enabled using the '<keyboard>' config node:
! <config>
! <keyboard layout="de"/>
! </config>
As built-in font, the terminal uses the beautiful 'Terminus' monospaced font.
Our port of the ncurses library that comes as 'libports' package has become
fully functional when combined with the terminal emulator described above.
It is tuned to use the Linux terminal capabilities.
Noux
====
Noux is a runtime environment that imitates the behavior of a UNIX kernel
but runs as plain Genode program. Our goal for this release was to be
able to execute VIM with no source-code modifications within Noux.
For pursuing this goal, we changed the I/O back end for the initial file
descriptors of the Noux init process to use the bidirectional terminal-session
interface rather than the unidirectional LOG session interface. Furthermore,
as VIM is an interactive program, it relies on a working 'select' call. So
this system call had to be added to the Noux session interface. Because
'select' is the first of Noux system calls that is able to block, support
for blocking Noux processes had to be implemented. Furthermore, we improved
the handling of environment variables supplied to the Noux init process,
the handling of certain 'ioctl' functions, and hard links in TAR archives
that Noux uses as file system.
We are happy to report that thanks to Noux we have become able to run VIM on
Genode now! If you like to give it a spin, please try out the run script
'ports/run/noux_vim.run'.
GDB monitor
===========
Support of user-level debugging is a topic we get repeatedly asked about. It
is particularly hard because the debugging facilities exposed by operating
systems highly depend on the respective kernel whereas most open-source
microkernels offer no user-level debugging support at all.
The current release will hopefully make the life of Genode application
developers much easier. Our new GDB monitor component allows GDB to be
connected to an individual Genode process as a remote target (via UART or TCP
connection). Thereby, a wide range of convenient debugging features become
available, for example
* The use of breakpoints,
* Single-stepping through assembly instructions or at function level,
* Source-level debugging,
* Printing of backtraces and call-frame inspection, and
* Observing different threads of a Genode process
Both statically linked programs as well as programs that use shared libraries
are supported, which we see as a significant improvement over the traditional
debugging tools. Please note, however, that, at the current stage, the feature
is only supported on a small subset of Genode's base platforms (namely
Fiasco.OC and partially OKL4). We will extend the support to other platforms
depending on public demand.
The work on GDB monitor required us to approach the topic in a quite holistic
manner, adding general support for user-level debugging to the Fiasco.OC kernel
as well as the Genode base framework, componentizing the facility for
bidirectional communication (terminal session), and creating the actual GDB
support in the form of the GDB monitor component. To paint a complete picture
of the scene, we have added the following documentation:
:[https://genode.org/documentation/developer-resources/gdb]:
User-level debugging on Genode
L4Linux / L4Android
###################
Update to kernel version 3.0
============================
We have updated our modified version of the L4Linux kernel to support the
latest L4Linux kernel version 3.0.0. Moreover, we fixed some issues with the
kernel's internal memory management under ARM.
Please don't forget to issue a 'make prepare' in the 'ports-foc' directory,
before giving the new version a try.
Stub-driver support
===================
With this release, we introduce a bunch of new stub-drivers in L4Linux. These
stubs enable the use of Genode's NIC, terminal, and block services from Linux
applications. To use a Genode session from Linux, it's sufficient to provide
an appropriate service to the Linux instance. The stub drivers for these
services simply try to connect to their service and register corresponding
devices if such a service exists. For example, if a NIC session is provided to
Linux, it will provide an ethernet device named 'eth0' to Linux applications.
For terminal sessions, it will provide a serial device named 'ttyS0'.
In contrast to the NIC and terminal stub drivers, the block driver supports
the usage of more than one block session. Therefore, you have to state the
name of the individual block devices in the configuration. So, it is possible
to state which block device in Linux gets routed to which block session. An
example L4Linux configuration may look like follows
! <start name="l4linux">
! <resource name="RAM" quantum="512M"/>
! <config args="mem=128M console=ttyS0>
! <block label="sda"/>
! <block label="sdb"/>
! </config>
! <route>
! <service name="Block">
! <if-arg key="label" value="l4android -> sda"/> <child name="rootfs"/>
! </service>
! <service name="Block">
! <if-arg key="label" value="l4android -> sdb"/> <child name="home"/>
! </service>
! ...
! </route>
! </start>
The configuration provides two block devices in Linux named 'sda' and 'sdb',
whereby the first one gets routed to a child of init named 'rootfs' and the
second to a child named 'home'. Of course, both children have to provide the
block session interface.
L4Android
=========
Besides the support of L4Linux, Genode provides support for a slightly changed
L4Linux variant called L4Android, that combines L4Linux with the Android
kernel patches. To give Android on top of Genode a try, you need to prepare
your 'ports-foc' directory to contain the L4Android contrib code by issuing:
! make prepare TARGET=l4android
After that, a run script can be used to build all necessary components,
download the needed Android userland images, assemble everything, and start
the demo via Qemu:
! make run/l4android
Beforehand, the 'dde_ipxe' and 'ports-foc' repositories must be enabled in the
'etc/build.conf' file in your build-directory.
Although, in general Android runs on top of Genode, it seems that the whole
run-time overhead of (no-kvm) full emulation, para-virtualized Linux and Java,
makes it almost unusable within Qemu. Therefore, we strongly advise you to use
the Android version for x86 and turn on KVM support (at least partially). This
can be configured in the 'etc/tools.conf' file in your build directory by
adding the following line:
! QEMU_OPT = -enable-kvm
Unfortunately, it very much depends on your Qemu version and configuration,
whether Fiasco.OC runs problem-free with KVM support enabled. If you encounter
problems, try to use a limited KVM option with Qemu, like '-no-kvm-irqchip', or
'-no-kvm-pit' instead of '-enable-kvm'.
Device drivers
##############
Device-driver environment for iPXE network drivers
==================================================
Genode used network-card driver code from Linux 2.6 and gPXE. Unfortunately,
the gPXE project seems not very active since mid-2010 and the Linux DDE shows
its age with our new tool chain. Therefore, we switched to the iPXE project,
the official successor of gPXE, for our NIC drivers. Currently, drivers for
Intel E1000/E1000e and PCnet32 cards are enabled in the new 'nic_drv'. The
Linux based driver was removed.
:[https://ipxe.org]:
iPXE open source boot firmware
PL110 display driver
====================
The PL110 driver was reworked to support both the PL110 and PL111 controller
correctly. Moreover, it now runs not only within Qemu, but on real hardware
too. At least it is tested on ARM's Versatile Express evaluation board.
UART driver
===========
The first version of the PL011 UART driver implemented the LOG interface to
cover the primary use case of directing LOG output to different serial ports.
However, with the addition of GDB support with the current release, the use for
UARTs goes beyond unidirectional output. To let GDB monitor communicate with
GDB over a serial line, bidirectional communication is needed. Luckily, there
is a Genode interface for this scenario already, namely the terminal-session
interface. Hence, we changed the PL011 UART driver to provide this interface
type instead of LOG. In addition, we added an UART driver for the i8250
controller as found on PC hardware.
Both UART drivers can be configured via the Genode's config mechanism to route
each communication stream to a specific port depending on the session label of
the client. The configuration concept is documented in
'os/src/drivers/uart/README'. For a ready-to-use example of the UART drivers
please refer to the run script 'os/run/uart.run'.
Platform support
################
NOVA Microhypervisor version 0.4
================================
Genode closely follows the development of the NOVA hypervisor. With version 0.4,
NOVA more and more develops toward a full-featured and production ready
hypervisor. Therefore little effort was needed to enable Genode 11.11 on the
current NOVA kernel. The few changes include a new hypercall (SC control),
capability-based assignment of GSIs (Global System Interrupts), and support for
revoke filtering. Also, we improved Genode's page-mapping behavior to take
advantage of large flexpage sizes.
Fiasco.OC microkernel
=====================
Update to revision 38
~~~~~~~~~~~~~~~~~~~~~
With the current release we switched to the latest available Fiasco.OC kernel
version (revision 38). After having some timing issues on different ARM
platforms with Fiasco.OC in the past, we applied a small patch to correct the
timing behavior of the kernel to the current version. The patch is applied
automatically if executing 'make prepare' in the 'base-foc' repository.
Querying and manipulating remote threads
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To support usage of GDB on top of Genode for Fiasco.OC, several enhancements
were developed. First, the thread state accessible via the CPU-session
interface has been extended to reflect the whole register set of the
corresponding thread depending to the underlying hardware platform. Moreover,
you can now stop and resume a thread's execution. On the x86 platform, it has
become possible to enable single-stepping mode for a specific thread. All
exceptions a thread raises are now reflected to the exception handler of
this thread. The exception handler can be set via the CPU-session interface. To
support stop/resume, single stepping and breakpoints on ARM, we had to modify
the Fiasco.OC kernel slightly. All patches to the Fiasco.OC kernel can be found
in 'base-foc/patches' and are automatically applied when issuing 'make
prepare'.
Versatile Express Cortex-A9x4
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
With the current release, we introduce support for a new platform on top of
Fiasco.OC. The ARM Versatile Express evaluation board with Coretile Cortex
A9x4 now successfully executes the well known Genode demo - have a look at the
'os/run/demo.run' run-script. Unfortunately, this platform is not supported by
most Qemu versions shipped with Linux distributions. Furthermore, our tests
with a Qemu variant that supports Versatile Express and the Fiasco.OC kernel
were not successful. Nevertheless, on a real machine the demo is working
nicely. Other drivers such as PL111 and the mouse driver are untested yet.
Linux
=====
New IPC implementation based on UNIX domain sockets
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
On Linux, Genode processes used to communicate via UDP-Sockets. So, any IPC
message could be addressed individually to a specific receiver without
establishing a connection beforehand. However, Genode was never designed to
work transparently over the network and UDP seems overkill for our
requirements. With this release, we tackled this fact by adapting the IPC
framework to use UNIX domain sockets.
The design uses two sockets per thread - client and server socket. The server
socket is used to receive requests from any client on 'Ipc_server::_wait' and
accessible as 'ep-<thread id>-server', just as the former UDP port. After
processing the request, the server replies to the requesting client and returns
to wait state. On 'Ipc_client::_call', the client socket is used to send the
request and receive the response.
This sounds trivial but marks an important step away from IPC istream and
ostream based design to explicit handling of RPC client and server roles. Linux
(as well as other platforms) will benefit from this in planned future changes.
During the design, we also addressed two other issues:
Child processes in Linux inherit open file descriptors from their parents.
Therefore, children further down the Genode tree formerly had plenty of open
files. The current implementation uses the close-on-exec flag to advise the
Linux kernel to close the marked file descriptors before executing the new
program on 'execve()'.
Genode resources appeared in the file system just under '/tmp', e.g.,
dataspaces as 'ds-<user id>-<count>'. This always filled the global temp
directory with dozens of Genode-specific files. Now, Genode resources are
located in '/tmp/genode-<user id>'.
Support for manually managing local sub address spaces
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
On microkernel-based platforms, Genode provides a powerful mechanism to manage
parts of a process' address space remotely (from another process called
dataspace manager) or locally. In contrast to those platforms, however, the
concept of managed dataspaces is not available on Linux because this kernel
lacks a mechanism to remotely manipulate address spaces. Naturally, in the
world of monolithic kernels, it is the task of the kernel to manage the virtual
address spaces of user-level programs.
The uses of managed dataspaces roughly fall into two categories: the provision
of virtual memory objects (dataspaces) in an on-demand-paged fashion and the
manual management of a part of the local address space. An example for the
latter is the manual management of the thread context area, which must be kept
clean of arbitrary dataspace mappings. Another use case is the manual placement
of shared-library segments within the local address space. Traditionally, we
had to address those problems with special cases on Linux. To support these use
cases in a generic way, we enhanced the memory management support for the Linux
base platform to support so-called sub-RM sessions in the local address space.
A sub RM session is the special case of a managed dataspace that is used only
local to the process and populated eagerly (not on-demand paged). With local
sub-RM sessions, a large part of the virtual memory of the process can be
reserved for attaching dataspaces at manually defined offsets.
The new example 'base/src/test/sub_rm' illustrates the use of sub RM
sessions. The example works across all platforms. It can be executed using
the run script 'base/run/sub_rm.run'.
Improved handling of hybrid Linux/Genode programs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Hybrid Linux/Genode programs are a special breed of programs that use both the
Genode API and Linux libraries found on the host Linux system. Examples for
such programs are the libSDL-based framebuffer driver, the ALSA-based audio
driver, and the tun/tap-based NIC driver - generally speaking, components that
interface Genode with the Linux environment. Because we expected those kind of
programs to be rare, not much attention was paid to make the creation of this
class of programs convenient. Consequently, the target-description files for
them were rather clumsy. However, we discovered that Genode can be used as a
component framework on Linux. In such a scenario, hybrid Linux/Genode programs
are the normal case rather than an exception, which prompted us to reconsider
the role of hybrid Linux/Genode programs within Genode. The changes are:
* The new 'lx_hybrid' library takes care of the peculiarities of the
linking stage of a hybrid program. In contrast to a plain Genode component,
such a program is linked with the host's linker script and uses the host's
dynamic linker.
* To support the common case of linking host libraries to a hybrid program,
we introduced the new 'LX_LIBS' variable. For each library listed in
'LX_LIBS', the build system queries the library's linking requirements using
'pkg-config'.
* The startup procedure differs between normal Genode programs and hybrid
programs. Plain Genode programs begin their execution with Genode's startup
code, which performs the initialization of the address space, executes all
static global constructors, and calls the 'main' function. In contrast,
hybrid programs start their execution with the startup code of the host's
libc, leaving the Genode-specific initializations unexecuted. To make sure
that these initializations are performed prior any application code, the
'lx_hybrid' library contains a highly prioritized constructor called
'lx_hybrid_init' that performs those initializations as a side effect.
L4ka::Pistachio microkernel
===========================
The Pistachio kernel recently moved from the Mercurial to the Git (on Github)
version control system. We have updated the configuration and build process of
the kernel and user-land tools within Genode accordingly.
Genode's 11.11 tool chain also required an adaption of the system call bindings
on x86. This was caused by a change of GCC inline assembler input constraint
handling. GCC now passes memory constraints using stack-relative addressing,
which can lead to serious problems when manipulating the stack pointer within
the assembly code.
Build system and tools
######################
New tool chain based on GCC 4.6.1
=================================
Early on in the genesis of Genode, we introduced a custom tool chain to
overcome several problems inherent to the use of standard tool chains installed
on Linux host platforms.
First, GCC and binutils versions vary a lot between different Linux systems.
Testing the Genode code with all those different tool chains and constantly
adapting the code to the peculiarities of certain tool-chain versions is
infeasible and annoying. Second, Linux tool chains use certain features that
stand in the way when building low-level system components. For example, the
'-fstack-protector' option is enabled by default on some Linux distributions.
Hence, we have to turn it off when building Genode. However, some tool chains
lack this option. So the attempt to turn it off produces an error. The most
important problem with Linux tool chains is the dependency of their respective
GCC support libraries on the glibc. When not using a Linux glibc, as the case
with Genode, this leads to manifold problems, most of them subtle and extremely
hard to debug. For example, the support libraries expect the Linux way of
implementing thread-local storage (using segment registers on x86_32). This
code will simply crash on other kernels. Another example is the use of certain
C-library functions, which are not available on Genode. Hence, Genode provides
custom implementations of those functions (in the 'cxx' library).
Unfortunately, the set of functions used varies across tool-chain versions. For
these reasons, we introduced a custom configured tool chain where we mitigated
those problems by pinning the tools to certain versions and tweaking the
compiler configuration to our needs (i.e., preventing the use of Linux TLS).
That said, the use a our custom configured tool chain was not free from
problems either. In particular, the script for creating the tool chain relied
on a libc being present on the host system. The header files of the libc would
be used to build the GCC support libraries. This introduced two problems. When
adding Genode's libc to the picture, which is based on FreeBSD's C library, the
expectations of the GCC support libraries did not match 100% with the semantics
implemented by Genode's libc (e.g., the handling of 'errno' differs). The
second problem is the limitation that the tool chain could only be built for
the platform that corresponds to the host. For example, on a Linux-x86_32
system, it was not possible to build a x86_64 or ARM tool chain. For this
reason we used the ARM tool chains provided by CodeSourcery.
With Genode 11.11, we addressed the root of the tool-chain problem by
completely decoupling the Genode tool chain from the host system that is used
to build it. The most important step was the removal of GCC's dependency on
a C library, which is normally needed to build the GCC support libraries. We
were able to remove the libc dependency by sneaking-in a small custom libc stub
into the GCC build process. This stub comes in the form of the single header
file 'tool/libgcc_libc_stub.h' and brings along all type definitions and
function declarations expected by the support-library code. Furthermore, we
removed all GNU-specific heuristics from the tool chain. Technically, the
Genode tool chain is a bare-metal tool chain. But in contrast to existing
bare-metal tool chains, C++ is fully supported.
With the libc dependency out of the way, we are now free to build the tool
chain for arbitrary architectures, which brings us two immediate benefits. We
do no longer have to rely on the CodeSourcery tool chain for ARM. There is now
a 'genode-arm' tool chain using the same compiler configuration as used on x86.
The second benefit is the use of multiarch libs on the x86 platform. The
genode-x86 tool chain can be used for both x86_32 and x86_64, the latter being
the default.
The new tool-chain script is located at 'tool/tool_chain'. It takes care of
downloading all components needed and building the tool chain. Currently, the
tool chain supports x86 and ARM. Note that the 'tool_chain' script can be
executed in an arbitrary directory. For example, to build the Genode tool chain
for x86 within your '/tmp/' directory, use the following commands:
! mkdir /tmp/tool_chain
! cd /tmp/tool_chain
! <genode-dir>/tool/tool_chain x86
After completing the build, you will be asked for your user password to
enable the installation of the result to '/usr/local/genode-gcc/'.
Since we introduced GDB support into Genode, we added GDB in addition to GCC
and binutils to the Genode tool chain. The version is supposed to match the one
expected by Genode's GDB facility, avoiding potential problems with mismatching
protocols between GDB monitor and GDB.
Optimization of the library-dependency build stage
==================================================
The Genode build process consists of two stages. The first stage determines
inter-library dependencies using non-parallel recursive make. It traverses
all targets to be built and the libraries those targets depend on, and stores
the dependency information between libraries and targets in the file
'<build-dir>/var/libdeps'. This generated file contains make rules to be
executed in the second build stage, which performs all compilation and linking
steps. In contrast to the first stage, the work-intensive second stage can be
executed in parallel using the '-j' argument of make. Because of the serialization
of the first build stage, it naturally does not profit from multiple CPUs.
This should be no problem because the task of the first stage is simple and
supposedly executed quickly. However, for large builds including many
targets, we found the time needed for the first stage to become longer
than expected. This prompted us to do a bit of profiling.
Tracing the 'execve' syscalls of the first build stage via 'strace' evidenced that
the echo commands used for creating the 'var/libdeps' file attributed
significantly to the overall time because each echo involves the spawning of a
shell. There are two counter measures: First, we eagerly detect already visited
libraries and do not visit them again (originally, this detection was performed
later when already revisiting the library). This change improves the
performance by circa 10%. Second and more importantly, the subsequent echo
commands are now batched into one command featuring multiple echoes. This way,
only one shell is started for executing the sequence. This improvement leads to
a performance improvement of about 300%-500%, depending on the size of the
build. Lesson learned: Using make rules as shell scripts is sometimes a bad
idea.
Improved libports and ports package handling
============================================
We also enhanced the package cleanup rules in 'libports'. Now it's possible
to clean up contribution code package-sensitive analog to the preparation of
packages. If you don't want to tidy up the whole libports repository, but for
instance just the LwIP code, just issue:
! make clean PKG=lwip