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

Eh bien, après une petite parenthèse, nous continuons avec notre série de tutoriels. Si nous revenons au code précédent, nous devons avoir l'ISR de la division par zéro. Nous devons maintenant remplir le reste des ISR pour lesquels nous avions posté (les 32 premiers). Eh bien maintenant nous allons continuer la programmation des interruptions, nous allons faire les IRQs aussi connus comme Interrompt les demandes. Ces IRQ sont générés par des périphériques matériels tels que des claviers, des souris, des imprimantes, etc. Au départ, les 8 premières IRQ sont automatiquement mappées aux positions IDT 8 à 15. Comme nous avons utilisé les 32 premières pour les exceptions, nous devons maintenant les remapper. Nous allons mettre l'IRQ de 32 à 45. Pour cela, il faut d'abord remapper les IRQ:

void ND::IRQ::Remap(int pic1, int pic2)
{
#define PIC1 0x20
#define PIC2 0xA0
#define ICW1 0x11
#define ICW4 0x01
/* send ICW1 */
ND::Ports::OutputB(PIC1, ICW1);
ND::Ports::OutputB(PIC2, ICW1);
/* send ICW2 */
ND::Ports::OutputB(PIC1 + 1, pic1); /* remap */
ND::Ports::OutputB(PIC2 + 1, pic2); /* pics */
/* send ICW3 */
ND::Ports::OutputB(PIC1 + 1, 4); /* IRQ2 -> connection to slave */
ND::Ports::OutputB(PIC2 + 1, 2);
/* send ICW4 */
ND::Ports::OutputB(PIC1 + 1, ICW4);
ND::Ports::OutputB(PIC2 + 1, ICW4);
/* disable all IRQs */
ND::Ports::OutputB(PIC1 + 1, 0xFF);
}

Maintenant, nous créons une fonction pour installer les IRQ:

void ND::IRQ::Install()
{
ND::Screen::SetColor(ND_SIDE_FOREGROUND,ND_COLOR_BLACK);
ND::Screen::PutString("\nInstalling IRQ...");
ND::IRQ::Remap(0x20,0x28);
ND::IDT::SetGate(32,(unsigned)ND::IRQ::IRQ1,0x08,0x8E);
ND::IDT::SetGate(33,(unsigned)ND::IRQ::IRQ2,0x08,0x8E);
ND::IDT::SetGate(34,(unsigned)ND::IRQ::IRQ3,0x08,0x8E);
ND::IDT::SetGate(35,(unsigned)ND::IRQ::IRQ4,0x08,0x8E);
ND::IDT::SetGate(36,(unsigned)ND::IRQ::IRQ5,0x08,0x8E);
ND::IDT::SetGate(37,(unsigned)ND::IRQ::IRQ6,0x08,0x8E);
ND::IDT::SetGate(38,(unsigned)ND::IRQ::IRQ7,0x08,0x8E);
ND::IDT::SetGate(39,(unsigned)ND::IRQ::IRQ8,0x08,0x8E);
ND::IDT::SetGate(40,(unsigned)ND::IRQ::IRQ9,0x08,0x8E);
ND::IDT::SetGate(41,(unsigned)ND::IRQ::IRQ10,0x08,0x8E);
ND::IDT::SetGate(42,(unsigned)ND::IRQ::IRQ11,0x08,0x8E);
ND::IDT::SetGate(43,(unsigned)ND::IRQ::IRQ12,0x08,0x8E);
ND::IDT::SetGate(44,(unsigned)ND::IRQ::IRQ13,0x08,0x8E);
ND::IDT::SetGate(45,(unsigned)ND::IRQ::IRQ14,0x08,0x8E);
ND::IDT::SetGate(46,(unsigned)ND::IRQ::IRQ15,0x08,0x8E);
ND::IDT::SetGate(47,(unsigned)ND::IRQ::IRQ16,0x08,0x8E);
ND::Screen::SetColor(ND_SIDE_FOREGROUND,ND_COLOR_GREEN);
ND::Screen::PutString("done");
asm volatile("sti");
}

La phrase d'ASM sti nous activons les IRQ. Eh bien maintenant, nous allons avec quelque chose de similaire à ISR. Les fonctions d'un IRQ de base:

void ND::IRQ::IRQ1()
{
asm volatile(
"cli \n"
"pushl 0\n"
"pushl 32\n"
"jmp ND_IRQ_Common"
);
}

Une partie commune (identique à ISR):

extern "C"
void ND_IRQ_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_IRQ_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"
);
}

Et un gestionnaire de base:

extern "C"
void ND_IRQ_Handler(struct regs* r)
{
void (*handler)(struct regs *r);
if(r->int_no >= 40)
{
ND::Ports::OutputB(0xA0,0x20);
}
ND::Ports::OutputB(0x20,0x20);
}

Avec cela, nous devrions déjà avoir l'IRQ activé même s'ils ne font toujours rien. Dans le chapitre suivant, nous verrons comment obtenir des données à partir de ces IRQ telles que l'horloge ou le clavier.

SuivantDivel-IRQ


Et avec cela se termine le post d'aujourd'hui. Comme vous pouvez le voir maintenant, j'écris moins régulièrement en raison d'autres problèmes. Même ainsi, je continuerai jusqu'à ce que j'aie un système d'exploitation plus complet


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.   aitor_cz dit

    Merci beaucoup Adrian, dès que j'aurai du temps (maintenant je suis assez occupé, entre autres aussi avec un système d'exploitation) je vais commencer à tester le tutoriel pas à pas.

  2.   Rubi dit

    Merci beaucoup pour le tute.

  3.   sasuke dit

    Une question que je fais un projet basé sur ces langages de programmation
    * Html5
    * Css3
    *Java
    Ma question est que je voudrais que ce projet soit exécutable, afin que les utilisateurs l'utilisent dans des systèmes d'exploitation tels que Linux et Windows, pourriez-vous me dire comment je fais cela

    1.    AdrianArroyoStreet dit

      Cela n'a rien à voir avec ça mais je vous réponds quand même. Je suppose que ce sera HTML5, CSS3 et JavaScript et non Java, car HTML5 et Java s'entendent mal. Avec HTML5, vous pouvez créer des sites Web comme auparavant, accessibles depuis Internet. Si vous souhaitez le rendre local, vous pouvez le conditionner en tant qu'application Firefox OS et Chrome OS. Si ce que vous voulez, c'est que dans chaque système d'exploitation il y a un exécutable jetez un œil à XUL Runner qui est un outil pour exécuter XUL (et donc HTML5 à l'intérieur de l'élément) avec le moteur Gecko.

    2.    Soid perez dit

      Le cadre ou le panneau Java est une très bonne option.J'ai créé des applications exécutables dans la fenêtre en utilisant les classes de cadre java comme navigateur Web, mais au lieu de l'utiliser pour n'importe quelle page, je lui donne un chemin direct dans le code et avec php j'exécute des phrases java grâce à un .jar qui prend soin de l'acier. Bien que je recommande d'utiliser HTML5, CSS3 et JavaScript car, comme le dit Adrian Java, cela prend Fatal avec Html5 et cela m'a apporté beaucoup de maux de tête

  4.   lurbain dit

    Un tutoriel sur la création de votre propre langage de programmation serait bien

  5.   Ivan dit

    Très bonne cette série d'articles sur la façon de construire un système d'exploitation, vous apprenez beaucoup de choses. J'attends avec impatience la prochaine entrée, je veux déjà avoir un clavier dans l'OS. J'ai déconné avec le code git et je n'ai pas pu le faire fonctionner avec les ports 0x60 et 0x64. Même si je pensais que pour le clavier, il y avait une interruption qui vous a donné la touche enfoncée.

    1.    AdrianArroyoStreet dit

      Vous pouvez en fait obtenir une entrée au clavier sans interruption, mais vous devez lire avec ND :: Ports :: InputB sur le port 0x60. Cependant, la manière idéale de le faire est d'utiliser des interruptions IRQ. J'essaie actuellement de le faire et cela prend un peu plus de temps à cause de cela.

      1.    carlosorta dit

        Salut Adrian, j'ai vérifié le code et je suis impressionné par ce qu'il fait et à quel point il m'a aidé à comprendre certaines choses.

        J'ai quelques petites questions sur son fonctionnement et la source est celle que j'ai obtenue de votre GIT:

        1.- Dans la partie des IRQ, vous avez mentionné que les positions de 0 à 32 de l'IDT étaient utilisées pour les exceptions et de 32 (0x20) à 45 (0x2D) pour les IRQ, mais les IRQ sont de 16 au total, le le remappage ne serait pas de 0x20 à 0x30?

        2.- Dans la partie IRQ, notez que les setgates ont été envoyés à la section IDT; Lorsque vous les séparez, notez qu'il ne produit plus l'exception de division par 0, il est donc nécessaire d'ajouter l'IDT Flush () pour chaque modification effectuée. Pourquoi l'IDT change-t-il lors du réglage de la minuterie et la division entre 0 cesse de fonctionner?

        3.- J'essayais de tracer le code avec quelques impressions à prendre comme indication de ce qu'il exécutait (afin de ne pas déboguer pas à pas) et j'ai réalisé qu'aucune IRQ n'est en cours d'exécution, dois-je enregistrer autre chose aux interruptions IRQ générées?

        1.    carlosorta dit

          J'ai oublié de mentionner que j'ai trouvé ces liens avec des informations:
          http://arstechnica.com/civis/viewtopic.php?f=20&t=899001
          http://www.superfrink.net/athenaeum/OS-FAQ/os-faq-pics.html
          http://orga2.exp.dc.uba.ar/data/downloads/clasespracticas/interrupciones2_clase_17.pdf
          http://www.intel-assembler.it/PORTALE/4/231468_8259A_PIC.pdf

          Apparemment, pour gérer les IRQ, il est nécessaire de prendre en compte le type de gestionnaire utilisé si, PIC, APIC, IOAPIC. . .etc. Existe-t-il un moyen de faire une gestion dynamique de l'IRQ ou avez-vous besoin de tenter la chance?

  6.   carlosorta dit

    Bonjour Adrian.

    J'ai vu que j'avais des problèmes avec les IRQ et c'est pourquoi le code ne pouvait pas être avancé, j'ai pris une copie du projet et j'ai commencé à l'analyser; J'ai ajouté une fonction à la sérigraphie pour imprimer les enregistrements reg de struct reg, au moment de l'interruption; J'ai trouvé plusieurs choses, parmi lesquelles un registre est en cours d'exécution et je ne trouve toujours pas pourquoi; changer l'interruption de la minuterie pour l'interruption du clavier pour tester et faire ce qu'il devrait mais je ne trouve pas le problème, pourriez-vous m'aider et continuer avec ce bon message? 😀

    Je laisse le lien (il a quelques modifications car j'utilise Mageia et j'utilise Grub2, j'utilise VirtualBox pour le tester)
    https://www.mediafire.com/?93psrgaoozatse8

    En attendant votre réponse attentive et si vous avez des questions ou avez besoin de quelque chose, j'aimerais vous aider 🙂

    1.    carlosorta dit

      J'ai oublié de mentionner que j'ai également vérifié le KernelPanic car les ISR ne fonctionnaient pas et j'ai le même problème en haut de la pile une valeur est filtrée et je ne sais pas si c'est mon compilateur ou s'il y a un problème, je utiliser GCC 4.8.2 avec Mageia 4

    2.    AdrianArroyoStreet dit

      J'aime vraiment que tu m'aides dans le projet. Je suis vraiment resté coincé dans la minuterie et je ne comprends pas pourquoi cela ne fonctionne pas. J'ai fait des tests en modifiant beaucoup de choses et cela n'a pas fonctionné. Actuellement, je ne peux pas modifier le code (je suis en vacances), mais je vais l'examiner dès que possible. Je vous donne un lien avec des informations sur ce problème qui semble être quelque chose de commun: http://wiki.osdev.org/I_Cant_Get_Interrupts_Working

      En ce qui concerne les exceptions, je pense que je me souviens que vous devez appeler "sti" dans ASM pour les activer bien qu'il soit clair qu'il y a quelque chose qui ne va pas quelque part.

      1.    carlosorta dit

        Merci pour votre réponse et oui, en effet. Les interruptions échouaient mais c'était un problème d'insertion des codes dans la pile et un problème de casting, je vérifierai le lien et je ferai des tests. Si je le résous, je vous le ferai savoir et sinon je vous informerai des progrès. Bonnes vacances 🙂

      2.    carlosorta dit

        Il n'y aura aucun moyen de voir le code assemblé? Quelque chose d'étrange se produit et je ne trouve pas quoi? Regardez cet écran (je mets le lien à la fin), c'est quelque chose d'étrange puisque dans la fonction IRQ 2 ) il entre dans la pile la valeur 0 et 0x20 (32, donc ajustez-le pour tester) puis pushal (les registres GPR 32 bits) suivi des registres de segmentation, puis du haut de la pile, puis appelez IRQ Handler. J'ai commencé à voir chaque pile et apparemment c'est dans l'ordre mais si vous pouvez voir la sortie de la VM, vous pouvez voir qu'elle empile un élément de plus, je ne peux pas trouver où, je sais seulement que c'est un 0x10 et le la structure est en panne. C'est la structure d'enregistrement.

        struct regs {
        uint32_t gs, fs, es, ds; / * a poussé les secondes en dernier * /
        uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; / * poussé par 'pushal' * /
        uint32_t int_no, err_code; /* Code d'erreur */
        uint32_t eip, cs, eflags, useresp, ss; / * Empilé à la pause * /
        };

        Cela me donne une boîte qui met un élément de plus en haut et je ne peux pas trouver où il est empilé si apparemment tout est empilé comme il se doit. Avez-vous une idée de ce que cela pourrait être?

        http://www.subeimagenes.com/img/sin-titulo-1036729.jpg

  7.   carlosorta dit

    Faites fonctionner l'interruption du clavier mais pas l'interruption du minuteur; l'erreur était dans la façon dont elle a été compilée, j'ai utilisé objdump pour voir l'objet final et il s'est avéré que chaque fonction qui était entrée même en utilisant "asm volatile" était également accompagnée d'un pushl ebp, mov ebp, esp. Ensuite, ajoutez simplement un popl ebp pour restaurer la pile initiale et il passera les arguments sans faute. Ici, je joins le code pour ceux qui veulent le vérifier et si vous pouvez découvrir pourquoi l'interruption n'est pas générée par le Timer j'aimerais beaucoup le savoir et j'attache un lien où ils parlent de multitâche http://www.jamesmolloy.co.uk/tutorial_html/9.-Multitasking.html
    Prochain Divel
    https://www.mediafire.com/?kmo83dxyzc7c3cz

    1.    AdrianArroyoStreet dit

      J? ai compris. C'était un bug dans un autre site qui affectait l'activation du Timer PIC, en particulier dans le remappage IRQ, il y avait deux lignes que je devais modifier. Grâce au fait que j'ai pu voir un code sur un site Web qui à ce moment-là avait quelque chose de différent et cliquez! Le changement allait dans le sens de:
      ND :: Ports :: OutputB (PIC1 + 1, 0xFF);
      ND :: Ports :: OutputB (PIC2 + 1, 0xFF);

      Vous avez dû changer la valeur de 0xFF (je dirais que cela indique désactivé) en 0x00 (je dirais que cela indique activé) bien que je ne sois pas vraiment sûr, mais cela fonctionne. J'ai mis à jour le code sur GitHub. Merci beaucoup de m'avoir aidé avec le projet que j'avais un peu abandonné à cause de ce problème. H

      1.    carlosorta dit

        De rien, j'attends avec impatience la prochaine mise à jour du sujet et vous pouvez compter sur moi pour tout 🙂 (Y)

      2.    carlosorta dit

        Changez la routine de capture de chaîne de clavier; car il lit lorsque la touche est relâchée et qu'il monte un 0 dans le tampon, cela pose des problèmes de lecture et à la fin le '\ n' changez-le en »pour que l'impression correcte fonctionne

  8.   Soid perez dit

    Bonjour, j'ai lu l'intégralité de votre post, bien qu'en pratique ce ne soit pas plus de 2 post, c'est vraiment très bien, enregistrez tout, mais il me faudra vraiment étudier le c ++ et le posix pour le comprendre car je connais le "c" (Je suis fasciné par ce langage de programmation) mais bien que c ++ soit c OO je n'ai jamais vraiment travaillé dessus, lisez-moi quelques tutoriels dans google et puis je reviens très intéressant et une question, est le démarrage de la fenêtre similaire à linux ?

    1.    AdrianArroyoStreet dit

      Le démarrage sous Windows est similaire en ce sens que c'est la manière de démarrer un système avec un processeur x86 et le système d'exploitation construit dessus a peu d'influence. Nous ne démarrons pas vraiment nous-mêmes de toute façon, cela démarre GRUB pour nous. GRUB, conçu pour démarrer Linux, peut démarrer Windows et dans ce cas NextDivel.

      1.    sérieux dit

        ok merci cela signifie que ce que je veux faire est possible.Je suis déjà en train d'étudier le c ++ et de créer des applications et d'installer votre système sur une clé USB et je l'étudie plus en détail est un très bon article