Autor Thema: Ebenfalls Interrupt-Problem.  (Gelesen 5322 mal)

WhiteDragon

  • Beiträge: 124
    • Profil anzeigen
Gespeichert
« am: 19. August 2005, 22:21 »
Hallo zusammen,

ich habe auch ein kleines Interrupt-Problem: Wenn ich unten stehenden Code ausführe (als Kernel, egal von welcher Startadresse aus) meldet er mir eine Exception 16, aber das war's dann - sowohl innerhalb von Bochs als auch beim "echten" Booten von Diskette.

Würde mich ja erstmal nicht stören, aber warum erhalte ich keine weiteren Exceptions? Es bleibt immer bei der einzigen ersten!

Wäre gut, wenn mir jemand helfen könnte oder aber wenigstens bestätigen würde, dass mein Code soweit in Ordnung ist (oder auch nicht)...

Danke!


use16

        ; A20-Line enablen für Speicherzugriff >1MB.
        call    EnableA20Gate

        ; Interrupts disablen.
        cli

        ; Hardware-Interrupts über PIC nach 20h.27h und 28h..2fh umbiegen.
        mov     al, 11h         ; ICW1.
        out     20h, al
        out     0a0h, al
        mov     al, 20          ; ICW2.
        out     21h, al
        mov     al, 28h
        out     0a1h, al
        mov     al, 4           ; ICW3.
        out     21h, al
        mov     al, 2
        out     0a1h, al
        mov     al, 1           ; ICW4.
        out     21h, al
        out     0a1h, al

        ; IDT laden.
        mov     ecx, IDT_TR
        lidt    [ecx]

        ; GDT laden.
        mov     ecx, GDT_TR
        lgdt    [ecx]

        ; In Protected Mode wechseln.
        mov     ecx, cr0
        or      cl, 01
        mov     cr0, ecx

.pm_far_jmp:

        db 0eah                         ; FAR-JMP-Befehl.
        dw .pm_1                        ; Offset im Zielsegment. Ist immer noch 0 - welch ein Glück!
        dw GDT_Kernel_Code - GDT_BEGIN  ; Deskriptor innerhalb der GDT.

; Im Protected Mode - daher use32!

use32

.pm_1:

        mov     ax, GDT_Kernel_Data - GDT_BEGIN
        mov     ds, ax                  ; DS mit Deskriptor laden.
        mov     es, ax                  ; ES mit Deskriptor laden.
        mov     fs, ax                  ; FS mit Deskriptor laden.
        mov     gs, ax                  ; GS mit Deskriptor laden.

        ; Stack liegt erstmal auch im normalen Datensegment, aber noch an gleicher Stelle.
        mov     ss, ax
        mov     esp, 9ffffh

        ; Bescheid geben, dass wir im Kernel sind.
        mov     si, msgInside
        call    WriteMessage

        ; Interrupts wieder frei geben.
        sti

.STOP1: jmp     .STOP1


Die Interrupt-Routinen für die Exceptions sehen bislang alle gleich aus (für "interrupt_nummer" einfach einen Wert 0 bis 31 angebend):


        sti
        pusha
        mov     eax, interrupt_nummer
        push    ds
        push    es
        push    fs
        push    gs

        mov     esi, msgException
        call    WriteMessage

        pop     gs
        pop     fs
        pop     es
        pop     ds
        popa
        cli
        iret

SSJ7Gohan

  • Beiträge: 398
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 19. August 2005, 23:01 »
Hast du für IRQ0 einen Handler?
Der IRQ0 wird 18,5 mal in der Sekunde aufgerufen, falls er nicht maskiert ist und keinen Handler hat sollte es zu einer General Protection Exception kommen, falls ein falsches Segment angegeben ist in der IDT (was der Fall sein sollte, wenn du keinen Handler hast).

WhiteDragon

  • Beiträge: 124
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 19. August 2005, 23:14 »
Hi,

danke für die Antwort! Ja, ich habe für alle IRQs 0 bis 47 die obige Routine als Handler (halt der erste Versuch). Aber IRQ 0 wird ja überhaupt nicht aufgerufen, sondern immer nur einmalig IRQ 16 und danach gar nichts mehr.

Die IDT ist auch für alle Interrupts bisher gleich aufgebaut:


IDT_??: dw IRQ_??
        dw GDT_Code32
        db 0
        db 10001110b
        dw 0


Jeweils an ?? die zweistellige IRQ-Nummer.

Da mein Kernel bei 0x0600 beginnt und die IDT Teil davon ist, müsste auch der Offset korrekt sein so. Ist er ja auch, sonst könnte ich die Ausgabe von Interrupt 16 nicht sehen.

Hast du noch eine andere Idee? Brauchst du noch mehr Infos/Code? Was genau?

Gruß!

WhiteDragon

  • Beiträge: 124
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 19. August 2005, 23:34 »
Hi,

noch eine Kuriosität, weil ich gerade am "Ausprobieren" bin:

Wenn ich unten stehenden Code als Interrupt-Handler für alle Interrupts verwende, kriege ich immer wieder Interrupt 16, aber seltsamer Weise nie Interrupt 0...

Ich verstehe die Welt (die PCs) irgendwie nicht...

Wäre cool, wenn noch jemand eine Idee hätte!

Gruß!


        sti
        pusha
        mov     eax, ??

        push    ds
        push    es
        push    fs
        push    gs

        mov     esi, msgException
        call    WriteMessage

        mov     al, 20h
        out     0a0h, al
        out     20h, al

        pop     gs
        pop     fs
        pop     es
        pop     ds
        popa
        cli
        iret

SSJ7Gohan

  • Beiträge: 398
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 19. August 2005, 23:44 »
Das EOI Signal musst du nur bei IRQs an den PIC senden, bei allen anderen Interrupts, also auch den Exceptions ist das nicht nötig, da sie ja nicht von der Hardware kommen. Ausserdem musst du das EOI Signal an den 2. Pic (out 0a0h, al) nur bei den IRQs 9-15 schicken. Das STI/CLI im Interrupthandler ist auch überflüssig, bei einem Interrupt Gate werden Interrupts automatisch deaktiviert und beim IRET wieder aktiviert, bei Trapgates dürfen auch wärend des Handlers Interupts auftreten. Trotzdem sollte eigentlich keine Exception ausgelöst werden.

Woher weißt du überhaupt was für ein Interrupt ausgelöst wird? WriteMessage gibt ja offensichtlich nur einen String und nicht die Nummer aus, oder?^^

WhiteDragon

  • Beiträge: 124
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 19. August 2005, 23:51 »
Das mit dem EOI-Signal war mir klar, das war halt nur so eine Spielerei, deren Auswirkungen ich nicht verstehe - daher auch als Kuriosität bezeichnet.

Dass CLI/STI nicht notwendig sind ist mir neu - aber danke für den Hinweis!

Die angegebenen Routine habe ich zusammengeschustert. Es ist wirklich Interrupt 16, ich fülle in jeder IRQ??-Routine eigens einen Teil der Variable msgException, die echten Routinen sehen wie folgt aus (wollte ich nur nicht so angeben, wegen der Verwirrung und der Menge Code):


IRQ_00: sti
        pusha
        mov     eax, 0
        mov     [msgException_Nr], word " 0"
        jmp     default_Exception_Routine
IRQ_01: sti
        pusha
        mov     eax, 1
        mov     [msgException_Nr], word " 1"
        jmp     default_Exception_Routine

...und so weiter...

IRQ_30: sti
        pusha
        mov     eax, 30
        mov     [msgException_Nr], word "30"
        jmp     default_Exception_Routine
IRQ_31: sti
        pusha
        mov     eax, 31
        mov     [msgException_Nr], word "31"
        jmp     default_Exception_Routine
IRQ_32: sti
        pusha
        mov     eax, 32
        jmp     default_HardwareInterrupt_Routine
IRQ_33: sti
        pusha
        mov     eax, 33
        jmp     default_HardwareInterrupt_Routine

...und so weiter...

IRQ_46: sti
        pusha
        mov     eax, 46
        jmp     default_HardwareInterrupt_Routine
IRQ_47: sti
        pusha
        mov     eax, 47
        jmp     default_HardwareInterrupt_Routine

; --------------------------------------------------------------
; Allgemeine Interrupt-Routine, solange keine andere für einen
; bestimmten Interrupt definiert wurde.
; --------------------------------------------------------------
default_Exception_Routine:
        push    ds
        push    es
        push    fs
        push    gs

        mov     esi, msgException
        call    WriteMessage

        pop     gs
        pop     fs
        pop     es
        pop     ds
        popa
        cli
        iret

; --------------------------------------------------------------
; Allgemeine Interrupt-Routine, solange keine andere für einen
; bestimmten Interrupt definiert wurde.
; --------------------------------------------------------------
default_HardwareInterrupt_Routine:
        push    ds
        push    es
        push    fs
        push    gs

        mov     esi, msgHarewareInterrupt
        call    WriteMessage

        ; Hardware-Interrupts wieder zulassen.
        mov     al, 20h
        out     0a0h, al
        out     20h, al

        pop     gs
        pop     fs
        pop     es
        pop     ds
        popa
        cli
        iret

msgException:            db "Exception: "
msgException_Nr:         db "  ", 13, 10, 0
msgHarewareInterrupt:    db "Hardware-Interrupt: "
msgHarewareInterrupt_Nr: db "  ", 13, 10, 0


Vielleicht fällt dir ja daran etwas auf...

WhiteDragon

  • Beiträge: 124
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 20. August 2005, 09:14 »
Guten Morgen zusammen,

eine Nacht drüber schlafen und nochmal genauer drauf schauen hat die Lösung gebracht:

Tipp-Fehler!

Beim ICW3 habe ich die Hex-Angabe vergessen, so wurde aus 20h dann 20 und das wird vom PIC wie 16 interpretiert...

Danke für eure Hilfen und Bemühungen!

Gruß!

 

Einloggen