Assembler springen im Geschützten Modus mit GDT
Ich bin derzeit rund um das Spiel mit x86-Assember, um zu schärfen, meine low-level-Programmierkenntnisse. Derzeit stehe ich vor einem kleinen problem mit der Adressierung in 32-Bit-Protected-Modus.
Die situation ist folgende:
Ich habe ein Programm geladen 0x7e0 die schaltet die CPU in den Protected-Mode und springt an die entsprechende Bezeichnung im code:
[...]
code to switch CPU in Protected Mode
[...]
jmp ProtectedMode
[...]
bits 32
ProtectedMode:
.halt:
hlt
jmp .halt
Dieser Werke absolut in Ordnung so weit. Die "jmp geschützten Modus" funktioniert auch ohne explizite weit springen, um zu löschen der prefetch-queue - da dieses Programm ist geladen mit offset 0 (org 0 am Anfang) - verursacht das code-segment an den richtigen Speicherort verweist.
Mein Aktuelles problem ist jetzt, dass innerhalb des "geschützten Modus" Etikett, das ich will springen Sie zu einem anderen Programm, das geladen wird, 0x8000 (ich überprüfte diese mit einem Speicher-dump, die laden-Funktion hat funktioniert und das Programm wird korrekt geladen, um 0x8000).
Da die CPU ist nun in den geschützten Modus und nicht RealMode mehr, die Adressierung schema anders ist. Den geschützten Modus verwendet Deskriptor-Selektoren zum nachschlagen einer Basis-Adresse und limit in einer Deskriptor-Tabelle hinzufügen, um den angegebenen offset und rufen Sie die physische Adresse (wie ich verstanden habe). Daher war es notwendig, eine GDT-vor Eintritt in den geschützten Modus.
Mine sucht, wie die folgenden:
%ifndef __GDT_INC_INCLUDED__
%define __GDT_INC_INCLUDED__
;*********************************
;* Global Descriptor Table (GDT) *
;*********************************
NULL_DESC:
dd 0 ; null descriptor
dd 0
CODE_DESC:
dw 0xFFFF ; limit low
dw 0 ; base low
db 0 ; base middle
db 10011010b ; access
db 11001111b ; granularity
db 0 ; base high
DATA_DESC:
dw 0xFFFF ; data descriptor
dw 0 ; limit low
db 0 ; base low
db 10010010b ; access
db 11001111b ; granularity
db 0 ; base high
gdtr:
Limit dw 24 ; length of GDT
Base dd NULL_DESC ; base of GDT
%endif ;__GDT_INC_INCLUDED__
geladen wird, um die GDT-register über
lgdt [gdtr]
Was ich nicht verstanden habe, so weit ist, wie ich heute springen, um die körperliche Adresse 0x8000 in den geschützten Modus über die GDT?
Meine ersten Gedanken waren, um wählen Sie die Code-Deskriptor (CODE_DESC), die zeigen sollte, zu 0x7e00 (waren das aktuelle Programm geladen wird) und den offset, die notwendig ist, um auf 0x8000 (512 bytes), die bei der jump-Anweisung:
jmp CODE_DESC:0x200
Aber das funktioniert nicht.
jmp 0x7e0:0x200
funktioniert auch nicht...
Haben Sie eine Idee, was ich hier vermisst? Vielleicht habe ich nicht verstanden, etwas wesentliches in der 32-Bit-geschützten Modus Adressierung und die Verwendung der GDT.
[BEARBEITEN] Vollständige code:
bits 16
org 0 ; loaded with offset 0000 (phys addr: 0x7e00)
jmp Start
Start:
xor ax, ax
mov ax, cs
mov ds, ax ; update data segment
cli ; clear interrupts
lgdt [gdtr] ; load GDT from GDTR (see gdt_32.inc)
call OpenA20Gate ; open the A20 gate
call EnablePMode ; jumps to ProtectedMode
;******************
;* Opens A20 Gate *
;******************
OpenA20Gate:
in al, 0x93 ; switch A20 gate via fast A20 port 92
or al, 2 ; set A20 Gate bit 1
and al, ~1 ; clear INIT_NOW bit
out 0x92, al
ret
;**************************
;* Enables Protected Mode *
;**************************
EnablePMode:
mov eax, cr0
or eax, 1
mov cr0, eax
jmp ProtectedMode ; this works (jumps to label and halts)
;jmp (CODE_DESC-NULL_DESC):ProtectedMode ; => does not work
;jmp 08h:ProtectedMode , => does not work
;***************
;* data fields *
;* &includes *
;***************
%include "gdt_32.inc"
;******************
;* Protected Mode *
;******************
bits 32
ProtectedMode:
;here I want to jump to physical addr 0x8000 (elf64 asm program)
.halt:
hlt
jmp .halt
Du musst angemeldet sein, um einen Kommentar abzugeben.
Gibt es mehrere Probleme im code.
Zuerst, Ihre
GDTR.Base
enthält den offset desGDT
aus dem Anfang des Codes, da dein code kompiliert wird, beginnen bei Adresse 0 (wegenorg 0
). Die Basis-Adresse muss der physischen Adresse, nicht eine relative Adresse. IOW, wenn Sie halten dieseorg 0
müssen SieCS
*16 (=0x7e00) zuBase
.Zweiten, weil der selben
org 0
die 32-bit-offsets im code (nachbits 32
undProtectedMode:
) nicht gleich zu physischen Adressen entsprechen, sind Sie 0x7e00 weniger als die physikalischen Adressen. OTOH, die Segmente definiert, die in Ihrer GDT start bei der physischen Adresse 0 (da die Basis-Teile der GDT-Einträge sind 0) und nicht auf 0x7e00. Dies bedeutet, dass, wenn Sie versuchen, diese Segmente mit dem code/Daten haben, werden Sie fehlen die Adressen von 0x7e00. Wenn Sie möchten, umorg 0
die base-Adressen in der GDT müssen so eingestellt werden, 0x7e00.Oder Sie können ändern
org 0
zuorg 0x7e00
und dann die Basen in der GDT sollte 0 sein. Und Sie müssen sich nicht anpassen GDTR.Basis von 0x7e00, 0 tun wird.Sollte dies funktionieren:
Beachten Sie, dass ein segment begrenzen, entspricht die segment-Größe minus 1.
Ein paar mehr Punkte... Laden alle segment-Register mit gültigen Selektoren oder 0. Außerdem legen Sie den Stapel. Wenn Sie Müll dort (oder alt-Werte von real-Modus), wenn Sie anfangen zu spielen mit interrupts/Ausnahmen, Sie haben mehr Unfälle.
Schließlich, ich weiß nicht, was elf64 ist, aber Sie kümmern sich um die
org
Sache für andere Module und stellen Sie sicher, dass alle generierten Adressen zu laden-Adressen. Und wenn Sie beabsichtigen, Sie zu aktivieren 64-bit-Modus, es gibt eine Menge Arbeit zu tun. Ich würde raten, nicht zu eilen, in die 64-bit-Modus doch da Sie stolpern über relativ einfache Sachen.Ein paar Dinge. Ersten, Ihren aktuellen code nicht technisch geben Sie den geschützten Modus. Sie betreten den geschützten Modus durch laden
cs
mit einem Deskriptor aus der GDT. Da kann man nicht direkt auf dascs
registrieren, ist der einfachste Weg, dies zu tun ist mit einem far-jump. Ersetzen Sie Ihre aktuellen springen, mit:Zweite, die Basis für Ihre code-segment ist 0, nicht 0x7e00. Wenn Sie einen Blick auf die vier bytes, beschriftet mit dem Wort "base", Sie sind alle 0. Sie haben zwei Optionen. Die GDT ist eine Basis von 0x7e00, oder fügen Sie die Richtlinien zu ändern Sie die load-Adresse für alle protected-Modus-code für eine Basis von 0.
Sobald Sie das getan haben, diese beiden Dinge, die Sie springen können, um Ihr Programm mit einem normalen Sprungbefehl. Wenn Sie sich entscheiden zu gehen Ihre GDT, wie es ist, verwenden Sie die vollständige Adresse:
Wenn Sie wählen, um zu ändern, die Basis Ihrer code-segment, müssen Sie die Adresse relativ zu dieser.
Mehr Informationen über die GDT
Mehr Informationen über den Eintritt in den geschützten Modus
jmp (CODE_DESC-NULL_DESC):ProtectedMode
?