Int 15h, Fkt. 83h Fehler in Award/Phoenix BIOS?

Diskussion zum Thema Programmierung unter DOS (Intel x86)
Antworten
wobo
DOS-Guru
Beiträge: 614
Registriert: So 17. Okt 2010, 14:40

Int 15h, Fkt. 83h Fehler in Award/Phoenix BIOS?

Beitrag von wobo »

Funktion 83h des Bios-Interrupts 15h setzt Bit 7 eines vom Aufrufer übergebenen Flags nach einer bestimmten, in Mikrosekunden zu bemessenden Zeit. ES:[BX] zeigt dabei auf das Flag (FAR-Zeiger), CX und DX enthalten Hi- und Lo-Word der zu verstreichenden Zeit.

Nachfolgendes Pascal - Programm ruft in einer Schleife ständig den Int 15h, Fkt. 83h auf und lässt das Flag alle 50 Millisekunden setzen. Sobald die 50 Millisekunden vorbei sind, sollte das Flag gesetzt sein und Int 15h, 83h wird erneut aufgerufen, solange bis eine Taste zum Programmabbruch betätigt wird.

Code: Alles auswählen

uses dos, crt;
var  r : registers;
     timeflag : byte;
     ticks : longint;
begin
  ClrScr;
  ticks := 0;
  timeflag := 1;
  Repeat
    inc( ticks );
    WriteLn( 'ticks: ', ticks);
    GotoXY( 1, whereY-1);
    Repeat Until timeflag<>0;
    timeflag := 0;
    r.ax := $8300;
    r.es := Seg(timeflag);
    r.bx := Ofs(timeflag);
    r.cx := 0;
    r.dx := 50000;
    intr( $15, r );
  Until KeyPressed;
  While KeyPressed Do ReadKey;
end.
Das Programm läuft auf allen mir zur Verfügung stehenden PCs und unter DosBOX v0.73 - auch stundenlang - absolut fehlerfrei.


Kombiniere ich nun den Aufruf von Int15h, Fkt. 83h mit dem Abfragen des Vertical Retraces der VGA hängt sich der PC unter den beiden oben genannten BIOSen auf.

Hier das Problemprogramm:

Code: Alles auswählen

uses dos, crt;
var  r : registers;
     timeflag : byte;
     ticks : longint;
begin
  ClrScr;
  ticks := 0;
  timeflag := 1;
  Repeat
    inc( ticks );
    WriteLn( 'ticks: ', ticks);
    GotoXY( 1, whereY-1);
    Repeat Until timeflag<>0;            { <-- PC bleibt hier hängen! }
    Repeat Until (Port[$3da] and 8) = 8; { <-- neu: Vertical Retrace }
    timeflag := 0;
    r.ax := $8300;
    r.es := Seg(timeflag);
    r.bx := Ofs(timeflag);
    r.cx := 0;
    r.dx := 50000;
    intr( $15, r );
  Until KeyPressed;
  While KeyPressed Do ReadKey;
end.
Wie gesagt, das Problemprogramm funktioniert - wiederum auch bei stundenlangen Testläufen - auf einem 286-12 (OAK VGA), 386sx16 (wd90c11), 386dx40 (et4000), 486sx25 (et4000), 486dx40vl (CL GD5426), AMD Duron 750 (ATI RAGE AGP 2x) und DosBox 0.73 jedenfalls fehlerfrei.

Auf einem 486dx4-100 (egal, welche VGA) mit AWARD BIOS 4.50G und auf einem p75 mit PhoenixBIOS Pentium 1.03 dagegen bleibt der PC früher oder später in der Schleife hängen, die das Flag abfragt. Meist erreicht die Zählervariable ticks
einen Wert zwischen 200-2000 bis der PC in der Repeat Until timeflag<>0 -Schleife festhängt.

Das Flag wird ab diesem Zeitpunkt vom Int15h nicht mehr gesetzt. Dies gilt auch, wenn man das Programm neu startet. Auch dann funktioniert Int15h, Fkt. 83h nicht mehr: das Flag wird einfach nicht mehr gesetzt. Dies gilt solange, bis ich ein Reset ausführe (Warmstart mittels Ctrl-Alt-Del reicht aus).


Ich kann mir den Fehler einfach nicht erklären. Einen Programmierfehler schließe ich eigentlich aus (oder?).

Ich habe das Ganze übrigens in allen mir möglichen Varianten programmiert, d.h. das Flag auf den Heap gelegt oder das Ganze in BASM ohne CRT und ohne DOS - Unit programmiert. Das Resultat war immer dasselbe: Sobald der Vertical-Retrace
abgefragt wird, hängt der PC -früher oder später - auf den beiden BIOSen (und nur bei diesen PCs) in der Flag-Abfrage-Schleife.

Wie gesagt: ich kann mir den Fehler auch im Ansatz nicht erklären. Was hat denn der Vertical Retrace mit der RTC zu tun?

Stutzig hat es mich allerdings schon gemacht, dass zwei verschiedene PCs mit verschiedenen BIOSen und verschiedenen Bus-System (vlb/pci) denselben Fehler aufweisen.
Brueggi

Re: Int 15h, Fkt. 83h Fehler in Award/Phoenix BIOS?

Beitrag von Brueggi »

Was passiert denn, wenn du, sobald das Timerflag auf 1 ist, also kurz bevor du den Timer erneut startest, diesen erstmal stoppst? Ist zwar abwegig (hab aber schon genügend solche "absurden" Sachen erlebt...), aber vielleicht bestehen manche BIOS-Version ja drauf?

Timer Stopp <= AH 83h/AL 01h
=> CF=1: Funktion nicht unterstützt
Stoppt den mit der Unterfunktion 00h gestarteten Timer

Ich such mal weiter, ob mir noch was einfällt! Viel erfolg :-)
wobo
DOS-Guru
Beiträge: 614
Registriert: So 17. Okt 2010, 14:40

Re: Int 15h, Fkt. 83h Fehler in Award/Phoenix BIOS?

Beitrag von wobo »

Brueggi hat geschrieben:Was passiert denn, wenn du, sobald das Timerflag auf 1 ist, also kurz bevor du den Timer erneut startest, diesen erstmal stoppst? Ist zwar abwegig (hab aber schon genügend solche "absurden" Sachen erlebt...), aber vielleicht bestehen manche BIOS-Version ja drauf?

Timer Stopp <= AH 83h/AL 01h
=> CF=1: Funktion nicht unterstützt
Stoppt den mit der Unterfunktion 00h gestarteten Timer

Ich such mal weiter, ob mir noch was einfällt! Viel erfolg :-)
Woher hast Du die Info, dass es auch eine Timer-Stopp-Funktion (al=01h) gibt? In PC-Intern 3.0 wird ausschließlich die einzige Funktion ax=8300h beschrieben....

Auch wenn die Idee genial ist, hat sie leider nicht geholfen hat. Die Biose unterstützen zwar die mir (bisher vollkommen unbekannte) Unterfunktion 01h, der PC hängt sich trotzdem auf (d.h. das Timeflag wird einfach nicht gesetzt). Ich habe testweise auch (einfach ins Blaue hinein) das Carry-Flag nach Aufruf der Unterfunktion 00h geprüft (Meine Doku PC-Intern 3.0 sagt, dass überhaupt keine Rückmeldung seitens des Bios erfolgt): Aber das Carry-Flag ist nie gesetzt.

Was mich, wie gesagt, so erstaunt hat, sind zwei Dinge:
1. Der Fehler tritt nur auf, wenn ich auch den Vertical Retrace teste. Tue ich das nicht, kann ich das Programm stundenlang das Timeflag setzen lassen.
2. Ist der Fehler einmal aufgetreten, geht die Funktion 8300h überhaupt nicht mehr. D.h. auch andere Programme können Funktion 8300h nicht mehr benutzen (bis zum Neustart).


Noch obskurer ist, dass ich jetzt eine Lösung gefunden habe, die ich mir noch weniger als den Fehler erklären kann:

Wenn ich nach Aufruf der Funktion 8300h die Statusregister $A, $B, $C sinnlos auslese, rennt das Ganze auch auf den beiden Problem-Biosen wieder fehlerfrei (zumindest die letzten 2 Stunden);

Code: Alles auswählen

    Repeat Until timeflag<>0;
    Repeat Until (Port[$3da] and 8) = 8;
    timeflag := 0;
    r.ax := $8300;
    r.es := Seg(timeflag);
    r.bx := Ofs(timeflag);
    r.cx := 0;
    r.dx := 21000;
    intr( $15, r );
    Port[$70] := $a;
    rtc := Port[$71];
    Port[$70] := $b;
    rtc := Port[$71];
    Port[$70] := $c;
    rtc := Port[$71];
Zwar hat die RTC vier Statusregister (A,B,C,D) es genügt aber, wenn die ersten drei ausgelesen werden. Die drei müssen es aber anscheinend sein....

Ich bleibe vorerst dabei: Datt is ´n Bios-Fehler.
freecrac
DOS-Guru
Beiträge: 861
Registriert: Mi 21. Apr 2010, 11:44
Wohnort: Hamburg Horn

Re: Int 15h, Fkt. 83h Fehler in Award/Phoenix BIOS?

Beitrag von freecrac »

wobo hat geschrieben:
Brueggi hat geschrieben:Was passiert denn, wenn du, sobald das Timerflag auf 1 ist, also kurz bevor du den Timer erneut startest, diesen erstmal stoppst? Ist zwar abwegig (hab aber schon genügend solche "absurden" Sachen erlebt...), aber vielleicht bestehen manche BIOS-Version ja drauf?

Timer Stopp <= AH 83h/AL 01h
=> CF=1: Funktion nicht unterstützt
Stoppt den mit der Unterfunktion 00h gestarteten Timer

Ich such mal weiter, ob mir noch was einfällt! Viel erfolg :-)
Woher hast Du die Info, dass es auch eine Timer-Stopp-Funktion (al=01h) gibt? In PC-Intern 3.0 wird ausschließlich die einzige Funktion ax=8300h beschrieben....
RBIL->inter61a.zip->Interrup.c

Code: Alles auswählen

--------B-1583-------------------------------
INT 15 - BIOS - SET EVENT WAIT INTERVAL (AT,PS50+)
	AH = 83h
	AL = subfunction
	    00h set interval
		CX:DX = microseconds to delay
		ES:BX -> byte whose high bit is to be set at end of interval
	    01h cancel wait interval
Return: CF set on error or function already busy
	    AH = status
		80h invalid command (PC,PCjr)
		86h function not supported (XT and later)
	CF clear if successful
Notes:	the resolution of the wait period is 977 microseconds on many systems
	  because many BIOSes use the 1/1024 second fast interrupt from the AT
	  real-time clock chip which is available on INT 70
	IBM AT 1984/1/10 BIOS ignores AL and always performs subfunction 00h
SeeAlso: AH=41h,AH=86h,INT 70,MEM 0040h:0098h,MEM 0040h:009Ch
Ich bin ebenfalls ratlos und kann es mir nicht erklären.

Dirk
Brueggi

Re: Int 15h, Fkt. 83h Fehler in Award/Phoenix BIOS?

Beitrag von Brueggi »

Hey, Wobo, hast Du lust, das Rätsel zu lösen? :-)
Vielleicht kommen wir ja drauf... :idea:

Ok, was man mal probieren könnte:
- Die Funktion 83/00 gibt ja laut den Doks im Netz folgendes zurück:
AL 00H =means fn is busy (note: only one timer can be set)
else=CMOS timer has been set
CF NC (0) no error
CY (1) error; fn is busy

Was gibt sie denn auf den Problemrechnern zurück, in dem Moment, in dem sie sich aufhängen?
- Wäre es möglich - was ich nicht glaube, das aus irgendeinen Grund der Interrupt gesperrt ist, während PORT[x] läuft, und deshalb das BIOS nicht mehr
erkennt, das der Timer abgelaufen ist (nur das manuelle Lesen der Statusregister bewirkt vielleicht irgendetwas?).

Gruß,

Brueggi
wobo
DOS-Guru
Beiträge: 614
Registriert: So 17. Okt 2010, 14:40

Re: Int 15h, Fkt. 83h Fehler in Award/Phoenix BIOS?

Beitrag von wobo »

Brueggi hat geschrieben:Hey, Wobo, hast Du lust, das Rätsel zu lösen? :-)
Vielleicht kommen wir ja drauf... :idea:
Naja, langsam habe ich keine Lust mehr drauf ;-): Schließlich nervt mich dieses Problem seit einer Woche und ich habe meinen 64k-großen Source peu a peu auf die obigen, relevanten Zeilen reduzieren müssen, nur um dann zu merken, dass es wohl erstmalig in meinem Leben kein Programmierfehler ist...

Brueggi hat geschrieben: Ok, was man mal probieren könnte:
- Die Funktion 83/00 gibt ja laut den Doks im Netz folgendes zurück:
AL 00H =means fn is busy (note: only one timer can be set)
else=CMOS timer has been set
CF NC (0) no error
CY (1) error; fn is busy

Was gibt sie denn auf den Problemrechnern zurück, in dem Moment, in dem sie sich aufhängen?
Dasselbe wie auf den anderen Rechnern: al ist immer <>0, CF ist nie gesetzt. Das Bios sagt also auch kurz vor dem Aufhängen immer "Alles klar!"
Brueggi hat geschrieben: - Wäre es möglich - was ich nicht glaube, das aus irgendeinen Grund der Interrupt gesperrt ist, während PORT[x] läuft, und deshalb das BIOS nicht mehr
erkennt, das der Timer abgelaufen ist (nur das manuelle Lesen der Statusregister bewirkt vielleicht irgendetwas?).
Gruß,

Brueggi
Ich denke so in etwa. Mein letztes Posting muss ich übrigens korrigieren. Es langt offensichtlich, dass nur das Statusregister C gelesen wird. Zumindest in dem letzten halbstündigen Dauertest lief es insoweit problemlos. Ohne Auslesen des Statusregisters C trat das Festlaufen in der Warteschlaufe meistens schon nach ein paar Sekunden auf. Außerdem kann man die nicht funktionierende Int.15h/ Fkt. 83h wieder dadurch in Gang bringen, dass man einfach das Statusregister C ausliest.

Das dürfte auch ein bischen was erklären:
Bit 7 des Statusregisters C ist gesetzt, wenn die RTC den Interrupt $70 (IRQ8) auslösen will oder ausgelöst hat.
Bit 6 des Statusregisters C ist gesetzt, wenn die RTC den IRQ8 ausgelöst hat, weil der periodische Timer von 1024 Ticks per Second ausgelöst wurde,
Bit 5 des Statusregisters C ist gesetzt, wenn die RTC den IRQ8 ausgelöst hat, weil die Alarmzeit erreicht wurde,
Bit 4 des Statusregisters C ist gesetzt, wenn die RTC den IRQ8 ausgelöst hat, weil die Systemzeit aktualisiert wurde.
Bit 3-0 sind wohl herstellerspezifisch.


Wenn sich jetzt nach ein paar tausend Aufrufen von Int 15h, Fkt. 83h der Problem-PC aufhängt, ist Bit 7 des Statusregisters ausnahmsweise gesetzt !

Bit 7 des Statusregisters (und nur Bit 7, nicht auch Bit 6,5,4) wird aber gelöscht, wenn es ausgelesen wird.

Dies bedeutet, die RTC wollte den IRQ8 auslösen. Der BIOS-IRQ8-Handler, der zwangsläufig das Statusregister C auslesen muss und es dadurch löschen würde, wurde aber gar nicht angesprungen.

Die RTC merkt vielleicht, dass Ihr Bit 7 noch gesetzt ist und löst deswegen keinen weiteren IRQ8 aus. Wenn ich nun Statusregister C händisch auslese, lösche ich aautomatisch Bit 7 dadurch und neue IRQ8s werden generiert.


Damit dürfte eigentlich das Bios als Fehlerquelle auszuschließen sein. Vielleicht ist die RTC fehlerhaft, oder irgendein anderer Baustein auf dem Mainboard hat ´nen kleinen Fehler (IRQ-Controller?). Vielleicht ist ja auch der Port-Controller (gibt es sowas?): Der Fehler tritt ja nur auf, wenn ich den Vertical Retrace der VGA teste, also in einer Schleife massiv einen Port-Abfrage.

VGA schließe ich dabei als Fehlerquelle auch aus. Zum einen funktionieren die beiden VGAs (ET4000 isa und Cirrus Logic GD5426 vlb) in einem anderen PC tadellos, d.h. ohne dass das hier beschriebene Problem auftritt. Zweitens ist es für die Problem-PCs auch egal, ob die ET4000 oder CL drin steckt. Drittens habe ich vorsorglich auch bei den VGAs das Bit explizit gelöscht, welches nach einem Vertical Retrace den IRQ2 (der ja auf IRQ8 kaskadiert) auslösen soll (was ja meistens ohnehin nicht geht). Für das Problem ist es schnurzpiepegal, ob ich das Bit für den Vertical Retrace - IRQ nun setze oder lösche. Es tritt unabhängig davon auf.


Ich verorte das Problem daher irgendwo auf dem Mainboard.

Der einzige Zusammenhang, den ich zwischen den beiden Problem-PCs (486dx4-100 vlb und p75 pci) herstellen kann, dürfte der Herstellungszeitraum sein. D.h. vielleicht verwenden die beiden PCs irgendwelche identischen Chips. Ich habe auch schon mal die Mainboards angekuckt. Aber für mich sehen alle Chips immer gleich aus (Ich bin schon froh, wenn ich die CPU finde).

Ich habe fertig. Flasche leer.

Nachtrag:
Hier habe ich sehr viele Infos zur RTC gefunden, die mir sehr geholfen haben und so detailliert auch nicht in PC-Intern standen:

http://home.germany.net/101-145626/bonus/rtc.txt

Ich habe auch geprüft, dass IRQ2 und IRQ8 nicht maskiert sind, d.h. daran kann es auch nicht liegen.
Antworten