home *** CD-ROM | disk | FTP | other *** search
-
- Rumtreiben im Speicher
-
- EMS selbstprogrammiert
- von Karsten Gieselmann
-
- Die als Einheitentreiber EMM.SYS beziehungsweise HIMEM.SYS
- einzubindenden Memory Manager für Expanded Memory (EMM)
- beziehungsweise Extended Memory (XMM) stellen alle nötigen
- Routinen bereit, um vorhandene Erweiterungsspeicher sinnvoll zu
- nutzen. Diese Leistungen sind, wie auch alle anderen systemnahen
- Dienste des PCs per Interrupt abzurufen. Funktionsnummer und
- Parameter müssen dabei vor dem Aufruf in CPU-Registern abgelegt
- werden, diese enthalten bei Rückkehr auch die erfragten Daten.
- Die Ansteuerung der Verwaltungssoftware aus einer Hoch-
- sprachenapplikation nimmt sinnvollerweise den Umweg über
- Bibliotheksmodule, die dem Programmierer die von den Memory
- Managern implementierten Dienste in einer der Hochsprache ange-
- messenen Form anbieten.
- Eine Vielzahl der PC-Implementationen von Hochsprachencompilern
- bietet heute die Möglichkeit hardwarenah zu programmieren, so
- daß es kein Problem sein sollte, die vorliegenden Pascal-Quellen
- in eine andere Sprache zu portieren.
-
- EMS-Interruptspezifikation als Pascal-Quelltext
-
- Dreh- und Angelpunkt der EMS-Verwaltung ist der Interrupt 67h,
- die Schnittstelle zum EMM. Waren bei LIM EMS 3.2 noch ganze 13
- Funktionen für das Management des Expanded Memory zuständig,
- wuchs diese Zahl mit der Absegnung von LIM EMS 4.0 auf 28 Funk-
- tionen mit insgesamt 54 verschiedenen Aufrufmöglichkeiten
- (Unterfunktionen).
- Das Unit EMS implementiert alle gebräuchlichen Funktionen des
- Standards LIM EMS 3.2 (die Funktionen 49h/4Ah sind reserviert)
- sowie eine Untermenge der neu hinzugekommenen Dienste der
- Version 4.0. Der Leistungsumfang von LIM EMS 3.2 reicht für die
- vernünftige Nutzung von Expanded Memory in eigenen Programmen
- zwar vollkommen aus, trotzdem bietet der erweiterte aktuelle
- Standard einige nützliche und interessante Ergänzungen. Auf eine
- aufwendige Fehlerbehandlung wurde aus Platzgründen verzichtet.
- Ähnlich der Behandlung von Fehlern beim File-I/O in Turbo Pascal
- kann das Ergebnis jedes EMM-Funktionsaufrufs in "Result" inspi-
- ziert werden. Ein Vergleich dieses Codes mit den als Konstanten
- deklarierten Klartext-Fehlermeldungen erlaubt jederzeit ein
- genaue Beurteilung der durchgeführten Operation. Gleiches gilt
- für die weiter unten besprochene Unit XMS zur Ansteuerung des
- Extended Memory Manager.
- Auch wurde darauf verzichtet, die Spezifikationen der EMS- und
- XMS-Funktionen extra aufzuführen. Die Prozedurrümpfe in beiden
- Units bestehen fast ausschließlich aus Register-I/O, was bei den
- ausführlichen Kommentaren zum Verständnis und als Grundlage zur
- Portierung für andere Sprachen vollkommen ausreicht. Um Code-
- und INTERFACE-Dokumentation nicht auseinanderzureißen, befindet
- sich die Beschreibung der exportierten Bezeichner deshalb aus-
- nahmsweise auch nicht im INTERFACE, sondern im IMPLEMENTATION-
- Teil. Auch wurden die Aufrufe fast ausnahmslos in der
- ursprünglichen Form belassen. Optimierungen sind sicherlich in
- einigen Fällen (zum Beispiel Abfrage nach freiem Speicher)
- sinnvoll, eine Realisierung bleibt der Phantasie des Lesers
- überlassen.
-
- Da oder nicht da?
-
- In der ersten Abbildung werden die typischen Schritte einer EMS
- benutzenden Applikation gezeigt. Zunächst ist zu prüfen, ob auch
- wirklich ein EMM vorhanden ist, da Aufrufe eines unbelegten
- Interrupts den Rechner nämlich mit ziemlicher Sicherheit ins
- "Nirwana" befördert. Das Unit EMS prüft deshalb im
- Initialisierungsteil, ob ein EMM eingebunden ist und setzt
- dementsprechend den Schalter (boolsche Variable) "Installed".
- Es gibt im wesentlichen zwei Möglichkeiten, die Existenz eines
- EMM nachzuweisen [4]. Da es sich bei dieser Software um einen
- Einheitentreiber mit dem Namen "EMMXXXX0" handelt, kann man
- versuchen, mit der DOS-Funktion 3Dh ("Open Handle") eine Datei
- beziehungsweise ein logisches Gerät mit diesem Namen zu öffnen.
- In Turbo Pascal würde man dazu folgendermaßen vorgehen
-
-
- Assign(f, 'EMMXXXX0');
- {$I-} Reset(f); {$I+}
- EMM_Exists := (IoResult = 0);
-
- Diese Methode hat allerdings den Nachteil, daß sie zum einen
- nicht unbedingt schnell ist, zum anderen besteht wenigstens
- theoretisch die Möglichkeit, daß eine gleichnamige Disketten-
- datei fälschlicherweise für den Treiber gehalten wird. Deshalb
- schlägt die Routine "CheckForEMM" im Unit EMS einen anderen Weg
- ein. Hier wird von der Tatsache Gebrauch gemacht, daß der Name
- eines Einheitentreibers immer ab Offset 0Ah im Codesegment des
- Treibers eingetragen ist. Nach Beschaffung der Segmentadresse
- über die DOS-Funktion 35h ("Get Interrupt Vector") reicht es
- dann aus, den Inhalt der Speicherstellen 0Ah..12h mit der
- Zeichenkette "EMMXXXX0" zu vergleichen.
-
- ...'ran an den Speicher!
-
- Wurde die Existenz eines EMM bestätigt, kann im nächsten Schritt
- die benötigte Menge an Speicherseiten (Blöcke a 16 KByte)
- angefordert werden ("AllocateMemory"). Steht eine genügende
- Menge an Expanded Memory zur Befriedigung der Anfrage bereit,
- sollte noch der aktuelle Zustand des EMS-Fensters (page frame)
- gesichert werden ("SavePageMap"), bevor es dann richtig losgeht.
- Die Benutzung der Funktionen "SavePageMap" am Anfang und
- "RestorePageMap" am Ende eines Programms stellt sicher, daß die
- betreffende Anwendung in Ruhe mit Expanded Memory arbeiten kann,
- ohne einem anderen, ebenfalls EMS nutzenden Prozeß das
- PageFrame-Fenster durcheinander zu bringen. Diese Operation ist
- zwar in erster Linie für TSR's und Multitasker gedacht, doch ist
- die Durchführung auch für gewöhnliche, geschachtelte Prozesse
- notwendig. Schaden kann es auf keinen Fall, zumal der für die
- Sicherung benötigte Speicherplatz bereits vom EMM reserviert
- ist.
-
- Nach diesem "Vorgeplänkel" steht einer Benutzung des Expanded
- Memory nun nichts mehr im Weg. Der in logische Seiten (0..N-1)
- unterteilte EMS-Speicher kann nach Belieben in die vier
- physikalischen Seiten (0..3) eingeblendet ("MapMemory") und
- beschrieben werden (PageFrameSegment:0000h, 4000h, 8000h,
- C000h). Welche Daten in den logischen Seiten ablegt und wie sie
- innerhalb der Seiten organisiert werden, ist allein Sache des
- Programmierers. Beispiele dazu finden Sie in "ASCII.EMS" und
- "BIGARRAY.PAS".
- Sind alle Transfers von und zum EMS-Speicher abgeschlossen,
- sollte der ursprüngliche Fensterzustand wiederhergestellt werden
- ("RestorePageMap"). Ferner muß man den am Anfang angeforderten
- EMS-Speicher wieder freigegeben ("DeallocateMemory"), soll er
- nicht bis zum nächsten Reset verloren sein. Dabei muß beachtet
- werden, daß der Fensterzustand in Verbindung mit einem Handle
- gespeichert wird. Daher muß das Fenster vor der Freigabe
- restauriert werden, da das Handle anderenfalls ja nicht mehr
- definiert wäre. Der EMM unterstützt den Programmierer in diesem
- Fall sogar noch etwas, da er die Freigabe von Speicher, zu dem
- noch ein gesicherter Fensterzustand existiert, gar nicht erst
- erlaubt.
-
- Speicher beim Namen nennen
-
- Eine Vielzahl der unter LIM EMS 4.0 neu hinzugekommenen
- Funktionen unterstützen hardwarespezifische Features wie
- Resetfestigkeit oder alternative Registersätze. Diese
- Eigenschaften sind allerdings nur auf EMS-Speicherkarten
- vorzufinden. Bei den weitverbreiteten EMS-Emulatoren (NEAT,
- 80386, Software) sucht man derartige Spezialitäten vergeblich,
- weshalb sie auch keine Berücksichtigung im EMS-Unit finden.
-
- Nichtsdestotrotz bietet die Version 4.0 eine Reihe nützlicher,
- auch auf Emulatoren verfügbare Erweiterungen. So ist es möglich,
- einem EMS-Bereich einen bis zu acht Buchstaben langen Namen
- zuzuordnen. Die Zeichenkette ist dabei als nullterminierter
- Ascii-String zu behandeln. Diese Option ist besonders für
- residente Programme mit EMS-Benutzung interessant. Durch solche
- Anwendungen ständig belegtes Expanded Memory kann anhand der
- Kennung anschaulich dem benutzenden Programm zugeordnet werden.
- Dieses Feature nutzt das Programm "EMSINFO.PAS" aus. Mit dieser
- Technik kann man auch erkennen, ob sich ein TSR-Programm bereits
- im Speicher breit gemacht hat.
- Ein weiterer Schwerpunkt ist die Vereinfachung des
- Datentransfers zwischen RAM und EMS. Die Funktionen "MoveMemory"
- und "ExchangeMemory" erlauben einen Datenaustausch zwischen
- beiden Speichern, ohne daß ein Ein- oder Ausblenden
- irgendwelcher Speicherseiten notwendig wäre. Außerdem ist es
- möglich, Daten direkt innerhalb des Expanded Memory ohne Umweg
- über das RAM zu verschieben.
- Man sollte sich als Programmierer allerdings im Klaren darüber
- sein, daß die Verwendung solcher Spezialitäten den Anwenderkreis
- einer Applikation auf die Gruppe derjenigen einschränkt, die mit
- LIM EMS 4.0 arbeiten. Diese Spezifikation avanciert zwar
- zunehmend zum Standard, doch ist die Anzahl der im Gebrauch
- befindlichen LIM EMS 3.2 Konfigurationen nicht unbeträchtlich.
- Da die betreffenden Dienste nicht unbedingt lebensnotwendig für
- ein Programm sind, sollten darauf basierende Features optional
- angeboten werden wie in "EMSINFO.PAS".
- Anwendungsmodule selbst der exotischsten Funktionen, wie zum
- Beispiel eine Unit zur Verwaltung von Riesenarrays im
- Erweiterungsspeicher, finden Sie zusammen mit vielen nützlichen
- Anwendungen auf der toolbox-Special-Diskette, die in dieser
- Ausgabe vorgestellt wird.
-
- Qualifizierte Dienste
-
- Das Extended-Memory-Gegenstück zu "EMS.PAS" ist die Unit
- "XMS.PAS". Es implementiert alle Routinen zum Datentransfer mit
- der "High Memory Area" und Extended Memory. Unter der "High
- Memory Area" -- kurz HMA -- versteht man die ersten 64 KByte
- oderhalb der 1-MB-Grenze, während das Extended Memory oberhalb
- der HMA beginnt.
- Die Upper Memory Area -- kurz UMA, Speicher zwischen 640 KByte
- und 1 MByte -- wurde nicht berücksichtigt, da die für diesen
- Bereich zuständigen Funktionen speziell im XMM implementiert
- werden müssen. Die in [2] vorgeschlagene Lösung zur Nutzung
- dieses Speichers ist ohnehin ungleich effizienter und auch
- einfacher.
- Beim Schnittstellenentwurf der beiden Units ergab sich das
- Problem, wie die vielen ähnlichen, aber auf unterschiedliche
- Speicher bezogenen Dienste verpackt werden sollten. Die Vergabe
- von unterschiedlichen Bezeichnern (zum Beispiel durch
- Integration des Speichertyps in die Bezeichner) fördert
- sicherlich nicht die Transparenz, vermeidet dafür aber
- Verwechslungen bei Verwendung beider Units in einem Programm.
- Das Problem ergibt sich wegen des Tatbestand, daß eim
- Exportieren eines gleichlautenden Bezeichners aus mehrere
- Units die Herkunft des vom Hauptprogramm tatsächlich
- importierten Bezeichners von der Reihenfolge der Units im USES-
- Statement abhängig.
- Eine elegante Kombination beider Forderungen auf
- Freiwilligenbasis erlaubt die sogenannte Qualifizierung der Be-
- zeichner. Hiermit ist die eindeutige Herkunftsbestimmung eines
- Bezeichners durch Voranstellen des Modulnamens gemeint (zum
- Beispiel "EMS.AllocateMemory"). So wurde, wo irgend möglich, auf
- eine peinlichst genaue Übereinstimmung in Syntax (formal) und
- Semantik (funktional) geachtet. Um Verwechslungen zu vermeiden,
- können Bezeichner mit den Kürzeln "EMS." beziehungsweiise "XMS."
- qualifiziert werden ("MEMORY.PAS"). Auch wenn nur die Dienste
- eine der beiden Units in Anspruch genommen werden, gewährleistet
- diese Vorgehensweise eine deutlich bessere Lesbarkeit des Pro-
- grammtextes wie das Programm "EMSINFO.PAS" demonstriert. Soll
- bewußt nur eine der beiden Units Verwendung finden, ist es mit
- dem Weglassen des Qualifizierers auch möglich, allein durch
- Austausch des Units im USES-Statement das Programm vollständig
- auf einen anderen Speichertyp umzustellen.
-
- Extrawurst
-
- Obwohl die Schöpfer der XMS-Spezifikation (Lotus, Intel,
- Microsoft) beim Funktionslayout größere Anleihen bei ihrer
- Erstgeburt EMS machten, mußte doch wieder eine Extrawurst
- gebraten werden. Die Kommunikation mit dem XMM läuft nämlich
- nicht wie bei EMS über einen Interrupt ab, sondern hochspra-
- chenfeindlich über Far Calls einer über den Multiplex-Interrupt
- 2Fh zu besorgenden Adresse. Dieser Umstand erfordert in Turbo
- Pascal einige Inline-"Pfriemeleien", bei anderen Compilern (zum
- Beispiel JPI Topspeed Modula-2) kommt man um einen eigenstän-
- digen Assemblerteil nicht herum. Lobenswerterweise ist dafür
- aber ein genormter Installationscheck im Multiplex-Interrupt
- vorgesehen ("CheckForXMM").
-
- Hoch hinaus
-
- Ausgesprochen einfach gestaltet sich die Benutzung der HMA als
- zusätzlicher Speicher in eigenen Programmen. Vorausgesetzt, die
- knapp 64 KByte oberhalb der 1 MByte-Grenze reichen für den
- Bedarf aus und sind noch nicht anderweitig belegt. Darüber
- hinaus ergibt sich ein nicht unbeträchtlicher
- Geschwindigkeitsvorteil gegenüber Extended Memory, da für HMA-
- Zugriffe keine Umschaltung zwischen Real und Protected Mode
- notwendig ist.
- Den Rumpf einer typischen HMA-Anwendung finden Sie in der
- zweiten Abbildung. Nach dem üblichen Vorgespräch (XMM
- installiert, HMA vorhanden und frei?) ist lediglich das
- Freischalten der Prozessorleitung A20 erforderlich, um
- Adreßberechnungen mit FFFFh:???? nicht wieder am Speicheranfang
- 0000h:???? sondern im Gebiet oberhalb 1 MByte enden zu lassen.
- Unter der Beachtung, daß sich die ersten 16 Bytes noch im
- Adreßraums des BIOS befinden, kann der restliche Speicher ab
- FFFFh:10h nun wie normales RAM angesprochen werden, wie Sie im
- PRogramm "ASCII.HMA" sehen können. Am Programmende
- beziehungsweise nach abgeschlossener Benutzung sollte A20 wieder
- gesperrt werden, um die Kompatibilität bei Adreßberechnungen zu
- gewährleisten.
-
- Der erste Blick kann täuschen
-
- Obwohl die Anfoderung von Extended Memory der von EMS sehr
- ähnlich ist, wie Abbildung drei zeigt, ergeben sich bei der
- Benutzung, also Lesen und Schreiben, doch signifikante
- Unterschiede. Während LIM EMS mit dem PageFrame-Fenster
- praktisch einen (mit 64 KByte recht großen) Puffer für den
- Datentransfer zu Verfügung stellt, ist der Programmierer beim
- Einsatz von Extended Memory selbst für die Pufferung der Daten
- verantwortlich. Daten werden direkt zwischen RAM und
- Erweiterungsspeicher befördert oder verschoben ("MoveMemory")
- beziehungsweise ausgetauscht ("ExchangeMemory"). Dafür kann
- Extended Memory aber auch in kleineren Portionen á 1 KByte
- allokiert werden, die Größe der zu transferierenden Daten ist
- gar bis auf 1 Wort genau spezifizierbar. Genau wie bei der
- Benutzung von EMS muß auch angefordertes Extended Memory bei
- Programmende wieder explizit freigegeben werden, falls es nicht
- bis zum nächsten Reset "verschwunden" sein soll.
-
- Nützliches rund um die Erweiterungsspeicher
-
- Nachdem zu Anschauungszwecken schon vielfach auf Programme und
- Programmteile hingewiesen wurde, sollen an dieser Stelle noch
- einige Erklärungen zu den diversen Quellen erfolgen. Alle
- Programme sind sowohl unter Turbo Pascal 4.0 als auch den
- Versionen 5.0 und 5.5 kompilierbar.
- "MEMORY.PAS" gibt einen Gesamtüberblick über alle installierten
- RAM/Expanded/Extended Memory Kapazitäten. Neben der Größe von
- belegtem und noch freiem Speicher erfährt man auch die
- Versionsnummer der zuständigen Verwaltungssoftware.
- Wer Genaueres über den Zustand seines Expanded Memory wissen
- will, ist mit "EMSINFO.PAS" gut bedient. Neben De-
- tailinformationen zur Organisation und Gesamtbelegung des EMS
- wird auch eine Art Directory angezeigt, welches zu jedem offenen
- Handle den belegten Speicher und - falls gesetzt - den Namen
- enthält.
- Weitere Dienstprogramme, die aus Platzgründen nicht
- veröffentlicht werden konnten, finden Sie auf der entsprechenden
- toolbox-Special-Diskette dieser Ausgabe:
- - Gute Dienste leistet "WIPEEMS.PAS". Dieses Utility löst das
- Problem der "verlorenen" EMS-Speicherseiten. In einem Programm
- fälschlicherweise nicht wieder freigegebenes Expanded Memory
- (zum Beispiel durch Laufzeitfehler-Abbruch) wird durch "WIPEEMS"
- wieder verfügbar gemacht. Die Syntax ist dem Programmtext bezie-
- hungsweise der Ausgabe bei einem Aufruf ohne Parameter zu
- entnehmen.
- - Eine simple Verwaltung von zweidimensionalen Feldern im
- Erweiterungsspeicher bietet die Unit "BIGARRAY.PAS". Je nach
- Zustand des Schalters "UseEms" für die bedingte Kompilierung
- wird Expanded oder Extended Memory zur Speicherung benutzt. Die
- Unit ist ein schönes Beispiel, wie transparent die Routinen von
- EMS und XMS benutzt werden können.
-
- PC-Zeichensatz im Griff
-
- - Last but not least wurde der speicherresidente Zeichensatz
- "ASCII.PAS" als Anwendungsdemonstration in die Special-Disk
- miteinbezogen. Dem Programm liegen vier verschiedene Includes
- (".RAM", ".HMA", ".XMS", ".EMS") bei, so daß jeder Leser dieses
- Utility auf seiner Konfiguration zum Laufen bekommen sollte. Die
- nicht gewünschten Speichertypen sind vor dem USES-Statement
- "auszudokumentieren". Das Programm belegt im RAM ca. 14 KByte,
- bei Benutzung eines der drei Erweiterungsspeicher sind es dann
- gute 5 KByte weniger.
- Anhand dieses Programms kann also gut beobachtet werden, wie man
- Speicherplatz unter Verwendung von Expanded- und Extended-Memory
- einsparen kann. Nur der Traum vieler Programmierer, ausführbaren
- Code normaler Programm in den EMS/XMS-Speicher zu legen, harrt
- noch einer Lösung. Da dem Programmierer naturgemäß nichts zu
- schwer ist, ist dies aber wohl auch nur eine Frage der Zeit.
- (ms)
-
-
-
- Literatur
-
-
- [1] Karsten Gieselmann: "640 Kilobyte - oder darf es etwas
- mehr sein?", Toolbox 3/89
- [2] Martin Ernst: "Treiber verschiebt Treiber", c't 8/89
- [3] Günter Born: "Das MS-DOS Programmierhandbuch", Mark &
- Technik 1989
- [4] Dave Williams: "Programming Technical Reference", Public
- Domain 1988
- [5] Ralf Brown: "IBM PC Interrupt List", Public Domain 1989
-
-
- Abbildungen
-
-
- +-----------------------------------------------+| |
- | BEGIN |
- | IF Installed THEN BEGIN |
- | Handle := AllocateMemory(Pages); |
- | IF Result = Ok THEN BEGIN |
- | SavePageMap(Handle); |
- | { Benutzung von EMS } |
- | RestorePageMap(Handle); |
- | DeallocateMemory(Handle); END |
- | ELSE |
- | { Nicht genügend Speicher! } END |
- | ELSE |
- | { EMM nicht installiert! } |
- | END. |
- | |
- +------------------------------------------------+
- Abb.1: Die typischen Schritte eines Programms
- zur Benutzung von Expanded Memory.
-
-
- +------------------------------------------------+
- | |
- | BEGIN |
- | IF Installed THEN |
- | IF HMA_Avail THEN |
- | IF RequestHMA($FFFF) THEN BEGIN |
- | GlobalEnableA20; |
- | { Benutzung von HMA } |
- | GlobalDisableA20; |
- | ReleaseHMA; END |
- | ELSE |
- | { HMA schon belegt! } |
- | ELSE |
- | { HMA nicht vorhanden! } |
- | ELSE |
- | { XMM nicht installiert! } |
- | END. |
- | |
- +------------------------------------------------+
-
- Abb.2: Nach Freischalten der Adreßleitung A20 kann
- die High Memory Area wie gewöhnliches RAM
- angesprochen werden.
-
-
- +------------------------------------------------+
- | |
- | BEGIN |
- | IF Installed THEN BEGIN |
- | Handle := AllocateMemory(KBytes); |
- | IF Result = Ok THEN BEGIN |
- | { Anwendung } |
- | DeallocateMemory(Handle); END |
- | ELSE |
- | { Nicht genügend Speicher! } END |
- | ELSE |
- | { XMM nicht installiert! } |
- | END. |
- | |
- +------------------------------------------------+
-
- Abb.3: Die Anforderung von Extended Memory hat
- verblüffende Ähnlichkeit mit der EMS-
- Verwaltung.
-