Hier die
Sub-Routine die ich benutze,
um in den 16 Bit-Unrealmode zu schalten und ein kurzes Beipiel wie man darüber etwas in den Speicherbereich oberhalb des ersten MiB schreiben kann.
Hinweis: Es wird nur DS auf 4 GiB erweitert, wenn andere Segmentregister(ES, FS, oder GS) erweitert werden sollen, dann kann die betreffende Zeilen ggf. unten vom Semikolon befreit werden.
(Mit DS braucht man nicht in jedem Fall Segment-Overide-Prefixe, sondern nur wenn man (E)BP, oder (E)SP als Adressregister verwenden möchte und trotzdem über DS adressieren möchte, oder wenn man über andere Segmentregister etwas adressieren möchte.)
Am Ende befindet sich die
Routine zum Freischalten der 21. Adressleitung. Auf meinen Rechnern funktionierte diese Routine bisher immer. Es gibt aber auch noch andere Methoden, falls es damit nicht funktionieren sollte.
Code: Alles auswählen
NMI_Port = 70h
START:
;--------------------------------
cli ; Software-Interrupts ausschalten
in al, NMI_Port ; Über CMOS-Baustein auch
or al, 80h ; die NMIS abschalten
out NMI_Port, al
call ESEG ; Segmente erweitern auf 32 Bit
in al, NMI_Port ; NMIs wieder einschalten
and al, 7Fh
out NMI_Port, al
sti ; Software-Interrupts einschalten
;--------------------------------
; Beispiel:
;--------------------------------
xor eax, eax
mov ax, DATEN ; Die genau Adresse unseres Datensegments wird vom Assembler eingetragen
mov ds, ax
shl eax, 4
mov edi, lineare 32 Bit Adresse oberhalb des ersten MiB
sub edi, eax
mov si, OFFSET TABELLE
mov eax, [si] ; Wir holen aus einer Tabelle im Datensegment ein DWORD über DS:SI
mov [edi], eax ; und schreiben es über DS:EDI zu einer Adresse oberhalb des ersten MiB.
; .....
;────────────────────────────────────────────────────────────────────────────
; GDT für den Protected Mode
;────────────────────────────────────────────────────────────────────────────
org START + ((($-START)/64)*64)+64 ; Code-Ausrichtung
;----------------------------------------------------------------------------
GDTZEIGER DW ? ; Länge der GDT
DW ? ; Adresse low -Word:SEGMENTE
DW ? ; Adresse high-Word:SEGMENTE
DW 0 ; reserviert
SEGMENTE DW 0 ; Bits: 0-15 Seg.länge(Bit0-15)
DW 0 ; Bits: 0-15 Basis-Adresse Deskriptor-Table
DB 0 ; Bits:16-23 Basis-Adresse Deskriptor-Table
DB 0 ; Bits: 0- 7 Zugriffsrechte
DB 0 ; Bits: 0- 3 Seg.länge(Bit16-19)/Bit7:1=4KByte/0=1Byte
DB 0 ; Bits:24-31 Basis-Adresse Deskriptor-Table
;-------------------------------------------- Selektor Segmente
DW 0FFFFh ; Segmentlänge Bits: 0-15 ┬──────┬ ┬─────────┬
DW 0 ; Adresse low Bits: 0-15 │ 08h │ │Code (CS)│
DB 0 ; Adresse high Bits:16-23 └──────┘ └─────────┘
DB 9Ah ; Zugriffsrechte
DB 0 ; Seg.Länge Bits:16-19 im Bit0-3 /Bit7:1=4KByte/0=1Byte
DB 0 ; Seg.Adresse Bits:24-31
;--------------------------------------------------- Selektor Segmente
DW 0FFFFh ; Segmentlänge Bits: 0-15 ┬──────┬ ┬──────────┬
DW 0 ; Adresse low Bits: 0-15 │ 10h │ │Stack (SS)│
DB 0 ; Adresse high Bits:16-23 └──────┘ └──────────┘
DB 92h ; Zugriffsrechte
DB 0 ; Seg.Länge Bits:16-19 im Bit0-3 /Bit7:1=4KByte/0=1Byte
DB 0 ; Seg.Adresse Bits:24-31
;--------------------------------------------------- Selektor Segmente
DW 0FFFFh ; Segmentlänge Bits: 0-15 ┬──────┬ ┬─────────────┬
DW 0 ; Seg.Adresse Bits: 0-15 │ 18h │ │(DS,ES,FS,GS)│
DB 0 ; Seg.Adresse Bits:16-23 └──────┘ └─────────────┘
DB 92h ; Zugriffsrechte
DB 0FFh ; Seg.Länge Bits:16-19 im Bit0-3//Bit7:1=4KByte/0=1Byte
DB 0FFh ; Seg.Adresse Bits:24-31
;---------------------------------------------------
SEGMENTE_END label WORD
Gdt_Groesse equ (OFFSET SEGMENTE_END - SEGMENTE -1)
;────────────────────────────────────────────────────────────────────────────
; Setzt für das DS,ES,FS,GS-Register eine neue Segmentlänge von 00FFFFFFh.
; Dazu wird in den Protected Mode umgeschaltet.
;────────────────────────────────────────────────────────────────────────────
org START + ((($-START)/32)*32)+32 ; Code-Ausrichtung
;----------------------------------------------------------------------------
ESEG: xor eax, eax
mov ax, cs
mov ds, ax
shl eax, 4 ; EAX ist nun physikalische
mov ebx, eax ; Segmentstartadresse
mov WORD PTR[SEGMENTE+0Ah], ax ; in den Deskriptoren
mov WORD PTR[SEGMENTE+12h], ax ; für CS
ror eax, 10h ; und SS in der
mov BYTE PTR[SEGMENTE+0Ch], al ; GDT abspeichern
mov BYTE PTR[SEGMENTE+14h], al
xor eax, eax ; EAX auf null
mov ax, OFFSET SEGMENTE ; 16-Bit-Offset
add ebx, eax ; GDT-Adresse im
mov WORD PTR[GDTZEIGER], Gdt_Groesse ; GDT-Deskriptor
mov DWORD PTR[GDTZEIGER+2], ebx
pushf ; Flags retten
lgdt FWORD PTR[GDTZEIGER] ; GDT laden
mov dx, ss ; SS retten
mov eax, cr0 ; Steuerwort 0 nach EAX
or al, 1 ; Protected Mode ein
mov cr0, eax ; im Steuerwort
; Prefetch-Puffer löschen
DB 0EAh ; die folgenden Zeilen
DW (OFFSET PMODE) ; erzeugen:
DW 8 ; JMP FAR CS:PMODE
;------------------------------------------------
org START + ((($-START)/32)*32)+32 ; Code-Ausrichtung
;------------------------------------------------
PMODE: mov ax, 10h ; SS-Selektor auf 64
mov ss, ax ; KByte begrenzen
mov ax, 18h
mov ds, ax ; DS,ES,FS,GS-Selektoren
; mov es, ax ; auf 16 MByte erweitern
; mov fs, ax
; mov gs, ax
mov eax, cr0 ; Steuerwort 0 nach EAX
and eax, not 1 ; Protected Mode aus
mov cr0, eax ; im Steuerwort
; Prefetch-Puffer löschen
DB 0EAh ; Die folgenden Zeilen er-
DW (OFFSET RMODE) ; zeugen das Kommando
AKTSEG DW (SEG RMODE) ; JMP FAR CS:RMODE
;------------------------------------------------
org START + ((($-START)/32)*32)+32 ; Code-Ausrichtung
;------------------------------------------------
RMODE: mov ss, dx ; SS zurueck
popf ; Flags holen
;----------------------------------------------------------------------------
; Schaltet das 21. Adreßbit des Prozessors ein.
;----------------------------------------------------------------------------
BIT_FREI: call W_8042 ; Warte auf 8042
jnz BACK
mov al, 0D1h ; Kommando schreiben
out 64h, al
call W_8042 ; fertig zum Emnpfang ?
jnz BACK
mov al, 0DFh ; ja,Leitung 20 freischalten
out 60h, al
;------------------------------------------------------------
; Wartet darauf, bis der 8042 bereit ist.
;------------------------------------------------------------
W_8042: xor cx, cx ; CX=0
STATUS: in al, 64h ; Status lesen
and al, 2 ; Puffer voll ?
loopnz STATUS ; bis nein oder Timeout
BACK: ret
Dirk