Je sais juste que Interrupt
est un hardware signal assertion
causé dans une broche de processeur. Mais j'aimerais savoir comment Linux OS le gère.
Quelles sont toutes les choses qui se produisent lorsqu'une interruption se produit?
Voici une vue de haut niveau du traitement de bas niveau. Je décris une architecture typique simple, de vraies architectures peuvent être plus complexes ou différer de façons qui n'ont pas d'importance à ce niveau de détail.
Lorsqu'une interruption se produit, le processeur recherche si les interruptions sont masquées. S'ils le sont, rien ne se passe tant qu'ils ne sont pas démasqués. Lorsque les interruptions deviennent démasquées, s'il y a des interruptions en attente, le processeur en sélectionne une.
Ensuite, le processeur exécute l'interruption en se ramifiant à une adresse particulière en mémoire. Le code à cette adresse est appelé gestionnaire d'interruption . Lorsque le processeur s'y branche, il masque les interruptions (le gestionnaire d'interruptions a donc un contrôle exclusif) et enregistre le contenu de certains registres à un certain endroit (généralement d'autres registres).
Le gestionnaire d'interruption fait ce qu'il doit faire, généralement en communiquant avec le périphérique qui a déclenché l'interruption pour envoyer ou recevoir des données. Si l'interruption a été déclenchée par le minuteur, le gestionnaire peut déclencher le planificateur du système d'exploitation pour basculer vers un autre thread. Lorsque le gestionnaire termine son exécution, il exécute une instruction spéciale de retour d'interruption qui restaure les registres enregistrés et démasque les interruptions.
Le gestionnaire d'interruption doit s'exécuter rapidement, car il empêche toute autre interruption de s'exécuter. Dans le noyau Linux, le traitement des interruptions est divisé en deux parties:
Comme d'habitude sur ce sujet, pour plus d'informations, lisez Linux Device Drivers ; chapitre 1 concerne les interruptions.
Gilles déjà décrit le cas général d'une interruption, ce qui suit s'applique spécifiquement à Linux 2.6 sur une architecture Intel (une partie de ceci est également basée sur les spécifications d'Intel).
Une interruption est un événement qui modifie la séquence d'instructions exécutées par le processeur.
Il existe deux types d'interruptions:
Les exceptions sont causées par des erreurs de programmation (fe Erreur de division, Défaut de page, Débordement) qui doit être géré par le noyau . Il envoie un signal au programme et tente de se remettre de l'erreur.
Les deux exceptions suivantes sont classées:
Les interruptions peuvent être émises par des périphériques d'E/S (clavier, adaptateur réseau, ..), des temporisateurs d'intervalle et (sur les systèmes multiprocesseurs) d'autres CPU. Lorsqu'une interruption se produit, la CPU doit arrêter son instruction actuelle et exécuter la nouvelle interruption arrivée. Il doit enregistrer l'ancien état de processus interrompu pour le reprendre (probablement) après le traitement de l'interruption.
La gestion des interruptions est une tâche délicate:
Deux niveaux d'interruption différents sont définis:
Chaque périphérique matériel possède sa propre ligne de demande d'interruption (IRQ). Les IRQ sont numérotés à partir de 0. Toutes les lignes IRQ sont connectées à un contrôleur d'interruption programmable (PIC). Le PIC écoute les IRQ et les affecte au CPU. Il est également possible de désactiver une ligne IRQ spécifique.
Les systèmes Linux multiprocesseurs modernes incluent généralement le nouveau PIC avancé (APIC), qui distribue les requêtes IRQ également entre les CPU.
L'étape intermédiaire entre une interruption ou une exception et sa gestion est la table de description d'interruption (IDT). Ce tableau associe chaque vecteur d'interruption ou d'exception (un nombre) à un gestionnaire spécifié (p. Ex. Erreur de division est géré par la fonction divide_error()
).
Grâce à l'IDT, le noyau sait exactement comment gérer l'interruption ou l'exception survenue.
Alors, que fait le noyau lorsqu'une interruption se produit?
Tout d'abord, les participants impliqués dans la gestion des interruptions sont les périphériques matériels, le contrôleur d'interruption, le CPU, le noyau du système d'exploitation et les pilotes. Les périphériques matériels sont responsables de la génération des interruptions. Ils affirment les lignes de demande d'interruption lorsqu'ils veulent l'attention du noyau du système d'exploitation. Ces signaux sont multiplexés par le contrôleur d'interruption, qui est responsable de la collecte des signaux d'interruption. Il est également responsable de la détermination de l'ordre dans lequel les signaux d'interruption seront transmis au CPU. Le contrôleur d'interruption est capable de désactiver temporairement la ligne de demande d'interruption particulière (IRQL) et de la réactiver à nouveau (masquage IRQL). Le contrôleur d'interruption transmet les demandes d'interruption collectées au processeur de manière séquentielle. Le CPU après la fin de l'exécution de chaque instruction CPU vérifie s'il y a des demandes d'interruption en attente du contrôleur d'interruption. Si l'UC constate qu'il y a une demande en attente ET que l'indicateur d'activation d'interruption est défini dans le registre de contrôle interne de l'UC, l'UC commence alors la gestion des interruptions. Comme vous pouvez le voir, en manipulant l'indicateur d'interruption dans le CPU et en communiquant avec le contrôleur d'interruption, le noyau Linux est capable de contrôler l'acceptation des interruptions. Par exemple, Linux peut désactiver l'acceptation des interruptions de l'appareil particulier ou désactiver l'acceptation des interruptions du tout.
Que se passe-t-il lorsque le processeur reçoit une demande d'interruption? Premièrement, le CPU désactive automatiquement les interruptions en réinitialisant le drapeau d'interruption. Ils seront réactivés une fois la gestion des interruptions terminée. Dans le même temps, le CPU effectue une quantité minimale de travail nécessaire pour passer du CPU du mode utilisateur au mode noyau de manière à lui permettre de reprendre l'exécution du code interrompu. Le CPU consulte des structures de contrôle CPU spéciales remplies par le noyau Linux pour trouver une adresse de code à laquelle le contrôle sera passé. Cette adresse est l'adresse de la première instruction du gestionnaire d'interruption, qui fait partie du noyau Linux.
Comme première étape de la gestion des interruptions, le noyau identifie le vecteur d'interruption reçu pour identifier le type d'événement qui s'est produit dans le système. Le vecteur d'interruption définit les actions que Linux entreprendra pour le gérer. Dans un deuxième temps, Linux enregistre le reste des registres du processeur (qui n'ont pas été enregistrés automatiquement par le processeur) et qui peuvent potentiellement être utilisés par le programme interrompu. C'est une action très importante, car elle permet à Linux de gérer les interruptions de manière transparente par rapport au programme interrompu. Dans une troisième étape, Linux accomplit le passage en mode noyau en définissant l'environnement du noyau et en définissant l'état CPU requis pour cela. Et enfin, le gestionnaire d'interruption dépendant du vecteur est appelé. (Vous pouvez consulter la macro BUILD_INTERRUPT3 dans Arch\x86\kernel\entry_32.S pour récupérer les détails supplémentaires de l'exemple lié à l'architecture x86) Dans le cas des périphériques, c'est une routine do_IRQ (). (Regardez dans Arch\x86\kernel\irq.c)
Le gestionnaire d'interruption dépendant du vecteur est généralement enveloppé par des appels à irq_enter () et irq_exit (). La zone de code entourée d'une paire de ces fonctions est atomique par rapport à toute autre zone de ce type et est également atomique par rapport aux paires de cli/sti. Irq_enter () et irq_exit () capture également certaines statistiques liées à la gestion des interruptions. Enfin, le noyau examine la table vector_irq pour trouver le numéro d'irq attribué au vecteur de l'interruption reçue et appelle handle_irq () (depuis Arch\x86\kernel\irq_32.c).
À ce stade, la partie commune de la gestion des interruptions sous Linux se termine, car le noyau regarde la routine de gestionnaire d'interruption dépendante du périphérique installée par le pilote de périphérique dans le descripteur irq et l'invoque. Si un tel gestionnaire n'a pas été installé par le pilote, le noyau acquitte simplement l'interruption sur le contrôleur d'interruption et quitte le gestionnaire d'interruption général.
Après la fin de la gestion des interruptions, le noyau restaure l'état du programme qui avait été interrompu précédemment et reprend l'exécution de ce programme.
Du point de vue de la théorie, presque tout a été expliqué. Mais si vous cherchez des explications sur le cadre du code de gestion des interruptions du noyau, le lien suivant devrait vous: ne promenade de code dans la gestion des interruptions du noya
Et si vous êtes toujours à la recherche de théorie sur les interruptions et les gestionnaires d'interruption, alors je vous recommande de lire ceci: Comprendre les interruptions et les gestionnaires d'interruption