Ich weiß nur, dass Interruptes sich um einen hardware signal assertionin einem Prozessor verursachten Pin handelt. Aber ich würde gerne wissen, wie Linux damit umgeht.
Was passiert alles, wenn ein Interrupt auftritt?
Hier ist eine Übersicht über die Verarbeitung auf niedriger Ebene. Ich beschreibe eine einfache typische Architektur, echte Architekturen können komplexer sein oder sich in einer Weise unterscheiden, die auf dieser Detailebene keine Rolle spielt.
Wenn ein Interrupt auftritt, prüft der Prozessor, ob Interrupts maskiert sind. Wenn dies der Fall ist, passiert nichts, bis sie entlarvt werden. Wenn Interrupts entlarvt werden und noch Interrupts anstehen, wählt der Prozessor einen aus.
Dann führt der Prozessor die Unterbrechung aus, indem er zu einer bestimmten Adresse im Speicher verzweigt. Der Code an dieser Adresse wird als Interrupt-Handler bezeichnet . Wenn der Prozessor dorthin verzweigt, maskiert er Interrupts (so dass der Interrupt-Handler die ausschließliche Kontrolle hat) und speichert den Inhalt einiger Register an einer bestimmten Stelle (normalerweise an einer anderen Stelle).
Der Interrupt-Handler erledigt das, was er tun muss, in der Regel durch Kommunikation mit dem Peripheriegerät, das den Interrupt zum Senden oder Empfangen von Daten ausgelöst hat. Wenn der Interrupt vom Timer ausgelöst wurde, kann der Handler den OS-Scheduler auslösen, um zu einem anderen Thread zu wechseln. Wenn der Handler die Ausführung beendet hat, führt er einen speziellen Rücksprungbefehl aus, der die gespeicherten Register wiederherstellt und Interrupts entlarvt.
Der Interrupt-Handler muss schnell ausgeführt werden, da er die Ausführung anderer Interrupts verhindert. Im Linux-Kernel besteht die Interrupt-Verarbeitung aus zwei Teilen:
Die "obere Hälfte" ist der Interrupt-Handler. Es macht das notwendige Minimum, kommuniziert normalerweise mit der Hardware und setzt irgendwo im Kernel-Speicher ein Flag.
Die „untere Hälfte“ erledigt jede andere notwendige Verarbeitung, zum Beispiel das Kopieren von Daten in den Prozessspeicher, das Aktualisieren von Kerneldatenstrukturen usw. Es kann einige Zeit dauern und sogar das Warten auf einen anderen Teil des Systems blockieren, da es mit aktivierten Interrupts ausgeführt wird.
Gilles bereits beschrieben den allgemeinen Fall einer Unterbrechung, die folgenden speziell auf Linux gilt 2.6 auf einer Intel - Architektur (Teil davon ist auch basiert auf dem Intel - Spezifikationen).
Ein Interrupt ist ein Ereignis, das die vom Prozessor ausgeführte Befehlsfolge ändert.
Es gibt zwei verschiedene Arten von Interrupts:
Synchroner Interrupt (Ausnahme), der von der CPU während der Verarbeitung von Anweisungen erzeugt wird
Asynchroner Interrupt (Interrupt) , der von anderen Hardwaregeräten ausgegeben wird
Ausnahmen sind Programmierfehler (zB Divide Error , Page Fault , Overflow ), die vom Kernel behandelt werden müssen. Er sendet ein Signal an das Programm und versucht, den Fehler zu beheben.
Die folgenden zwei Ausnahmen werden klassifiziert:
Vom Prozessor erkannte Ausnahmebedingung, die von der CPU beim Erkennen eines anormalen Zustands generiert wurde; unterteilt in drei Gruppen: Fehler können generell behoben werden, Traps melden eine Ausführung, Abbrüche sind schwerwiegende Fehler.
Vom Programmierer angeforderte programmierte Ausnahme , die wie eine Falle behandelt wird.
Interrupts können von E / A-Geräten (Tastatur, Netzwerkadapter, ..), Intervall-Timern und (auf Multiprozessorsystemen) anderen CPUs ausgegeben werden. Wenn ein Interrupt auftritt, muss die CPU seinen aktuellen Befehl stoppen und den neu eingetroffenen Interrupt ausführen. Er muss den alten unterbrochenen Prozessstatus speichern, um ihn (wahrscheinlich) wieder aufzunehmen, nachdem der Interrupt bearbeitet wurde.
Der Umgang mit Interrupts ist eine heikle Aufgabe:
Interrupts können jederzeit auftreten, der Kernel versucht, sie so schnell wie möglich aus dem Weg zu räumen
Ein Interrupt kann durch einen anderen Interrupt unterbrochen werden
Es gibt Regionen im Kernel, die überhaupt nicht unterbrochen werden dürfen
Es sind zwei verschiedene Interrupt-Ebenen definiert:
Maskierbare Interrupts von E / A-Geräten; kann in zwei Zuständen vorliegen, maskiert oder nicht maskiert. Es werden nur nicht maskierte Interrupts verarbeitet.
Nicht maskierbare Interrupts ; kritische Störungen (zB Hardwarefehler); immer von der CPU verarbeitet.
Jedes Hardwaregerät verfügt über eine eigene IRQ-Leitung (Interrupt Request). Die IRQs sind ab 0 nummeriert. Alle IRQ-Leitungen sind mit einem programmierbaren Interrupt-Controller (PIC) verbunden. Der PIC lauscht auf IRQs und weist sie der CPU zu. Es ist auch möglich, eine bestimmte IRQ-Leitung zu deaktivieren.
Moderne Multiprocessing-Linux-Systeme enthalten im Allgemeinen den neueren Advanced PIC (APIC), der IRQ-Anforderungen gleichmäßig auf die CPUs verteilt.
Der Mittelschritt zwischen einem Interrupt oder einer Ausnahme und deren Behandlung ist die Interrupt Descriptor Table (IDT). Diese Tabelle ordnet jedem Interrupt- oder Ausnahmevektor (eine Zahl) einen bestimmten Handler zu (z. B. wird der Divisionsfehler von der Funktion behandelt divide_error()).
Durch die IDT weiß der Kernel genau, wie mit dem aufgetretenen Interrupt oder der aufgetretenen Ausnahme umgegangen werden soll.
Also, was macht der Kernel, wenn ein Interrupt auftritt?
Die CPU prüft nach jedem Befehl, ob ein IRQ vom (A) PIC vorliegt
Wenn ja, konsultiert das IDT, um den empfangenen Vektor einer Funktion zuzuordnen
Überprüft, ob der Interrupt von einer autorisierten Quelle ausgegeben wurde
Speichert die Register des unterbrochenen Prozesses
Rufen Sie die entsprechende Funktion auf, um den Interrupt zu behandeln
Laden Sie die zuletzt gespeicherten Register des unterbrochenen Prozesses und versuchen Sie, ihn fortzusetzen
Können Sie das klären „prüft die CPU nach jedem Befehl , wenn ein IRQ von dem (A) PIC gibt es“ . Wie genau passiert das? VIPBezieht es sich auf -flag in flags register oder was auch immer? Vielen Dank im Voraus
red0ct
7
An der Interrupt-Behandlung sind zunächst Peripheriegeräte, Interrupt-Controller, CPU, Betriebssystemkern und Treiber beteiligt. Peripheriegeräte sind für die Interrupt-Generierung verantwortlich. Sie machen Interrupt-Anforderungsleitungen geltend, wenn sie die Aufmerksamkeit des Betriebssystemkerns wünschen. Diese Signale werden vom Interrupt-Controller gemultiplext, der für die Erfassung der Interruptsignale verantwortlich ist. Es ist auch verantwortlich für die Bestimmung der Reihenfolge, in der Interruptsignale an die CPU weitergeleitet werden. Interrupt-Controller ist in der Lage, bestimmte Interrupt-Anforderungsleitungen (IRQL) vorübergehend zu deaktivieren und wieder zu aktivieren (IRQL-Maskierung). Der Interrupt-Controller leitet die gesammelten Interrupt-Anforderungen nacheinander an die CPU weiter. CPU prüft nach Abschluss der Ausführung jeder Anweisung, ob vom Interrupt-Controller noch Interrupt-Anforderungen vorliegen. Wenn die CPU feststellt, dass eine Warteanforderung vorliegt UND das Flag "Interrupt Enable" im internen CPU-Steuerregister gesetzt ist, beginnt die CPU mit der Interrupt-Behandlung. Wie Sie sehen, kann der Linux-Kernel durch Manipulation des Interrupt-Flags in der CPU und Kommunikation mit dem Interrupt-Controller die Interrupt-Akzeptanz steuern. Beispielsweise kann Linux die Annahme von Interrupts von einem bestimmten Gerät oder die Annahme von Interrupts überhaupt deaktivieren. Der Linux-Kernel kann die Interrupt-Akzeptanz steuern. Beispielsweise kann Linux die Annahme von Interrupts von einem bestimmten Gerät oder die Annahme von Interrupts überhaupt deaktivieren. Der Linux-Kernel kann die Interrupt-Akzeptanz steuern. Beispielsweise kann Linux die Annahme von Interrupts von einem bestimmten Gerät oder die Annahme von Interrupts überhaupt deaktivieren.
Was passiert, wenn der Prozessor eine Interrupt-Anfrage erhält? Erstens deaktiviert die CPU Interrupts automatisch, indem sie das Interrupt-Flag zurücksetzt. Sie werden wieder aktiviert, sobald die Interrupt-Behandlung abgeschlossen ist. Gleichzeitig nimmt die CPU nur minimalen Arbeitsaufwand in Kauf, um die CPU so vom Benutzermodus in den Kernelmodus zu versetzen, dass die Ausführung des unterbrochenen Codes fortgesetzt werden kann. Die CPU verwendet spezielle CPU-Kontrollstrukturen, die vom Linux-Kernel ausgefüllt werden, um eine Codeadresse zu finden, an die die Kontrolle übergeben wird. Diese Adresse ist die Adresse des ersten Befehls des Interrupt-Handlers, der Teil des Linux-Kernels ist.
Als einen ersten Schritt der Unterbrechungsbehandlung identifiziert der Kern den Vektor der empfangenen Unterbrechung, um zu identifizieren, welche Art von Ereignis in dem System aufgetreten ist. Der Interrupt-Vektor definiert, welche Aktionen Linux ausführen soll, um damit umzugehen. In einem zweiten Schritt speichert Linux die restlichen CPU-Register (die nicht automatisch von der CPU gespeichert wurden) und die möglicherweise vom unterbrochenen Programm verwendet werden können. Dies ist eine sehr wichtige Aktion, da Linux Interrupts transparent für das unterbrochene Programm verarbeiten kann. In einem dritten Schritt wechselt Linux in den Kernel-Modus, indem es die Kernel-Umgebung und den dafür erforderlichen CPU-Status einstellt. Schließlich wird ein vektorabhängiger Interrupt-Handler aufgerufen. (Sie können das Makro BUILD_INTERRUPT3 in arch \ x86 \ kernel \ entry_32 anzeigen. S, um die zusätzlichen Details für das x86-Architektur-bezogene Beispiel zu erfassen.) Bei Peripheriegeräten ist dies eine Routine do_IRQ (). (Schauen Sie in die arch \ x86 \ kernel \ irq.c)
Der vektorabhängige Interrupt-Handler wird normalerweise von Aufrufen von irq_enter () und irq_exit () umschlossen. Ein Codebereich, der in einem Paar dieser Funktionen eingeschlossen ist, ist in Bezug auf irgendwelche anderen derartigen Bereiche atomar und ist auch in Bezug auf Paare von cli / sti atomar. Irq_enter () und irq_exit () erfassen auch einige Statistiken im Zusammenhang mit der Interrupt-Behandlung. Schließlich durchsucht der Kernel die Tabelle vector_irq nach der dem Vektor des empfangenen Interrupts zugewiesenen IRQ-Nummer und ruft handle_irq () auf (von arch \ x86 \ kernel \ irq_32.c).
An diesem Punkt endet der allgemeine Teil der Interrupt-Behandlung unter Linux, da der Kernel die vom Gerätetreiber als Teil des IRQ-Deskriptors installierte Interrupt-Handler-Routine als Teil des IRQ-Deskriptors ansieht und aufruft. Wenn ein solcher Handler nicht vom Treiber installiert wurde, bestätigt der Kernel einfach den Interrupt auf dem Interrupt-Controller und beendet den allgemeinen Interrupt-Handler.
Nach Beendigung der Interrupt-Behandlung stellt der Kernel den Zustand des zuvor unterbrochenen Programms wieder her und nimmt diese Programmausführung wieder auf.
CPU consults with special CPU control structures filled by Linux kernel to find an address of code to which control will be passed.Ja! Ich frage mich, was diese speziellen Kontrollstrukturen sind ...
Antworten:
Hier ist eine Übersicht über die Verarbeitung auf niedriger Ebene. Ich beschreibe eine einfache typische Architektur, echte Architekturen können komplexer sein oder sich in einer Weise unterscheiden, die auf dieser Detailebene keine Rolle spielt.
Wenn ein Interrupt auftritt, prüft der Prozessor, ob Interrupts maskiert sind. Wenn dies der Fall ist, passiert nichts, bis sie entlarvt werden. Wenn Interrupts entlarvt werden und noch Interrupts anstehen, wählt der Prozessor einen aus.
Dann führt der Prozessor die Unterbrechung aus, indem er zu einer bestimmten Adresse im Speicher verzweigt. Der Code an dieser Adresse wird als Interrupt-Handler bezeichnet . Wenn der Prozessor dorthin verzweigt, maskiert er Interrupts (so dass der Interrupt-Handler die ausschließliche Kontrolle hat) und speichert den Inhalt einiger Register an einer bestimmten Stelle (normalerweise an einer anderen Stelle).
Der Interrupt-Handler erledigt das, was er tun muss, in der Regel durch Kommunikation mit dem Peripheriegerät, das den Interrupt zum Senden oder Empfangen von Daten ausgelöst hat. Wenn der Interrupt vom Timer ausgelöst wurde, kann der Handler den OS-Scheduler auslösen, um zu einem anderen Thread zu wechseln. Wenn der Handler die Ausführung beendet hat, führt er einen speziellen Rücksprungbefehl aus, der die gespeicherten Register wiederherstellt und Interrupts entlarvt.
Der Interrupt-Handler muss schnell ausgeführt werden, da er die Ausführung anderer Interrupts verhindert. Im Linux-Kernel besteht die Interrupt-Verarbeitung aus zwei Teilen:
Wie in diesem Thema üblich finden Sie weitere Informationen unter Linux-Gerätetreiber . In Kapitel 10 geht es um Interrupts.
quelle
Gilles bereits beschrieben den allgemeinen Fall einer Unterbrechung, die folgenden speziell auf Linux gilt 2.6 auf einer Intel - Architektur (Teil davon ist auch basiert auf dem Intel - Spezifikationen).
Ein Interrupt ist ein Ereignis, das die vom Prozessor ausgeführte Befehlsfolge ändert.
Es gibt zwei verschiedene Arten von Interrupts:
Ausnahmen sind Programmierfehler (zB Divide Error , Page Fault , Overflow ), die vom Kernel behandelt werden müssen. Er sendet ein Signal an das Programm und versucht, den Fehler zu beheben.
Die folgenden zwei Ausnahmen werden klassifiziert:
Interrupts können von E / A-Geräten (Tastatur, Netzwerkadapter, ..), Intervall-Timern und (auf Multiprozessorsystemen) anderen CPUs ausgegeben werden. Wenn ein Interrupt auftritt, muss die CPU seinen aktuellen Befehl stoppen und den neu eingetroffenen Interrupt ausführen. Er muss den alten unterbrochenen Prozessstatus speichern, um ihn (wahrscheinlich) wieder aufzunehmen, nachdem der Interrupt bearbeitet wurde.
Der Umgang mit Interrupts ist eine heikle Aufgabe:
Es sind zwei verschiedene Interrupt-Ebenen definiert:
Jedes Hardwaregerät verfügt über eine eigene IRQ-Leitung (Interrupt Request). Die IRQs sind ab 0 nummeriert. Alle IRQ-Leitungen sind mit einem programmierbaren Interrupt-Controller (PIC) verbunden. Der PIC lauscht auf IRQs und weist sie der CPU zu. Es ist auch möglich, eine bestimmte IRQ-Leitung zu deaktivieren.
Moderne Multiprocessing-Linux-Systeme enthalten im Allgemeinen den neueren Advanced PIC (APIC), der IRQ-Anforderungen gleichmäßig auf die CPUs verteilt.
Der Mittelschritt zwischen einem Interrupt oder einer Ausnahme und deren Behandlung ist die Interrupt Descriptor Table (IDT). Diese Tabelle ordnet jedem Interrupt- oder Ausnahmevektor (eine Zahl) einen bestimmten Handler zu (z. B. wird der Divisionsfehler von der Funktion behandelt
divide_error()
).Durch die IDT weiß der Kernel genau, wie mit dem aufgetretenen Interrupt oder der aufgetretenen Ausnahme umgegangen werden soll.
Also, was macht der Kernel, wenn ein Interrupt auftritt?
quelle
VIP
Bezieht es sich auf -flag in flags register oder was auch immer? Vielen Dank im VorausAn der Interrupt-Behandlung sind zunächst Peripheriegeräte, Interrupt-Controller, CPU, Betriebssystemkern und Treiber beteiligt. Peripheriegeräte sind für die Interrupt-Generierung verantwortlich. Sie machen Interrupt-Anforderungsleitungen geltend, wenn sie die Aufmerksamkeit des Betriebssystemkerns wünschen. Diese Signale werden vom Interrupt-Controller gemultiplext, der für die Erfassung der Interruptsignale verantwortlich ist. Es ist auch verantwortlich für die Bestimmung der Reihenfolge, in der Interruptsignale an die CPU weitergeleitet werden. Interrupt-Controller ist in der Lage, bestimmte Interrupt-Anforderungsleitungen (IRQL) vorübergehend zu deaktivieren und wieder zu aktivieren (IRQL-Maskierung). Der Interrupt-Controller leitet die gesammelten Interrupt-Anforderungen nacheinander an die CPU weiter. CPU prüft nach Abschluss der Ausführung jeder Anweisung, ob vom Interrupt-Controller noch Interrupt-Anforderungen vorliegen. Wenn die CPU feststellt, dass eine Warteanforderung vorliegt UND das Flag "Interrupt Enable" im internen CPU-Steuerregister gesetzt ist, beginnt die CPU mit der Interrupt-Behandlung. Wie Sie sehen, kann der Linux-Kernel durch Manipulation des Interrupt-Flags in der CPU und Kommunikation mit dem Interrupt-Controller die Interrupt-Akzeptanz steuern. Beispielsweise kann Linux die Annahme von Interrupts von einem bestimmten Gerät oder die Annahme von Interrupts überhaupt deaktivieren. Der Linux-Kernel kann die Interrupt-Akzeptanz steuern. Beispielsweise kann Linux die Annahme von Interrupts von einem bestimmten Gerät oder die Annahme von Interrupts überhaupt deaktivieren. Der Linux-Kernel kann die Interrupt-Akzeptanz steuern. Beispielsweise kann Linux die Annahme von Interrupts von einem bestimmten Gerät oder die Annahme von Interrupts überhaupt deaktivieren.
Was passiert, wenn der Prozessor eine Interrupt-Anfrage erhält? Erstens deaktiviert die CPU Interrupts automatisch, indem sie das Interrupt-Flag zurücksetzt. Sie werden wieder aktiviert, sobald die Interrupt-Behandlung abgeschlossen ist. Gleichzeitig nimmt die CPU nur minimalen Arbeitsaufwand in Kauf, um die CPU so vom Benutzermodus in den Kernelmodus zu versetzen, dass die Ausführung des unterbrochenen Codes fortgesetzt werden kann. Die CPU verwendet spezielle CPU-Kontrollstrukturen, die vom Linux-Kernel ausgefüllt werden, um eine Codeadresse zu finden, an die die Kontrolle übergeben wird. Diese Adresse ist die Adresse des ersten Befehls des Interrupt-Handlers, der Teil des Linux-Kernels ist.
Als einen ersten Schritt der Unterbrechungsbehandlung identifiziert der Kern den Vektor der empfangenen Unterbrechung, um zu identifizieren, welche Art von Ereignis in dem System aufgetreten ist. Der Interrupt-Vektor definiert, welche Aktionen Linux ausführen soll, um damit umzugehen. In einem zweiten Schritt speichert Linux die restlichen CPU-Register (die nicht automatisch von der CPU gespeichert wurden) und die möglicherweise vom unterbrochenen Programm verwendet werden können. Dies ist eine sehr wichtige Aktion, da Linux Interrupts transparent für das unterbrochene Programm verarbeiten kann. In einem dritten Schritt wechselt Linux in den Kernel-Modus, indem es die Kernel-Umgebung und den dafür erforderlichen CPU-Status einstellt. Schließlich wird ein vektorabhängiger Interrupt-Handler aufgerufen. (Sie können das Makro BUILD_INTERRUPT3 in arch \ x86 \ kernel \ entry_32 anzeigen. S, um die zusätzlichen Details für das x86-Architektur-bezogene Beispiel zu erfassen.) Bei Peripheriegeräten ist dies eine Routine do_IRQ (). (Schauen Sie in die arch \ x86 \ kernel \ irq.c)
Der vektorabhängige Interrupt-Handler wird normalerweise von Aufrufen von irq_enter () und irq_exit () umschlossen. Ein Codebereich, der in einem Paar dieser Funktionen eingeschlossen ist, ist in Bezug auf irgendwelche anderen derartigen Bereiche atomar und ist auch in Bezug auf Paare von cli / sti atomar. Irq_enter () und irq_exit () erfassen auch einige Statistiken im Zusammenhang mit der Interrupt-Behandlung. Schließlich durchsucht der Kernel die Tabelle vector_irq nach der dem Vektor des empfangenen Interrupts zugewiesenen IRQ-Nummer und ruft handle_irq () auf (von arch \ x86 \ kernel \ irq_32.c).
An diesem Punkt endet der allgemeine Teil der Interrupt-Behandlung unter Linux, da der Kernel die vom Gerätetreiber als Teil des IRQ-Deskriptors installierte Interrupt-Handler-Routine als Teil des IRQ-Deskriptors ansieht und aufruft. Wenn ein solcher Handler nicht vom Treiber installiert wurde, bestätigt der Kernel einfach den Interrupt auf dem Interrupt-Controller und beendet den allgemeinen Interrupt-Handler.
Nach Beendigung der Interrupt-Behandlung stellt der Kernel den Zustand des zuvor unterbrochenen Programms wieder her und nimmt diese Programmausführung wieder auf.
quelle
CPU consults with special CPU control structures filled by Linux kernel to find an address of code to which control will be passed.
Ja! Ich frage mich, was diese speziellen Kontrollstrukturen sind ...Aus theoretischer Sicht wurde fast alles erklärt. Wenn Sie jedoch nach einer Erklärung zum Code-Framework für die Behandlung von Kernel-Interrupts suchen, folgen Sie diesem Link: Ein Code, der sich mit der Behandlung von Kernel-Interrupts befasst
Und wenn Sie immer noch auf der Suche nach einer Theorie zu Interrupts und Interrupt-Handlern sind, empfehle ich Folgendes: Interrupts und Interrupt-Handler verstehen
quelle