Linus Torvalds emulieren: Erstellen Sie Ihr eigenes Betriebssystem aus 0 (V)

In diesem fünften Teil sehen wir eine Tabelle, die der GDT sowohl theoretisch als auch in der Verwendung sehr ähnlich ist. Wir beziehen uns auf die IDT. IDT steht für Interrupts Beschreibungstabelle y ist eine Tabelle, die zur Behandlung auftretender Interrupts verwendet wird. Zum Beispiel macht jemand eine Division durch 0, die für die Verarbeitung zuständige Funktion wird aufgerufen. Diese Funktionen sind die ISR (Serviceroutinen unterbrechen). Erstellen wir also die IDT und fügen ISR hinzu.

Zuerst deklarieren wir die Strukturen, die dem IDT entsprechen:

struct Entry{
uint16_t base_low;
uint16_t sel;
uint8_t always0;
uint8_t flags;
uint16_t base_high;
} __attribute__((packed));
struct Ptr{
uint16_t limit;
uint32_t base;
} __attribute__((packed));

Wie Sie sehen, wenn Sie es mit dem GDT vergleichen, ist die Ptr-Struktur identisch und der Eintrag ist ziemlich ähnlich. Daher sind die Funktionen zum Einfügen eines Eintrags (SetGate) und zum Installieren (Installieren) sehr ähnlich.

void ND::IDT::SetGate(uint8_t num,uint32_t base,uint16_t sel, uint8_t flags)
{
idt[num].base_low=(base & 0xFFFF);
idt[num].base_high=(base >> 16) & 0xFFFF;
idt[num].sel=sel;
idt[num].always0=0;
idt[num].flags=flags;
}

Installieren:

idtptr.limit=(sizeof(struct ND::IDT::Entry)*256)-1;
idtptr.base=(uint32_t)&idt;
ND::Memory::Set(&idt,0,sizeof(struct ND::IDT::Entry)*256);
ND::IDT::Flush();

Wenn wir uns das ansehen, werden wir sehen, dass die Installationsfunktion die ND :: Memory :: Set-Funktion verwendet, die wir im anderen Beitrag deklariert haben. Wir können auch verstehen, dass wir SetGate noch nicht aufrufen und ND :: IDT :: Flush aufrufen. Für diese Funktion verwenden wir erneut die flüchtige Anweisung asm:

asm volatile("lidtl (idtptr)");

Wenn alles gut geht und wir eine ästhetische Vereinbarung treffen, sollte es so aussehen:

NextDive-IDT

Ok, jetzt fangen wir an, die RTD mit Interrupts zu füllen. Hier werde ich nur eine erstellen, aber im Übrigen wäre es das gleiche. Ich werde die Division durch Null machen. Wie Sie in der Mathematik wissen, kann eine Zahl nicht durch 0 geteilt werden. Wenn dies im Prozessor geschieht, wird eine Ausnahme generiert, da sie nicht fortgesetzt werden kann. In IDT entspricht der erste Interrupt in Liste (0) diesem Ereignis.

Wir fügen dies zwischen der Speichereinstellung und dem Flush innerhalb der Installationsfunktion des IDT hinzu:

ND::IDT::SetGate(0,(unsigned)ND::ISR::ISR1,0x08,0x8E);

Die Rückruffunktion wird ND :: ISR :: ISR1 sein, was ziemlich einfach ist, obwohl wir ASM verwenden müssen:

void ND::ISR::ISR1()
{
asm volatile(
"cli \n"
"pushl 0 \n"
"pushl 0 \n"
"jmp ND_ISR_Common \n"
);
}

ND_ISR_Common definieren wir es als eine Funktion in C-Sprache. Um Dateien zu speichern und die Lesbarkeit zu verbessern, können wir externes «C» {} verwenden:

extern "C"
void ND_ISR_Common()
{
asm volatile(
"pusha \n"
"push %ds \n"
"push %es \n"
"push %fs \n"
"push %gs \n"
"movw $0x10, %ax \n"
"movw %ax, %ds \n"
"movw %ax, %es \n"
"movw %ax, %fs \n"
"movw %ax, %gs \n"
"movl %esp, %eax \n"
"push %eax \n"
"movl $ND_ISR_Handler, %eax \n"
"call *%eax \n"
"popl %eax \n"
"popl %ds \n"
"popl %es \n"
"popl %fs \n"
"popl %gs \n"
"popa \n"
"addl 8, %esp \n"
"iret \n"
);
}

Dieser Code in ASM kann etwas schwierig zu verstehen sein, aber dies liegt daran, dass wir eine Struktur in C deklarieren, um auf die vom Interrupt generierten Daten zuzugreifen. Wenn Sie das nicht wollten, können Sie natürlich einfach die Kernel-Panik in ND :: ISR :: ISR1 oder so etwas aufrufen. Die Struktur hat eine solche Form, dass:

struct regs{
uint32_t ds;
uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax;
uint32_t int_no, err_code;
uint32_t eip, cs, eflags, useresp, ss;
};

Und schließlich machen wir die ND_ISR_Handler-Funktion (auch mit einem C-Link), in der wir eine Kernel-Panik und eine kleine Beschreibung des Fehlers gemäß der in einer Fehlerliste angegebenen anzeigen.

extern "C"
void ND_ISR_Handler(struct regs *r)
{
if(r->int_no < 32) { ND::Panic::Show(exception_messages[r->int_no]);
for(;;);
}
}

Gut und damit sind wir bereits in der Lage, diese Unterbrechung zu bewältigen. Bei den restlichen Unterbrechungen würde es ähnlich passieren, außer dass es einige gibt, die Parameter zurückgeben, und wir würden die reg-Struktur verwenden, um sie zu erhalten. Sie fragen sich vielleicht, woher wir wissen, ob es wirklich funktioniert. Um zu testen, ob es funktioniert, werden wir nach ND :: IDT :: Install () eine einfache Zeile einführen:

int sum=10/0;

Wenn wir es kompilieren, erhalten wir eine Warnung und wenn wir versuchen, es auszuführen, erhalten wir einen schönen Bildschirm:

NextDive-ISR


Und mit diesem Ende dieses Beitrags denke ich, dass es einer der umfangreichsten, aber ziemlich funktionalen ist.


Hinterlasse einen Kommentar

Ihre E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind markiert mit *

*

*

  1. Verantwortlich für die Daten: Miguel Ángel Gatón
  2. Zweck der Daten: Kontrolle von SPAM, Kommentarverwaltung.
  3. Legitimation: Ihre Zustimmung
  4. Übermittlung der Daten: Die Daten werden nur durch gesetzliche Verpflichtung an Dritte weitergegeben.
  5. Datenspeicherung: Von Occentus Networks (EU) gehostete Datenbank
  6. Rechte: Sie können Ihre Informationen jederzeit einschränken, wiederherstellen und löschen.

  1.   mesodierbarer sagte

    Ich ging zu LFS, es ist kontinuierlicher.

  2.   eliotime3000 sagte

    Heilig ... Wie auch immer, die Tutorials sind gut.

  3.   sc sagte

    Sehr gut, ich habe es von Anfang an verfolgt. Könnten Sie die Codes an jeden Anhänger anhängen?

    1.    AdrianArroyoStreet sagte

      Sie haben den gesamten Quellcode auf GitHub verfügbar: http://github.com/AdrianArroyoCalle/next-divel Von dort können Sie eine ZIP, eine TAR.GZ herunterladen oder einfach git verwenden.

  4.   nuanciert sagte

    Hahaha sehr gut! Genehmigen! 🙂