Ich schreibe kleines Betriebssystem - für die Praxis. Ich begann mit dem Bootloader.
Ich möchte ein kleines Befehlssystem erstellen, das im 16-Bit-Realmodus läuft (für den Moment).
Ich habe einen Bootloader erstellt, der das Laufwerk zurücksetzt und dann den Sektor nach dem Bootloader lädt.
Das Problem liegt darin, dass nach jmp
function tatsächlich nichts passiert.
Ich versuche nicht, den nächsten Sektor bei 0x7E00 zu laden (ich bin nicht ganz sicher, wie ich die Adresse mit es: bx ansprechen kann, so dass es ein Problem ist, glaube ich, dass seine Adresse: offset), gleich nach dem Bootloader.
Dies ist der Code:
%Vor%Ich habe diesen Code mit VirtualBox getestet, aber tatsächlich passiert nichts, der Lesefehler wird nicht angezeigt, ebenso wie die Nachricht, die gedruckt werden sollte.
Die primären Probleme mit diesem Code waren:
Der erste war in diesem Code:
%Vor% Die Frage möchte den Sektor von der Festplatte in 0x0000:0x7E00
( ES: BX ) laden. Dieser Code setzt das ES: BX auf 0x7E00:0x0000
, das in eine physikalische Adresse von 0x7E000
aufgelöst wird ((0x7E00 & lt; & lt; 4) + 0x0000). Ich denke, die Absicht war, 0x07E0
in ES zu laden, was eine physikalische Adresse von 0x7E00
((0x07E0 & lt; & lt; 4) + 0x0000) ergeben würde. Sie können mehr über 16:16 Speicheradressierungsberechnungen hier erfahren. Die Multiplikation des Segments mit 16 entspricht der Verschiebung um 4 Bits.
Das zweite Problem im Code ist hier:
%Vor%Die Nummer für den zweiten 512-Block-Sektor auf der Festplatte ist 2, nicht 1. Um also den obigen Code zu beheben, müssen Sie CL entsprechend einstellen:
%Vor%Andere Probleme, die den laufenden Code auf verschiedenen Emulatoren, virtuellen Maschinen und echter physischer Hardware auslösen können, sind:
lodsb
, movsb
etc verwendete Richtungs-Flag könnte entweder gesetzt oder gelöscht werden. Wenn das Richtungsflag falsch eingestellt ist, können SI / DI -Register möglicherweise in die falsche Richtung eingestellt werden. Verwenden Sie STD
/ CLD
, um es in die gewünschte Richtung zu setzen (CLD = vorwärts / STD = rückwärts). In diesem Fall nimmt der Code die Vorwärtsbewegung an, daher sollte CLD
verwendet werden. Mehr dazu finden Sie in einer Befehlssatzreferenz
Um das erste und zweite Element aufzulösen, kann dieser Code nahe dem Start des Bootloaders verwendet werden:
%Vor% Ein paar Dinge zu beachten. Wenn Sie den Wert des SS -Registers ändern (in diesem Fall über MOV
), soll der Prozessor die Interrupts für diese Anweisung ausschalten und sie bis nach deaktivieren die folgende Anweisung. Normalerweise müssen Sie sich keine Gedanken über die Deaktivierung von Interrupts machen, wenn Sie SS aktualisieren, unmittelbar gefolgt von einer Aktualisierung von SP . Es gibt einen Fehler in sehr frühen 8088-Prozessoren, bei dem dies nicht berücksichtigt wurde. Wenn Sie also auf die größtmögliche Anzahl von Umgebungen abzielen, ist es eine sichere Sache, diese explizit zu deaktivieren und erneut zu aktivieren. Wenn Sie nicht beabsichtigen, jemals an einem fehlerhaften 8088 zu arbeiten, können die Anweisungen CLI
/ STI
im obigen Code entfernt werden. Ich kenne diesen Bug aus erster Hand mit meiner Arbeit, die ich Mitte der 80er Jahre auf meinem PC gemacht habe.
Die zweite Sache, die ich beachten muss, ist, wie ich den Stapel aufstelle. Für Leute, die neu zu 8088/8086 16-Bit-Montage sind, kann der Stapel eine Vielzahl von Möglichkeiten gesetzt werden. In diesem Fall setze ich den oberen Teil des Stapels (unterster Teil im Speicher) auf 0x8000
( SS ). Ich setze dann den Stapelzeiger ( SP ) auf 0
. Wenn Sie etwas im Stapel schieben im 16-Bit-Real-Modus dekrementiert der Prozessor zuerst den Stack-Zeiger um 2 und dann platziert ein 16-Bit WORD an dieser Position.Somit würde der erste Schub zum Stapel bei 0x0000-2 = 0xFFFE (-2) liegen. Sie hätten dann ein SS: SP , das wie 0x8000:0xFFFE
aussieht. In diesem Fall läuft der Stapel von 0x8000:0x0000
bis 0x8000:0xFFFF
.
Wenn Sie mit dem Stack arbeiten, der auf einem 8086 läuft (gilt nicht für 80286,80386+ Prozessoren), ist es eine gute Idee, den Stack-Pointer ( SP ) auf eine gerade Zahl zu setzen. Wenn Sie auf dem ursprünglichen 8086 SP auf eine ungerade Zahl setzen, würden Sie sich eine 4-Takt-Strafe zulegen Jeder Zugriff auf Stapelspeicher. Da der 8088 einen 8-Bit-Datenbus hatte, gab es diesen Nachteil nicht, aber das Laden eines 16-Bit Wortes auf 8086 dauerte 4 Taktzyklen, während der 8088 (zwei 8-Bit-Speicher) 8 Taktzyklen benötigte liest).
Schließlich, wenn Sie CS: IP explizit so festlegen möchten, dass CS bis zu dem Zeitpunkt, zu dem JMP abgeschlossen ist, richtig eingestellt ist Ihr Kernel), dann wird empfohlen, FAR JMP ( Siehe Operationen, die die Segmentregister beeinflussen / < em> FAR springen ). In der NASM-Syntax würde die JMP
wie folgt aussehen:
Einige (zB MASM / MASM32) Assembler haben keine direkte Unterstützung um einen FAR JMP zu kodieren, so wie es manuell gemacht werden kann:
%Vor%Wenn Sie GNU Assembler verwenden, sieht es so aus:
%Vor%Tags und Links assembly virtualbox nasm bootloader 16-bit