home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
World of Shareware - Software Farm 2
/
wosw_2.zip
/
wosw_2
/
CPROG
/
UMM02.ZIP
/
UMM.ASM
< prev
next >
Wrap
Assembly Source File
|
1991-10-05
|
11KB
|
534 lines
;; umm.asm v0.2
;; 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)
;; snow@drycas.club.cc.cmu.edu (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
;; 0.1 Provided 80286 support
;; 0.2 Memory test added. Bug in UMB merge code fixed by
;; ajr@cybill.inesc.pt (Antonio Julio Raposo).
;;
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)
macro pushfm
pushf
push cs
endm
macro popfm
call iretm
endm
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 humber (high word)
extra dq ? ; extra (unused)
ends
segment umm use16
devhdr dd -1 ; device header
devflg dw 0a000h
devstr dw ummstr
devint dw ummint0
devnam db 'UMMXXXX0'
fpseg dw ? ; paragraph address of freep
label rhptr dword ; pointer to request header
rhoff dw ?
rhseg dw ?
label xmmptr dword ; pointer to XMM
xmmoff dw ?
xmmseg dw ?
iretm: iret ; part of pushfm/popfm macro set
align 16 ; force freep to be paragraph-aligned
freep dw -1 ; segment of first free UMB
proc ummstr far ; strategy routine
assume cs:umm
mov [rhoff], bx
mov [rhseg], es
ret
endp
proc ummint far ; resident interrupt routine
assume cs:umm
push si ; save registers
push ds
lds si, [rhptr] ; ds:si = request header
mov [rhds.st], 8103h ; return error (unknown command)
pop ds ; restore registers
pop si
ret
endp
label hdrend unknown ; HEADER SECTION ENDS HERE
proc ummctl far ; UMM control function
assume cs:umm
jmp short $$1 ; XMS requires this
nop
nop
nop
$$1: pushfm ; save flags
cmp ah, 10h ; request UMB
je short $$2
cmp ah, 11h ; release UMB
je short $$3
popfm
jmp [xmmptr] ; chain to old XMM
$$2: push ds ; save segment registers
push es
call requmb ; request UMB
jmp short $$4
$$3: push ds ; save segment registers
push es
call relumb ; release UMB
$$4: pop es ; restore segment registers
pop ds
popfm ; restore flags before returning
ret
endp
proc requmb near ; request UMB
assume cs:umm
cmp [freep], -1 ; any UMBs available?
jne short $$1
xor ax, ax ; return failure code
mov bl, 0b1h ; no UMBs available
ret
$$1: mov ds, [fpseg] ; get paragraph address of freep
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:umm
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: mov ds, [fpseg] ; get paragraph address of freep
$$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
mov ds, [fpseg] ; 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 ummend unknown ; RESIDENT PORTION ENDS HERE
align 4 ; start this section on dword boundary
newsp dw stktop ; stack for initialization routine
newss dw ?
oldsp dw ? ; original stack
oldss dw ?
proc ummint0 far ; initial interrupt routine
assume cs:umm
pushfm ; save flags
pusha ; save registers
push ds
push es
push cs
pop ds
mov [ds:newss], ds
les di, [ds: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
popfm ; 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 ss, [newss] ; enable new stack
mov sp, [newsp]
mov ah, 9 ; write banner
mov dx, offset eHello
int 21h
mov [devint], offset ummint ; enable resident interrupt routine
mov ax, offset freep ; initialize fpseg
shr ax, 4
add ax, [newss]
mov [fpseg], ax
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 hdrend
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 ummend
mov [rhes.st], 0100h ; return success code
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
mov [xmmoff], ax ; link ourselves into the chain
mov [xmmseg], es
mov [word es:bx], offset ummctl
mov [word es:bx+2], cs
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 es, [cs:fpseg] ; get paragraph address of freep
$$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.2', 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 umm
end