Émulation de Linus Torvalds: créez votre propre système d'exploitation à partir de 0 (V)

Dans cette cinquième tranche, nous verrons un tableau assez similaire au GDT à la fois en théorie et en utilisation, nous nous référons à l'IDT. IDT signifie Tableau de description des interruptions y est une table utilisée pour gérer les interruptions qui se produisent. Par exemple, quelqu'un fait une division par 0, la fonction en charge du traitement est appelée. Ces fonctions sont les ISR (Routines de service d'interruption). Alors créons l'IDT et ajoutons des ISR.

Nous allons d'abord déclarer les structures correspondant à l'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));

Comme on peut le voir si vous le comparez avec le GDT, la structure Ptr est identique et l'entrée est assez similaire. Par conséquent, les fonctions de mise d'une entrée (SetGate) et d'installation (Install) sont très similaires.

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

Installer:

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

Si nous regardons, nous verrons que la fonction d'installation utilise la fonction ND :: Memory :: Set que nous avions déclarée dans l'autre article. Nous pouvons également comprendre comment nous ne faisons pas encore d'appels à SetGate et nous appelons ND :: IDT :: Flush, pour cette fonction, nous utilisons à nouveau l'instruction volatile asm:

asm volatile("lidtl (idtptr)");

Si tout se passe bien et que nous faisons un arrangement esthétique, cela devrait ressembler à ceci:

SuivantDivel-IDT

Ok, maintenant nous allons commencer à remplir l'IDT avec des interruptions. Ici, je vais en créer un seul mais pour le reste ce serait pareil. Je vais faire la division par zéro pause. Comme vous le savez bien en mathématiques, un nombre ne peut pas être divisé par 0. Si cela se produit dans le processeur, une exception est générée car elle ne peut pas continuer. En IDT, la première interruption de la liste (0) correspond à cet événement.

Nous ajoutons ceci entre le paramètre de mémoire et le vidage dans la fonction d'installation de l'IDT:

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

La fonction de rappel va être ND :: ISR :: ISR1, ce qui est assez simple bien que nous devions utiliser ASM:

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

Nous définirons ND_ISR_Common comme une fonction en langage C. Pour enregistrer les fichiers et améliorer la lisibilité, nous pouvons utiliser extern «C» {}:

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

Ce code en ASM peut être un peu difficile à comprendre mais c'est parce que nous allons déclarer une structure en C pour accéder aux données générées par l'interruption. De toute évidence, si vous ne le vouliez pas, vous pouvez simplement appeler Kernel Panic dans ND :: ISR :: ISR1 ou quelque chose comme ça. La structure a une forme telle que:

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

Et enfin nous faisons la fonction ND_ISR_Handler (également avec un lien C) dans laquelle nous montrons une panique du noyau et une petite description de l'erreur en fonction de celle que nous avons dans une liste d'erreurs.

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

Bien et avec cela, nous sommes déjà en mesure de gérer cette interruption. Avec le reste des interruptions, cela se passerait de manière similaire, sauf qu'il y en a qui renvoient des paramètres et que nous utiliserions la structure reg pour l'obtenir. Cependant, vous vous demandez peut-être comment nous savons si cela fonctionne vraiment. Pour tester si cela fonctionne, nous allons introduire une ligne simple après ND :: IDT :: Install ():

int sum=10/0;

Si nous le compilons, cela nous donnera un avertissement et si nous essayons de l'exécuter, nous obtiendrons un bel écran:

SuivantDivel-ISR


Et avec cela se termine ce post, je pense que c'est l'un des plus étendus mais assez fonctionnel.


Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont marqués avec *

*

*

  1. Responsable des données: Miguel Ángel Gatón
  2. Finalité des données: Contrôle du SPAM, gestion des commentaires.
  3. Légitimation: votre consentement
  4. Communication des données: Les données ne seront pas communiquées à des tiers sauf obligation légale.
  5. Stockage des données: base de données hébergée par Occentus Networks (EU)
  6. Droits: à tout moment, vous pouvez limiter, récupérer et supprimer vos informations.

  1.   Mésodableur dit

    Je suis passé à LFS, c'est plus continu.

  2.   éliotime3000 dit

    Saint ... Bref, les tutoriels sont bons.

  3.   sc dit

    Très bien, je le suis depuis le début. Pourriez-vous joindre les codes à chaque remorque?

    1.    AdrianArroyoStreet dit

      Vous avez tout le code source disponible sur GitHub: http://github.com/AdrianArroyoCalle/next-divel De là, vous pouvez télécharger un ZIP, un TAR.GZ ou simplement utiliser git.

  4.   nuancé dit

    Hahaha très bien! Approuver! 🙂