home *** CD-ROM | disk | FTP | other *** search
- ;; 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)
- ;; 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 for 80386 only.
- ;; 0.1 Provided 80286 support.
- ;; 0.2 Memory test added. Bug in UMB merge code fixed by
- ;; ajr@cybill.inesc.pt (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
-