Autor Thema: [Tutorial Stufe 5 - Interrupts] Bekomme keine Interrupts  (Gelesen 3750 mal)

matt1491

  • Beiträge: 4
    • Profil anzeigen
Gespeichert
Hallo,
und zwar beschäftige ich mich schon länger mit der Entwicklung eines Betriebssystems. Hab aber nie den richtigen Einstieg geschafft.

Nun habe ich mal damit angefangen und stecke gerade bei der bearbeitung der Interrupts.
Mein Code sieht ziemlich so aus, wie der Beispielcode im Teil 5 des Tutorials.

Wenn ich selber Interrupts erzeuge (asm volatile("int $0x0");), dann wird dieser auch angezeigt.
Nur ich stehe auf dem Schlauch, wie ich die Interrupts der Hardware (z.B. Tastatur) in mein Programm kriege.

Und noch ne kleine Verständnisfrage am Rande:
In dem C-Code wird die Funktion intr_stub_0 aufgerufen (also sie wird an die Funktion idt_set_entry übergeben). Woher weiß der C-Compiler jetzt, dass dadurch das Assembler-Makro intr_stub mit dem Parameter 0 aufgerufen werden muss? Blick da irgendwie nicht durch.

Hoffe mir kann jemand helfen.
Danke ;)

Programm Noob

  • Gast
Gespeichert
« Antwort #1 am: 27. November 2010, 14:59 »
Du rufst in der assemblerdatei die makros für alle Exeptions und IRQS auf.

und wegen der Interrupts.
asm("sti");im C Kernel. NACH dem initialisieren von der IDT.
Damit schaltest du die Interupts wieder ein.

PNoob

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 27. November 2010, 16:29 »
Mein Code sieht ziemlich so aus, wie der Beispielcode im Teil 5 des Tutorials.

Wenn ich selber Interrupts erzeuge (asm volatile("int $0x0");), dann wird dieser auch angezeigt.
Nur ich stehe auf dem Schlauch, wie ich die Interrupts der Hardware (z.B. Tastatur) in mein Programm kriege.
Wenn Softwareinterrupts gehen, schau dir den Abschnitt zum PIC nochmal genauer an, da sitzt dann wahrscheinlich dein Fehler.

Die andere Möglichkeit wäre, dass du keinen sinnvollen Interrupthandler für die Tastatur eingerichtet hast. Wenn du dich an das Tutorial gehalten hast, ist IRQ 1 (der Tastaturinterrupt) auf 0x21 gemappt. asm volatile("int $0x21"); wäre also vielleicht auch noch einen Versuch wert.

Zitat
In dem C-Code wird die Funktion intr_stub_0 aufgerufen (also sie wird an die Funktion idt_set_entry übergeben). Woher weiß der C-Compiler jetzt, dass dadurch das Assembler-Makro intr_stub mit dem Parameter 0 aufgerufen werden muss? Blick da irgendwie nicht durch.
C-Code ruft nicht direkt ein Assembler-Makro auf. Wir haben einmal dieses Makro:
.macro intr_stub nr
.global intr_stub_\nr
intr_stub_\nr:
    pushl $0
    pushl $\nr
    jmp intr_common_handler
.endm

Das produziert erstmal für sich überhaupt keinen Code im Kompilat, das ist nur ein Makro. Ein paar Zeilen später wird das Makro dann benutzt (in dieser langen Liste):
intr_stub 0
Das wird dann vom Assembler zu folgendem Code expandiert:
.global intr_stub_0
intr_stub_0:
    pushl $0
    pushl $0
    jmp intr_common_handler

Und damit haben wir dann eine Symbol definiert, das von C aus wieder als Funktion angesprochen werden kann.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

matt1491

  • Beiträge: 4
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 28. November 2010, 08:31 »
Danke für die Antworten bisher.

@PNoob: Das Einschalten der Interrupts kommt bei mir (wie im Tutorial) am Ende der Funktion, wo die IDT initialisiert wird.

@taljeth: Ich hab mir mittlerweile das 5. Tutorial 1 zu 1 runtergeladen um Schreibfehler etc. auszuschließen. Ich glaube eher ich hab da noch ein Verständnisproblem, wie das ganze funktioniert.

Es ist doch so, dass ich im ASM-Code für jeden Interrupt-Kanal eine Funktion definiert habe. Diese ruft dann eine gemeinsame C-Funktion auf, die das ganze dann behandelt. Anhand der Nummer, die im CPU-State mit drin steht (intr) kann die Funktion feststellen auf welchem IRQ ein Interrupt erfolgte, oder?
Warscheinlich bin ich da aber komplett auf dem Holzweg -.-

Die andere Möglichkeit wäre, dass du keinen sinnvollen Interrupthandler für die Tastatur eingerichtet hast. Wenn du dich an das Tutorial gehalten hast, ist IRQ 1 (der Tastaturinterrupt) auf 0x21 gemappt. asm volatile("int $0x21"); wäre also vielleicht auch noch einen Versuch wert.
Ist das nur zum Testen, was passiert? Meine IRQ-Handler-Funktion unterscheidet nicht nach Nummer, wie die aus dem Tutorial, sonder ich lasse mir einfach zum Interrupt alle Informationen aus dem CPU-State ausgeben. Außerdem wird die CPU angehalten (habs auch schon ohne probiert -> Keine Änderung).

Ich kann über int alle Möglichen Interrupts erzeugen, aber ich möchte die, die direkt von der Hardware (z.B. Tastatur) in mein Programm bekommen.

Was evtl auch noch hilfreich ist:
Wenn ich im "main"-Programm kein Interrupt werfe (Also nur GDT und IDT initialisiere), gibt das Programm direkt beim Start auch schon einen Interrupt 32 aus.
Hier mal die Ausgabe:

Exception 32, Kernel angehalten!
eax: 524424
ebx: 184288
ecx: 524424
edx: 1109504
esi: 184643
edi: 184648
ebp: 425644
intr: 32
error: 0
eip: 1048598
cs: 8
eflags: 518
esp: 0
ss: 10

Edit:
Meine handle_interrupt sieht jetzt folgendermaßen aus:
void handle_interrupt(struct cpu_state* cpu) {
    if (cpu->intr <= 0x1f) {
kprintf("Exception %d, Prozessor angehalten!\n",cpu->intr);
        while(1) {
            asm volatile("cli; hlt");
        }
    } else if (cpu->intr >= 0x20 && cpu->intr <= 0x2f) {
        kprintf("Interrupt %d\n",cpu->intr);
if (cpu->intr >= 0x28) {
            outb(0xa0, 0x20);
        }
        outb(0x20, 0x20);
    } else {
        kprintf("Unbekannter Interrupt\n");
        while(1) {
            asm volatile("cli; hlt");
        }
    }
}

Ich werfe in meinem Hauptprogramm keinen Interrupt. Jetzt kommt in einer Endlosschleife in Interrupt 32 o.Ô
« Letzte Änderung: 28. November 2010, 08:41 von matt1491 »

Programm Noob

  • Gast
Gespeichert
« Antwort #4 am: 28. November 2010, 09:18 »
Moin

Hast du die Tastatur eingeschaltet? soweit ich weiß gibt es vorher auch keine IRQ's.

Dann würde ich das zum testen erstmal so machen
void handle_interrupt(struct cpu_state* cpu) {
    if (cpu->intr <= 0x1f) {
kprintf("Exception %d, Prozessor angehalten!\n",cpu->intr);
        while(1) {
            asm volatile("cli; hlt");
        }
    } else if (cpu->intr >= 0x20 && cpu->intr <= 0x2f) {
        kprintf("IRQ %d\n",cpu->intr - 0x20);
if (cpu->intr >= 0x28) {
            outb(0xa0, 0x20);
        }
        outb(0x20, 0x20);
    } else {
        kprintf("Unbekannter Interrupt %d\n", cpu->intr);
        while(1) {
            asm volatile("cli; hlt");
        }
    }
}

Also gib egal was da für ein Interrupt/IRQ/Exception kommt alles aus. und bei den IQ's empfiehlt sich 0x20 abzuziehen, damit IRQ 0 auch als IRQ 0 angezeigt wird. die Funktion, so wie ich sie jetzt gepostet hab, kannst du einfach an die stelle der alten einfügen. die Änderungen habe ich schon drinnen.

PNoob

matt1491

  • Beiträge: 4
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 28. November 2010, 12:50 »
Also eingeschaltet habe ich noch nix.

Ich bin aber jetzt (vom Verständnis her) so weit, dass ich weiß, dass ich was auf 0x60 senden muss.
Nur was muss ich da senden?

Also wenn ich auf 0xFF auf 0x60 sende (also einen Reset der Tastatur auslöse), antwortet die Tastatur mit 0xFA (Acknowledge) auf 0x60. Scheint also schonmal soweit zu funktionieren.

--------
Edit: Hab gerade gelesen, dass die Tastatur beim Reset die LEDs an und abschaltet. Dies tut mein (PS/2) Tastatur NICHT. Bedeutet das, dass es nicht funktioniert?
--------

Die Werte habe ich von http://www.marjorie.de/ps2/ps2_keyboard.htm

Mein nächster Schritt war jetzt eine Funktion handle_keyboard aufzurufen, sobald ein Interrupt auf 0x21 (IRQ 1) gesendet wird. In dieser Funktion lese ich, was auf 0x60 anliegt. Ich dachte eigentlich, dass da jetzt der Code der gedrückten Taste drinsteht (bzw. irgendwas, wie ich da dann hinkomme).

Irgend ein Schritt fehlt mir noch und ich komm einfach nicht drauf.
« Letzte Änderung: 28. November 2010, 12:58 von matt1491 »

Programm Noob

  • Gast
Gespeichert
« Antwort #6 am: 28. November 2010, 15:51 »
im Wiki steht ein Code, den kannst du fast einfach so verwenden.
Teste den mal. und gucke, was der anders macht als du

PNoob

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 28. November 2010, 16:42 »
Int 32 wird dein IRQ0 sein also der Timer. Generell wenn ein IRQ ausgelöst wurde musst du ein EOI (End Of Interrupt) an den PIC senden damit er neu IRQs durch stellt.

Edit: Oops. Ich sehe da gerade was von out(0x20,0x20). Das ist das EOI signal, oder?

Edit2: Bekommst du jetzt eigentlich schon deine IRQ1s?
« Letzte Änderung: 28. November 2010, 16:52 von MNemo »
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 28. November 2010, 16:49 »
Ja, das ist der EOI. Sonst würde er nur einen einzigen IRQ 0 bekommen. ;)

matt1491, deine Erklärung sieht eigentlich richtig aus. Was liest du denn unerwartetes von Port 0x60?
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

matt1491

  • Beiträge: 4
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 28. November 2010, 17:44 »
So jetz gehts endlich.

Die Lösung:
Das EOI-Signal wurde nicht am Ende meiner keyboard_handler-Routine aufgerufen. Bin danach einfach aus dem interrupt_handler herausgesprungen.

Jetzt bekomme ich alle Interrupts und meine Abfrage der Tastatur funktioniert auch. Jetzt mach ich mal an die Keycode Tabelle.

Danke an alle, die mir geholfen haben. Echt top Forum ;)

 

Einloggen