Cet article concerne le processus de livraison d'interruption à partir de périphériques externes dans le système x86. Il essaie de répondre à des questions telles que:
- Qu'est-ce que la photo et à quoi sert-elle?
- Qu'est-ce que l'APIC et à quoi sert-il? Quel est l'objectif du LAPIC et des E / S 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 rôle des tables $ PIR, MPtable et ACPI?
Si vous souhaitez connaître la réponse à l'une de ces questions, ou si vous souhaitez simplement connaître l'évolution du contrôleur d'interruption, n'hésitez pas.
Présentation
Pour ceux qui ne savent pas ce qu'est une interruption, voici une citation de Wikipedia:
Dans la programmation système, une interruption est un signal envoyé au processeur par un matériel ou un logiciel indiquant un événement qui nécessite une attention immédiate. Une interruption avertit le processeur d'une condition de priorité élevée nécessitant l'interruption du code actuel que le processeur exécute. Le processeur répond en suspendant ses activités en cours, en enregistrant son état et en exécutant une fonction appelée gestionnaire d'interruption (ou routine de service d'interruption, ISR) pour gérer l'événement. Cette interruption est temporaire et, une fois le gestionnaire d'interruptions terminé, le processeur reprend ses activités normales.
Il existe deux types d'interruptions: les interruptions matérielles et les interruptions logicielles (softirqs):
- Les interruptions matérielles sont utilisées par les périphériques pour communiquer qu'elles nécessitent l'attention du système d'exploitation. En interne, les interruptions matérielles sont mises en œuvre à l'aide de signaux d'alerte électroniques qui sont envoyés au processeur à partir d'un périphérique externe, qui fait partie de l'ordinateur lui-même, tel qu'un contrôleur de disque, ou d'un périphérique externe. Par exemple, appuyer sur une touche du clavier ou déplacer la souris déclenche des interruptions matérielles qui obligent le processeur à lire la position de la frappe ou de la souris. L'acte d'initier une interruption matérielle est appelé une demande d'interruption (IRQ).
- Une interruption logicielle est provoquée soit par une condition exceptionnelle dans le processeur lui-même, soit par une instruction spéciale dans le jeu d'instructions qui provoque une interruption lors de son exécution. Le premier est souvent appelé un piège ou une exception et est utilisé pour les erreurs ou événements survenant pendant l'exécution du programme qui sont suffisamment exceptionnels pour ne pas être traités dans le programme lui-même. Par exemple, une exception de division par zéro sera levée si l'unité logique arithmétique du processeur reçoit l'ordre de diviser un nombre par zéro car cette instruction est une erreur et impossible.
Cet article concerne les interruptions matérielles / externes IRQ.
Quel est le but des interruptions? Par exemple, nous voulons effectuer une action avec un paquet entrant de la carte réseau dès que le paquet arrive. Si vous ne souhaitez pas demander en continu à la carte réseau "Mon paquet est-il arrivé?" et perdre votre temps processeur, vous pouvez utiliser IRQ d'interruption de matériel externe. La ligne d'interruption d'un périphérique doit être connectée à la ligne INTR du CPU, et après la réception de chaque paquet, la carte réseau émettra un signal sur cette ligne. Le CPU détectera ce signal et saura que la carte réseau a des informations pour cela. Ce n'est qu'après que le CPU lira le paquet entrant.
Mais que devons-nous faire s'il y a beaucoup de périphériques externes? Il serait très improductif de créer une tonne de broches INTR sur le processeur pour chacun d'eux.

Pour résoudre ce problème, une puce spéciale a été inventée - un contrôleur d'interruption.
Pic
(
wiki /
osdev )
La première puce de contrôleur d'interruption était l'
Intel 8259 PIC . Il avait 8 lignes d'entrée (IRQ0-7) et 1 ligne de sortie (qui connecte le contrôleur d'interruption à la ligne INTR de la CPU). En cas d'interruption d'un des appareils sur ses lignes d'entrée, le 8259 émet un signal sur la ligne INTR. Après cela, le CPU saura que certains périphériques nécessitent son attention immédiate, et le processeur demandera au PIC laquelle des 8 lignes d'entrée (IRQx) était la source de cette interruption. Il y a des frais généraux à ce sondage, mais maintenant nous avons 8 lignes d'interruption au lieu de 1.

Bientôt, 8 lignes ne suffisent plus. Pour augmenter le nombre total de lignes d'interruption, deux contrôleurs 8259 (maître et esclave) ont été connectés en cascade (Dual PIC).
Les IRQ de 0 à 7 sont traités avec le premier Intel 8259 PIC (maître) et les IRQ de 8 à 15 sont traités avec le second Intel 8259 PIC (maître). Seul le maître est connecté à la CPU et peut signaler les interruptions entrantes. S'il y a une interruption sur les lignes 8-15, le deuxième PIC (esclave) le signalera au maître sur la ligne IRQ2, puis le maître signalera le CPU. Cette interruption en cascade supprime 1 des 16 lignes, mais effectue un total de 15 interruptions pour tous les périphériques externes.

Ce schéma a été adopté par la communauté, et maintenant quand quelqu'un parle de PIC (Programm Interrupt Controller), il s'agit de ce système Dual PIC. Après un certain temps, les contrôleurs 8259 ont été améliorés et ont obtenu un nouveau nom: 8259A. Avec ces contrôleurs, le système DUAL PIC était inclus dans le chipset. À une époque où le bus principal pour la connexion des périphériques externes était l'ISA, ce système était suffisant. Il était seulement nécessaire que différents appareils ne se connectent pas à la même ligne IRQ, car les interruptions ISA ne sont pas partageables.
Le mappage des interruptions de l'appareil était à peu près standard:
Exemple (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 puces 8259 sont effectués avec des ports d'E / S:
La documentation complète du 8259A est disponible
ici .
Le bus PCI a ensuite remplacé le bus ISA. Malheureusement, le nombre de périphériques a commencé à dépasser le nombre 15. De plus, au lieu du bus ISA statique, des périphériques dans le bus PCI peuvent être ajoutés dynamiquement au système, ce qui pourrait potentiellement entraîner encore plus de problèmes. Mais heureusement, les interruptions du bus PCI peuvent être partagées, il est donc possible de connecter de nombreux périphériques à une ligne d'interruption IRQ. Au final, pour résoudre le problème du manque de lignes d'interruption, il a été décidé de regrouper les interruptions de tous les périphériques PCI en lignes PIRQ (Programmable Interrupt Request).
Par exemple, supposons que nous ayons 4 lignes d'interruption libres sur le contrôleur PIC et 20 périphériques PCI. Nous pouvons combiner les interruptions de 5 appareils en une seule ligne PIRQx et connecter ces lignes PIRQx au contrôleur PIC. Dans ce cas, s'il y a une interruption sur l'une des lignes PIRQx, le processeur devra demander à tous les périphériques connectés à cette ligne à propos de l'interruption de savoir qui en est responsable, mais au final cela résout le problème. Le périphérique qui connecte les lignes d'interruption PCI aux lignes PIRQ est souvent appelé routeur PIR.
Avec cette méthode, il est nécessaire de s'assurer que les lignes PIRQx ne se connectent pas aux lignes avec des interruptions ISA (car cela produira des conflits) et que les lignes PIRQx sont équilibrées (plus il y a de périphériques connectés à une ligne, plus le CPU aura besoin de périphériques pour interroger lorsqu'il doit vérifier quel appareil est responsable de l'interruption).
Remarque : sur l'image, le mappage du périphérique PCI -> PIR est représenté de manière abstraite, car dans le cas réel, c'est un peu plus compliqué. Dans le monde réel, chaque périphérique PCI possède 4 lignes d'interruption (INTA, INTB, INTC, INTD) et jusqu'à 8 fonctions, où chaque fonction ne peut avoir qu'une seule de ces interruptions INTx. La ligne INTx qui sera utilisée par chaque fonction est déterminée par la configuration du chipset.
De par leur nature, les fonctions sont des blocs logiques séparés. Par exemple, un périphérique PCI peut avoir une fonction de contrôleur Smbus, une fonction de contrôleur SATA et une fonction de pont LPC. Du point de vue d'un système d'exploitation (OS), chaque fonction est comme un appareil séparé avec son propre espace de configuration (configuration PCI).
Les informations sur un routage d'interruption du contrôleur PIC sont envoyées au système d'exploitation par le BIOS, à l'aide de la table $ PIR et via 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.
Une spécification pour la table $ PIR était récemment
sur le site Web de Microsoft , mais n'est actuellement pas disponible. Il est possible de comprendre le contenu de la table à partir de la
spécification BIOS PCI [4.2.2. Obtenir les options de routage d'interruption PCI] ou à partir d'
ici (le dernier lien est en russe, mais vous pouvez essayer de google «Spécification de la table de routage PCI IRQ»)
Apic
(
wiki ,
osdev )
La dernière méthode a fonctionné jusqu'à l'arrivée des systèmes multiprocesseurs. Par nature, le PIC ne peut envoyer des interruptions qu'à un seul processeur, et dans un système multiprocesseur, il est souhaitable de charger les CPU de manière équilibrée. La solution à ce problème a été la nouvelle interface APIC (PIC avancé).
Un contrôleur spécial appelé LAPIC (Local APIC) a été ajouté pour chaque processeur, ainsi que le contrôleur d'
E / S APIC pour le routage des interruptions à partir de périphériques externes. Tous ces contrôleurs sont combinés dans un bus commun avec le nom APIC (notez que les systèmes modernes utilisent un bus système standard au lieu d'un bus APIC séparé pour cette tâche).
Lorsqu'une interruption externe arrive sur l'entrée I / O APIC, le contrôleur envoie un message d'interruption au LAPIC de l'un des CPU du système. De cette façon, le contrôleur d'E / S APIC permet d'équilibrer la charge d'interruption entre les processeurs.
La première puce APIC était la
82489DX , qui était une puce distincte qui avait en elle-même un LAPIC connecté et un APIC d'E / S. Pour un système à deux processeurs, trois de ces puces étaient nécessaires: deux pour LAPIC et une pour I / O APIC. Plus tard, la fonctionnalité LAPIC a été directement incluse dans les processeurs et la partie E / S APIC a été séparée de la puce 82093AA.
L'E / S APIC
82093AA avait 24 entrées et l'architecture APIC pouvait prendre en charge jusqu'à 16 CPU. Les interruptions 0-15 ont été laissées pour les anciennes interruptions ISA pour la compatibilité avec les anciens systèmes, et les interruptions 16-23 étaient destinées à tous les périphériques PCI. Avec cette délimitation, tous les conflits entre les interruptions ISA et PCI pourraient être facilement évités. Avec 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 s'effectue à l'aide de MMIO. Les registres LAPIC sont généralement placés à l'adresse 0xFEE00000 et les E / S APIC s'inscrivent à l'adresse 0xFE0000, bien qu'il soit possible de les reconfigurer.
Comme dans le cas PIC, des puces séparées au début sont devenues une partie du chipset plus tard.
L'architecture APIC a ensuite été modernisée et sa nouvelle variante a été nommée xAPIC (x - étendu). Avec une compatibilité descendante complète, le nombre total de CPU possibles dans le système a été augmenté à 256.
La prochaine étape du développement de l'architecture a été nommée
x2APIC . Le nombre de CPU possibles dans le système a été augmenté à 2 ^ 32. Ces contrôleurs peuvent fonctionner dans un mode de compatibilité descendante avec xAPIC, ou ils peuvent fonctionner dans le nouveau mode x2APIC. Dans ce nouveau mode, la programmation du contrôleur ne se fait pas via MMIO, mais via les registres MSR (qui sont beaucoup plus rapides). Selon
ce lien , le support IOMMU est nécessaire pour ce mode.
Il convient de noter qu'il est possible d'avoir plusieurs contrôleurs APIC d'E / S dans le système. Par exemple, un pour 24 interruptions dans un southbridge et l'autre pour 32 interruptions dans un northbridge. Dans le contexte d'E / S APIC, les interruptions sont généralement appelées GSI (Global System Interrupt). Ainsi, le système susmentionné a des GSI 0-55.
Comment déterminer si un CPU a un LAPIC interne et quelle architecture APIC il prend en charge? Il est possible de répondre à ces questions en inspectant les indicateurs de bits de CPUID.
Pour aider le système d'exploitation à découvrir LAPIC et les E / S APIC, le BIOS doit présenter des informations à leur sujet via une table MPtable (ancienne méthode) ou via une table ACPI (une table MADT dans ce cas). Outre les informations courantes, la table MPtable et l'ACPI (dans ce cas, une table DSDT) doivent contenir des informations sur le routage d'interruption. Cela signifie des informations sur quel périphérique utilise quelle ligne d'interruption (similaire à la table $ PIR).
Vous pouvez lire sur la MPtable dans les
spécifications officielles. Auparavant, la spécification était sur le site Web d'Intel, mais actuellement, il n'est possible de la trouver que dans une version archive. La spécification ACPI se trouve sur le site Web de l'UEFI (la version actuelle est
6.2 ). Il convient de noter qu'avec ACPI, il est possible de déclarer le routage d'interruption pour les systèmes sans APIC (au lieu de fournir une table $ PIR distincte).
Msi
(
wiki )
La dernière variante d'APIC était bonne, mais pas sans inconvénients. Toutes les lignes d'interruption des appareils ont rendu le système très compliqué et ont donc augmenté la probabilité d'erreur. Le bus PCI express est venu remplacer le bus PCI, ce qui a complètement simplifié tous les systèmes d'interruption. Il n'a pas du tout de lignes d'interruption. Pour des raisons de rétrocompatibilité, les signaux d'interruption (INTx #) sont émulés avec un type de message distinct. Avec les lignes d'interruption PCI, leur connexion a été établie avec des fils physiques. Avec les lignes d'interruption PCI express, une connexion est logique et est établie par des ponts PCI express. Mais cette prise en charge des interruptions INTx héritées n'existe que pour une compatibilité descendante avec le bus PCI. PCI express introduit une toute nouvelle méthode de livraison d'interruption - MSI (Message Signaled Interrupts). Dans cette méthode, un appareil signale l'interruption simplement en écrivant à un endroit spécial dans la région MMIO des CPU LAPIC.

Auparavant, un seul périphérique PCI (c'est-à-dire toutes ses fonctions) ne pouvait avoir que 4 interruptions, mais maintenant il est devenu possible d'adresser jusqu'à 32 interruptions.
Dans le cas de MSI, il n'y a pas de partage de lignes d'interruption: chaque interruption correspond naturellement à son appareil.
Les interruptions MSI résolvent également un autre problème. Par exemple, imaginons une situation où un périphérique effectue une transaction d'écriture en mémoire et souhaite signaler son achèvement via l'interruption. Mais une transaction d'écriture peut être retardée sur le bus au cours de sa transmission (et l'appareil ne pouvait pas le savoir). Dans ce cas, le signal de l'interruption arrivera en premier au CPU, donc le processeur lira les données non encore valides. Si MSI est utilisé, les informations sur le MSI sont transmises de la même manière que les messages de données et ne peuvent donc pas venir plus tôt.
Il est intéressant de noter que les interruptions MSI ne peuvent pas fonctionner sans LAPIC, mais les MSI peuvent remplacer les E / S APIC (une simplification de conception de plus).
Après un certain temps, la méthode MSI a été étendue à MSI-X. Désormais, chaque appareil peut avoir jusqu'à 2048 interruptions. Il est également désormais possible de spécifier quelle CPU doit traiter quelle interruption. Il peut être très utile pour les appareils à haute charge, comme les cartes réseau par exemple.
Il n'est pas nécessaire de disposer d'une table BIOS distincte pour la prise en charge MSI. Mais l'appareil doit indiquer sa prise en charge MSI via l'une des capacités de son espace de configuration PCI. En outre, un pilote de périphérique doit inclure toute la prise en charge nécessaire pour travailler avec le MSI.
Conclusion
Dans cet article, nous avons étudié les informations sur l'évolution du contrôleur d'interruption et avons acquis des connaissances théoriques communes sur la distribution d'interruptions à partir de périphériques externes dans le système x86.
Dans la partie suivante, nous allons nous entraîner et voir comment engager chacun des contrôleurs d'interruption susmentionnés sous Linux.
Dans la troisième partie, nous examinerons le code du coreboot et verrons quels paramètres sont nécessaires dans le chipset pour un routage d'interruption correct.
Liens:
Segments reconnus
Un merci spécial à Jacob Garber de la communauté
coreboot de m'avoir aidé avec la traduction de cet article.