home *** CD-ROM | disk | FTP | other *** search
- (* ------------------------------------------------------ *)
- (* XMS.PAS *)
- (* UNIT zur Verwaltung des Extended Memory nach XMS 2.0 *)
- (* Turbo Pascal 4.0 und 5.x *)
- (* Copyright (c) 1989 Karsten Gieselmann & TOOLBOX *)
- (* ------------------------------------------------------ *)
- (* Im Programmtext verwendete Abkürzungen: *)
- (* *)
- (* XMS = eXtended Memory Specification *)
- (* XMM = eXtended Memory Manager *)
- (* HMA = High Memory Area *)
- (* EMB = Extended Memory Block *)
- (* ------------------------------------------------------ *)
-
- {$R-,S-} (* Keine Bereichs- oder Stacküberlauf-Prüfung *)
-
- UNIT XMS;
-
- INTERFACE
-
- USES
- DOS;
-
- (* ------------------ XMM-Fehlercodes ------------------- *)
-
- CONST
- Ok = $00;
- Function_not_implemented = $80;
- Vdisk_detected = $81;
- A20_error_occurred = $82;
- General_driver_error = $8E;
- Unrecoverable_driver_error = $8F;
- HMA_does_not_exist = $90;
- HMA_already_in_use = $91;
- Invalid_HMA_request = $92;
- HMA_not_allocated = $93;
- A20_line_still_enabled = $94;
- All_extended_memory_allocated = $A0;
- All_available_handles_allocated = $A1;
- Invalid_handle = $A2;
- Invalid_source_handle = $A3;
- Invalid_source_offset = $A4;
- Invalid_destination_handle = $A5;
- Invalid_destination_offset = $A6;
- Invalid_length = $A7;
- Invalid_move_overlap = $A8;
- Parity_error_occurred = $A9;
- EMB_not_locked = $AA;
- EMB_locked = $AB;
- EMB_lock_count_overflowed = $AC;
- Lock_failed = $AD;
- Only_smaller_UMB_available = $B0;
- No_UMB_available = $B1;
- Invalid_UMB_segment_number = $B2;
- Not_installed = $FF;
-
- (* ------------ Nützliche Typdeklarationen -------------- *)
-
- TYPE (* Speicherbeschreibungstyp *)
- Descriptor = RECORD
- CASE RAM : BOOLEAN OF
- FALSE : (Handle : WORD;
- Offset : LONGINT);
- TRUE : (Address : POINTER);
- END;
-
- (* ----------------- Fehlerbehandlung ------------------- *)
-
- VAR
- Installed : BOOLEAN; (* XMM installiert? *)
- Result : BYTE; (* Fehlercode des letzten XMM-Aufrufs *)
-
- (* -------------- High-Memory-Funktionen ---------------- *)
-
- PROCEDURE GetVersion(VAR Version, Revision : WORD);
- FUNCTION HMA_Avail : BOOLEAN;
- FUNCTION RequestHMA(BytesNeeded : WORD) : BOOLEAN;
- PROCEDURE ReleaseHMA;
- PROCEDURE GlobalEnableA20;
- PROCEDURE GlobalDisableA20;
- PROCEDURE LocalEnableA20;
- PROCEDURE LocalDisableA20;
- FUNCTION A20Enabled : BOOLEAN;
-
- (* ------------ Extended-Memory-Funktionen -------------- *)
-
- PROCEDURE QueryMemory(VAR MemAvail, MaxAvail : WORD);
- FUNCTION AllocateMemory(KBytesNeeded : WORD) : WORD;
- PROCEDURE DeallocateMemory(Handle : WORD);
- PROCEDURE MoveMemory(VAR Source, Destination : Descriptor;
- WordCount : LONGINT);
- FUNCTION LockMemory(Handle : WORD) : LONGINT;
- PROCEDURE UnlockMemory(Handle : WORD);
- PROCEDURE GetHandleInfo(Handle : WORD; VAR KBytes : WORD;
- VAR LockCount, FreeHandles : BYTE);
- PROCEDURE ReallocateMemory(Handle, KBytes : WORD);
-
- (* ------------------------------------------------------ *)
-
- IMPLEMENTATION
-
- CONST
- Multiplex = $2F; (* Nummer des Multiplex-Interrupts *)
-
- VAR
- EntryPoint : POINTER; (* Einsprungadresse für XMM-Aufr. *)
- Regs : Registers; (* für Kommunikation mit dem XMM *)
-
- (* -------------------- XMM-Aufruf ---------------------- *)
-
- PROCEDURE XMM(Call : BYTE);
- (* führt einen XMM-Funktionsaufruf aus; die Funktions-
- nummer (0..11h) wird dazu in das AH-Register geladen.
- Bei AX=1 wurde die Funktion ordnungsgemäß ausgeführt,
- bei AX=0 weist der Inhalt von BL (-> Result) auf die
- genaue Fehlerursache (siehe Fehlercodes oben) hin. *)
- BEGIN
- IF NOT Installed THEN
- Result := Not_installed
- ELSE BEGIN
- Regs.AH := Call; (* Funktionsnummer laden *)
- WITH Regs DO BEGIN
- Inline(
- $8D/$3E/Regs/(* lea di,[Regs] ;Basisadresse Regs *)
- $4F/ (* dec di ;Basis-Korrektur *)
- $57/ (* push di ;<di> sichern *)
- $1E/ (* push ds ;<ds> sichern... *)
- $1E/ (* push ds ;...zur Referenz... *)
- $07/ (* pop es ;...nach <es> holen *)
- $8B/$85/AX/ (* mov ax,[di+AX] ;Register mit den *)
- $8B/$9D/BX/ (* mov bx,[di+BX] ;Eingangsparametern *)
- $8B/$95/DX/ (* mov dx,[di+DX] ;besetzen *)
- $8B/$B5/SI/ (* mov si,[di+SI] ; *)
- $8E/$9D/DS/ (* mov ds,[di+DS] ; *)
- $26/$FF/$1E/
- EntryPoint/ (* call far es:[..];XMM-Funktion rufen *)
- $1F/ (* pop ds ;<ds> restaurieren *)
- $5F/ (* pop di ;Basisadresse holen *)
- $89/$85/AX/ (* mov [di+AX],ax ;Ausgaben wieder *)
- $89/$9D/BX/ (* mov [di+BX],bx ;in Regs-Variablen *)
- $89/$95/DX); (* mov [di+DX],dx ;unterbringen *)
- IF AX = $0001 THEN
- Result := Ok
- ELSE BEGIN
- Result := BL;
- END;
- END;
- END;
- END;
-
- (* -------------- High-Memory-Funktionen ---------------- *)
-
- PROCEDURE GetVersion(VAR Version, Revision : WORD);
- (* erfragt die Version und die interne Revisionsnummer
- der XMS-Software; beide Nummern sind als 16-Bit BCD-
- codierte Zahlen aufzufassen (0206h = Version 2.06). *)
- BEGIN
- XMM($00);
- Version := Regs.AX; (* XMS-Version *)
- Revision := Regs.BX; (* interne Revisionsnummer *)
- END;
-
- FUNCTION HMA_Avail : BOOLEAN;
- (* prüft, ob die High Memory Area vorhanden ist. *)
- BEGIN
- XMM($00);
- HMA_Avail := (Regs.DX = 1); (* existiert die HMA? *)
- END;
-
- FUNCTION RequestHMA(BytesNeeded : WORD) : BOOLEAN;
- (* reserviert Speicher im High Memory; da dieser Bereich
- nur von einem Programm zur Zeit genutzt werden kann,
- empfiehlt sich in der Regel die Reservierung der ma-
- ximal möglichen HMA-Kapazität (BytesNeeded = $FFFF).
- Bei Erfolg liefert die Funktion den Wert TRUE. *)
- BEGIN
- Regs.DX := BytesNeeded; (* gewünschte Größe in Bytes *)
- XMM($01);
- RequestHMA := (Result = Ok);
- END;
-
- PROCEDURE ReleaseHMA;
- (* Freigabe des mit "RequestHMA" reservierten Bereichs. *)
- BEGIN
- XMM($02);
- END;
-
- PROCEDURE GlobalEnableA20;
- (* schaltet die Adreßleitung A20 frei und ermöglicht
- mit der Steuerung dieser Leitung durch die CPU den
- Zugriff auf das High Memory (der Bereich FFFF:????). *)
- BEGIN
- XMM($03);
- END;
-
- PROCEDURE GlobalDisableA20;
- (* sperrt die Adreßleitung A20 und verhindert Zugriffe
- auf das High Memory; diese Funktion sollte am Ende
- eines Programms unbedingt ausgeführt werden! *)
- BEGIN
- XMM($04);
- END;
-
- PROCEDURE LocalEnableA20;
- (* ermöglicht in Verbindung mit "LocalDisableA20" ein
- verschachteltes Freischalten/Sperren von A20. *)
- BEGIN
- XMM($05);
- END;
-
- PROCEDURE LocalDisableA20;
- (* ermöglicht in Verbindung mit "LocalEnableA20" ein
- verschachteltes Freischalten/Sperren von A20. *)
- BEGIN
- XMM($06);
- END;
-
- FUNCTION A20Enabled : BOOLEAN;
- (* gibt an, ob die Adreßleitung A20 durch die CPU ge-
- steuert werden kann. *)
- BEGIN
- XMM($07);
- A20Enabled := (Regs.AX = 1); (* A20 freigeschaltet? *)
- END;
-
- (* ------------ Extended-Memory-Funktionen -------------- *)
-
- PROCEDURE QueryMemory(VAR MemAvail, MaxAvail : WORD);
- (* erfragt die Gesamtgröße des noch freien Extended Me-
- mory (abzüglich HMA) und die Länge des größten, noch
- freien Blocks. All Angaben sind in KByte gemeint. *)
- BEGIN
- XMM($08);
- MemAvail := Regs.DX; (* insgesamt freier Speicherplatz *)
- MaxAvail := Regs.AX; (* Länge des größten Blocks *)
- END;
-
- FUNCTION AllocateMemory(KBytesNeeded : WORD) : WORD;
- (* reserviert einen Bereich im Extended Memory (EMB)
- und gibt das mit dem Block assoziierte Handle zurück.*)
- BEGIN
- Regs.DX := KBytesNeeded; (* gewünschte Größe in KBytes *)
- XMM($09);
- AllocateMemory := Regs.DX; (* Handle des Speicherblocks *)
- END;
-
- PROCEDURE DeallocateMemory(Handle : WORD);
- (* gibt einen reservierten Speicherblock wieder frei *)
- BEGIN
- Regs.DX := Handle; (* Handle des Speicherblocks *)
- XMM($0A);
- END;
-
- PROCEDURE MoveMemory(VAR Source, Destination : Descriptor;
- WordCount : LONGINT);
- (* kopiert einen Bereich der Länge "WordCount" zwischen
- Hauptspeicher und Extended Memory oder innerhalb ei-
- nes dieser Speicher. Quell- (Source) und Zielbereich
- (Destination) sind dabei wie folgt zu spezifizieren:
- bei Hauptspeicher ist die Adresse mit Segment:Offset
- des Bereichs zu besetzen. Bereiche im Extended Memory
- werden durch Angabe des Handles und des linearen 32-
- Bit-Offsets im Speicherblock (EMB) gekennzeichnet.
- Kopiervorgänge mit überlappenden Quell- und Zielbe-
- reichen sind nur dann erlaubt, wenn die Quelladresse
- kleiner als die Zieladresse ist. *)
- VAR
- Desc : RECORD (* Datenstruktur für Funktion 0Bh *)
- BytesToMove : LONGINT;
- SourceHandle : WORD;
- SourceOffset : LONGINT;
- DestinationHandle : WORD;
- DestinationOffset : LONGINT;
- END;
- BEGIN
- WITH Desc DO BEGIN
- BytesToMove := WordCount * 2;
- IF Source.RAM THEN BEGIN
- SourceHandle := 0;
- SourceOffset := LongInt(Source.Address);
- END ELSE BEGIN
- SourceHandle := Source.Handle;
- SourceOffset := Source.Offset;
- END;
- IF Destination.RAM THEN BEGIN
- DestinationHandle := 0;
- DestinationOffset := LongInt(Destination.Address);
- END ELSE BEGIN
- DestinationHandle := Destination.Handle;
- DestinationOffset := Destination.Offset;
- END;
- END;
- Regs.DS := Seg(Desc); (* Deskriptor-Adresse nach DS:SI *)
- Regs.SI := Ofs(Desc);
- XMM($0B);
- END;
-
- FUNCTION LockMemory(Handle : WORD) : LONGINT;
- (* verriegelt einen Speicherblock gegen das Verlagern
- durch den XMM; zurückgegeben wird die lineare 32-Bit
- Adresse des Speicherblocks im Extended Memory. *)
- BEGIN
- Regs.DX := Handle; (* Handle des Speicherblocks *)
- XMM($0C);
- LockMemory := LongInt(Ptr(Regs.DX, Regs.BX));(* Adresse *)
- END;
-
- PROCEDURE UnlockMemory(Handle : WORD);
- (* entriegelt einen gegen Verlagerungen durch den XMM
- im Extended Memory geschützten Speicherblock. *)
- BEGIN
- Regs.DX := Handle; (* Handle des Speicherblocks *)
- XMM($0D);
- END;
-
- PROCEDURE GetHandleInfo(Handle : WORD; VAR KBytes : WORD;
- VAR LockCount, FreeHandles : BYTE);
- (* erfragt Informationen zu einem Speicherblock *)
- BEGIN
- Regs.DX := Handle; (* Handle des Speicherblocks *)
- XMM($0E);
- KBytes := Regs.DX; (* Größe des Blocks in KBytes *)
- LockCount := Regs.BH; (* Anzahl verriegelter Blöcke *)
- FreeHandles := Regs.BL; (* Anzahl noch freier Handles *)
- END;
-
- PROCEDURE ReallocateMemory(Handle, KBytes : WORD);
- (* verändert die Größe eines Speicherblocks *)
- BEGIN
- Regs.DX := Handle; (* Handle des Speicherblocks *)
- Regs.BX := KBytes; (* neue Größe des Blocks in KBytes *)
- XMM($0F);
- END;
-
- (* --------------- Installationsroutinen ---------------- *)
-
- PROCEDURE CheckForXMM(Var XMM_Found : BOOLEAN);
- (* prüft, ob der XMM installiert ist. *)
- VAR
- Regs : Registers;
- BEGIN
- Regs.AX := $4300; (* "XMS Installation Check" *)
- Intr(Multiplex, Regs);
- XMM_Found := (Regs.AL = $80); (* XMM installiert? *)
- END;
-
- FUNCTION DriverEntryPoint : POINTER;
- (* ermittelt die Einsprungadresse für XMM-Aufrufe. *)
- VAR
- Regs : Registers;
- BEGIN
- Regs.AX := $4310; (* "Get XMS Driver Address" *)
- Intr(Multiplex, Regs);
- DriverEntryPoint := Ptr(Regs.ES, Regs.BX); (* Adresse *)
- END;
-
- BEGIN (* Initialierungsteil *)
- CheckForXMM(Installed);
- IF Installed THEN BEGIN
- EntryPoint := DriverEntryPoint; (* Einsprungadresse *)
- END;
- END.
- (* ------------------------------------------------------ *)
- (* Ende von XMS.PAS *)