Frage

Ich arbeite an Kernel-Design, und ich habe einige Fragen bezüglich Paging bekam.

Die Grundidee, die ich bisher habe, ist dies: Jedes Programm seine eigenen bekommt (oder so denkt, dass es) 4G Speicher, minus ein Abschnitt irgendwo, dass ich für die Kernel-Funktionen behalten, die das Programm aufrufen kann. Also, das Betriebssystem muss einen Weg herauszufinden, die Seiten in den Speicher zu laden, die das Programm muss während des Betriebs verwenden.

Wenn man nun annimmt, dass wir unendlich viel Arbeitsspeicher und Prozessorzeit hatten, konnte ich von jeder Seite des Programm geschrieben oder gelesen laden / zuordnen, wie es Seitenfehlern für Seiten geschah mit, die nicht existieren (oder wurden ausgelagert) so könnte das Betriebssystem schnell sie zuweisen oder tauschen sie in. in der realen Welt aber ich brauche diesen Prozess zu optimieren, so dass wir ein Programm nicht ständig den gesamten Speicher raubend haben, dass es jemals berührt.

Also ich meine Frage erraten ist, wie funktioniert ein Betriebssystem im Allgemeinen über diese gehen? Mein erster Gedanke ist, eine Funktion zu erstellen, die das Programm aufruft / freie Seiten zu setzen, die sie dann Speicher auf seinem eigenen Verwaltung, aber tut ein Programm im Allgemeinen dies zu tun, oder ist der Compiler annimmt, dass es freie Herrschaft hat? Auch, wie sie die Compiler Situationen umgehen, wo es ein ziemlich großes Speichersegment zuzuordnen muss? Muß ich eine Funktion zur Verfügung zu stellen, die es um X-Seiten zu geben versucht?

Dies ist offensichtlich nicht eine Sprache spezifische Frage, aber ich bin teilweise auf Standard-C und gut mit C ++, so würde ich alle Code-Beispiele wie in entweder dieser oder eine Baugruppe zu sein. (Montage sollte nicht notwendig sein, beabsichtige ich, die Datei ganz wie möglich mit so viel C-Code funktioniert, und optimieren als letzter Schritt.)

Eine andere Sache, die einfacher sein sollte, wie auch beantworten: Wie wird man im allgemeinen Kernfunktionen behandeln, die ein Programm aufrufen muss? Ist es in Ordnung, nur einen Satz Speicherbereich zu haben (ich war gegen Ende des virtuellen Raumes zu denken), dass die meisten Grundfunktionen / prozessspezifischen Speicher enthält, dass das Programm aufrufen kann? Mein Gedanke von dort wäre die Kernel-Funktionen etwas zu tun haben, sehr extravagant und tauscht die Seiten aus (so dass Programme nicht empfindlich Kernel-Funktionen in ihrem eigenen Raum sehen konnten), wenn Programme benötigen etwas größere zu tun, aber ich bin nicht wirklich wobei der Schwerpunkt auf Sicherheit an dieser Stelle.

Also ich, ich mache mir mehr Sorgen über die allgemeinen Design-Ideen als die Besonderheiten erraten. Ich mag die Kernel komplett mit GCC (irgendwie) kompatibel machen, und ich brauche, um sicherzustellen, dass es alles bietet, was ein normales Programm benötigen würde.

Vielen Dank für jede Beratung.

War es hilfreich?

Lösung

Ein guter Ausgangspunkt für all diese Fragen ist zu prüfen, wie Unix tut es. Als ein berühmtes Zitat sagt: „Diejenigen, die UNIX nicht verstehen, sind dazu verdammt, sie neu zu erfinden, schlecht.“

Zuerst über Kernel-Funktionen aufrufen. Es ist nicht genug, um einfach die Funktionen haben irgendwo kann ein Programm nennen, da das Programm höchstwahrscheinlich in „Benutzermodus“ (Ring 3 auf IA-32) läuft und der Kernel in „Kernel-Modus“ (in der Regel Ring 0 läuft auf IA-32) seine privilegierten Operationen zu tun. Sie müssen irgendwie zwischen den beiden Modi den Übergang zu tun, und das ist sehr Architektur spezifisch ist.

Auf IA-32, ist die traditionelle Art und Weise ein Tor in der IDT zu verwenden, zusammen mit einem Software-Interrupt (Linux verwendet int 0x80). Neuere Prozessoren haben andere (schneller) Möglichkeiten, es zu tun, und welche verfügbar sind, hängt davon ab, ob sich die CPU von AMD oder Intel, und auf der spezifischen CPU-Modell. Zu empfangen diese Variante verwendet aktuelle Linux-Kernel eine Seite von Code vom Kernel an der Spitze des Adressraumes für jeden Prozess abgebildet. Also, auf den letzten Linux, ein System zu tun rufen Sie eine Funktion auf dieser Seite aufrufen, die wiederum werden tun, was nötig ist, um Kernel-Modus zu wechseln (der Kernel mehr als eine Kopie dieser Seite, und choses, welche Kopie zu verwenden, beim Booten je nach Ausstattung Ihres Prozessors).

Nun wird die Speicherverwaltung. Dies ist ein großes Thema; Sie könnte ein großes Buch darüber schreiben und nicht das Thema exaust.

Achten Sie darauf, im Auge zu behalten, dass es zumindest zwei Blick auf den Speicher: die physische Ansicht (die wirkliche Reihenfolge der Seiten, sichtbar für das Hardware-Speicher-Subsystem und oft an externe Peripheriegeräte) und die logische Sicht (die Reihenfolge der Seiten durch Programme gesehen auf der CPU ausgeführt wird). Es ist ganz einfach beide zu verwechseln. Sie werden die Zuweisung physische Seiten und sie logische Adressen auf dem Programm oder Kernel-Adressraum zuweisen. Eine einzelne physikalische Seite kann mehrere logischen Adressen hat und kann auf verschiedene logische Adressen in verschiedenen Prozessen zugeordnet werden.

Der Kernel-Speicher (für den Kernel reserviert) wird in der Regel an der Spitze des Adressraumes von jedem Prozess abgebildet. Es ist jedoch so einrichten, kann es nur auf Kernel-Modus acessed werden. Es besteht keine Notwendigkeit für ausgefallene Tricks, den Teil des Speichers zu verbergen; die Hardware macht die ganze Arbeit, den Zugang zu blockieren (auf IA-32, es wird über Seite Flaggen oder Segmentgrenze durchgeführt).

Die Programme weisen Speicher auf den Rest des Adressraums in mehrfacher Hinsicht:

  • Ein Teil des Speichers wird durch den Kernel-Programmlader zugeordnet. Dies beinhaltet den Programmcode (oder „Text“), die Daten-Programm initialisiert ( „Daten“), geht das Programm nicht initialisierte Daten ( „BSS“ Nullen gefüllt), um den Stapel, und mehrere Gewinnchancen und endet. Wie viel zuzuteilen, wo, was sollten die anfänglichen Inhalte sein, die Schutz-Flags zu verwenden, und einige andere Dinge werden aus den Header auf der ausführbaren Datei gelesen geladen werden.
  • Traditionell auf Unix, gibt es einen Bereich des Speichers ist, die wachsen und schrumpfen (seine Obergrenze kann über den brk() Systemaufruf geändert werden). Dies wird traditionell von der Halde verwendet wird (die Speicherzuordner auf der C-Bibliothek, von denen malloc() eine der Schnittstellen ist, ist verantwortlich für den Heap).
  • Sie können oft den Kernel gebeten, eine Datei auf einen Bereich von Adressraum abzubilden. Liest und schreibt zu diesem Bereich sind (via Paging Magie) auf die Trägerdatei gerichtet. Dies wird in der Regel mmap() genannt. Mit einem anonymen mmap, können Sie neue Bereiche des Adressraumes zugewiesen, die nicht von jeder Datei gesichert, aber ansonsten die gleiche Art und Weise handeln. Die Programmlade Kernel wird oft mmap verwenden Teile des Programmcodes zuweisen (zum Beispiel kann der Programmcode durch die ausführbare Datei selbst gesichert werden).

Bereiche des Adreßraums acessing, die nicht in irgendeiner Weise zugeordnet sind (oder werden für den Kernel reserviert) wird ein Fehler betrachtet wird, einnd auf Unix ein Signal verursachen, um das Programm zu senden.

Der Compiler entweder reserviert Speicher statisch (indem sie auf die ausführbare Datei-Header angibt; die Programmlade des Kernels wird der Speicher zuweisen, wenn das Programm geladen) oder dynamisch (durch Aufruf einer Funktion auf der Standardbibliothek Sprache, die in der Regel dann ein ruft Funktion in der Sprache C-Standardbibliothek, die dann die Kernel-Speicher zuzuweisen ruft und unterteilt es, falls erforderlich).

Der beste Weg, die Grundlagen des all dies zu lernen, ist eine der mehr Bücher über Betriebssysteme zu lesen, insbesondere diejenigen, die eine Unix-Variante als Beispiel verwenden. Es geht in Art und Weise näher als ich es könnte auf eine Antwort auf Stackoverflow.

Andere Tipps

Die Antwort auf diese Frage ist sehr Architektur abhängig. Ich werde Sie sprechen x86 zu übernehmen. Mit x86, bietet ein Kernel im Allgemeinen eine Reihe von Systemaufrufen , die Eintrittspunkte in den Kernel vorgegeben sind. Benutzercode kann nur den Kernel an diesen bestimmten Punkten geben, so dass der Kernel sorgfältige Kontrolle hat, wie es in Wechselwirkung mit Benutzercode ein.

In x86 gibt es zwei Möglichkeiten, Systemaufrufe zu implementieren: mit Unterbrechungen und mit den SYSENTER / SYSEXIT Anweisungen. Mit Unterbrechungen, setzt der Kernel eine Interrupt-Deskriptortabelle (IDT) auf, die die möglichen Einstiegspunkte in den Kernel definiert. Benutzercode kann dann die int Anweisung, ein Soft-Interrupt zu erzeugen, in den Kernel zu nennen. Interrupts können auch durch Hardware (sogenannte Hard-Interrupts) erzeugt werden; diese Unterbrechungen sollten von Soft-Interrupts im Allgemeinen verschieden sein, aber sie müssen nicht sein.

Die SYSENTER und SYSEXIT Anweisungen sind ein schneller Weg, Systemaufrufe durchzuführen, da die Interrupt-Behandlung langsam ist; Ich bin nicht so vertraut mit der Verwendung von ihnen, so kann ich nicht kommentieren, ob sie sind eine bessere Wahl für Ihre Situation.

Unabhängig davon, welche Sie verwenden, müssen Sie den Systemaufruf-Schnittstelle definieren. Sie wollen wahrscheinlich Systemaufruf Argumente in den Registern und nicht auf dem Stapel passieren, da Sie einen Interrupt erzeugen, verursacht Stacks an den Kernel-Stack zu wechseln. Das bedeutet, Sie werden mit ziemlicher Sicherheit des Benutzer-Modus Ende einiger Assemblersprachen Stubs auf beide schreiben müssen, um den Systemaufruf zu machen und wieder auf dem Kernel Ende den Systemaufruf Argumente zu sammeln und die Register speichern.

Wenn Sie alle, dass an der richtigen Stelle, können Sie anfangen zu denken über Seite Umgang mit Fehlern. Seitenfehler sind effektiv nur eine andere Art von Interrupt - wenn der Benutzercode versucht, eine virtuelle Adresse zuzugreifen, für die es keine Seitentabelleneintrag, wird es Interrupt-14 erzeugen, und Sie werden auch die Verwerfungen Adresse als Fehlercode erhalten. Der Kernel kann diese Informationen nimmt und dann entscheiden, in der fehlenden Seite von der Festplatte, fügen Sie die Seitentabellenzuordnung und springt zurück in Benutzercode zu lesen.

empfehle ich Ihnen einige der Materialien einen Blick aus den MIT Betriebssysteme Klasse. Überprüfen Sie den Abschnitt Referenzen aus, es hat viele gute Sachen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top