|
zurück zur Homepage
Tutorial zum 80386-Nachweis
An dieser Stelle ein kleines Tutorial zur Erkennung eines 80386-Prozessors (oder höher). Sollten mir Fehler unterlaufen sein, so übernehme ich keinerlei Haftung für durch diese aufgekommene Schäden. Außerdem bin ich dankbar für jeden Hinweis, der mir die Möglichkeit gibt, dieses Tutorial von Fehlern zu befreien oder es zu verbessern. Auch nehme ich Kritik und Lob hierzu gerne entgegen. Man kann mit mir über whitedragon@chris-soft.de in Verbindung treten und möge nicht verärgert sein, falls ich nicht sofort antworte. Eine Antwort erhalten Sie auf jeden Fall!
Hintergrund: Wer sich heute daran setzt, ein Betriebssystem zu entwickeln, kommt am Thema Protected Mode nicht drum herum. Ein Betriebssystem ohne diesen ist nicht viel mehr als ein Standalone-Programm, das bootfähig ist, obwohl ich niemandem auf die Füße treten möchte, der so etwas schreibt: Allein dies ist schon eine reife Leistung, wenn man es auf einen lauffähigen Stand gebracht hat! Doch wer ein "richtiges" Betriebssystem schreiben möchte, der sollte sich mit dem Protected Mode befassen. Nun ist es aber so, dass dieser Betriebsmodus erst seit dem Prozessor 80286 existiert und erst mit Einführung des 80386 praktikabel zu handhaben ist. Auf Grund dieser Tatsache nehmen die meisten Entwickler einen 80386 als Mindestanforderung für ihr Betriebssystem, was in der heutigen Zeit kein Problem mehr darstellt. Dennoch bleibt ein gewisses "Restrisiko", dass doch mal jemand hingeht und einen Uralt-PC aus seinem Keller holt, um das neu erworbene oder aus dem Internet geladene Betriebssystem darauf auszuprobieren. Für diese Fälle sollte man nicht riskieren, dass es beim Versuch in den Protected Mode zu schalten abstürzt - vielmehr sollte man den User freundlichst darauf aufmerksam machen, dass seine Kiste nicht ausreichend ist. Um dies tun zu können, muss man jedoch erst einmal wissen, ob es auch wirklich kein 80386 ist, auf dem das System gerade gebootet wird. Wie so etwas funktioniert, möchte ich im Folgenden erläutern.
Der Test auf einen 80386 oder höher wird in zwei Einzel-Tests untergliedert. Zuerst prüfen wir, ob wir mindestens einen 80286 vor uns haben, danach erfolgt die Prüfung auf einen 80386. Warum wir uns den ersten Schritt nicht sparen können, werde ich zum Schluss ebenfalls kurz erläutern.
Zunächst einmal gehen wir davon aus, einen 8086/8088-Prozessor vor uns zu haben (das können wir beruhigt tun!). In dessen Microcode steckt ein kleiner Fehler, der erst ab dem 80286 ausgemerzt wurde, also im 80186/80188 ebenfalls noch enthalten ist. Dieser Fehler besteht darin, dass beim Befehl
push sp
der Stackpointer zuerst dekrementiert und anschließend auf den Stack gelegt wird. Wenn man also die Befehlsfolge
push sp
pop ax
ausführt, so haben im Anschluss daran sp und ax verschiedene Werte. Man braucht sie also nur noch vergleichen und wenn sie ungleich sind, haben wir keinen 80286 vor uns und können dem User mitteilen, das sein PC nicht unseren Mindestanforderungen entspricht.
Nun gehen wir aber davon aus, dass wir mindestens einen 80286 haben und wollen prüfen, ob es sich vielleicht sogar um einen 80386 handelt. Für diesen Fall nutzen wir den Interrupt mit der Nummer 6. Dieser wird vom Prozessor immer dann aufgerufen, wenn er auf einen ungültigen OP-Code trifft (mit anderen Worten: auf einen Maschinenbefehl, den es aus seiner Sicht gar nicht gibt). Wenn wir uns also einen Befehl aussuchen, der erst mit dem 80386 eingeführt wurde, so wissen wir nach seiner erfolgreichen Ausführung, dass wir einen 80386 vor uns und unser Ziel somit erreicht haben. Falls dem aber nicht so ist, wird der Interrupt 6 ausgelöst. Daher müssen wir zunächst dessen Interrupt-Vektor in der Interrupt-Vektor-Tabelle am Beginn des Speichers auf unsere eigene Routine umbiegen, denn sonst kriegen wir nicht mit, dass der Fehler überhaupt aufgetreten ist (zumindest kriegt unser Programm es sonst nicht mit).
Das Verbiegen des Interrupt-Vektors auf unsere eigene Routine ist sehr simpel. Da in der Interrupt-Vektor-Tabelle für jeden Interrupt 4 Bytes reserviert sind und sie ab Speicheradresse 0 steht, müssen wir also unsere Routine in den Adressen 24 bis 27 einrichten:
mov [24], word fehlerroutine
mov [26], cs
Jetzt können wir beruhigt unseren 80386-Befehl ausführen. Ich verwende gerne cwde, aber der ist so gut wie die meisten anderen auch. Man kann allerdings nicht jeden nehmen, da manche Befehle im Real Mode ungültig sind und erst innerhalb des Protected Mode gültig werden.
Wird jetzt also der Befehl hinter dem cwde ausgeführt, so wissen wir: Das Programm läuft mindestens auf einem 80386!
Die komplette Prüfung könnte also beispielsweise wie folgt aussehen:
; Zuerst auf 80286 testen.
push sp
pop ax
cmp ax, sp
jne ShowNo80386MessageAndStop
; Dann auf 80386 testen.
mov word [18h], ShowNo80386MessageAndStop
mov [1ah], cs
cwde
; Alles okay, wir haben einen 386!
In diesem Code-Schnipsel werden also die beiden von mir oben beschriebenen Tests durchgeführt. Wenn sich bei einem davon heraus stellt, dass es sich nicht um mindestens einen 80386 handelt, verzweigt das Programm in eine Routine ShowNo80386MessageAndStop. Ich verwende diesen Code in meinem Bootsektor und wenn der erkannte Prozessor zu klein ist, wird einfach ein kurzer Hinweis ausgegeben und der Bootsektor bleibt in einer Endlosschleife stehen. Wenn man aber nach der Erkennung eines zu kleinen Prozessors mit dem Programm fortfahren möchte, so sollte man sich für beide Tests verschiedene Fehlerroutinen schreiben, da die Routine im ersten Fall über den jne-Sprung aufgerufen wird und im zweiten Fall über einen Interrupt.
Nun aber noch die Klärung der oben angekündigten Frage, warum wir nicht direkt die Prüfung mittels des illegalen OP-Codes verwendet haben: Der Aufruf des Interrupts 6 bei ungültigem OP-Code wurde erst mit dem 80186 eingeführt. Hätten wir also auf einem 8086/8088 so etwas ausprobiert, hätte der Computer sonstwie reagiert, mit Sicherheit aber nicht mit dem Aufruf unserer Fehlerroutine; so einfach ist das! ;-)
Noch ein Hinweis zum Schluss: Die Prüfung über den Interrupt 6 funktioniert natürlich auch bei Folge-Prozessoren. Man kann sie also auch verwenden, wenn man prüfen möchte, ob das Programm auf einem 80486, Pentium usw. läuft. Auch kann man diese Routinen generell zur Ermittlung von Prozessortypen verwenden, dann sollte man allerdings noch eine Unterscheidung zwischen 8086/8088 und 80186/80188 einbauen, die ich hier nicht erläutert habe.
Viel Erfolg beim Testen und Entwickeln!
(w) by Christian Packenius, 13.08.2005
zurück zur Homepage
|