2 Stand der Technik
2.1 Unix-Systeme auf Mikrokernen
In der Vergangenheit waren Unix-Implementationen auf Mikrokernen schon
oft ein Forschungsthema. Motivation dafür ist der Wunsch, die
Vorteile eines Mikrokerns auszunutzen (Modularität, Flexibilität,
Anpaßbarkeit) und dennoch nicht auf das Betriebssystem Unix als
Werkzeug und Entwicklungsplattform verzichten zu müssen.
Um auf einem Mikrokern die Unix-Funktionalität zu erbringen, wurden
verschiedene Ansätze entwickelt: [6]
- Single-Server.
- In dieser Architektur erbringt eine einzelne auf dem Mikrokern
im Nutzer-Modus laufende Task die Unix-Funktionalität. Beispiele sind
der Mach-Single-Server der CMU [7], Lites [8], Mklinux [1], OSF/1
und Suns Spring Unix-Server [9].
Die vier erstgenannten Vertreter sind Portierungen von monolithischen
Unix-Betriebssystemen auf den Mikrokern Mach [10].
Solche Portierungen sind ein geeignetes Mittel, um schnell zu einer
Unix-Emulation auf einem Mikrokern zu gelangen, und bieten sich für
Single-Server an, da diese prinzipiell ein in den Nutzer-Modus
verlegtes monolithisches System darstellen.
- Multi-Server.
- Implementiert man ein Unix-System als mehrere Server-Module, die
jeweils einen Teil der Unix-Funktionalität erbringen, so erhält man
einen Multi-Server. Beispiele für diesen Aufbau sind der
Mach-Multi-Server der CMU [11] und GNU Hurd [12].
Der klare Vorteil dieser Architektur ist die verbesserte Modularität,
die es bei geeignetem Design erlaubt, einzelne Teile der
Unix-Emulation bei Bedarf auszutauschen oder zu erweitern. So wird es
beispielsweise möglich, durch mehrere Emulationsmodule einem Rechner
gleichzeitig mehrere Betriebssystem-,,Persönlichkeiten'' zu geben. Ein
weiteres Beispiel ist Hurds Translator-Konzept: Es ermöglicht die
Interpretation beliebiger Daten als Dateisystem, vorausgesetzt es
existiert ein geeigneter Translator. So ist es beispielsweise
möglich, Translatoren für tar-Archive oder ftp-Server zu
bauen. [12]
Allen bisherigen Ansätzen gemein ist, daß im allgemeinen die
Leistung der Unix-Emulationen schlechter ausfällt als die
vergleichbarer monolithischer Systeme. Bisher wurde dafür oft der
Mikrokern-Ansatz insgesamt verantwortlich gemacht; jedoch konnte in
neuerer Forschung gezeigt werden, daß der Leistungsverlust im
wesentlichen durch die Konstruktionsprinzipien älterer Mikrokerne
bedingt war. Dies führte sowohl zur Entwicklung von
Optimierungsverfahren für diese Kerne (z.B. Binden von Server-Code in
den Adreßraum des Mikrokerns in Mach [13] und
SPIN [2]) als auch zur Konstruktion neuer Mikrokerne
einer zweiten Generation wie L3, L4 und QNX. [14]
[4] [3] 2.2 Der Mikrokern L4
L4 ist ein Mikrokern der zweiten Generation für Intel-CPUs, der von
Jochen Liedtke an der GMD entwickelt wurde. Er wurde nach dem
Minimalitätsprinzip konstruiert und implementiert nur eine kleine
Anzahl von Primitiven und Kernobjekten. Aufbauend auf diesen können
flexibel Betriebssysteme konstruiert werden. [4]
Implementiert sind Operationen für folgende Objekte:
- Flexibel große Seiten, Flexpages, die den Zugriff auf
bestimmte Adressen des Speicher- und des I/O-Adreßraums der CPU
erlauben.
- Virtuelle Adreßräume, die aus Seiten aufgebaut sind.
Flexpages (Mengen von Seiten) können zwischen Tasks (s.u.) durch
IPC-Operationen eingeblendet (map) und weitergereicht
(grant) werden, und es gibt einen Systemruf zum Ausblenden
(flush) von Flexpages.
- Threads sind Aktivitäten, die in Adreßräumen ablaufen. Sie sind
durch eindeutige IDs identifizierbar und können durch
IPC-Operationen miteinander kommunizieren.
- L4 kennt zwei Sicherheits-Domänen:
- Tasks bestehen aus einem Adreßraum und mindestens einem
darin ablaufenden Thread. Der Adreßraum einer Task kann nur durch die
zugeordneten Threads manipuliert werden (Taskautonomie).
- Clans bestehen aus einer Chief-Task und den von ihr
erzeugten Kind-Tasks (die ihrerseite wieder Chiefs ihres eigenen Clans
sind). L4 leitet jede IPC-Nachricht, die Clan-Grenzen überschreitet,
zunächst an den nächsten Chief weiter. Der Chief hat die Möglichkeit,
die Nachricht unter Verwendung beliebiger Algorithmen zu verarbeiten
oder zu überprüfen und dann auf dem IPC-Pfad weiterzuleiten. So wird
es möglich, Sicherheits-Strategien zu implementieren, um zum Beispiel
das System vor Tasks eines Clans zu schützen. [15]
[16]
L4 ist ein sehr kleiner, außerordentlich schneller Mikrokern:
- Sein IPC-Mechanismus ist eine Größenordnung schneller als bei
traditionellen Mikrokernen.
- L4s Paging-Mechanismus ist durch seine Leichtgewichtigkeit
besonders effizient.
- Die Kontextwechsel- und Adreßraumumschaltzeiten konnten durch eine
geeignete Konstruktion des Kerns minimiert werden, so daß es nicht
nötig ist, Code in den Kern zu binden, um eine gute Leistung zu
erzielen. [4]
L4 enthält keinerlei Gerätetreiber, sondern unterstützt auf
Nutzerebene implementierte Gerätetreiber durch folgende Mechanismen:
- Der I/O-Adreßraum der Intel-CPU kann, wie der Speicheradreßraum
auch, durch das Versenden von Flexpages in beliebige Tasks
eingeblendet werden.
- Privilegierten Tasks ist es gestattet, das CPU-Statusregister zu
manipulieren, so daß Interrupts gesperrt und wieder freigegeben werden
können.
- Threads können sich an Interrupt-Quellen ,,anschließen''.
Hardware-Interrupts werden vom L4-Kern in Nachrichten umgewandelt und
dem angeschlossenen Thread zugestellt.
[15]
Ähnlich werden auch Speicher-Manager und Scheduler auf Nutzer-Ebene
unterstützt:
- Seitenfehler werden vom L4-Kern in Nachrichten umgewandelt und an
einen bei der Thread-Erzeugung zu definierenden Pager-Thread gesendet.
Der unterbrochene Thread wird fortgesetzt, wenn der Pager eine Flexpage
zurücksendet, die den Seitenfehler auflöst.
- Scheduling auf Nutzer-Ebene wird durch sogenannte ,,Preemption
Handler'' unterstützt: Läuft die aktuelle Zeitscheibe eines unter der
Kontroll eines Preemption Handlers laufenden Threads ab, so wird
dieser vom L4-Kern mit einer IPC-Nachricht unterrichtet. Der Thread
wird erst nach einer Antwortnachricht des Preemption Handlers
fortgesetzt.
[15]
2.3 Das Betriebssystem Linux
Linux ist eine frei verfügbare Unix-Implementation für Rechner mit
den CPUs Intel-x86, Motorola-68k, Digital-Alpha, PowerPC und SPARC
(Portierungen auf weitere Maschinen sind in Arbeit). Es unterstützt
eine Vielzahl von Anwendungen traditioneller Unix-Systeme wie das
X-Window-System, TCP/IP-Netzwerksoftware, Emacs u.v.a.m. [17]
Der Linux-Kern wurde von Linus Torvalds aus Helsinki und vielen
freiwilligen Helfern entwickelt. Es handelt sich um einen
traditionellen monolithischen Kern, der alle Aufgaben klassischer
Betriebssystem-Kerne übernimmt. Dazu enthält er folgende
Bestandteile:
- eine maschinenabhängige Schicht, die für die anderen
Kernbestandteile Funktionen und Abstraktionen bereitstellt, die die
eigentliche Hardware kapseln;
- Gerätetreiber, davon einige maschinenabhängig;
- Protokolltreiber für Netzwerk-Protokolle;
- Dateisysteme; und
- Verwaltung aller Maschinen-Ressourcen wie zum Beispiel Rechenzeit
und Speicher. [18]
Durch die wohldefinierte maschinen- (oder architektur-) abhängige
Schicht erreicht der Linux-Kern eine hohe Portabilität: Die restlichen
Kernbestandteile sind dadurch maschinenunabhängig und müssen bei einer
Portierung des Linux-Kerns auf eine andere Architektur nicht
modifiziert werden.
Da es in dieser Arbeit um die Portierung des Linux-Kerns auf den
Mikrokern L4 geht, wollen wir auf diese Schicht noch etwas genauer
eingehen.
Der architekturabhängige Teil muß Schnittstellen für folgende
Aufgabenbereiche implementieren: [19]
- ABI-Definition
- Dieser Teil definiert die Schnittstelle zwischen
Applikationsprogrammen und dem Linux-Kern (ABI = Application
Binary Interface), zum Beispiel Nummern von Systemrufen, Signalen
usw. Wenn es für eine Architektur bereits eine andere
Unix-Implementation gibt, so verwendet man oft deren ABI als
Anhaltspunkt, um Binärkompatibilität zu erreichen.
- Gerätetreiberunterstützung
- Dazu gehört die Kapselung von Hardwareschnittstellen, die es auf
mehreren Architekturen gibt, die aber architekturabhängig angesteuert
werden müssen, wie die Floppy- und DMA-Hardware und Zugriffe auf den
I/O-Adreßraum der Maschine.
- Interruptverwaltung
- Dieser Teil stellt den Gerätetreibern und dem architekturunabhängigen
Linux-Code eine architekturübergreifende Schnittstelle zur
Interrupt-Hardware zur Verfügung.
- Aktivitäten
- sind eine kern-interne Abstraktion der
Linux-Prozesse.(1) Sie bestehen aus
einem Prozessorzustand (Thread) und einem Kontext.
In dieser Arbeit unterscheiden wir zwischen Nutzer- und
Kern-Aktivitäten. Zum Kontext einer Nutzer-Aktivität gehört im
wesentlichen ein Nutzer-Adreßraum (der Adreßraum des Linux-Prozesses).
Jeder Nutzer-Aktivität ist eine Kern-Aktivität zugeordnet, zu deren
Kontext neben dem aktuellen Zustand der Nutzer-Aktivität ein
Kern-Stack und der (von allen Kern-Aktivitäten gemeinsam benutzte)
Kern-Adreßraum gehören.
Der maschinenabhängige Teil muß Methoden zur Erzeugung und zum Löschen
von Aktivitäten sowie zum Umschalten zwischen ihnen bereitstellen.
Ferner gehören Operationen zur Manipulation des Nutzeradreßraums
(Copy-In/Out) und zum Betreten und Verlassen des
Kern-Modus dazu.
- Weitere Schnittstellen
- unter anderem solche zum Booten und Rebooten und zur
Unterstützung für das proc-Dateisystem und zum Schreiben einer
core-Datei.
Fußnoten:
- Aktivitäten werden im Linux-Quelltext
,,Threads'' genannt. Wir vermeiden diesen Begriff hier, um Aktivitäten
nicht mit den L4-Threads durcheinanderzubringen.
Michael Hohmuth
29. August 1996