Emulând Linus Torvalds: Creați-vă propriul sistem de operare de la 0 (V)

În această a cincea tranșă vom vedea un tabel destul de similar cu GDT atât în ​​teorie, cât și în utilizare, ne referim la IDT. IDT înseamnă Tabel de descriere a întreruperilor y este un tabel care este utilizat pentru a gestiona întreruperile care apar. De exemplu, cineva face o împărțire la 0, funcția responsabilă de procesare este numită. Aceste funcții sunt ISR (Întrerupeți rutinele de service). Deci, să creăm IDT și să adăugăm niște ISR.

Mai întâi vom declara structurile corespunzătoare IDT:

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));

După cum se poate vedea dacă îl comparați cu GDT, structura Ptr este identică, iar intrarea este destul de similară. Prin urmare, funcțiile de plasare a unei intrări (SetGate) și instalare (Instalare) sunt foarte similare.

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;
}

Instalare:

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();

Dacă ne uităm, vom vedea că funcția de instalare folosește funcția ND :: Memory :: Set pe care am declarat-o în cealaltă postare. De asemenea, putem vedea cum nu efectuăm încă niciun apel către SetGate și apelăm la ND :: IDT :: Flush, pentru această funcție folosim din nou declarația asm volatile:

asm volatile("lidtl (idtptr)");

Dacă totul merge bine și facem un aranjament estetic ar trebui să arate astfel:

NextDivel-RTD

Bine, acum vom începe să completăm IDT-ul cu întreruperi. Aici am de gând să creez doar una, dar în rest ar fi la fel. Voi face divizarea la pauză zero. După cum știți bine în matematică, un număr nu poate fi împărțit la 0. Dacă acest lucru se întâmplă în procesor, se generează o excepție, deoarece nu poate continua. În IDT prima întrerupere din lista (0) corespunde acestui eveniment.

Adăugăm acest lucru între setarea de memorie și flush în funcția de instalare a IDT:

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

Funcția de apel invers va fi ND :: ISR :: ISR1, care este destul de simplă, deși trebuie să folosim ASM:

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

ND_ISR_Common o vom defini ca o funcție în limbajul C. Pentru a salva fișiere și a îmbunătăți lizibilitatea, putem folosi „C” {} extern:

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"
);
}

Acest cod din ASM poate fi puțin dificil de înțeles, dar acest lucru se datorează faptului că vom declara o structură în C pentru a accesa datele generate de întrerupere. Evident, dacă nu doriți acest lucru, puteți apela Kernel Panic în ND :: ISR :: ISR1 sau ceva de genul acesta. Structura are o formă astfel încât:

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;
};

Și în cele din urmă facem funcția ND_ISR_Handler (de asemenea, cu o legătură C), în care afișăm o panică de nucleu și o mică descriere a erorii în conformitate cu cea pe care o avem într-o listă de erori.

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

Bine și cu aceasta suntem deja capabili să gestionăm această întrerupere. Cu restul întreruperilor s-ar întâmpla similar, cu excepția faptului că există unii care returnează parametrii și am folosi structura reg pentru a o obține. Cu toate acestea, vă puteți întreba cum știm dacă funcționează cu adevărat. Pentru a testa dacă funcționează, vom introduce o linie simplă după ND :: IDT :: Install ():

int sum=10/0;

Dacă compilăm, ne va da un avertisment și dacă încercăm să-l executăm vom primi un ecran frumos:

NextDivel-ISR


Și odată cu încheierea acestui post, cred că este una dintre cele mai extinse, dar destul de funcționale.


Lasă comentariul tău

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *

*

*

  1. Responsabil pentru date: Miguel Ángel Gatón
  2. Scopul datelor: Control SPAM, gestionarea comentariilor.
  3. Legitimare: consimțământul dvs.
  4. Comunicarea datelor: datele nu vor fi comunicate terților decât prin obligație legală.
  5. Stocarea datelor: bază de date găzduită de Occentus Networks (UE)
  6. Drepturi: în orice moment vă puteți limita, recupera și șterge informațiile.

  1.   mezodabil el a spus

    Am trecut la LFS, este mai continuu.

  2.   eliotime3000 el a spus

    Sfânt ... Oricum, tutorialele sunt bune.

  3.   sc el a spus

    Foarte bine, am urmărit-o de la început. Ați putea atașa codurile la fiecare remorcă?

    1.    AdrianArroyoStreet el a spus

      Aveți tot codul sursă disponibil pe GitHub: http://github.com/AdrianArroyoCalle/next-divel De acolo puteți descărca un ZIP, un TAR.GZ sau pur și simplu utilizați git.

  4.   nuantat el a spus

    Hahaha foarte bine! Aproba! 🙂