Autor Thema: IDT und PIC  (Gelesen 6265 mal)

bongo

  • Beiträge: 6
    • Profil anzeigen
Gespeichert
« am: 02. August 2008, 15:35 »
Hallo, Leute euer Board gefällt, mir allerdings ist leider nicht mehr viel los. Dennoch, villeicht kann mir ja wer weiterhelfen.

Ich möchte momentan mein Keyboard zum laufen bringen. Dazu muss ich im Protected Mode ja, den PIC neuprogrammieren, sowie einen IDT aufsetzen, auf den der PIC dann zugreift.

Fürs PIC programmieren hab ich bereits ein super Tutorial auf TeeJays Website gefunden, dass ich nur empfehlen kann, allerdings fehlen mir noch ein paar Infos zur IDT. Hier mein IDT Code:

idt:

idt01:
dw IRQ_00
                dw 08h
                db 0
                db 10001110b
                dw 0

idt02:
dw IRQ_01
                dw 08h
                db 0
                db 10001110b
                dw 0


idt_end:               


idt_desc:                     
        dw idt_end - idt - 1 
        dd idt

Zum laden der IDT verwende ich:

lidt [idt_desc]
Ein Test IRQ sieht momentan so aus:

IRQ_00:

mov byte [ds:0B8140h], 'I'
iret

Das wars schon, hoffe auf Antworten

bongo

P.S.: Der Code funktioniert übrigens wenn man Int 00h aufruft kommt eine 0 an die vorgegebene Position.
« Letzte Änderung: 02. August 2008, 17:55 von bongo »

Korona

  • Beiträge: 94
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 02. August 2008, 17:35 »
dw IRQ_00
                dw 08h
                db 0
                db 10001110b
                dw 0
Ich nehme an, das du in diesen Eintrag zu Laufzeit die richtige Offsetaddresse einfügst? So wie er in diesem Codeabschnitt definiert ist, ist der Eintrag noch nicht korrekt.

Zitat
Muss ich, damit ich die ersten Software-Interrupts habe 36 dieser Einträge erstellen?
Diese Frage verstehe ich nicht ganz, wenn dein Interrupt per "int 0" aufgerufen wird funktioniert der Handler doch schon. Du brauchst nur so viele IDT Einträge, wie du Interrupts hast, es ist aber sinnvoll zumindest die ersten 32 Einträge zu füllen, dort befinden sich Exceptionhandler. Meistens erstellt man einfach eine IDT mit allen 256 Einträgen - so kann man sie später einfach erweitern bzw. auf einen Default-Handler verweisen lassen und die paar Bytes die verschwendet werden sind auf heutigen PCs wohl vollkommen egal.

Eine Liste der Exceptions findest du in den Intelmanuals. Falls eine Exception auftritt empfiehlt es sich normalerweise das laufende Programm zu beenden, falls die Exception nicht behoben werden kann. Manche Exceptions lassen sich beheben, es ist zum Beispiel möglich (wenn man Paging implementiert hat) Pages aus dem RAM auf die Festplatte zu schreiben (um physischen Speicher zu sparen). Die jeweilige Page markiert man dann als nicht-present. So wird beim Zugriff auf die Page eine Exception (Pagefault) ausgelöst und der Kernel kann die Page zurück in den RAM laden und das Programm einfach weiter laufen lassen. Zunächst kannst du bei Exceptions einfach eine Fehlermeldung anzeigen und abbrechen. Solange du kein Multitasking hast kannst du mit ihnen nicht sehr viel Sinnvolles anfangen. Einige Exceptions schreiben außerdem einen Fehlercode auf den Stack, der nährere Informationen zu der Exception gibt.

Für die übrigen Interrupts gibt es keinen Standard, du kannst sie für beliebige Funktionen verwenden. Unter Linux laufen z.B. alle Kernelaufrufe über den Interrupt 0x81. Die anderen Interrupts werden von Linux nicht benutzt. (Evt. gibt es Treiber die auch andere nutzen, alle normalen Anwendungen nutzen nur 0x81)

bongo

  • Beiträge: 6
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 02. August 2008, 17:59 »
Zitat
Ich nehme an, das du in diesen Eintrag zu Laufzeit die richtige Offsetaddresse einfügst? So wie er in diesem Codeabschnitt definiert ist, ist der Eintrag noch nicht korrekt.

Nein, eigentlich verändere ich daran nichts mehr, was ist denn falsch? Funktionieren tut es auf jedenfall. Wenn ich in ds irgendeinen ungültigen Wert reinschreibe bekomm ich einen General Protecten Fault angezeigt.

Ok, aber ich hab bereits desöfteren gelsen *von Intel reserviert*, was passiert wenn ich den Eintrag einfach mit einem Default überschreibe?

Gibts eine Möglichkeit, so eine Eintragsstruktur von NASM generieren zu lassen (ähnlich wie das aufüllen auf 510 Byte im Bootloader), denn alle Einträge per Hand anzulegen, dauert wohl trotzdem eine Weile und ist ziemlich lang.

Korona

  • Beiträge: 94
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 02. August 2008, 19:01 »
Von Intel reserviert heißt bei den ISRs lediglich,  dass dieser ISR von späteren Prozessorgenerationen als Exception benutzt werden könnte und er daher nicht für deine Softwareinterrupts benutzt werden sollte.

Zum Generieren der IDT kannst du dir einfach das NASM Manual ansehen, besonders diese Abschnitte:
http://alien.dowling.edu/~rohit/nasmdoc4.html#section-4.5
bzw.
http://alien.dowling.edu/~rohit/nasmdoc4.html#section-4.3

bongo

  • Beiträge: 6
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 02. August 2008, 19:43 »
Ok, herrzlichen Dank!

Du sagtest erst noch etwas von Veränderung der IDT Einträge wärend der Laufzeit, was meintest du damit?

Korona

  • Beiträge: 94
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 02. August 2008, 23:38 »
Der Descriptor ist so wie du ihn da stehen hast nicht korrekt: Das Offset steht in den ersten zwei Bytes (dort stehen die niedrigeren  16 Bits des Offsets) sowie in den letzten zwei Bytes (dort stehen die höheren 16 Bits des Offsets). Dein Code trägt nur die unteren 16 Bits ein. Da NASM und andere Assembler keine Bitwise-Operationen auf Labels zulassen kannst du das korrekte Offset nicht einfach so eintragen:

dw IRQ_00 & 0xFFFF
dw 08h
db 0
db 10001110b
dw IRQ_00 >> 16

Die einfachste Lösung dafür ist, die beiden Offsetfelder zunächst freizulassen und vor dem Laden der IDT auszufüllen, etwa so:
; aufruf mit eax = interrupt nummer und edx = handleraddresse
setzeIdtHandler:
   mov [idt + eax * 8], dx
   shr edx, 16
   mov [idt + eax * 8 + 6], dx
   ret

bongo

  • Beiträge: 6
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 03. August 2008, 09:57 »
Ok, muss ich mir genauer anschauen, aber wieso funktionierts dann trotzdem? Sowohl der Einstieg in den Interrupt als auch das korrekte verlassen?

Danke dennoch für die Antworten!

EDIT:

So, hab das jetzt noch so eingebaut, wie du gesagt hast. Funktioniert eigentlich alles. Meine eigenen Interrupts hauen ohne Probleme hin, und nachdem ich alle IRQs bis auf den Keyboard IRQ gemaskt habe kann ich auch Interrupts von der Tastertur empfangen. Dann heißts jetzt wohl Keyboard-Treiber schreiben ;-)
« Letzte Änderung: 03. August 2008, 13:33 von bongo »

 

Einloggen