home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / 1990 / 04 / algorith / xms.pas < prev    next >
Pascal/Delphi Source File  |  1989-12-28  |  13KB  |  365 lines

  1. (* ------------------------------------------------------ *)
  2. (*                        XMS.PAS                         *)
  3. (*  UNIT zur Verwaltung des Extended Memory nach XMS 2.0  *)
  4. (*               Turbo Pascal 4.0 und 5.x                 *)
  5. (*    Copyright (c) 1989  Karsten Gieselmann & TOOLBOX    *)
  6. (* ------------------------------------------------------ *)
  7. (*         Im Programmtext verwendete Abkürzungen:        *)
  8. (*                                                        *)
  9. (*           XMS = eXtended Memory Specification          *)
  10. (*           XMM = eXtended Memory Manager                *)
  11. (*           HMA = High Memory Area                       *)
  12. (*           EMB = Extended Memory Block                  *)
  13. (* ------------------------------------------------------ *)
  14.  
  15. {$R-,S-}    (* Keine Bereichs- oder Stacküberlauf-Prüfung *)
  16.  
  17. UNIT XMS;
  18.  
  19. INTERFACE
  20.  
  21. USES
  22.   DOS;
  23.  
  24. (* ------------------ XMM-Fehlercodes ------------------- *)
  25.  
  26. CONST
  27.   Ok                              = $00;
  28.   Function_not_implemented        = $80;
  29.   Vdisk_detected                  = $81;
  30.   A20_error_occurred              = $82;
  31.   General_driver_error            = $8E;
  32.   Unrecoverable_driver_error      = $8F;
  33.   HMA_does_not_exist              = $90;
  34.   HMA_already_in_use              = $91;
  35.   Invalid_HMA_request             = $92;
  36.   HMA_not_allocated               = $93;
  37.   A20_line_still_enabled          = $94;
  38.   All_extended_memory_allocated   = $A0;
  39.   All_available_handles_allocated = $A1;
  40.   Invalid_handle                  = $A2;
  41.   Invalid_source_handle           = $A3;
  42.   Invalid_source_offset           = $A4;
  43.   Invalid_destination_handle      = $A5;
  44.   Invalid_destination_offset      = $A6;
  45.   Invalid_length                  = $A7;
  46.   Invalid_move_overlap            = $A8;
  47.   Parity_error_occurred           = $A9;
  48.   EMB_not_locked                  = $AA;
  49.   EMB_locked                      = $AB;
  50.   EMB_lock_count_overflowed       = $AC;
  51.   Lock_failed                     = $AD;
  52.   Only_smaller_UMB_available      = $B0;
  53.   No_UMB_available                = $B1;
  54.   Invalid_UMB_segment_number      = $B2;
  55.   Not_installed                   = $FF;
  56.  
  57. (* ------------ Nützliche Typdeklarationen -------------- *)
  58.  
  59. TYPE                          (* Speicherbeschreibungstyp *)
  60.   Descriptor = RECORD
  61.                  CASE RAM : BOOLEAN OF
  62.                    FALSE : (Handle  : WORD;
  63.                             Offset  : LONGINT);
  64.                    TRUE  : (Address : POINTER);
  65.                END;
  66.  
  67. (* ----------------- Fehlerbehandlung ------------------- *)
  68.  
  69. VAR
  70.   Installed : BOOLEAN;                (* XMM installiert? *)
  71.   Result : BYTE;    (* Fehlercode des letzten XMM-Aufrufs *)
  72.  
  73. (* -------------- High-Memory-Funktionen ---------------- *)
  74.  
  75. PROCEDURE GetVersion(VAR Version, Revision : WORD);
  76. FUNCTION  HMA_Avail : BOOLEAN;
  77. FUNCTION  RequestHMA(BytesNeeded : WORD) : BOOLEAN;
  78. PROCEDURE ReleaseHMA;
  79. PROCEDURE GlobalEnableA20;
  80. PROCEDURE GlobalDisableA20;
  81. PROCEDURE LocalEnableA20;
  82. PROCEDURE LocalDisableA20;
  83. FUNCTION  A20Enabled : BOOLEAN;
  84.  
  85. (* ------------ Extended-Memory-Funktionen -------------- *)
  86.  
  87. PROCEDURE QueryMemory(VAR MemAvail, MaxAvail : WORD);
  88. FUNCTION  AllocateMemory(KBytesNeeded : WORD) : WORD;
  89. PROCEDURE DeallocateMemory(Handle : WORD);
  90. PROCEDURE MoveMemory(VAR Source, Destination : Descriptor;
  91.                          WordCount : LONGINT);
  92. FUNCTION  LockMemory(Handle : WORD) : LONGINT;
  93. PROCEDURE UnlockMemory(Handle : WORD);
  94. PROCEDURE GetHandleInfo(Handle : WORD; VAR KBytes : WORD;
  95.                         VAR LockCount, FreeHandles : BYTE);
  96. PROCEDURE ReallocateMemory(Handle, KBytes : WORD);
  97.  
  98. (* ------------------------------------------------------ *)
  99.  
  100. IMPLEMENTATION
  101.  
  102. CONST
  103.   Multiplex = $2F;     (* Nummer des Multiplex-Interrupts *)
  104.  
  105. VAR
  106.   EntryPoint : POINTER; (* Einsprungadresse für XMM-Aufr. *)
  107.   Regs : Registers;      (* für Kommunikation mit dem XMM *)
  108.  
  109. (* -------------------- XMM-Aufruf ---------------------- *)
  110.  
  111. PROCEDURE XMM(Call : BYTE);
  112.   (* führt einen XMM-Funktionsaufruf aus; die Funktions-
  113.      nummer (0..11h) wird dazu in das AH-Register geladen.
  114.      Bei AX=1 wurde die Funktion ordnungsgemäß ausgeführt,
  115.      bei AX=0 weist der Inhalt von BL (-> Result) auf die
  116.      genaue Fehlerursache (siehe Fehlercodes oben) hin.   *)
  117. BEGIN
  118.   IF NOT Installed THEN
  119.     Result := Not_installed
  120.   ELSE BEGIN
  121.     Regs.AH := Call;             (* Funktionsnummer laden *)
  122.     WITH Regs DO BEGIN
  123.       Inline(
  124.       $8D/$3E/Regs/(* lea  di,[Regs]  ;Basisadresse Regs  *)
  125.       $4F/         (* dec  di         ;Basis-Korrektur    *)
  126.       $57/         (* push di         ;<di> sichern       *)
  127.       $1E/         (* push ds         ;<ds> sichern...    *)
  128.       $1E/         (* push ds         ;...zur Referenz... *)
  129.       $07/         (* pop  es         ;...nach <es> holen *)
  130.       $8B/$85/AX/  (* mov  ax,[di+AX] ;Register mit den   *)
  131.       $8B/$9D/BX/  (* mov  bx,[di+BX] ;Eingangsparametern *)
  132.       $8B/$95/DX/  (* mov  dx,[di+DX] ;besetzen           *)
  133.       $8B/$B5/SI/  (* mov  si,[di+SI] ;                   *)
  134.       $8E/$9D/DS/  (* mov  ds,[di+DS] ;                   *)
  135.       $26/$FF/$1E/
  136.        EntryPoint/ (* call far es:[..];XMM-Funktion rufen *)
  137.       $1F/         (* pop  ds         ;<ds> restaurieren  *)
  138.       $5F/         (* pop  di         ;Basisadresse holen *)
  139.       $89/$85/AX/  (* mov  [di+AX],ax ;Ausgaben wieder    *)
  140.       $89/$9D/BX/  (* mov  [di+BX],bx ;in Regs-Variablen  *)
  141.       $89/$95/DX); (* mov  [di+DX],dx ;unterbringen       *)
  142.       IF AX = $0001 THEN
  143.         Result := Ok
  144.       ELSE BEGIN
  145.         Result := BL;
  146.       END;
  147.     END;
  148.   END;
  149. END;
  150.  
  151. (* -------------- High-Memory-Funktionen ---------------- *)
  152.  
  153. PROCEDURE GetVersion(VAR Version, Revision : WORD);
  154.   (* erfragt die Version und die interne Revisionsnummer
  155.      der XMS-Software; beide Nummern sind als 16-Bit BCD-
  156.      codierte Zahlen aufzufassen (0206h = Version 2.06).  *)
  157. BEGIN
  158.   XMM($00);
  159.   Version  := Regs.AX;                     (* XMS-Version *)
  160.   Revision := Regs.BX;         (* interne Revisionsnummer *)
  161. END;
  162.  
  163. FUNCTION HMA_Avail : BOOLEAN;
  164.   (* prüft, ob die High Memory Area vorhanden ist.        *)
  165. BEGIN
  166.   XMM($00);
  167.   HMA_Avail := (Regs.DX = 1);       (* existiert die HMA? *)
  168. END;
  169.  
  170. FUNCTION RequestHMA(BytesNeeded : WORD) : BOOLEAN;
  171.   (* reserviert Speicher im High Memory; da dieser Bereich
  172.      nur von einem Programm zur Zeit genutzt werden kann,
  173.      empfiehlt sich in der Regel die Reservierung der ma-
  174.      ximal möglichen HMA-Kapazität (BytesNeeded = $FFFF).
  175.      Bei Erfolg liefert die Funktion den Wert TRUE.       *)
  176. BEGIN
  177.   Regs.DX := BytesNeeded;    (* gewünschte Größe in Bytes *)
  178.   XMM($01);
  179.   RequestHMA := (Result = Ok);
  180. END;
  181.  
  182. PROCEDURE ReleaseHMA;
  183.   (* Freigabe des mit "RequestHMA" reservierten Bereichs. *)
  184. BEGIN
  185.   XMM($02);
  186. END;
  187.  
  188. PROCEDURE GlobalEnableA20;
  189.   (* schaltet die Adreßleitung A20 frei und ermöglicht
  190.      mit der Steuerung dieser Leitung durch die CPU den
  191.      Zugriff auf das High Memory (der Bereich FFFF:????). *)
  192. BEGIN
  193.   XMM($03);
  194. END;
  195.  
  196. PROCEDURE GlobalDisableA20;
  197.   (* sperrt die Adreßleitung A20 und verhindert Zugriffe
  198.      auf das High Memory; diese Funktion sollte am Ende
  199.      eines Programms unbedingt ausgeführt werden!         *)
  200. BEGIN
  201.   XMM($04);
  202. END;
  203.  
  204. PROCEDURE LocalEnableA20;
  205.   (* ermöglicht in Verbindung mit "LocalDisableA20" ein
  206.      verschachteltes Freischalten/Sperren von A20.        *)
  207. BEGIN
  208.   XMM($05);
  209. END;
  210.  
  211. PROCEDURE LocalDisableA20;
  212.   (* ermöglicht in Verbindung mit "LocalEnableA20" ein
  213.      verschachteltes Freischalten/Sperren von A20.        *)
  214. BEGIN
  215.   XMM($06);
  216. END;
  217.  
  218. FUNCTION A20Enabled : BOOLEAN;
  219.   (* gibt an, ob die Adreßleitung A20 durch die CPU ge-
  220.      steuert werden kann.                                 *)
  221. BEGIN
  222.   XMM($07);
  223.   A20Enabled := (Regs.AX = 1);     (* A20 freigeschaltet? *)
  224. END;
  225.  
  226. (* ------------ Extended-Memory-Funktionen -------------- *)
  227.  
  228. PROCEDURE QueryMemory(VAR MemAvail, MaxAvail : WORD);
  229.   (* erfragt die Gesamtgröße des noch freien Extended Me-
  230.      mory (abzüglich HMA) und die Länge des größten, noch
  231.      freien Blocks. All Angaben sind in KByte gemeint.    *)
  232. BEGIN
  233.   XMM($08);
  234.   MemAvail := Regs.DX;  (* insgesamt freier Speicherplatz *)
  235.   MaxAvail := Regs.AX;        (* Länge des größten Blocks *)
  236. END;
  237.  
  238. FUNCTION AllocateMemory(KBytesNeeded : WORD) : WORD;
  239.   (* reserviert einen Bereich im Extended Memory (EMB)
  240.      und gibt das mit dem Block assoziierte Handle zurück.*)
  241. BEGIN
  242.   Regs.DX := KBytesNeeded;  (* gewünschte Größe in KBytes *)
  243.   XMM($09);
  244.   AllocateMemory := Regs.DX; (* Handle des Speicherblocks *)
  245. END;
  246.  
  247. PROCEDURE DeallocateMemory(Handle : WORD);
  248.   (* gibt einen reservierten Speicherblock wieder frei    *)
  249. BEGIN
  250.   Regs.DX := Handle;         (* Handle des Speicherblocks *)
  251.   XMM($0A);
  252. END;
  253.  
  254. PROCEDURE MoveMemory(VAR Source, Destination : Descriptor;
  255.                          WordCount : LONGINT);
  256.   (* kopiert einen Bereich der Länge "WordCount" zwischen
  257.      Hauptspeicher und Extended Memory oder innerhalb ei-
  258.      nes dieser Speicher. Quell- (Source) und Zielbereich
  259.      (Destination) sind dabei wie folgt zu spezifizieren:
  260.      bei Hauptspeicher ist die Adresse mit Segment:Offset
  261.      des Bereichs zu besetzen. Bereiche im Extended Memory
  262.      werden durch Angabe des Handles und des linearen 32-
  263.      Bit-Offsets im Speicherblock (EMB) gekennzeichnet.
  264.      Kopiervorgänge mit überlappenden Quell- und Zielbe-
  265.      reichen sind nur dann erlaubt, wenn die Quelladresse
  266.      kleiner als die Zieladresse ist.                     *)
  267. VAR
  268.   Desc : RECORD         (* Datenstruktur für Funktion 0Bh *)
  269.            BytesToMove       : LONGINT;
  270.            SourceHandle      : WORD;
  271.            SourceOffset      : LONGINT;
  272.            DestinationHandle : WORD;
  273.            DestinationOffset : LONGINT;
  274.          END;
  275. BEGIN
  276.   WITH Desc DO BEGIN
  277.     BytesToMove := WordCount * 2;
  278.     IF Source.RAM THEN BEGIN
  279.       SourceHandle := 0;
  280.       SourceOffset := LongInt(Source.Address);
  281.     END ELSE BEGIN
  282.       SourceHandle := Source.Handle;
  283.       SourceOffset := Source.Offset;
  284.     END;
  285.     IF Destination.RAM THEN BEGIN
  286.       DestinationHandle := 0;
  287.       DestinationOffset := LongInt(Destination.Address);
  288.     END ELSE BEGIN
  289.       DestinationHandle := Destination.Handle;
  290.       DestinationOffset := Destination.Offset;
  291.     END;
  292.   END;
  293.   Regs.DS := Seg(Desc);  (* Deskriptor-Adresse nach DS:SI *)
  294.   Regs.SI := Ofs(Desc);
  295.   XMM($0B);
  296. END;
  297.  
  298. FUNCTION LockMemory(Handle : WORD) : LONGINT;
  299.   (* verriegelt einen Speicherblock gegen das Verlagern
  300.      durch den XMM; zurückgegeben wird die lineare 32-Bit
  301.      Adresse des Speicherblocks im Extended Memory.       *)
  302. BEGIN
  303.   Regs.DX := Handle;         (* Handle des Speicherblocks *)
  304.   XMM($0C);
  305.   LockMemory := LongInt(Ptr(Regs.DX, Regs.BX));(* Adresse *)
  306. END;
  307.  
  308. PROCEDURE UnlockMemory(Handle : WORD);
  309.   (* entriegelt einen gegen Verlagerungen durch den XMM
  310.      im Extended Memory geschützten Speicherblock.        *)
  311. BEGIN
  312.   Regs.DX := Handle;         (* Handle des Speicherblocks *)
  313.   XMM($0D);
  314. END;
  315.  
  316. PROCEDURE GetHandleInfo(Handle : WORD; VAR KBytes : WORD;
  317.                         VAR LockCount, FreeHandles : BYTE);
  318.   (* erfragt Informationen zu einem Speicherblock         *)
  319. BEGIN
  320.   Regs.DX := Handle;         (* Handle des Speicherblocks *)
  321.   XMM($0E);
  322.   KBytes      := Regs.DX;   (* Größe des Blocks in KBytes *)
  323.   LockCount   := Regs.BH;   (* Anzahl verriegelter Blöcke *)
  324.   FreeHandles := Regs.BL;   (* Anzahl noch freier Handles *)
  325. END;
  326.  
  327. PROCEDURE ReallocateMemory(Handle, KBytes : WORD);
  328.   (* verändert die Größe eines Speicherblocks             *)
  329. BEGIN
  330.   Regs.DX := Handle;         (* Handle des Speicherblocks *)
  331.   Regs.BX := KBytes;   (* neue Größe des Blocks in KBytes *)
  332.   XMM($0F);
  333. END;
  334.  
  335. (* --------------- Installationsroutinen ---------------- *)
  336.  
  337. PROCEDURE CheckForXMM(Var XMM_Found : BOOLEAN);
  338.   (* prüft, ob der XMM installiert ist.                   *)
  339. VAR
  340.   Regs : Registers;
  341. BEGIN
  342.   Regs.AX := $4300;           (* "XMS Installation Check" *)
  343.   Intr(Multiplex, Regs);
  344.   XMM_Found := (Regs.AL = $80);       (* XMM installiert? *)
  345. END;
  346.  
  347. FUNCTION DriverEntryPoint : POINTER;
  348.   (* ermittelt die Einsprungadresse für XMM-Aufrufe.      *)
  349. VAR
  350.   Regs : Registers;
  351. BEGIN
  352.   Regs.AX := $4310;           (* "Get XMS Driver Address" *)
  353.   Intr(Multiplex, Regs);
  354.   DriverEntryPoint := Ptr(Regs.ES, Regs.BX);   (* Adresse *)
  355. END;
  356.  
  357. BEGIN                               (* Initialierungsteil *)
  358.   CheckForXMM(Installed);
  359.   IF Installed THEN BEGIN
  360.     EntryPoint := DriverEntryPoint;   (* Einsprungadresse *)
  361.   END;
  362. END.
  363. (* ------------------------------------------------------ *)
  364. (*                   Ende von XMS.PAS                     *)
  365.