Category : Utilities for DOS and Windows Machines
Archive   : UMM03.ZIP
Filename : UMM.ASM

 
Output of file : UMM.ASM contained in archive : UMM03.ZIP
;; umm.asm v0.3
;; Upper Memory Manager for MS-DOS
;; Copyright (C) 1991 Kenneth Gober
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2 of the License, or
;; (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program; if not, write to the Free Software
;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
;;
;; To contact the author about changes, enhancements, bug reports, or
;; other comments, send electronic mail to:
;;
;; snow@drycas (from Bitnet sites)
;; [email protected] (from Internet sites)
;;
;; If you are unable to contact the author through electronic mail,
;; try sending a letter (as a last resort, only) to the following address:
;;
;; Kenneth Gober
;; 412 Robin Road
;; Cedar Hill, TX 75104 (USA)
;;
;; Please note that mail sent to this address may not yield a response
;; for several months!
;;
;; Version History:
;;
;; 0.0 Initial release for 80386 only.
;; 0.1 Provided 80286 support.
;; 0.2 Memory test added. Bug in UMB merge code fixed by
;; [email protected] (Antonio Julio Raposo).
;; 0.3 Resident portion relocated to upper memory.
;;

ideal ; Use TASM Ideal mode syntax
p286n ; Assemble for the 80286 (real mode)
locals $$ ; local labels preceded by '$$'

mbds equ (mb ds:0)
mbes equ (mb es:0)
rhds equ (rh ds:si)
rhes equ (rh es:di)

struc rh ; request header
len db ?
dev db ?
cmd db ?
st dw ?
rsvd dq ?
ct db ?
aoff dw ?
aseg dw ?
dptr dd ?
ends

struc mb ; UMB header
nxt dw ? ; next UMB in chain
siz dw ? ; size of UMB (without header)
mlo dw ? ; magic number (low word)
mhi dw ? ; magic number (high word)
extra dq ? ; extra (unused)
ends

group umm umml, ummh, umm0

segment umml use16 ; low-memory resident segment

devhdr dd -1 ; device header
devflg dw 0a000h
devstr dw ummstr
devint dw ummint0
devnam db 'UMMXXXX0'

label rhptr dword ; pointer to request header
rhoff dw ?
rhseg dw ?

proc ummstr far ; strategy routine
assume cs:umml

mov [umml:rhoff], bx
mov [umml:rhseg], es
ret
endp

proc ummint far ; resident interrupt routine
assume cs:umml

push si ; save registers
push ds
lds si, [umml:rhptr] ; ds:si = request header
mov [rhds.st], 8103h ; return error (unknown command)
pop ds ; restore registers
pop si
ret
endp

label endl unknown ; HEADER SECTION ENDS HERE

ends umml

segment ummh use16 ; upper-memory resident segment

label begh unknown

freep dw -1 ; segment of first free UMB

label xmmptr dword ; pointer to XMM
xmmoff dw ?
xmmseg dw ?

rpopf: iret ; for reliable popf

proc ummctl far ; UMM control function
assume cs:ummh

jmp short $$1 ; XMS requires this
nop
nop
nop

$$1: pushf ; save flags
push cs
cmp ah, 10h ; request UMB
je short $$2
cmp ah, 11h ; release UMB
je short $$3
call ummh:rpopf ; restore flags
jmp [ummh:xmmptr] ; chain to old XMM

$$2: push ds ; save segment registers
push es
call ummh:requmb ; request UMB
jmp short $$4

$$3: push ds ; save segment registers
push es
call ummh:relumb ; release UMB

$$4: pop es ; restore segment registers
pop ds
call ummh:rpopf ; restore flags before returning
ret
endp

proc requmb near ; request UMB
assume cs:ummh

cmp [ummh:freep], -1 ; any UMBs available?
jne short $$1
xor ax, ax ; return failure code
mov bl, 0b1h ; no UMBs available
ret

$$1: push cs ; get paragraph address of freep
pop ds
push cx
xor cx, cx

$$2: cmp [mbds.nxt], -1 ; last UMB?
jne short $$3
xor ax, ax ; return failure code
mov bl, 0b0h ; smaller UMB available
mov dx, cx
pop cx
ret

$$3: mov ax, ds ; save previous UMB
mov ds, [mbds.nxt] ; move to next UMB
cmp [mbds.siz], cx ; remember size of largest UMB
jbe short $$4
mov cx, [mbds.siz]

$$4: cmp cx, dx ; big enough?
jb short $$2
sub cx, dx ; split into two UMBs if necessary
cmp cx, 1
ja short $$5
mov es, ax ; unlink current UMB
mov ax, [mbds.nxt]
mov [mbes.nxt], ax
jmp short $$6

$$5: mov ax, ds ; determine address of new UMB
add ax, cx
dec cx ; shorten old UMB
mov [mbds.siz], cx
mov ds, ax ; initialize new UMB
mov [mbds.siz], dx
mov [mbds.mlo], 4c4bh
mov [mbds.mhi], 0047h

$$6: mov ax, 1 ; return success code
mov bx, ds ; return address of UMB
inc bx
pop cx
ret
endp

proc relumb near ; release UMB
assume cs:ummh

push dx
dec dx
mov es, dx
cmp [mbes.mlo], 4c4bh ; check magic number
jne short $$1
cmp [mbes.mhi], 0047h
je short $$2

$$1: xor ax, ax ; return failure code
mov bl, 0b2h ; invalid UMB
pop dx
ret

$$2: push cs ; get paragraph address of freep
pop ds

$$3: cmp [mbds.nxt], dx ; step through linked list
ja short $$4
mov ds, [mbds.nxt]
jmp short $$3

$$4: mov ax, [mbds.nxt] ; link UMB back into list
mov [mbes.nxt], ax
mov [mbds.nxt], dx
push cs
pop ds ; try to merge adjacent UMBs
mov ds, [mbds.nxt]

$$5: cmp [mbds.nxt], -1 ; end of chain?
jne short $$6
mov ax, 1 ; return success code
pop dx
ret

$$6: mov ax, ds ; advance to next UMB
mov ds, [mbds.nxt]
mov es, ax ; see if UMBs are adjacent
add ax, [mbes.siz]
inc ax
mov dx, ds
cmp ax, dx
jne short $$5
mov ax, [mbds.nxt] ; unlink second UMB
mov [mbes.nxt], ax
mov ax, [mbds.siz] ; merge UMBs
inc ax
add [mbes.siz], ax
push es ; try merging this UMB again
pop ds
jmp short $$5
endp

label endh unknown ; RESIDENT SECTION ENDS HERE

ends ummh

segment umm0 use16 ; initialization segment

oldsp dw ? ; original stack
oldss dw ?

proc ummint0 far ; initial interrupt routine
assume cs:umm, ds:umm

pushf ; save flags
push cs
pusha ; save registers
push ds
push es
push cs
pop ds
les di, [rhptr] ; es:di = request header
mov [rhes.st], 8103h ; assume error (unknown command)
mov al, [rhes.cmd] ; only cmd 0, INIT is legal
or al, al
jnz short $$1
call init

$$1: pop es ; restore registers
pop ds
popa
call rpopf ; restore flags before returning
ret
endp

proc init near ; initialize driver
assume cs:umm, ds:umm

mov [oldss], ss ; save old stack
mov [oldsp], sp
mov bx, ds
mov ss, bx ; enable new stack
mov sp, offset stktop
mov ah, 9 ; write banner
mov dx, offset eHello
int 21h
mov [devint], offset ummint ; enable resident interrupt routine
mov ax, 4300h ; check for an XMS driver
int 2fh
cmp al, 80h ; is the XMS driver loaded?
je short lexer
mov dx, offset eNoXMS

abort: call error ; abort installation
mov [rhes.aseg], cs ; discard everything after header
mov [rhes.aoff], offset endl
mov [rhes.st], 810ch ; return error (general failure)
mov ss, [oldss] ; restore old stack
mov sp, [oldsp]
ret

badch: pop ds ; bad character found by lexer
mov dx, offset eLexer
jmp short abort

lexer: push ds ; lexical analyzer
lds si, [rhes.dptr] ; ds:si = command line arguments
cld

s0: lodsb ; state 0, skip filename
call eol
je short done
call blank
jne short s0

s1: lodsb ; state 1, skip blanks
call eol
je short done
call blank
je short s1
call digit
ja short badch

cbw
mov cx, ax
s2: lodsb ; state 2, found 1 decimal digit
cmp al, '@'
je short s4
call digit
ja short badch

imul cx, 10
add cx, ax
s3: lodsb ; state 3, found 2 decimal digits
cmp al, '@'
jne short badch

s4: lodsb ; state 4, get first hex digit (a-f)
call hexaf
ja short badch
add al, 10
mov bh, al

s5: lodsb ; state 5, get second hex digit (0-f)
mov bl, al
call digit
jbe short $$1
mov al, bl
call hexaf
ja short badch
add al, 10

$$1: shl bh, 4
or bh, al
xor bl, bl

s6: lodsb ; state 6, get third hex digit (0)
cmp al, '0'
jne short badch

s7: lodsb ; state 7, get fourth hex digit (0)
cmp al, '0'
jne short badch
call newumb ; create new UMB
jmp short s1

done: pop ds ; command-line processing done
mov [rhes.aseg], cs ; discard initialization section
mov [rhes.aoff], offset endh
mov [rhes.st], 0100h ; return success code
mov cx, offset ummh:endh ; relocate resident portion
mov dx, cx ; find size in paragraphs
add dx, 15
shr dx, 4
mov bx, cs ; call UMM control function
mov ax, offset begh ; find segment
shr ax, 4
add bx, ax
mov ah, 10h
push bx ; save ummh segment value
push cs ; push return address
push offset $$ret
push bx ; push call address
push offset ummh:ummctl
retf ; this is a far call
$$ret: test ax, ax ; UMB available?
jz hook
pop ax ; replace saved ummh segment value
push bx ; and relocate ummh to UMB
mov [rhes.aoff], offset endl
mov es, bx
mov si, offset begh
xor di, di
cld
rep movsb

hook: mov ax, 4310h ; hook XMS control function
int 2fh
$$2: cmp [byte es:bx], 0ebh ; does it start with a short jump?
je short $$3
les bx, [es:bx+1] ; if not, follow far jump
jmp short $$2
$$3: mov [byte es:bx], 0eah ; change to a long jump
inc bx ; load byte displacement
mov al, [byte es:bx]
cbw ; convert to word offset
add ax, bx
inc ax
pop ds ; restore saved ummh segment value
assume cs:umm, ds:ummh
mov [ummh:xmmoff], ax ; link ourselves into the chain
mov [ummh:xmmseg], es
mov [word es:bx], offset ummh:ummctl
mov [word es:bx+2], ds
mov ss, [oldss] ; restore old stack
mov sp, [oldsp]
ret
endp

proc eol near ; check if al is an eol or eof
assume cs:umm

cmp al, 13
je short $$1
cmp al, 26
$$1: ret
endp

proc blank near ; check if al is a space or tab
assume cs:umm

cmp al, 32
je short $$1
cmp al, 9
$$1: ret
endp

proc digit near ; check if al is a decimal digit
assume cs:umm

sub al, '0'
cmp al, 9
ret
endp

proc hexaf near ; check if al is in the range 'a'-'f'
assume cs:umm

or al, 32
sub al, 'a'
cmp al, 5
ret
endp

proc error near ; write an error message
assume cs:umm, ds:umm

mov ah, 9
push dx
mov dx, offset eError ; write error prefix
int 21h
pop dx ; specify which error
int 21h
ret
endp

proc newumb near ; create a new UMB
assume cs:umm

push ds
push es
mov dx, cs ; get paragraph address of freep
mov ax, offset freep
shr ax, 4
add dx, ax
mov es, dx

$$1: cmp [mbes.nxt], bx ; step through linked list
ja short $$2
mov es, [mbes.nxt]
jmp short $$1

$$2: push es ; memory test
push bx
push cx
push di
mov dx, cx
mov ax, 0a396h ; test pattern

$$3: mov es, bx ; write test pattern to page
mov cx, 2048
xor di, di
rep stosw
mov cx, 2048 ; read test pattern from page
xor di, di
repe scasw
jne short $$4
inc bh ; move to next page
dec dx
jnz short $$3
jmp short $$5

$$4: add sp, 14 ; error in memory test
pop ds
les di, [ds:rhptr]
mov dx, offset eNoMem
jmp abort

$$5: pop di ; memory tested ok
pop cx
pop bx
pop es
xchg cl, ch ; convert pages to paragraphs
dec cx
mov ds, bx
mov ax, [mbes.nxt] ; link UMB into list
mov [mbds.nxt], ax
mov [mbes.nxt], bx
mov [mbds.siz], cx ; initialize UMB
mov [mbds.mlo], 4c4bh
mov [mbds.mhi], 0047h
pop es
pop ds
ret
endp

eHello db 'Upper Memory Manager v0.3', 13, 10
db 'Copyright (C) 1991 Kenneth Gober'
eNL db 13, 10, 13, 10, '$'
eError db 'Error installing UMM: $'
eNoXMS db 'XMS driver not found', 13, 10, '$'
eLexer db 'Invalid arguments', 13, 10, '$'
eNoMem db 'Memory test failed', 13, 10, '$'

align 4 ; start stack on dword boundary

stkbot db 512 dup (?) ; initialization stack
label stktop word

ends umm0
end


  3 Responses to “Category : Utilities for DOS and Windows Machines
Archive   : UMM03.ZIP
Filename : UMM.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/