Artikel

Jörg Matthaei

Speicherengpaß
entschärft

64 KByte mehr Speicher für den AT

AT-Anwender verschenken kostbaren Arbeitsspeicher; denn über einen Treiber kann die 80286-CPU unter DOS zusätzliche 64 KByte adressieren. Von Microsoft wurde dieser Speicher als high memory area (HMA) spezifiziert. Auch selbstgeschriebene Programme können von HMA profitieren.

Die Prozessoren 8086 und 8088 von Intel können über ihre 20 Adreßleitungen bis zu 1 MByte Arbeitsspeicher adressieren. Dagegen kann eine 80286-CPU auf einen wesentlich größeren Speicher zugreifen: 16 MByte – allerdings nicht unter DOS. Hier bleibt es immer noch bei dem einen Megabyte (Bild 1). Aber mit einem Trick adressiert die 80286-CPU auch unter DOS mehr als 1 MByte RAM.
Die letzte Adresse, auf die eine 8086-CPU oder 8088 zugreifen kann, ist FFFFFh. In der Zwei-Komponentenform, bestehend aus Segment und Offset, heißt genau dieselbe Adresse FFFF:000Fh. Würde der Adreßzeiger um eins erhöht, kommt es zu einem Überlauf auf Adresse 0000:0000h, den Anfang des Arbeitsspeichers. Dieser Überlauf wird auch als address wrap around bezeichnet. Wenn man bei einem 80286-Prozessor die 21. Adreßleitung (A20) aktivieren würde, käme es nicht zu einem Überlauf und der Speicher von FFFF:0010h bis FFFF:FFFFh könnte für Daten und Programme von DOS genutzt werden. Durch diesen kleinen Trick erhält man einen zusätzlichen Speicherbereich – nur 16 Byte kleiner als 64 KByte – der als HMA (high memory area) bezeichnet wird.
1988 hat Microsoft die Extended-Memory-Spezifikation (XMS) entwickelt, die genau festlegt, wie Programmierer extended memory und HMA nutzen sollen. Der XMS-Treiber von Microsoft HIMEM.SYS wird mit der Version 4.0 von DOS oder mit MS-Windows geliefert. Wenn man den HMA-Treiber mit der Anweisung DEVICE = HIMEM.SYS in die Datei CONFIG.SYS eingebunden hat, kann man diesen Speicher über bestimmte Funktionen anfordern oder freigeben.
Das Programm HMA.ASM (Bild 2) gibt einige Beispiele, wie man HMA-Funktionen anwendet. Zuerst prüft es, ob bereits ein XMS-Treiber installiert ist. Anschließend holt es sich die Einsprungadresse für die XMS-Funktionen. Danach wird der HMA-Treiber aufgerufen, wobei im Register DX die Anzahl der anzufordernden Bytes stehen muß. Zum Schluß aktiviert das Programm die Adreßleitung A20. Nun kann man den zusätzlichen Speicherbereich verwenden. Es ist sinnvoll, möglichst viel Programmcode und Daten in diesem Bereich unterzubringen, um die unteren 640 KByte zu entlasten. Wie wird ein schon vorhandenes speicherresidentes Programm in den HMA-Bereich gelegt? Ganz einfach – der Programmcode, die Daten und die Installationsroutine bleiben bis auf die Funktion terminate and stay resident (TSR) unverändert (Bild 3). Der Interrupt 27h oder die DOS-Funktion 31h wird durch die Programmende-Funktion (DOS-Funktion 4Ch) ersetzt. Sodann wird die HMA-Laderoutine (Bild 4) an den bestehenden Quellcode angefügt und vor dem ersten Befehl ein direkter Sprung auf die HMA-Laderoutine eingefügt. Die HMA-Laderoutine, im Programm mit HMA_LOADER bezeichnet, fordert zuerst 64 KByte HMA an und verschiebt das gesamte Programm in diesen Speicherbereich. Anschließend wird das Programm ab dem ursprünglichen Beginn der alten speicherresidenten Routine ausgeführt, und die Interruptvektoren werden verbogen. Sie zeigen jetzt auf das Programm im hohen Speicherbereich.

Übersicht der HMA-Funktionen
AH-Register HMA-Funktionen
00h XMS-Versionsnummer
01h HMA anfordern
02h HMA freigeben
03h A20 global ermöglichen
04h A20 global sperren
05h A20 lokal ermöglichen
06h A20 lokal sperren
07h A20 abfragen

Tips für den Umgang mit HMA

In Programmen, die im hohen Speicherbereich laufen, müssen alle Segmentregister auf das gleiche Segment zeigen. Bei Programmen, die mit dem Speicherüberlauf bei 1 MByte arbeiten, muß vor Verlassen der speicherresidenten Routine die Adreßleitung A20 deaktiviert werden. Programme, die den unteren Bereich des extended memory wie alte VDISK-Versionen benutzen, dürfen nicht gleichzeitig verwendet werden. Wer keinen AT mit extended memory besitzt, kann auch den RAM-Bereich einer EGA oder VGA im Textmodus nutzen. Doch dann darf kein Programm mehr die Videoschnittstelle in den Grafikmodus umschalten. Beim HMA-Lader muß die Adresse, zu der die speicherresidente Routine verschoben werden soll, geändert werden. Bei EGA und VGA ist das Adresse B900h.

Literatur
  1. [1] Chip, Anderson: 64 KByte mehr Speicher adressieren unter DOS,
         MS-System-Journal 1989, März/April.
  2. [2] NCR-DOS Programmers Guide 1985.

 

0000:0000h - 0000:FFFFh (60 KByte) : DOS    —    0001:0000h - 9000:FFFFh (640 KByte) : Programme    —    A000:0000h - B000:FFFFh (768 KByte) : Video-RAM    —    F000:0000h - F000:FFFFh (1 MByte) : BIOS-ROM
Bild 1. Speicherbelegung eines AT unter DOS
;---------------------------------------------------
;  HMA.ASM
;
;  Programm zur Veranschaulichung der HMA-Funktionen
;  des Microsoft Himem.sys Drivers.
;
;  Datum: 06.06.89
;  Autor: Jörg Matthaei
;---------------------------------------------------
;  Macros
display macro   string
        lea     dx,string
        mov     ah,09
        int     21h
endm

cseg    segment 'code'
        assume cs:cseg,ds:cseg,es:cseg

        org     80h
parms   equ     this byte

        org     100h

begin:
        mov     ax,4300h
        int     2Fh                     ; ist ein HMA Treiber instaliert ?
        cmp     al,80h
        jz      hmada

        display msgnohma                ; nein !
fin:    mov     ah,4Ch                  ; Programmende
        int     21h
                                        ; ja hole Einsprungadresse für HMA-
hmada:  push    es                      ; Funktionen.
        mov     ax,4310h
        int     2Fh
        mov     word ptr[hmaofs],bx     ; speichere Einsprungadressen
        mov     word ptr[hmaseg],es
        pop     es

        cmp     byte ptr [parms],0      ; prüfe auf Parameter
        jne     anf0
        display msgsyntx                ; Anzeige von gültigen Parametern
        jmp     fin

anf0:   cmp     byte ptr [parms+3],'a'  ; verzweige je nach Parametern
        je      alloc
        cmp     byte ptr [parms+3],'f'
        je      free
        cmp     byte ptr [parms+3],'s'
        je      status
        jmp     fin

; Die Funktion alloc reserviert 64KB HMA

alloc:  mov     dx,0FFFFh               ; reserviere FFFF Bytes HMA
        mov     ah,01
        call    dword ptr hmaofs
        dec     ax
        jz      enab_himem              ; HMA reseviert
        display msgused                 ; Reservierung nicht möglich !
        jmp     fin
enab_himem:
        mov     ah,03                   ; A20 global ermöglichen
        call    dword ptr hmaofs
        display msgresv
        jmp     fin

; Die Funktion free gibt den mit alloc reservierten
; HMA Bereich wieder frei

free:   mov     ah,04                   ; A20 global sperren
        call    dword ptr hmaofs
        mov     ah,02                   ; HMA freigeben
        call    dword ptr hmaofs
        display msgfree
        jmp     fin

; Die Funktion status versucht HMA anzufordern,
; gelingt dies gibt sie die Meldung HMA wird nicht benutzt aus.
; Ist eine Reservierung nicht möglich, so ist der HMA Bereich
; bereits von einem anderen Programm benutzt.

status:
        mov     dx,0FFFFh               ; versuche FFFFh Bytes
        mov     ah,01                   ; HMA anzufordern
        call    dword ptr hmaofs
        dec     ax
        jz      stat1

        display msgused                 ; HMA bereits genutzt
        jmp     fin

stat1:  mov     ah,02                   ; von Funktion status reservierte
        call    dword ptr hmaofs        ; HMA wieder freigeben
        display msgnouse
        jmp     fin

hmaofs    dw   0                        ; HMA-DRIVER OFFSET
hmaseg    dw   0                        ; HMA-DRIVER SEGMENT

msgnohma  db   13,10,'Himem Driver ist nicht installiert',13,10,'$'
msgnouse  db   13,10,'HMA wird nicht benutzt',13,10,'$'
msgresv   db   13,10,'64KB HMA sind reserviert.',13,10,'$'
msgused   db   13,10,'HMA wird schon benutzt',13,10,'$'
msgfree   db   13,10,'HMA wieder freigegeben.',13,10,'$'
msgsyntx  db   13,10,'Die Syntax für HMA lautet :',13,10
          db   'hma /a  für anfordern von 64KB HMA',13,10
          db   'hma /f  für freigeben von belegter HMA',13,10
          db   'hma /s  für Status HMA',13,10,'$'

cseg   ends
       end    begin
Bild 2. Demoprogramm für den Treiber Himem.sys von Microsoft

 

TSR-Programm mit und ohne HMA-Laderoutine
Bild 3. Speicherresidente Routinen in HMA
;-------------------------------------------------
; Dieses Programm wird an Ihre bestehende
; TSR-Routine angefügt und mit einem JMP-Befehl
; an erster Stelle in Ihrer TSR-Routine aktiviert.
;
; Datum : 03.06.89
; Autor : Jörg Matthaei
;-------------------------------------------------

himem   proc    near

begin:   call   hmada                   ; Teste ob Himem-Driver aktiv ist
         jnz    fin
         mov    cx,pgende-pganf         ; pgende ist die End-Adresse Ihrer
         mov    dx,-1                   ; TSR-Routine bzw.
         mov    ah,01                   ; pganf ist die Start-Adresse
                                        ; cx enthält somit die Anzahl der
                                        ; Bytes die in die HMA zu kopieren
                                        ; sind

         call   dword ptr hmaofs        ; reserviere HMA
         dec    ax
         jz     him1
         ret                            ; Reservierung nicht möglich

him1:    mov    ah,03
         call   dword ptr hmaofs        ; A20 global ermöglichen
         dec    ax
         jnz    him2
                                        ; kopiere PSP ab 10h in
         push   cx                      ; den HMA Bereich
         mov    ax,0FFFFh
         mov    es,ax
         mov    di,10h
         mov    si,10h
         mov    cx,0F0h
         rep    movsb
         pop    cx
         mov    di,offset pganf         ; verschiebe TSR Routine
         mov    si,di                   ; in den HMA Bereich
         rep    movsb
         cli
         mov    ds,ax                   ; ds=0FFFFh
         db     0EAh
         dw     103h,0FFFFh             ; JMP FAR auf TSR Routine
         sti                            ; die sich nun selbst im
         ret                            ; HMA Bereich installiert !

him2:    mov    ah,04                   ; A20 sperren
         call   dword ptr hmaofs
         mov    ah,02                   ; HMA Bereich wieder freigeben
         call   dword ptr hmaofs
         ret

hmada:   mov    ax,4300H                ; Teste ob Himem.sys aktiv ist
         int    2Fh
         cmp    al,80H
         jz     alloc
         mov    dx,offset msgins        ; Himem.sys nicht aktiv
         mov    ah,09
         int    21h
         ret

alloc:   push   es
         mov    ax,4310H                ; hole HMA Einsprungadresse
         int    2Fh
         mov    hmaofs,bx
         mov    hmaseg,es
         pop    es
         and    al,0
         ret

fin:     mov    ah,4Ch
         int    21h

msgins   db     10,13,9,'XMS - Driver nicht installiert !',10,13,'$'

hmaofs   dw     0                       ; HMA-Driver Offset
hmaseg   dw     0                       ; HMA-Driver Segment

himem   endp
Bild 4. HMA-Routine für speicherresidente Programme

 

aus mc 03/90 – Seite 77-80