Interruptions à partir de périphériques externes dans un système x86. Partie 1. L'évolution des contrôleurs d'interruption

Dans cet article, je voudrais examiner les mécanismes de livraison des interruptions à partir de périphériques externes dans le système x86 et essayer de répondre aux questions:

  • Qu'est-ce que le PIC et à quoi sert-il?
  • Qu'est-ce que l'APIC et à quoi sert-il? A quoi servent LAPIC et I / O APIC?
  • Quelles sont les différences entre APIC, xAPIC et x2APIC?
  • Qu'est-ce que MSI? Quelles sont les différences entre MSI et MSI-X?
  • Quel est le lien entre les tables $ PIR, MPtable et ACPI?

Si vous êtes intéressé à recevoir une réponse à l'une de ces questions ou si vous voulez simplement vous familiariser avec l'évolution des contrôleurs d'interruption dans le système x86, bienvenue à cat.

Présentation


Nous savons tous ce qu'est une interruption. Pour ceux qui ne le sont pas, citez wikipedia:

Interruption (interruption en anglais) - signal provenant d'un logiciel ou d'un matériel informant le processeur de la survenue de tout événement nécessitant une attention immédiate. L'interruption informe le processeur de l'occurrence d'un événement de haute priorité nécessitant une interruption du code actuel exécuté par le processeur. Le processeur répond en suspendant son activité actuelle, en enregistrant son état et en exécutant une fonction appelée gestionnaire d'interruption (ou gestionnaire d'interruption) qui répond à l'événement et le traite, après quoi il rend le contrôle au code interrompu.

Selon la source du signal d'interruption, ils sont répartis en:

  • asynchrone ou externe (matériel) - événements qui proviennent de périphériques matériels externes (tels que des périphériques) et peuvent se produire à tout moment arbitraire: un signal provenant d'une minuterie, d'une carte réseau ou d'un lecteur de disque, des frappes de touches, un mouvement de souris. Le fait qu'une telle interruption se produit dans le système est interprété comme une demande d'interruption (IRQ) - les périphériques signalent qu'ils nécessitent une attention de la part du système d'exploitation;
  • événements synchrones ou internes dans le processeur lui-même résultant de la violation de certaines conditions lors de l'exécution du code machine: division par zéro ou débordement de pile, accès à des adresses mémoire non valides ou code opération non valide;
Dans cet article, je voudrais discuter des interruptions IRQ externes.

Pourquoi sont-ils nécessaires? Supposons que nous voulons effectuer une action avec un paquet d'entrée pour une carte réseau à son arrivée. Afin de ne pas demander constamment à la carte réseau "avez-vous un nouveau package?" et ne gaspillez pas les ressources du processeur à ce sujet; vous pouvez utiliser l'interruption IRQ. La ligne d'interruption du périphérique est connectée à la ligne INTR du processeur et lorsqu'un paquet est reçu, la carte réseau «tire» cette ligne. Le processeur comprend qu'il contient des informations et lit le paquet.

Mais que faire s'il y a beaucoup d'appareils? Vous ne pouvez pas obtenir suffisamment de tous les périphériques externes des jambes du processeur.



Pour résoudre ce problème, ils ont proposé une puce - un contrôleur d'interruption.

Pic


( wiki / osdev )

La première était une puce Intel 8259 PIC . 8 lignes d'entrée (IRQ0-7) et une sortie reliant le contrôleur à la ligne INTR du processeur. Lorsqu'une interruption d'un périphérique se produit, 8259 tire la ligne INTR, le processeur comprend que certains périphériques signalent une interruption et interroge le PIC pour comprendre quel segment IRQx a provoqué l'interruption. Il y a un délai supplémentaire pour cette enquête, mais le nombre de lignes d'interruption passe à 8.



Cependant, 8 lignes se sont rapidement révélées petites, et pour augmenter leur nombre, 2 contrôleurs 8259 (maître et esclave) connectés en cascade (Dual PIC) ont commencé à être utilisés.

Les IRQ 0 à 7 sont traités par le premier PIC Intel 8259 (maître) et les IRQ 8 à 15 sont traités par le second PIC 8259 (esclave). Seul un maître signale l'occurrence d'une interruption. Si une interruption se produit sur les lignes 8 à 15, le deuxième PIC (esclave) signale une interruption au maître via IRQ 2, et le maître à son tour signale la CPU. Cette interruption en cascade prend l'une des 16 lignes, mais donne finalement 15 interruptions disponibles pour les appareils.



Le circuit s'est imposé, et c'est ce qu'ils veulent dire quand ils parlent maintenant de PIC (Programm Interrupt Controller). Par la suite, les contrôleurs 8259 ont reçu quelques améliorations et sont devenus connus sous le nom de 8259A, et ce circuit a été inclus dans le chipset. À une époque où le bus principal pour connecter des périphériques externes était le bus ISA, un tel système dans son ensemble était suffisant. Il était seulement nécessaire de s'assurer que différents périphériques ne se connectaient pas à la même ligne IRQ pour éviter les conflits, car les interruptions ISA ne sont pas partagées.

La disposition des interruptions pour les appareils était généralement plus ou moins standard

Exemple (tiré d'ici ):
IRQ 0 - minuterie système
IRQ 1 - contrôleur de clavier
IRQ 2 - cascade (interruption du contrôleur esclave)
IRQ 3 - port série COM2
IRQ 4 - port série COM1
IRQ 5 - port parallèle 2 et 3 ou carte son
IRQ 6 - contrôleur de disquette
IRQ 7 - port parallèle 1
IRQ 8 - Minuterie RTC
IRQ 9 - ACPI
IRQ 10 - ouvert / SCSI / NIC
IRQ 11 - ouvert / SCSI / NIC
IRQ 12 - contrôleur de souris
IRQ 13 - coprocesseur mathématique
IRQ 14 - Canal ATA 1
IRQ 15 - Canal ATA 2

La configuration et le travail avec les microcircuits 8259 sont effectués via les ports d'E / S:
PuceS'inscrirePort d'E / S
Photo maîtreCommande0x0020
Photo maîtreLes données0x0021
Pic esclaveCommande0x00A0
Pic esclaveLes données0x00A1

→ La documentation du 8259A est disponible ici.

Le bus ISA a été remplacé par le bus PCI. Et le nombre de périphériques a clairement commencé à dépasser le nombre 15, de plus, contrairement au bus ISA statique, dans ce cas, les périphériques peuvent être ajoutés dynamiquement au système. Mais heureusement, dans ce bus, les interruptions peuvent être partagées (c'est-à-dire que plusieurs appareils peuvent être connectés à la même ligne IRQ). En conséquence, afin de résoudre le problème du manque de lignes IRQ, ils ont décidé de regrouper les interruptions de tous les périphériques PCI en lignes PIRQ (Programmable Interrupt Request).

Disons que nous avons 4 lignes d'interruption librement sur le contrôleur PIC et 20 périphériques PCI. Nous combinons les interruptions de 5 appareils par ligne PIRQx et connectons les lignes PIRQx au contrôleur. Si une interruption se produit sur la ligne PIRQx, le processeur devra interroger tous les périphériques connectés à cette ligne afin de comprendre de qui provient l'interruption, mais en général cela résout le problème. Un périphérique qui lie des lignes d'interruption PCI dans une ligne PIRQ est souvent appelé un routeur PIR.

Dans cette méthode, vous devez vous assurer que les lignes PIRQx ne sont pas connectées aux lignes IRQx sur lesquelles les interruptions ISA sont déjà démarrées (car cela entraînera des conflits), et que les lignes PIRQx sont équilibrées (après tout, plus nous avons connecté d'appareils à la même ligne PIRQ, plus vous avez besoin d'appareils interrogera le processeur pour comprendre lequel de ces périphériques a provoqué l’interruption).



Remarque : le périphérique PCI -> le mappage PIR est montré de manière abstraite dans l'image, car en fait c'est un peu plus compliqué. En réalité, chaque périphérique PCI possède 4 lignes d'interruption (INTA, INTB, INTC, INTD). Chaque périphérique PCI peut avoir jusqu'à 8 fonctions, et maintenant chaque fonction a une interruption INTx. L'INTx que chaque fonction de l'appareil va tirer est déterminée par la configuration du chipset.

En substance, les fonctions sont des blocs logiques séparés. Par exemple, dans un périphérique PCI, il peut y avoir une fonction de contrôleur Smbus, une fonction de contrôleur SATA, une fonction de pont LPC. Côté OS, chaque fonction est un périphérique distinct avec son propre espace de configuration PCI Config.

Le système d'exploitation a transmis des informations sur les interruptions de routage sur le BIOS du contrôleur PIC à l'aide de la table $ PIR et en remplissant les registres 3Ch (INT_LN Interrupt Line (R / W)) et 3Dh (INT_PN Interrupt Pin (RO)) de l'espace de configuration PCI pour chaque fonction. La spécification de la table $ PIR était auparavant sur le site Web de Microsoft , mais maintenant elle n'est plus là. Le contenu des lignes de la table $ PIR peut être compris à partir de la spécification PCI BIOS [4.2.2. Obtenez les options de routage d'interruption PCI] ou lisez ici

Apic


( wiki , osdev )

La méthode précédente a fonctionné jusqu'à l'apparition de systèmes multiprocesseurs. Le fait est que dans son appareil, PIC peut transmettre des interruptions à un seul processeur principal. Mais je voudrais que la charge des processeurs due à la gestion des interruptions soit équilibrée. La solution à ce problème a été la nouvelle interface APIC (Advanced PIC).

Pour chaque processeur, un contrôleur LAPIC spécial (APIC local) est ajouté et un contrôleur APIC d'E / S est ajouté pour acheminer les interruptions des périphériques. Tous ces contrôleurs sont combinés dans un bus commun appelé APIC (les nouveaux systèmes sont désormais connectés via un bus système standard).

Lorsqu'une interruption d'un périphérique arrive à la broche APIC d'E / S, le contrôleur achemine l'interruption vers le LAPIC de l'un des processeurs. La présence d'E / S APIC vous permet d'équilibrer la répartition des interruptions des périphériques externes entre les processeurs.

La première puce APIC était 82489DX , c'était une puce séparée qui combine LAPIC et I / O APIC. Pour créer un système de 2 processeurs, 3 de ces microcircuits étaient nécessaires. 2 fonctionneraient comme LAPIC et un comme I / O APIC. Plus tard, la fonctionnalité LAPIC a été directement incluse dans les processeurs et la fonctionnalité I / O APIC a été encadrée dans la puce 82093AA.

L'E / S APIC 82093AA contenait 24 broches d'entrée et l'architecture APIC pouvait prendre en charge jusqu'à 16 CPU. Pour maintenir la compatibilité avec les anciens systèmes, 0 à 15 interruptions ont été allouées aux anciennes interruptions ISA. Et les interruptions des périphériques PCI ont commencé à s'afficher sur la ligne IRQ 16-23. Maintenant, il était possible de ne pas penser aux conflits d'interruption des périphériques ISA et PCI. De plus, grâce à l'augmentation du nombre de lignes d'interruption libres, il est également devenu possible d'augmenter le nombre de lignes PIRQx.



La programmation des E / S APIC et LAPIC se fait via MMIO. Les registres LAPIC sont généralement situés à 0xFEE00000, les registres d'E / S APIC à 0xFE00000. Bien que, en principe, toutes ces adresses puissent être reconfigurées.

Comme dans le cas du PIC, au départ, les puces individuelles sont devenues plus tard une partie du chipset.

Par la suite, l'architecture APIC a été modernisée et la nouvelle version a été appelée xAPIC (x - extended). Rétrocompatibilité conservée avec la version précédente. Le nombre de CPU possibles dans le système est passé à 256.

La prochaine phase de développement de l'architecture s'appelait x2APIC . Le nombre de CPU possibles dans le système est passé à 2 ^ 32. Les contrôleurs peuvent fonctionner en mode de compatibilité xAPIC, ou dans le nouveau mode x2APIC, où la programmation LAPIC est effectuée non pas via MMIO, mais via les registres MSR (ce qui est beaucoup plus rapide). A en juger par ce lien, le support IOMMU est requis pour que ce mode fonctionne.

Il convient de noter que le système peut avoir plusieurs contrôleurs APIC d'E / S. Par exemple, un pour 24 interruptions dans le pont sud, l'autre pour 32 dans le nord. Dans le contexte des E / S, les interruptions APIC sont souvent appelées GSI (Global System Interrupt). Donc, dans un tel système sera GSI 0-55.

Y a-t-il un LAPIC intégré dans le CPU et quelle architecture peut être comprise par les drapeaux de bits dans le CPUID.
Pour que le système détecte LAPIC et I / O APIC, le BIOS doit fournir des informations à leur sujet au système via MPtable (l'ancienne méthode) ou via la table ACPI (MADT dans ce cas). En plus des informations générales, la table MPtable et l'ACPI (cette fois dans la table DSDT) doivent contenir des informations sur le routage des interruptions, c'est-à-dire des informations sur le périphérique qui se trouve sur quelle ligne d'interruption (analogue à la table $ PIR).

Le tableau MPTable se trouve dans les spécifications officielles. Auparavant, la spécification était sur le site Web d'Intel, mais maintenant elle ne peut être trouvée que dans les archives. La spécification ACPI se trouve désormais sur le site Web de l'UEFI (version actuelle 6.2 ). Il convient de noter qu'en utilisant ACPI, vous pouvez spécifier le routage d'interruption pour les systèmes sans APIC (au lieu d'utiliser la table $ PIR).

Msi


( wiki )

La version précédente avec APIC est bonne, mais pas sans défauts. Toutes ces lignes d'interruption de périphérique compliquent les circuits et augmentent la probabilité d'erreurs. Le bus PCI a été remplacé par PCI express, dans lequel les lignes d'interruption ont simplement été décidées d'être supprimées. Pour maintenir la compatibilité, les signaux d'interruption (INTx #) sont émulés par certains types de messages. Dans ce schéma, l'ajout logique de lignes d'interruption, qui se faisait auparavant par une connexion physique des fils, est tombé sur les épaules des ponts PCI. Cependant, la prise en charge des interruptions INTx héritées ne prend en charge que la compatibilité descendante avec le bus PCI. En fait, PCI express a proposé une nouvelle méthode de livraison des messages d'interruption - MSI (Message Signaled Interrupts). Dans cette méthode, pour signaler une interruption, l'appareil écrit simplement dans la zone MMIO allouée au processeur LAPIC.



Auparavant, seules 4 interruptions étaient attribuées à un périphérique PCI (c'est-à-dire à toutes ses fonctions), mais il est désormais possible d'adresser jusqu'à 32 interruptions.

Dans le cas de MSI, il n'y a pas de partage pour les lignes, chaque interruption correspond à son appareil.

Les interruptions MSI résolvent également un autre problème. Supposons qu'un périphérique effectue une transaction d'écriture en mémoire et souhaite signaler son achèvement via une interruption. Mais une transaction d'écriture peut être retardée sur le bus pendant le processus de transfert (que le périphérique ne connaît pas du tout), et le signal d'interruption arrivera avant le processeur. Ainsi, le CPU lira toujours les données invalides. Si MSI est utilisé, les informations sur MSI sont transmises ainsi que les données, et ne pourront tout simplement pas arriver plus tôt.

Il convient de noter que les interruptions MSI ne peuvent pas fonctionner sans LAPIC, mais l'utilisation de MSI peut nous remplacer par I / O APIC (simplification de la conception).

Par la suite, cette méthode a reçu l'extension MSI-X. Désormais, chaque appareil peut avoir jusqu'à 2048 interruptions. Et il est devenu possible d'indiquer individuellement à chaque interruption sur quel processeur elle devait être exécutée. Cela peut être très utile pour les appareils lourdement chargés tels que les cartes réseau.

Aucune table BIOS supplémentaire n'est requise pour la prise en charge MSI. Mais le périphérique doit signaler la prise en charge MSI dans l'une des capacités de sa configuration PCI, et le pilote de périphérique doit prendre en charge l'utilisation de MSI.

Conclusion


Dans cet article, nous avons examiné l'évolution des contrôleurs d'interruption et reçu des informations théoriques générales sur la livraison des interruptions à partir de périphériques externes dans un système x86.

Dans la partie suivante, nous verrons comment utiliser sous Linux chacun des contrôleurs décrits dans la pratique.

Références:


Source: https://habr.com/ru/post/fr430548/


All Articles