Problem mit eigener Interrupt Service Routine
-
Ich kriege es einfach nicht hin, einen einfachen Interrupt zu verbiegen. Dies ist mein Code, ich weiss beim besten Willen nicht, was man daran falsch machen kann! Assemblieren lässt es sich problemlos, und er springt sogar in die entsprechende Routine! Allerdings nur ein einziges Mal! Es sollte doch nun eigentlich 18.2 Mal pro Sekunde so ein "." auf den Bildschirm geschrieben werden?? Stattdessen wir lediglich ein einziges solches "." auf den Bildschirm geschrieben. Was mache ich denn falsch?
cli mov ax,09000h mov ss,ax xor sp,sp sti mov ax,0012h int 10h mov ax,0000h mov ds,ax cli mov [0020h],word Inter mov [0022h],word 07c0h sti jmp $ Inter: mov bx,0002h mov ah,0eh mov al,'.' int 10h iret
Lg Ishildur
-
Da gibt es mehrere Moeglichkeiten.
Es liegt dabei an dir, aller systematisch zu ueberpruefen und auszuschliessen.
Angenommen, dein IRQ-Handler wird tatsaechlich korrekt aufgerufen...Es koennte zu Problemen kommen, da deine Routine Register veraendert.
Es koennte sein, dass die Teletype-Funktion nicht korrekt arbeitet.
Und mit ziemlicher Sicherheit wird der IRQ-Controller irgendwann stecken bleiben, wenn du ihm am Ende deiner Routine kein Ack (20h nach Port 20h) gibst.
...Nur noch so als Tipp: Wenn du noch vor hast, zB. weiter den int 13h zu benutzen, solltest du zumindest noch in den entsprechenden Zeitintervallen von deinem Handler zum Original-Handler des BIOS springen, sonst haengt sich das Zeug evtl. auch auf.
-
Das mit dem Acknowledge an den Interruptkontroller war die Lösung
Ich habe hier 6 ausgedruckte Tutorials vor mir, wie man den Timerinterrupt 08h verbiegt, aber in keiner wird dieses Acknowledge gesendet! Ich frage mich manchmal, ob diese Leute, welche diese Tutorials schreiben, diese eigentlich selbst testen oder einfach irgendwo abschreiben und schliesslich mit eigenen Worten neu verfassen! :pWie ist das eigentlich, ich muss eben die Frequenz des Timers ändern und ich möchte nicht, dass die CMOS Uhr dadurch schneller läuft! Ich habe mir überlegt, dass ich einfach alle 18.2 Sekunden das BIOS informiere, aber wie mache ich denn dass, ich habe ja den Eintrag in der IVT mit meiner eigenen ISR überschrieben.
Wie muss ich da nun vorgehen? Folgende Gedanken habe ich mir dazu gemacht!^
Möglichkeit 1:
Ich verbiege innerhalb meiner ISR den Interrupt 08h wieder auf die Routine des BIOS und rufe diese mit int 08h auf. Allerdings geht ja das BIOS davon aus, dass dieser Interrupt vom Interruptkontroller kommt und wird ein Acknowledge senden, obwohl ich dies ja bereits getan habe. Moment... oder ich sende in diesem Fall einfach KEIN Acknowledge und lasse dies das BIOS für mich erledigen? Nun ja, die verbleibende Frage ist nun natürlich, was genau bewirkt das IRET, welches ja sicher am Ender der Standard ISR des BIOS stehen wird? Kehrt Ausführung anschliessend in meine TSR zurück oder nicht? Weil ich muss ja den Eintrag in der IVT wieder auf meine ISR zurückverbiegen, bevor ich diese verlasse...Meine Frage sich also nun darauf, was genau passiert, wenn ich aus einer ISR eine weitere ISR aufrufe? Kehrt diese anschliessend zur ersten ISR zurück, oder direkt ins Hauptprogramm?
Lg Ishildur
-
Ishildur schrieb:
Das mit dem Acknowledge an den Interruptkontroller war die Lösung
Ich habe hier 6 ausgedruckte Tutorials vor mir, wie man den Timerinterrupt 08h verbiegt, aber in keiner wird dieses Acknowledge gesendet! Ich frage mich manchmal, ob diese Leute, welche diese Tutorials schreiben, diese eigentlich selbst testen oder einfach irgendwo abschreiben und schliesslich mit eigenen Worten neu verfassen! :pEntweder das, oder du hast da irgendwas falsch verstanden... ka.
Ishildur schrieb:
Wie ist das eigentlich, ich muss eben die Frequenz des Timers ändern und ich möchte nicht, dass die CMOS Uhr dadurch schneller läuft! Ich habe mir überlegt, dass ich einfach alle 18.2 Sekunden das BIOS informiere, aber wie mache ich denn dass, ich habe ja den Eintrag in der IVT mit meiner eigenen ISR überschrieben.
Viel interessanter wuerde ich da die Frage finden: Wie stellst du es an, bei veraenderter Frequenz den BIOS-Handler immer noch in der alten Frequenz aufzurufen.
Eine naheliegende Loesung waere da natuerlich, dass du als neue Frequenz ein Vielfaches der alten waehlst, und in deiner Routine einen Zaehler laufen laesst...Ishildur schrieb:
Möglichkeit 1:[...]
Warum so umstaendlich?
Moeglichkeit 2:
Du sicherst den Eintrag des BIOS-Handlers in der IVT in irgendeine Variable, bevor du ihn ueberschreibst.
In deinem Handler tust du nun, was immer du tun wolltest. Zum Ende ueberpruefst du ggF. bei geaenderter Frequenz des PIT deinen Zaehler, oder was auch immer, und machst entweder dein IRQC-Ack und iret, oder stellst alle evtl. gepushten Register wieder her und machst einen Far-Jump ueber die aus der IVT gesicherten Variable zum BIOS-Handler. Der BIOS-Handler macht dann von sich aus sein IRQC-Ack und kehrt mit iret zum unterbrochenen Code zurueck.Ishildur schrieb:
Allerdings geht ja das BIOS davon aus, dass dieser Interrupt vom Interruptkontroller kommt und wird ein Acknowledge senden, obwohl ich dies ja bereits getan habe. Moment... oder ich sende in diesem Fall einfach KEIN Acknowledge und lasse dies das BIOS für mich erledigen?
Jup, wie gesagt... Doppelter Ack ist natuerlich zu vermeiden.
Ishildur schrieb:
Meine Frage sich also nun darauf, was genau passiert, wenn ich aus einer ISR eine weitere ISR aufrufe? Kehrt diese anschliessend zur ersten ISR zurück, oder direkt ins Hauptprogramm?
Wenn du das tun wuerdest (via int, oder ein anderer IRQ oder eine Exception kommen dir dazwischen), wuerden diese idR. in deine ISR zurueckkehren, aber nicht ins Hauptprogramm (es sei denn, du hast sie extra so geschrieben).
Ishildur schrieb:
Nun ja, die verbleibende Frage ist nun natürlich, was genau bewirkt das IRET, welches ja sicher am Ender der Standard ISR des BIOS stehen wird?
iret holt im Grunde nur den (e)ip, cs und die Flags (in der Reihenfolge) vom Stack.
-
@Nabuo T
Irgendwie kriege ich das mit dem far jump nicht gebacken! Ich meine, folgendes funktioniert einwandfrei:jmp 0000h:0000h
Aber sonst auch gar nichts, ich meine die Addressen sind ja in Variablen gespeichert, also muss ich indirekt addressieren können:
jmp [Base]:[Offset] ;invalid combination of opcode and operands jmp [[Base]:[Offset]] ;expression syntax error jmp ax:bx ;invalid combination of opcode and operands jmp [ax:bx] ;invalid segment override jmp [ds:ax] ;invalid effective address jmp ds:[VAR_ISR] ;invalid combination of opcode and operands
Wie zum Teufel lautet die korrekte Syntax??? Im Manual von NASM sowie im Internet habe ich absolut nichts gefunden!
Lg Ishildur
P.S.
Was mir nun bereits seit längerem durch den Kopf geht: Wie ist das eigentlich mit dem 80386 und dem Realmode?1. Darf man da intern die 32-Bit Register verwenden?
2. Wie gross ist denn ein Stackeintrag, ich meine, weil ich ja nun einen ESP habe, 16-Bit oder 32-Bit?
-
Ishildur schrieb:
@Nabuo T
Irgendwie kriege ich das mit dem far jump nicht gebacken![...]Wie zum Teufel lautet die korrekte Syntax??? Im Manual von NASM sowie im Internet habe ich absolut nichts gefunden!... zB. Section 3.3 bzw. B.4.130 in den NASM Docs.
Und AFAIR hatte ich irgendwie auch schon ein bissel was dazu geschrieben. Keine Ahnung, wie du auf diese abenteuerlichen Kombinationen kommst. Die indirekte Adressierung funktioniert uA. bei Jumps genau wie bei normalen Variablenzugriffen auch. Ich schlage vor, du liest dir deshalb beides (NASM-Docs und mein Geschreibsel zur Adressierung in einem deiner Threads) nochmal in Ruhe durch.Ishildur schrieb:
P.S.
Was mir nun bereits seit längerem durch den Kopf geht: Wie ist das eigentlich mit dem 80386 und dem Realmode?1. Darf man da intern die 32-Bit Register verwenden?
Was heisst "intern"?
Wie auch immer: Du kannst auch im RealMode auf die vollen 32Bit-Register zugreifen. Was du nicht kannst, ist auf Speicher ueber 1MB zugreifen. => Der Hauptunterschied bei den CPU-Modi betrifft die Speicheradressierung/Zugriff.Ishildur schrieb:
2. Wie gross ist denn ein Stackeintrag, ich meine, weil ich ja nun einen ESP habe, 16-Bit oder 32-Bit?
Was verstehst du unter einem "Stackeintrag"?
Die 32Bit x86er koennen via push/pop ein word oder dword auf den/vom Stack verfrachten - das hat erstmal gar nichts mit sp oder esp zu tun.
Im RealMode wird der Stack allerdings ohnehin immer nur mit den unteren 16Bit von esp (dh. mit sp) adressiert.
-
Ich kapiers im Moment wirklich nicht!
Ich habe zwei Variablen, von welchen die Eine die Segmentadresse und die andere die Offsetadresse beinhaltet!.bss Base resw 01h ; will be determined at runtime Offset resw 01h ; will also be determined at runtime
Ich möchte nun also enen far jump auf die Base:Offset Adresse machen, welche in jenen Variablen gespeichert ist!
Könntest du mir ein Codebeispiel geben?
Lg Ishildur
P.S.
In der Doku habe ich nochmals zu rate gezogen, doch wird da nur das funktionierende Beispiel mit 0000h:1234h gemacht...
-
Hm, dann hast du vielleicht eine andere Docu?
NASM Manual schrieb:
B.4.130 JMP: Jump
JMP imm ; E9 rw/rd [8086]
JMP SHORT imm ; EB rb [8086]
JMP imm:imm16 ; o16 EA iw iw [8086]
JMP imm:imm32 ; o32 EA id iw [386]
JMP FAR mem ; o16 FF /5 [8086]
JMP FAR mem32 ; o32 FF /5 [386]
JMP r/m16 ; o16 FF /4 [8086]
JMP r/m32 ; o32 FF /4 [386]
[...]
The JMP FAR mem forms execute a far jump by loading the destination address out of memory. The address loaded consists of 16 or 32 bits of offset (depending on the operand size), and 16 bits of segment. The operand size may be overridden using JMP WORD FAR mem or JMP DWORD FAR mem.BTW: Die Reihenfolge von Segment und Offset muss so wie hier angegeben im Speicher stehen, dh. auch in dieser Reihenfolge definiert werden. Also zuerst Offset und danach das Segment.