|
| | | |
Design of RMoX
[ top-level
| base-layers
| kernel
| driver-core
]
This page gives some details on how RMoX is structured, and how its various components fit together.
The diagram on the right shows the top-level structure of the RMoX system:
At the bottom of this is the hardware, i.e. the machine (or emulator) that RMoX runs on. Interacting directly with the hardware are
RMoX's device-drivers and the base-layer.
The base-layer provides an abstract interface to the hardware and can be
changed depending on the desired use of RMoX. The main functions of the base-layer are to provide the bootstrap, discovery and
initialisation of certain hardware (e.g. the MMU, SMP), access to physical memory, interrupts and IO/memory-mapped devices.
The scheduler component is responsible for occam-pi process scheduling and communication in RMoX. At the moment, this is a slightly modified build of the CCSP
run-time kernel used in KRoC.
The device-drivers, mostly written in occam-pi, allow RMoX and its applications to use hardware devices (in the same way that device-drivers in other operating systems do).
We currently have drivers for a variety of standard PC hardware devices, including keyboards, mice, USB host controllers, and the particular hardware found on our PC104+ systems
(including a framebuffer driver for the AMD Geode GX, and a touchscreen input driver for the Philips UCB1400).
On top of the device-drivers and scheduler sits the RMoX kernel proper. Described below, this is the process network that provides our operating-system functionality
(including running applications).
The two base-layers currently supported are:
Bare-metal base-layer: this is now the default base-layer, written in a small amount of assembler and C, performing basic initialisation and providing support
functions for the run-time system.
User-mode base-layer: this provides a hardware abstraction for running RMoX in an existing Linux system as a normal user-mode application. This approach is
particularly useful for debugging high-level functionality.
Three other base-layers that we have used previously, but are no longer supported, are:
Minlinux base-layer: a stripped-down version of the Linux kernel (2.4 series) that essentially replaces
the traditional "init" task with the RMoX system.
Linux26 base-layer: a minimal configuration and wrappers for Linux 2.6, that loads the RMoX system as a module when booted (unconditionally transferring
control to it). This approach is slightly cleaner than the minlinux base-layer as it does not require any modifications to the Linux 2.6 kernel tree.
OSKit base-layer: a piecemeal collection of OS structural components from the Flux OSKit.
Planned for the future are:
The diagram on the right shows the top-level process network for RMoX. Most of the system's code and functionality is contained within the
four core server processes. The kernel process acts largely as a switch, redirecting requests from the console and elsewhere to the
appropriate server.
The four core servers are:
The fs.core process network is responsible for managing file-systems in RMoX. The way this is currently presented to the rest of the
systems is as a Unix/POSIX style interface, with a single root and individual file-systems mounted in a tree-fashion. The currently supported file-systems
include a ramdisk-fs and device-fs (one way of accessing device drivers), with a process file-system, ROM-disk and FAT16/FAT32 support under construction.
The driver.core process network contains the various device-drivers. There are currently around 55 device-drivers, many of which are
for real devices (e.g. Geode GX graphics, PC serial port, i8042 keyboard and mouse, AIM104-multi-io board, etc.), and some of which are pseudo-devices (e.g.
generic keyboard, pointer, virtual PWM driver).
The network.core process network is responsible for implementing the network stack in RMoX. This currently includes rudimentary support for IP, ICMP, UDP and
TCP protocols.
The service.core process network provides various services to RMoX applications (and other kernel components). This currently includes things
such as the font-engine service (provides fonts to graphical applications), and the posix-service, that provides a POSIX API style channel interface.
The system 'startup' happens inside the console process. This is where initial device-drivers are loaded and started, and the ramdisk file-system mounted, before
starting up the six virtual consoles (and processes that switch the keyboard and screen between them). The first virtual terminal is used for log-output, which is also
dumped to a serial-port by default (specified in the RMoX configuration). The fifth and sixth virtual terminals run instances of the system-console process,
into which a user can type commands, etc. The other three virtual terminals, if so configured, run demonstration animations (dining philosophers, bar simulation and matrix
simulation), otherwise these are available for use. The function keys F1 - F6 can be used to switch between virtual terminals.
The diagram on the right shows a selection of the internals of the driver-core process network, specifically those that handle keyboard input in some fashion.
In fact, this is only part of the picture, as the "usb.hcd" driver will be connected to the "pci" driver (to get access to the PCI based USB host controller).
The "usb.hcd" driver will also be connected to the "system" driver, to receive interrupts, as will the "i8042" driver (for keyboard and mouse interrupts).
The "i8042" driver is also connected to the generic "pointer" driver, which like the "keyboard", can receive events from multiple sources.
The "dnotify" driver is used to organise rendezvous between components. For instance, when the "usb.keyboard" driver is started, it establishes a connection
to "dnotify", and requests to be notified of USB keyboard class devices as they become available. The "usb.driver" process network is also connected to
"dnotify". When a new USB keyboard is connected to the system, "usb.driver" will send a notification message to "dnotify", which in turn notifies the
"usb.keyboard" driver. On receipt of such a message, the "usb.keyboard" driver establishes one connection to the "usb.driver", to interact with the
device (whose I/O traffic is scheduled on the USB bus managed by the "usb.driver"), and another connection to the generic "keyboard" driver, to which it sends
keystrokes received from the USB device. In a similar fashion, the "i8042" driver also delivers keystrokes to the "keyboard" driver. As with typical operating
systems, any keyboards plugged into the system become available for use on the system console. However, things don't have to be arranged this way: we can easily modify the system
to deliver keystrokes from newly connected USB keyboards elsewhere.
Outside of the driver core, keystrokes are passed up to the "console" process, which intercepts F1 through F6 for switching between virtual terminals, and passes any other
keystrokes to the particular process running in those terminals (e.g. the "system.console").
Only six driver processes are shown above, and then, only at the outermost level — most of the device drivers are implemented as process networks. An actual up and running
system may have in excess of 30 top-level drivers, with hundreds of processes running inside these. The resulting connections established dynamically throughout the system can
become complicated (to look at), but are not complex: like the overall system, these construct their own client-server (or IO-PAR) process networks, which we can reason about formally,
and for which we can have guarantees of deadlock and livelock freedom. The technicalities of actually doing this are under construction (requiring CSP-based compiler analysis of occam-pi
code). In essense, specifications for process interactions are developed, with which the compiler can ensure correct implementation, and which we (with the help of proof tools) can
use to reason about the compositional correctness of these interaction specifications.
|