Dies war eine großartige Lernkurve, die mir anscheinend geholfen hat, theoretische und konzeptionelle Ideen zu den zugrunde liegenden Geheimnissen von Betriebssystemen und Kerneln zu fördern. Ich hatte vermutet, ich hatte eine gute Idee, wie Oss funktioniert hat. Das Erstellen meines eigenen Betriebssystems war jedoch absolut eindeutiger als nur das Lesen. In meiner eigenen, ehrliche Meinung. Dies war eine Möglichkeit für mich, ein besseres Verständnis der Software zu haben, mit der ich im Kernel -Modus und im Benutzermodus anlegen möchte.
Bevor wir beginnen, obwohl das Kernel und das Betriebssystem 32bit sind. Ich werde auch in 64 Bit Konzepten erklären, offensichtlich ist einer von ihnen einen langen Modus.
Modi
Interrupts
Deskriptoren
Paging
Weitere Informationen zum geschützten Modus finden Sie in Intel® 64 und IA-32 Architekturen-Softwareentwicklerhandbuch Volume 3A: System-Programmierhandbuch, Teil 1; Kapitel 3 *
Was sind Interrupts?
Sie können sich Interrupts als ein Signal oder Daten vorstellen, das von einem Gerät wie Tastatur, Solid -State -Laufwerk, harten Treiber oder Maus und Software gesendet wird, die die CPU mitteilt, dass ein Ereignis stattgefunden hat und sofort aufhören muss, was es derzeit tut, um zu dem, was ihm die Interrupts zu schicken.
ZB, wenn Sie eine Maus verschieben/klicken, sendet der Mauscontroller einen Interrupt an den Interrupt -Controller für die CPU. Nach der Unterbrechung der Maus wird die CPU weiterhin vor dem Interrupt tun oder einen weiteren Interrupt verwalten, wenn es ein Signal wurde.
+------------------------+ +------------+
| TYPES OF INTERRUPTS |------------| Exceptions |
+------------------------+ +------------+
/
/
/
+------------+ +------------+
| HARDWARE | | SOFTWARE |
| INTERRUPTS | | INTERRUPTS |
+------------+ +------------+
IRQ-Linien oder PIN-basierte IRQs: Diese werden in der Regel statisch auf dem Chipsatz weitergeleitet. Drähte oder Linien werden von den Geräten auf dem Chipsatz zu einem IRQ -Controller ausgeführt, der die von Geräten gesendeten Interrupt -Anforderungen serialisiert und sie nach dem anderen an die CPU senden, um Rennen zu verhindern. In vielen Fällen sendet ein IRQ -Controller mehrere IRQs gleichzeitig an die CPU, basierend auf der Priorität des Geräts. Ein Beispiel für einen sehr bekannten IRQ-Controller ist die Intel 8259-Controller-Kette, die in allen IBM-PC-kompatiblen Chipsätzen vorhanden ist und zwei Controller miteinander verkettet und jeweils 8 Eingangsstifte für insgesamt 16 nutzbare IRQ-Signalstifte am Legacy IBM-PC bereitstellen.
Nachrichtenbasierte Interrupts: Diese werden signalisiert, indem ein Wert an einen Speicherort geschrieben wird, der für Informationen über das Unterbrechungsgerät, den Interrupt selbst und die Vectoring -Informationen reserviert ist. Dem Gerät wird ein Ort zugewiesen, an den es entweder nach Firmware oder durch die Kernel -Software schreibt. Anschließend wird ein IRQ vom Gerät unter Verwendung eines für den Bus des Geräts spezifischen Arbitrationsprotokolls erzeugt. Ein Beispiel für einen Bus, der meldungsbasierte Interrupt -Funktionen liefert, ist der PCI -Bus. Von wiki.osdev - https://wiki.osdev.org/interrupts
Eintrag - Der Eintrag definiert eine Region im Speicher, die zusammen mit der Grenze der Region und den mit dem Eintrag verbundenen Zugangsberechtigungen zu beginnen. Zugriff auf Privilegien wie bei der Ermittlung des Prozessors, ob das Betriebssystem in System (Ring 0) oder Anwendung (Ring 3) ausgeführt wird. Es verhindert, dass Anwendungen oder Usmode Zugriff auf bestimmte Register/Operanden und Mnemonik haben. Wie CR -Register bzw. CLI/STI.
Grenze - die Größe des Segmentdeskriptors
Segment Selector - Sie sind Register, die den Index der Deskriptoren enthalten
Um expliziter zu sein, ist ein Index kein Selektor
Dinge, die ein Segmentregister gilt:
Zugriff auf die Deskriptor -Tabelle hat auch Privilegde. Dies wird für jedes Register als RPL (Request Privilege Level) bezeichnet, aber für das cs wird CPL (aktuelle Privilegienebene) bezeichnet. Sie bedienen beide unterschiedliche Zwecke, die Sie in den Intel- oder AMD -Handbüchern herausfinden können.
Die Tabelle, die zum Betrachten verwendet werden soll. Eine Tabelle ist die GDT Die andere ist die LDT.
Eine informelle Regel, um sich die Verwendung von Selektor konzeptionell vorzustellen: Die informelle Regel lautet also:
selector = index + table_to_use + privilege table_to_use + index = Descriptor = alle Informationen über das zu verwendende Speichersegment -Segment
wobei das Pluszeichen keine arithmetische Operation ist
Bit -Feld des Segment -Selektorregisters:
15 3 2 0
+--------------------------------------------------+----+--------+
| Index | TI | RPL |
+--------------------------------------------------+----+--------+
TI = Table Indicator: 0 = GDT, 1 = LDT
The TI specify if the Descriptor were dealing with is a GDT or LDT
IF(TI == 0) THEN
... THE DESCRIPTOR IS A GDT
ELSEIF(TI == 1) THEN
... THE DESCRIPTOR IS A LDT
GDT ist 1: 1 mit logischer Adresse, ein Beispiel für die GDT mit dem Selektor:
<---- Selector ----> +----- Segment Selector Register
+-------+----+-----+ v
| Index | TI | RPL | = DS
+-------+----+-----+ GDT LDT
| | +---------------------+ +---------------------+
| +------------>| Null Descriptor | | Null Descriptor |
| +---------------------+ +---------------------+
| | Descriptor 1 | | Descriptor 1 |
| +---------------------+ +---------------------+
| | | | |
| ... ... ... ... ... ... ... ...
| | |
| +---------------------+
+------------------->| Descriptor K |
+---------------------+
| |
... ... ... ...
RPL (Request Privilege Level) describes the privilege for accessing the descriptor
Wir speichern die GDT -Basis (Adresse) und die Grenze (Größe unseres GDT) im GDTR. Das GDTR verweist auf alle unsere GDT -Einträge im Speicher, beginnend von der Basis. Danach wird es dann mit dem lgdt Mnemonic geladen:
typedef union _gdt_descriptor
{
struct
{
uint64_t limit_low : 16 ;
uint64_t base_low : 16 ;
uint64_t base_middle : 8 ;
uint64_t access : 8 ;
uint64_t granularity : 8 ;
uint64_t base_high : 8 ;
};
} __attribute__((packed)) gdt_entry_t ;
gdt_entry_t gdt_entrys[ 256 ];
/* The GDTR (GDT Register) */
struct gdtr
{
uint16_t limit;
uint32_t base;
} __attribute__((packed)) gdtr;
...
gdtr.base = &gdt_entrys;
gdtr.limit = ( sizeof (gdt_descr) * 256 ) - 1 )
Weitere Informationen finden Sie im Handbuch des AMD64 -Architekturprogrammierers, Band 2, Abschnitt 4.7 (S. 84 - 90 {+}).
Hinweis darauf und darauf. https://notes.shichao.io/utlk/ch2/#paging-in-hardware Dies war bei weitem der größte Spaß, den ich hatte. Ich war sehr aufgeregt, als ich es verstand.
X86 OS Legacy-Paging Virtuelle Adresse mit 4 KB-Seiten:
X86 OS CR4.Pae Paging Virtuelle Adresse mit 4KB -Seite:
x86_64 (IA-32E) OS CR4.lme/Cr4.Pae Paging Virtual Adresse mit 4KB-Seite:
• Die WP- und PG -Flaggen im Kontrollregister CR0 (Bit 16 bzw. Bit 31).
• Die PSE-, PAE-, PGE-, PCID-, SMEP-, SMAP- und PKE -Flaggen im Kontrollregister CR4 (Bit 4, Bit 5, Bit 7, Bit 17, Bit 20, Bit 21 bzw. Bit 22).
• Die LME- und NXE -Flaggen in der MSR Ia32_efer (Bit 8 bzw. Bit 11). • Die Wechselstromflagge im EFLAGS -Register (Bit 18). Von Kapitel 4 von Intel® 64 und IA-32 Architekturen-Softwareentwicklerhandbuch Volume 3A: System-Programmierhandbuch, Teil 1; Kapitel 4
• Die LME- und NXE -Flaggen in der MSR Ia32_efer (Bit 8 bzw. Bit 11). • Die Wechselstromflagge im EFLAGS -Register (Bit 18). Kapitel 4 von Intel® 64 und IA-32 Architekturen-Softwareentwickler Handbuch Volume 3A: System-Programmierhandbuch, Teil 1; Kapitel 4
Wenn Cr4.pae und/oder cr4.lme auf 1 eingestellt sind, wird PSE vollständig ignoriert.
Kein Terminal hinzugefügt
cd smkrnl; make run
Für den Funken der Inspiration/Unterstützung bei meiner kontinuierlichen Bemühungen zu diesem Projekt und für die Unterstützung mir, bestimmte Konzepte in der Entwicklung von Kernel/Betriebssystemen zu verstehen. =))