; HIMEM-Erweiterung auf UMBs fr MS-DOS 5;
; Original (c) Peter Siering, erschienen in c't 8/91
; Erweiterte Version von as, 15-AUG-91. Aufruf mit:
; DEVICE=UMBADD.SYS /I=aaaa-bbbb /I=cccc-dddd....
; Beispiel: DEVICE=UMBADD.SYS /I=BC00-C000 /I=C000-C800
.MODEL SMALL
.CODE
INITREQUEST STRUC ; Parameterblock fr INIT
irLength db ? ; Gesamtumfang des Parameterblocks
irUnit db ? ; nicht verwendet
irFunction db ? ; Funktion $00, d.h. Init
irStatus dw ? ; Ergebniscode der Initialisierung
irReserved db 8 dup (?) ; "reserviert", nicht verwendet
irUnits db ? ; Zahl der vom Treiber bedienten Ger„te
irEndAddress dd ? ; h”chste verfgbare/belegte Speicheradresse
irParamAddress dd ? ; Adresse der Kommandozeile (device=...)
irDriveNumber db ? ; erste nicht belegte Laufwerks-Kennz.
irMessageFlag db ? ; Flag fr Fehlermeldungen
INITREQUEST ENDS
; Ger„tetreiberkopf
DNext dd -1 ; Adresse des n„chsten Treibers: FFFF:FFFF
DAttr dw 0E000h ; Attribute
DStrat dw OFFSET Strat ; Offset der "Strategie"-Routine
DIntr dw OFFSET Intr ; Offset der "Interrupt"-Routine
DName db 'UMBADDXX' ; Name (oder Units)
ParamAddr dd ? ; Zwischenspeicher fr INIT-Parameterblock
; Strategie-Routine, speichert lediglich ES:BX (Parameterblock-Adresse)
Strat PROC FAR
mov Word Ptr [ParamAddr],bx
mov Word Ptr [ParamAddr+2],es
IDEAL
push ds
push es
push dx
xor dx,dx
mov ds,dx
les dx,[9*4]
mov [cs:OldInt9Ofs],dx
mov [cs:OldInt9Seg],es
mov [word 9*4],offset NewInt9
mov [9*4+2],cs
pop dx
pop es
pop ds
MASM
retf
Strat ENDP
; Interrupt-Routine, definiert nur die INIT-Funktion
Intr PROC FAR
push ax ; mehr als diese drei Register
push bx ; werden momentan nicht gebraucht
push es
pushf
les bx,[ParamAddr] ; ES:BX = Parameterblock
mov es:[bx+irStatus],8103h ; pessimistischer Ansatz
mov al,es:[bx+irFunction] ; Funktionsnummer
or al,al ; Init?
jnz OtherCmd ; Code "Befehl unbekannt" gesetzt
call InitFunc ; INIT - liefert Status in AX
les bx,[ParamAddr]
mov es:[bx+irStatus],ax
OtherCmd: popf
pop es
pop bx
pop ax
retf
Intr ENDP
UMBEntry STRUC
Start dw ? ; Startadresse (Paragraphs)
Len dw ? ; L„nge Paragraphs
UMBEntry ENDS
UMBList dw 22 dup(0) ; maximal 10 Eintr„ge
; wird von IntFunc in die Kette eingesetzt und von DOS
; zum Belegen der UMBs aufgerufen.
; Aufruf: DX = gewnschte GrӇe (Bytes), Flags auf dem Stack
; Zurck: DX = GrӇe gefundener Block, BX = Segment, AX = 1
; bzw. AX = 0 und BL = $B1 fr "berhaupt kein Block"
; bzw. AX = 0 und BL = $B0 fr "Block zu klein"
UMBRequest:
;Suchstrategie First Fit (DOS #0), keine MCB-Verwendung!
push ds
push si
push cx
push bx
push cs
pop ds ; DS aufs Codesegment
mov si,OFFSET UMBList
xor cx,cx ; fr GrӇenvergleich
cld ; aufsteigende Richtung
UMBSearch:
lodsw ; ein Eintrag der UMB-Liste
or ax,ax ; Listenende?
jz UMBNFnd ; -> ja, Fehler
mov bx,ax ; Startsegment festhalten
lodsw
cmp bx,-1 ; bereits voll?
jz UMBSearch ; -> ja, n„chster Eintrag
cmp ax,cx ; bis dato grӇter Block?
jb ChkSize
mov cx,ax ; ja, GrӇe festhalten
ChkSize: cmp ax,dx ; reicht die GrӇe?
jb UMBSearch ; -> nein, n„chster Block
mov Word Ptr[si-4],-1 ; Block als vergeben markieren
mov dx,ax ;GrӇe in DX
pop ax ;altes BX vom Stack
mov ax,1 ;Signal fr Erfolg
jmp Short UMBDone
UMBNFnd:xor ax,ax
pop bx ; BX-Original (BH)
mov bl,0B0h ; Annahme: Block nur zu klein
mov dx,cx ; zurckzuliefernde BlockgrӇe
or dx,dx ; irgendetwas gefunden?
jnz UMBDone ; -> ja, nur zu klein
inc bl ; gar nichts gefunden: BL = $B1
UMBDone:pop cx
pop si
pop ds
popf
retf
; Kette von HIMEM.SYS
XMSOrgJmp dd ? ; Originalwert
NewChain: jmp short NewCtrl
nop ; an dieser Stelle wrde der n„chste
nop ; Handler seinen Sprung einsetzen
nop
NewCtrl: pushf
cmp ah,10h ; UMB request?
jz UMBRequest ; Flags auf dem Stack!
popf
jmp [XMSOrgJmp] ;Near?
NewInt9: PUSH AX ;Ansprung durch Tastendruck
PUSH DS
XOR AX,AX
MOV DS,AX
MOV AL,DS:[0417h] ;AL=Tastatur-Status
AND AL,00001100b ;nur noch Ctrl & Alt - Flag
CMP AL,00001100b ;Ctrl+Alt gedrckt ?
JNZ intcont
IN AL,60h ;AL=Make-Code der gedr. Taste
CMP AL,53h ; Make-Code = >DEL< ?
JNZ intcont ; NEIN -> dann weiter
; mov ds:[word ptr 472h],1234h
xor ax,ax
mov bx,ax
int 10h ;Videomodus 0
mov ah,2
mov dx,12*256+14
int 10h ;Cursorpos.
mov si,offset txt
txto: mov al,cs:[si]
or al,al
jz $ ;Warten bis ewig
mov ah,0eh
int 10h
inc si
jmp short txto ;Warteschlange
INTCONT: POP DS
POP AX
db 0eah ;Jump Far
OldInt9Ofs dw ? ;Sprung-Adresse (Absturz !)
OldInt9Seg dw ?
txt: db 'Press RESET',0
; *** Beginn des nicht residenten Teils ***
CRLF db 13,10,'$'
PrintString:
push dx
mov dx,OFFSET CRLF
call DoPrint
pop dx
call DoPrint
mov dx,OFFSET CRLF
DoPrint: mov ah,09h
int 21h
ret
; Ausgabe einer Hex-Zahl mit vier Stellen (AX)
PrHex: push ax
mov al,ah
call ahex
pop ax
ahex: push ax ;Werte erhalten
mov cl,4 ;oberes Nibble auf Bit 3...0
shr al,cl ; schieben
call ahex1
pop ax
ahex1: and al,0fh
add al,90h ;Hex -> ASCII
daa
adc al,40h
daa
mov dl,al
mov ah,2
int 21h
ret
; Ausgabe einer Fehlermeldung ber die DOS-Funktion $09 und Abbruch
; Aufruf mit DS:DX = Text der Meldung
ErrOut: call PrintString ; Textausgabe
les bx,[ParamAddr]
mov Word Ptr es:[bx+irEndAddress],0 ; 0 Bytes Platzbedarf
mov ax,8100h ; Fehler (unspezifisch)
jmp InitEnd
; Initialisierung - wird mit ES:DI = Parameterblock und ES,BX,AX/Flags
; auf dem Stack aufgerufen, d.h. muá sich um diese Register nicht
; mehr kmmern
InitFunc PROC NEAR
push cx
push dx
push si
push di
push ds
push cs
pop ds ; DS aufs Codesegment
mov Word Ptr es:[bx+irEndAddress],OFFSET CRLF
mov Word Ptr es:[bx+irEndAddress+2],cs ; Endaddr eintragen
; HIMEM installiert?
mov ax,4300h ; Installationsprfung von HIMEM
int 2Fh
cmp al,80h ; vorhanden?
jz GetXMSCall ; -> ja
mov dx,OFFSET NoXMS$
jmp ErrOut
; Kette ermitteln
GetXMSCall:
mov ax,4310h ; HIMEM: Einsprungadresse
int 2Fh
mov Word Ptr [XMSOrgJmp+2],es
mov word ptr [xmsorgjmp],bx
; Existiert bereits ein UMB Server?
mov ah,16
mov dx,0FFFh ; Anfordern eines Blocks mit 64 KByte
call [XMSOrgJmp]
cmp bl,80h ; nicht installiert?
jz GetCmdLine ; -> OK
mov dx,OFFSET UMBPresent$
jmp ErrOut ; da ist schon wer!
; Kommandozeile auswerten
GetCmdLine:
les di,[ParamAddr] ; Parameterblock
les di,es:[di+irParamAddress] ; ES:DI auf Kommandozeile
call SetList ; Auswerten und Liste setzen
jnc TestAreas ; -> OK
mov dx,OFFSET BadCmd$
jmp ErrOut ; Kommandozeile ausgeben
TestAreas:
mov si,OFFSET UMBList
cld
NextUMB: lodsw ; Startadresse
or ax,ax ; Ende der Liste erreicht?
jz AreasTested
mov es,ax ; Startadresse in ES
lodsw ; GrӇe (Paragraphs)
TstBlocks: xor di,di
mov bx,es:[di] ; momentanen Inhalt lesen
mov dx,bx
xor dx,0FFFFh ; Umdrehen
mov es:[di],dx ; und Schreiben
mov cx,80h ; einen Moment warten, falls die
loop $ ; Operation ins Leere gehen sollte
cmp es:[di],dx ; haben wir einen konstanten Wert?
mov es:[di],bx ; alten Inhalt zurck
jnz NoRAM ; -> kein RAM an dieser Stelle!
mov bx,400h
mov dx,es
add dx,bx ;next 16K
mov es,dx
sub ax,bx
jg TstBlocks ;L„nge minus 16K
jmp NextUMB ; -> n„chster UMB-Bereich
NoRAM: push es ; Segmentadresse des Blocks
mov dx,OFFSET RAMFail1$
call DoPrint ; Ausgabe ohne CRLF
pop ax
call PrHex ; Segmentadresse ausgeben
mov dx,OFFSET RAMFail2$
jmp ErrOut
; Hier geht es nach einen erfolgreichen RAM-Test mit dem Einsetzen
; des eigenen "Hook" in die von HIMEM.SYS aufgebaute Sprungkette weiter
AreasTested: les di,[XMSOrgJmp]
ScanHooks: mov al,Byte Ptr es:[di]
cmp al,0EBh ; JMP SHORT?
jz HookFound ; OK - momentanes Kettenende
les di,DWord Ptr es:[di+1] ; sonst n„chstes Element
cmp al,0EAh ; war das berhaupt ein JMP FAR?
jz ScanHooks
mov dx,OFFSET HookErr$ ; Hook-Kette besch„digt
jmp ErrOut
HookFound: cli ; *keine* St”rungen hier, bitte!
dec Byte Ptr es:[di] ; JMP SHORT -> JMP FAR
mov Word Ptr es:[di+1], OFFSET NewChain ; eigene Routine
mov Word Ptr es:[di+3], cs ; einsetzen
add di,5 ; echte Originaladresse (hinter den NOPS)
mov Word Ptr [XMSOrgJmp],di
mov Word Ptr [XMSOrgJmp+2],es
sti
mov ax,0100h ; Initialisierung fehlerfrei
InitEnd: pop ds
pop di
pop si
pop dx
pop cx
ret
InitFunc ENDP
Copyright$ db 'UMBADD c''t 8/91 - Peter Siering/Arne Sch„pers/ToGraWu/h#s$'
NoXMS$ db 'Kein XMS-Treiber vorhanden!$'
UMBPresent$ db 'UMB Server bereits installiert!$'
BadCmd$ db 'Probleme mit den Bereichsangaben in CONFIG.SYS!',13,10
Help$ db 'Format: DEVICE=UMBADD.EXE /Iaaaa-bbbb /Icccc-dddd ...(Anfang und Ende+1!)$'
RAMFail1$ db 13,10,'Kein RAM im Segment (hex) $'
RAMFail2$ db '- Installation abgebrochen -$'
HookErr$ db 'Hook-Chain von HIMEM.SYS besch„digt/unbekanntes Format!$'
; Aufruf mit ES:DI als Index in die Kommandozeile
; zurck mit DI+4, Wert bzw. 0 in DX und gel”schtem/gesetzten Z-Flag
HexToVal: push cx
mov cx,0404h ; Z„hler, Shift-Z„hler
xor dx,dx ; Wert
DoDigit: shl dx,cl ; eine Stelle nach links
mov al,es:[di] ; ein Zeichen
inc di
cmp al,'9'
jbe IsDigit
and al,0DFh ; Groábuchstaben
cmp al,'A'
jb NoChar ; Fehler
cmp al,'F'
ja NoChar ; dito
sub al,55 ; 'A'..'F' -> 10..16
jmp short SetDig ; Einsetzen
IsDigit: cmp al,'0'
jb NoChar ; Fehler
sub al,'0' ; '0'..'9' -> 0..9
SetDig: or dl,al ; Einsetzen
dec ch
jnz DoDigit
jmp Short DigDone
NoChar: xor dx,dx ; Fehleranzeige: dx = 0
DigDone: pop cx
or dx,dx
ret
; Auswertung der Kommandozeile. Aufruf mit ES:DI = Kommandozeile,
; zurck mit gesetzter UMBList und gesetztem/gel”schten Carry
SetList PROC NEAR
; call ram_on
xor bx,bx ; Index in UMBList
DoElem: mov al,es:[di]
inc di
cmp al,13 ; CR?
jz ListSet ; -> ja, Ende
cmp al,10 ; LF?
jz ListSet ; -> dito
cmp al,'/' ; Schr„gstrich von "/I=..."?
jnz DoElem
mov ax,es:[di]
and al,0DFh ; Umsetzung 'i' -> 'I'
cmp ax,'=I' ; ist "I="? (verkehrtherum)
jnz ListErr ; -> nein, Fehler
add di,2 ; Ok, berspringen
call HexToVal ; Hexzahl auswerten -> DX
jz ListErr ; -> war nichts
mov al,es:[di]
cmp al,'-' ; Trennstrich?
inc di
mov cx,dx ; Startadresse festhalten
call HexToVal ; Endadresse ermitteln
jz ListErr ; -> war nichts
mov Word Ptr[UMBList+bx],cx ; Eintrag Startadresse
mov ax,dx
sub ax,cx ; GrӇe in Paragraphs
mov Word Ptr[UMBList+bx+2],ax
add bx,4
cmp bx,40 ; mehr als 10 Eintr„ge?
jb DoElem ; -> nein, weiter
ListErr: stc
ret
ListSet: sub bx,1 ; setzt Carry, wenn BX = 0
ret
SetList ENDP
HELP:
push cs
pop ds
mov dx,offset copyright$
call PrintString
mov dx,offset help$
call PrintString
mov ax,4c00h
int 21h
END help
ram_on proc near
push ax
push cx
push es
push si
mov al,68h
out 22h,al
jmp a1
a1: in al,23h
or al,11110000b ;Speicher von D000-DFFF einblenden
push ax
mov al,68h
out 22h,al
jmp a2
a2: pop ax
out 23h,al ;in NEAD-Register schreiben
mov al,65h
out 22h,al
jmp a3
a3: in al,23h
and al,10111111b ;R/W fr D000-DFFF setzen
push ax
mov al,65h
out 22h,al
jmp a4
a4: pop ax
out 23h,al
in al,70h
push ax
or al,10000000b
out 70h,al ;NMI abschalten
in al,71h ;Dummy read notwendig!!!
mov ax,0D000h ;Seg. ADR begin Init
mov es,ax
mov si,0h
cli
a5: mov word ptr es:[si],0 ;RAM Init
inc si
inc si
cmp si,0
jne a5
sti
in al,61h ;Port b,Parity-Enable-Bit
xor al,14h
out 61h,al ;setzen
jmp a6
a6: xor al,14h ;und zurcksetzen
out 61h,al
pop ax
and al,10000000b
out 70h,al
in al,71h
pop si
pop es
pop cx
pop ax
ret
ram_on endp
END
Detected encoding: UTF-8 | 0
|