Post by Benjamin NehlsPost by Dirk Wolfgang GlompIch versuche es mal kurz zusammenzufassen. Wenn du es noch detailierter
wissen möchtest sag bescheid.
Auf jedenfall, klingt interessant und ich würde so eine Konfiguration
gern mal am real PC austesten.
Ich hab hier noch nen AMD-K6 450 MHz und 256 MB Ram rumstehen der sich
zum Testen eignen würde.
Welche Treiber / Programme sind dafür denn nötig um alles hinter dem 65
MB Speicher zu setzen.
Es werden dabei nur jene Daten nach oben befördert die eine Anwendung
auch selber dort nach oben hineinschreibt. Ich benutze dafür keinerlei
Treiber, sondern schreibe/lese unmittelbar selber in den dortigen
Speicherbereich.
Post by Benjamin NehlsWenn ich das richtig verstenden habe ist das dann quasie alles nur noch
im Protect Mode und alles spielt sich hinterher dann in dem emulierten
Realmode vom PM ab?
Nein, der Unrealmode unterscheidet sich nicht so grundlegend vom RM.
Ich schalte wieder zurück in den nun erweiterten RM der als Un-Realmode,
oder als Big-Realmode bezeichnet wird. Es wird nichts emuliert und auch
kein PM ist dabei mehr aktiv. Lediglich die Segmentlänge der erweiterten
Segmente bleibt dabei auch nach dem zurückschalten in den RM immer noch
erhalten, solange nicht wieder in den PM geschaltet wird.
Post by Benjamin Nehlsist das richtig bzw. war das doch so, das man vom RM
zwar in den PM schalten kann aber nicht umgekehrt?
Auch für 80286(16Bit) gibt es einen Trick wieder zurück in den RM zu
schalten und ab den 80386er(32Bit) wurde es regulär implementiert.
Post by Benjamin NehlsNaja wie gesagt ich würde gerne mehr wissen vorallem würde ich mich über
eine kleine Anleitung freuen um das mal an meinem Test-Pc zu testen. :)
Vorallem wie sieht das denn mit 16-Bit Treibern z.B. für die
Netzwerkkarte oder die Soundkarte aus die Funktionieren dann auch noch
einwandfrei?
16-Bit Treiber für den RM verwenden selber nur den unteren Bereich und
benutzen dafür die dort übliche Verwendung der 64KB großen Segmente. Damit
kann ein Adressbereich von 1MB+64KB-1Byte adressiert werden.
....
[--Detailiertere Anleitung für den Unrealmode--]
Um in den Unrealmode zu schalten müssen wir in den PM schalten,
die Segmentlänge erweitern und zurück in den RM schalten.
Für den PM selber brauchen wir keine Interrupts(IRQs) und auch keine
dafür geeingnete IRQ-Tabelle, da wir ja auch nicht im PM bleiben wollen.
Daher sperren wir die IRQs für diesen gesamten Vorgang. Dafür löschen wir
das dafür zuständige Interrupt-Bit im Flagregister und verhindern so das
Interrupts aufgeführt werden. Wir benutzen dafür den cli-Befehl der genau
dieses für uns erledigt.
Der Non-Maskable-Interrupt(NMI) ist davon allerding nicht betroffen und so
müssen wir dieses im dafür zuständigen CMOS-Baustein selber vornehmen.
Über die Portadresse 70h und das dortige oberste Bit kann man den NMI
aus/an schalten. Zum Auschalten des NMIs muss dieses Bit gesetzt sein.
Wir holen uns über den Port 70h das Byte und setzen das oberste Bit und
übertragen danach das veränderte Byte wieder zurück.
Nun können wir in den PM schalten die Segmente erweitern. Danach können wir
den NMI und die IRQs wieder anschalten.
Im folgenden Verlauf benutze ich Assembler-Befehle im MASM-Syntax
(Makro-Assembler von Microsoft) die sich vom AT-Syntax unterscheiden.
Ich habe die nötigen Teile um in den Unrealmode zu schalten in ein
Roh-Gerüst zum assemblieren hineingelegt, so das daraus eine fertige
Anwendung erstellt werden kann, die allerding in diesem Beispiel nicht
anderes macht, als ein 32Bit-Wert aus unseren im Programm deklarierten
Datenbereich zu laden und ihn in das 65.MB zu schreiben. Für eine
sinnvollere Verwendung muss daher noch entsprechender Opcode hinzugefügt
werden.
.MODEL SMALL
.386P
CODE SEGMENT use16 'CODE'
assume cs:CODE,ds:DATEN,ss:STAPEL
;-----------------------------
; -- Start des Programms --
START:
; -- Beispiel Opcodes die vorher ausgeführt werden ---
mov ax,DATEN ; DS auf Daten-Bereich
mov ds,ax
;-- weitere Opcodes ---
;------------------------------------------------------------------------
;-- Ab hier nun die wesentliche Teile für den Unrealmode --
cli ; IRQs sperren
in al,70h ; NMI sperren
or al,80h
out 70,al
call UNREAL ; Sprung zur Subroutine die in den Unrealmode schaltet
; und danach zurückspringt
in al,70h ; NMI wieder einschalten
and al,7Fh
out 70,al
sti ; IRQs wieder einschalten
;------------------------------------------------------------------------
; Lineare Zugriffe auf den gesamten 4GB-Adressraum
; Hier ein Beispiel:
mov ebx, 00100000h * 64 ; Adresse vom 65.MB
xor eax,eax
mov ax,DATEN
mov ds,ax ; DS auf Datenbereich
shl eax,4
sub ebx,eax
mov eax,[WERT] ; 32Bit-Wert aus Datenbereich über DS:16Bit-Adresse holen
mov [ebx],eax ; ...und an den Anfang vom 65.MB über DS:EBX schreiben
; Hierfür wird nun die Segmentadresse(in DS) + die 32Bit-Offsetadresse
; aus dem Adressregister(in EBX) zum adressieren verwendet.
;--------------------------------------------------------------
;--- Programm-Ende und Rücksprung nach DOS ---
mov al,ERRORLEVEL ; muss durch einen Wert(0-255) ersetzt werden
mov ah,4Ch
int 21h
;---------------------------------------------------------------
; --- Subroutinen ---
;-----------------------------
; -- GDT für den Protected Mode (im Code-Breich) --
org START + ((($-START)/32)*32)+32 ; Aligment
;-----------------------------
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
;--------------------------------------------
DW 0FFFFh ; Segmentlänge Bits: 0-15
DW 0 ; Adresse low Bits: 0-15
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
;---------------------------------------------------
DW 0FFFFh ; Segmentlänge Bits: 0-15
DW 0 ; Adresse low Bits: 0-15
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 18h)
DW 0FFFFh ; Segmentlänge Bits: 0-15
DW 0 ; Seg.Adresse Bits: 0-15
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)
;---------------------------------------------------
org START + ((($-START)/32)*32)+32 ; Code-Aligment
;---------------------------------------------------
UNREAL:
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-Aligment
;-----------------------------------
PMODE:
mov ax,10h ; SS-Selektor auf 64
mov ss,ax ; KByte begrenzen
mov ax,18h
mov ds,ax ; DS-Selektor mit erweiterter Segmentlänge laden
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-Aligment
;-----------------------------------
RMODE:
mov ss,dx ; SS zurueck
popf ; Flags holen
;------------------------------
; Das 21.Adreßbit einschalten
;------------------------------
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 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
;------------------- unser Datenbereich -------------------------------
DATEN SEGMENT use32 'DATA'
WERT DD 12345678h
DATEN ends
;------ unser Stack ---------------------------------------------------
STAPEL SEGMENT use16 STACK 'STACK'
DB 100h dup (0)
STAPEL ends
;-----
end
Zum Assemblieren dieses Quellcodes kann man MASM5 unter DOS, oder auch
MASM6 für Windows verwenden um daraus eine *.obj-Datei zu erhalten.
Damit wir aber eine 16Bit-Anwendung bekommen müssen wir einen
16Bit-Linker dafür verwenden, der bei MASM5 mitgeliefert wurde.
So eine Unrealmode-Anwendung kann allerdings nur unter puren DOS
ausgeführt werden. Auch darf vorher kein Memmorymanager wie emm386
vorher gestartet worden sein.
MASM5:
MASM /Z 4GB.asm,4GB.obj,4GB.lst,4GB.crf
LINK /CP:1 4GB.obj,4GB.exe,4GB.map,,
MASM6(mit link.exe von MASM5):
ML /c /Zm 4GB.asm
LINK /CP:1 4GB.obj,4GB.exe,,,
MASM6 beherrscht schon MMX, SSE und 3DNow-Befehle die MASM5 noch nicht
kennt. Wer also unter puren DOS mit MASM5 arbeitet wird solche Befehle
daher von Hand kodieren und als Bytes selber in den Opcode einfügen müssen.
Beispiel: DB 0Fh,6Fh,4 ; movq mm0,[si]
Dirk