home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Multimedia & CD-ROM 3
/
mmcd03-jun1995-cd.iso
/
utils
/
various
/
utils-1
/
ems40.asm
< prev
next >
Wrap
Assembly Source File
|
1991-06-24
|
121KB
|
2,201 lines
;============================================================================
;EMS40.SYS an Expanded Memory Simulator for the IBM AT
;
; Revision History:
;
; Version 1.0 Initial Release PC Mag Vol 8, Num 12
;
; Version 1.1 Enlarged internal save July 18, 1989
; area for functions 8 & 9.
;
; Reduced default number of
; possible from 255 to 127.
;
; Bug fixes:
; Fun 23. Preserve CX on call.
; Fun 2500. Return size in CX.
;
;============================================================================
PAGE ,132
CODE SEGMENT PUBLIC'code'
ASSUME CS:CODE
;-----------------------------------------------------------------------------
;Structure of the device driver request header
;-----------------------------------------------------------------------------
REQ_STRUC STRUC
LEN DB ?
UNIT DB ? ;unit number
COMMAND DB ? ;command code
STATUS DW ? ;return status
RESERVE DB 8 DUP (?)
MEDIA DB ?
ADDRESS DD ? ;Transfer address
CONFIG_PTR DD ? ;Pointer to line in config
REQ_STRUC ENDS
;-----------------------------------------------------------------------------
;Segment descriptor structure
;-----------------------------------------------------------------------------
DAT_SEG_DES STRUC ;data segment descriptor
SEG_LIM DW 0 ;length of segment
BASE_ADRL DW 0 ;base address of segment
BASE_ADRH DB 0
DB 0 ;access rights byte
DW 0 ;reserved
DAT_SEG_DES ENDS
;=============================================================================
;Device header begin
;=============================================================================
ORG 0 ;drivers start at offset 0
HEADER DD -1 ;Pointer to next driver
DW 8000H ;device attribute word
DW OFFSET STRATEGY ;pointer to strategy routine
DW OFFSET INTERRUPT ;pointer to interrupt routine
DB 'EMMXXXX0' ;name of driver
;Device header end
SWAP_POINTER DW OFFSET EMS_EXCH_PAG
PROGRAM DB "EMS 4.0 Simulator, Ver. 1.1"
COPYRIGHT DB " (C) 1989 Ziff Communications",13,10
PROGRAMMER DB "PC Magazine ",254," Douglas Boling",13,10,"$",26
REQ_HEADADR DD ? ;Far pointer to request header
;-----------------------------------------------------------------------------
;Global Descriptor table needed for moves to and from extended memory.
;-----------------------------------------------------------------------------
GDT LABEL BYTE
DAT_SEG_DES <> ;Dummy
DAT_SEG_DES <> ;GDT descriptor
SOURCE DAT_SEG_DES <4000H,,,93H,> ;source descriptor
DEST DAT_SEG_DES <4000H,,,93H,> ;destination descriptor
DAT_SEG_DES <> ;bios code descriptor
DAT_SEG_DES <> ;stack segment descriptor
;=============================================================================
;Strategy routine. This routine stores the address of the request header
;=============================================================================
STRATEGY PROC FAR
ASSUME CS:CODE,DS:NOTHING,ES:NOTHING
MOV WORD PTR CS:[REQ_HEADADR],BX ;save offset
MOV WORD PTR CS:[REQ_HEADADR+2],ES ;save segment
RET
STRATEGY ENDP
;=============================================================================
;Interrupt routine. This routine executes the command code in the req header.
;=============================================================================
INTERRUPT PROC FAR
ASSUME CS:CODE,DS:NOTHING,ES:NOTHING
PUSHF
PUSH AX ;save every register used
PUSH BX
PUSH CX
PUSH DX
PUSH DI
PUSH SI
PUSH DS
PUSH ES
PUSH CS ;Set DS
POP DS
ASSUME DS:CODE
CLD ;any string operations move up.
;Get command from request header
LES DI,[REQ_HEADADR] ;load address of req header
ASSUME ES:NOTHING
MOV BL,ES:[DI.COMMAND]
CMP BL,0
JNE PROCESS1
CALL INITIALIZE
JMP SHORT DONE
PROCESS1: CMP BL,16 ;see if command out of range
JBE DONE
MOV AX,8003H ;unknown command error code
DONE: OR AX,0100H ;set the 'done' bit
MOV ES:[DI.STATUS],AX
POP ES ;restore registers before exit
POP DS
POP SI
POP DI
POP DX
POP CX
POP BX
POP AX
POPF
RET
INTERRUPT ENDP
DRIVER_END = $ ;Last part of driver code
;======================================================================
;EMS Driver code starts here.
;======================================================================
OLD_INT15H LABEL DWORD
OLD_INT15HO DW ? ;offset of old interrupt vector
OLD_INT15HS DW ? ;segment
EXT_MEM_LIMIT DW 0 ;adjusted top of avail memory
OS_ENABLED DB 1 ;Enable os functions 1=enabled
OS_PASS_LOW DW 0 ;Operating system password.
OS_PASS_HIGH DW 0
ALT_MAP_PTRS DW 0 ;Mapping pointer for funct 28
ALT_MAP_PTRO DW 0
WINDOW_SEG DW ? ;starting segment of ems win
WINDOW_ADDR_BASE DD 4 DUP(0) ;address of each page
EXTEND_ADRL DW ? ;base of extended memory used
EXTEND_ADRH DB ?
TOTAL_PAGES DW 24 ;default to 384k of exp mem.
TOTAL_HANDLES DW 127 ;Default number of handles
INT_SAVE_SIZE DW 15 ;Number of save areas for 8/9
PAG_OWNER_TBL DW ? ;Pointer to page table
HANDLE_ARRAY DW ? ;Pointer to handle table
MAP_ARRAY_PTR DW ? ;Pointer to map array
MOVE_BUSY_FLAG DB 0 ;Indicates blk move active
SAVED_ADDR_LOW DW 0 ;Saved address of block
SAVED_ADDR_HIGH DB 0 ; being moved.
;======================================================================
;Interrupt 15h routine. Intercept extended memory size determine.
;======================================================================
INT_15H PROC FAR
ASSUME CS:CODE,DS:NOTHING,ES:NOTHING
CMP AH,88H
JE INT15_F88
JMP CS:[OLD_INT15H]
INT15_F88: MOV AX,CS:EXT_MEM_LIMIT ;provide new limit
CLC ;clear error flag
RET 2
INT_15H ENDP
;-----------------------------------------------------------------------------
;Jump table for EMS driver commands
;-----------------------------------------------------------------------------
EMS_CMDS DW OFFSET EMS_01 ;Get status
DW OFFSET EMS_02 ;Get page frame seg address
DW OFFSET EMS_03 ;Get unallocated page count
DW OFFSET EMS_04 ;Allocate pages
DW OFFSET EMS_05 ;Map/unmap handle pages
DW OFFSET EMS_06 ;Deallocate pages
DW OFFSET EMS_07 ;Get version
DW OFFSET EMS_08 ;Save page map
DW OFFSET EMS_09 ;Restore page map
DW OFFSET EMS_UNSP ;reserved
DW OFFSET EMS_UNSP ;reserved
DW OFFSET EMS_12 ;Get handle count
DW OFFSET EMS_13 ;Get handle pages
DW OFFSET EMS_14 ;Get all handle pages
DW OFFSET EMS_15 ;Page map functions
DW OFFSET EMS_16 ;Partial page map functions
DW OFFSET EMS_17 ;Map/unmap multiple hndl pages
DW OFFSET EMS_18 ;Reallocate pages
DW OFFSET EMS_19 ;Handle attribute
DW OFFSET EMS_20 ;Handle name
DW OFFSET EMS_21 ;Handle directory
DW OFFSET EMS_22 ;Alter page map and jump
DW OFFSET EMS_23 ;Alter page map and call
DW OFFSET EMS_24 ;move/exchange memory region
DW OFFSET EMS_25 ;Get mappable phys addr array
DW OFFSET EMS_26 ;Hardware configuration
DW OFFSET EMS_27 ;Allocate standard pages
DW OFFSET EMS_28 ;Alternate map register set
DW OFFSET EMS_UNSP ;Warmboot preparation
DW OFFSET EMS_30 ;OS/E functions
;======================================================================
;Interrupt 67h routine. EMS driver function dispatcher.
;======================================================================
INT_67H PROC FAR
ASSUME CS:CODE,DS:NOTHING,ES:NOTHING
PUSH BP
MOV BP,SP ;set up stack addressing
CLD ;any string operations move up.
PUSH CX ;Save registers
PUSH DI ;NOTE: Don't change the
PUSH SI ; order of the register save.
PUSH DS ; Many of the routines depend
PUSH ES ; on the correct order.
PUSH CS ;point ds to code segment
POP DS
ASSUME DS:CODE
CMP AH,5DH ;Check for a cmd out of range
JA EMS_CMD_ERR
CMP AH,40H
JL EMS_CMD_ERR
MOV DI,OFFSET RETURN_ADDR ;Push return address onto
PUSH DI ; stack.
PUSH AX ;save AX
SUB AH,40H ;Convert command code in AX
MOV AL,AH ; into a jump address.
XOR AH,AH ;Clear upper byte
SAL AX,1 ;Convert to word offset
ADD AX,OFFSET EMS_CMDS ;add offset of jump table
MOV DI,AX ;Copy to DI
POP AX ;restore AX
PUSH [DI] ;Put offset of routine on stk
MOV DI,[BP-4] ;Restore DI
CALL EMS_CHECK_HDL ;check for valid handle in DX
DB 0C3h ;RETN opcode to call function.
RETURN_ADDR: POP ES ; The RETN instruction is
POP DS ; hand assembled to force a
POP SI ; near return in a far proc.
POP DI ; For MASM 5.0, the RETN can
POP CX ; be specified as an opcode.
POP BP
IRET
EMS_CMD_ERR: MOV AH,84H ;EMS command out of range
JMP SHORT RETURN_ADDR
INT_67H ENDP
;======================================================================
;Function 1. Get status.
;======================================================================
EMS_01 PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
XOR AX,AX
RET
EMS_01 ENDP
;======================================================================
;Function 2. Get segment address of EMS window
;======================================================================
EMS_02 PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
MOV BX,WINDOW_SEG ;store starting seg of window
XOR AX,AX
RET
EMS_02 ENDP
;======================================================================
;Function 3. Get count of unallocated pages
;======================================================================
EMS_03 PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
XOR DX,DX ;search for hndl =-1 (unaloc)
DEC DX
CLC ;fake 'handle ok' flag
CALL EMS_13
MOV DX,TOTAL_PAGES ;Load total pages
XOR AX,AX ;Clear return code
RET
EMS_03 ENDP
;======================================================================
;Function 4. Get handle and allocate pages
;======================================================================
EMS_04 PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
OR BX,BX ;Check for 0 page request
JE EMS_04_ERR ;If so, error
CALL EMS_27 ;Let function 27 do the work
EMS_04_EXIT: RET
EMS_04_ERR: MOV AH,89H ;attempt to allocate 0 pages
JMP SHORT EMS_04_EXIT
EMS_04 ENDP
;======================================================================
;Function 5, Map / Unmap pages.
;======================================================================
EMS_05 PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
PUSH BX
PUSH DX
JC EMS_05_EXIT ;carry set, invalid handle
CMP AL,3 ;Check for physical page out
JA EMS_05_ERR0 ; of range
CMP BX,0FFFFH ;See if unmap page. If so,
JNE EMS_05_S1 ; save current mapped page
MOV BL,AL ; but don't map new page.
XOR AX,AX
XOR DX,DX ;DL:AX=0 indicates no map
JMP SHORT EMS_05_S2
EMS_05_S1: PUSH AX ;Save physical page to map
CALL EMS_LOG2PHY ;Convert page into an address
POP BX ;Put phy page into BX for call
JC EMS_05_EXIT ;If error, exit
EMS_05_S2: CALL EMS_EXCH_PAG ;Map the page
XOR AX,AX ;Clear return code
EMS_05_EXIT: POP DX ;Restore registers.
POP BX
RET
EMS_05_ERR0: MOV AH,8BH ;Physical page out of range
JMP SHORT EMS_05_EXIT
EMS_05 ENDP
;======================================================================
;Function 6, Deallocate pages.
;======================================================================
EMS_06 PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
PUSH BX
PUSH DX
JC EMS_06_EXIT ;carry set, invalid handle
MOV BL,0FFH ;clear all pages
CALL EMS_DEALLOC ;Deallocate memory
OR DL,DL ;handle zero cannot be
JE EMS_06_GOOD ; deallocated
PUSH CS ;Deallocate handle
POP ES
ASSUME ES:CODE
MOV DI,HANDLE_ARRAY
MOV AX,DX ;copy handle
MOV CX,9 ;convert handle to an index into
MUL CX ; the handle array.
ADD DI,AX
XOR AL,AL ;Erase handle flag and name.
REP STOSB
EMS_06_GOOD: XOR AX,AX ;clear return code
EMS_06_EXIT: POP DX
POP BX
RET
EMS_06 ENDP
;======================================================================
;Function 7. Get version number
;======================================================================
EMS_07 PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
MOV AX,0040H ;store ver num and ret code
RET
EMS_07 ENDP
;======================================================================
;Function 8. Save page map.
;======================================================================
EMS_08 PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
PUSH BX
PUSH DX
JC EMS_08_EXIT ;Carry set, invalid handle
;Search the mapping arrays to find an array that is empty. At the same
; time, make sure that the handle doesn't have an array currently saved.
MOV SI,MAP_ARRAY_PTR ;Start search of map arr lbls
MOV CX,INT_SAVE_SIZE ;Search all save map arrays
XOR BX,BX ;Initialize free pointer
EMS_08_L1: ADD SI,18 ;Look at next map array
CMP WORD PTR [SI],0FFFFh ;See if free
JNE EMS_08_S1
MOV DI,SI ;If so, copy address
JMP SHORT EMS_08_S3
EMS_08_S1: CMP [SI],DX ;See if curr hndl used before
JNE EMS_08_S2
MOV AH,8DH ;Handle already used for save
JMP SHORT EMS_08_EXIT
EMS_08_S2: LOOP EMS_08_L1 ;Loop back
MOV AH,8CH ;No room to store page map
JMP SHORT EMS_08_EXIT
EMS_08_S3: PUSH CS ;Point ds:si to page array
POP ES
ASSUME ES:CODE ;Point es:di to save array
MOV SI,MAP_ARRAY_PTR
MOV [SI],DX ;Label arrays with handle
MOV CX,9
REP MOVSW
XOR AX,AX ;Clear return code
EMS_08_EXIT: POP DX
POP BX
RET
EMS_08 ENDP
;======================================================================
;Function 9. Restore page map
;======================================================================
EMS_09 PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
PUSH BX
PUSH DX
JC EMS_09_EXIT ;carry set, invalid handle
;find the saved page map in the save array.
MOV SI,MAP_ARRAY_PTR
MOV CX,INT_SAVE_SIZE
EMS_09_L1: ADD SI,18 ;look at next map array
CMP [SI],DX ;See if array label matches
JE EMS_09_S1 ; the handle.
LOOP EMS_09_L1
MOV AH,8EH ;no saved page map found
JMP SHORT EMS_09_EXIT
;Now that the saved array has been found, call restore map routine.
EMS_09_S1: CALL EMS_15_1 ;restore map
MOV WORD PTR [SI],0FFFFh ;mark saved array as free
XOR AX,AX ;clear return code
EMS_09_EXIT: POP DX
POP BX
RET
EMS_09 ENDP
;======================================================================
;Function 12, Get Handle Count
;======================================================================
EMS_12 PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
MOV DI,HANDLE_ARRAY ;point to handle array
XOR BX,BX ;clear count and compare regs
MOV CX,TOTAL_HANDLES ;look at all handles 0 - feh
EMS_12_L1: CMP BH,[DI] ;if handle id = 0 then that
JE EMS_12_S1 ; handle has not been allocated.
INC BL ;Add one to open handle count
EMS_12_S1: ADD DI,9 ;Move di to point to next id.
LOOP SHORT EMS_12_L1
XOR AX,AX ;clear return code
EMS_12_EXIT: RET
EMS_12 ENDP
;======================================================================
;Function 13 Get Handle pages
;Entry: dx = handle to search for
;Exit: ax = return code. bx = number of matches found.
;======================================================================
EMS_13 PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
PUSH DI
JC EMS_13_EXIT ;carry set, invalid handle
MOV DI,PAG_OWNER_TBL ;point to owner table
MOV CX,TOTAL_PAGES
XOR BX,BX ;Clear page count
EMS_13_LOOP: CMP DL,[DI] ;Compare handle to table
JNE EMS_13_SKIP
INC BX ;Inc count of pages
EMS_13_SKIP: ADD DI,3 ;Point to next entry
LOOP EMS_13_LOOP
XOR AX,AX ;Clear return code.
EMS_13_EXIT: POP DI
RET
EMS_13 ENDP
;======================================================================
;Function 14. Get All Handle Pages
;======================================================================
EMS_14 PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
PUSH DX
XOR DX,DX ;Handle currently being checked
XOR SI,SI ;SI total open handles counter
EMS_14_L1: CALL EMS_CHECK_HDL ;See if handle active
CALL EMS_13 ;Count pages for handle
JC EMS_14_S1 ;If bad handle, skip
INC SI ;Add to handle count
MOV ES:[DI],DX ;Write results to the array
MOV ES:2[DI],BX
EMS_14_S1: INC DX ;Point to next handle
ADD DI,4 ;Incriment array pointer
CMP DX,TOTAL_HANDLES ;Have we check all handles?
JL EMS_14_L1 ;No, loop back.
MOV BX,SI ;Get number of active handles
XOR AX,AX ;Clear return code
EMS_14_EXIT: POP DX
RET
EMS_14 ENDP
;======================================================================
;Function 15. Get/Set Page Map
;======================================================================
EMS_15_TBL DB 3 ;Max value of subfunction
DW OFFSET EMS_15_0 ;Jump table for subfunctions
DW OFFSET EMS_15_1
DW OFFSET EMS_15_2
DW OFFSET EMS_15_3
EMS_15 PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
PUSH BX
PUSH DX
MOV DS,SS:[BP-8] ;Get original DS
ASSUME DS:NOTHING
MOV DI,OFFSET EMS_15_TBL ;Point to jump table structure
CALL EMS_DISPATCHER ;Dispatch routine calls
EMS_15_EXIT: POP DX ; subfunction routine.
POP BX
RET
EMS_15 ENDP
;----------------------------------------------------------------------
;Function 15.0 Get mapping array
;----------------------------------------------------------------------
EMS_15_0 PROC NEAR
ASSUME DS:NOTHING,ES:NOTHING
PUSH SI
PUSH DS
PUSH CS
POP DS
ASSUME DS:CODE
MOV SI,MAP_ARRAY_PTR ;DS:SI points to page array
MOV CX,9 ;ES:DI points to destination
REP MOVSW ;Copy mapping array
XOR AH,AH
POP DS
POP SI
RET
EMS_15_0 ENDP
;----------------------------------------------------------------------
;Function 15.1 Set mapping array
;----------------------------------------------------------------------
EMS_15_1 PROC NEAR
ASSUME DS:NOTHING,ES:NOTHING
PUSH SI
XOR BX,BX ;start with logical page 0
ADD SI,2 ;move si past the handle ptr
EMS_15_1_L1: MOV AX,DS:[SI] ;get current page address
MOV DX,DS:[SI+2]
PUSH BX
CALL EMS_EXCH_PAG ;Exchange current window page
POP BX ;Point si to next address
ADD SI,4
INC BX
CMP BL,3 ;Have we done all 4 pages?
JLE EMS_15_1_L1 ;No, loop back
XOR AH,AH
EMS_15_1_EXIT: POP SI
RET
EMS_15_1 ENDP
;----------------------------------------------------------------------
;Function 15.2 Get & Set mapping array
;----------------------------------------------------------------------
EMS_15_2 PROC NEAR
ASSUME DS:NOTHING,ES:NOTHING
PUSH DI
CALL EMS_15_0 ;Save current mapping array
POP DI
CALL EMS_15_1 ;Set new mapping context
XOR AH,AH
RET
EMS_15_2 ENDP
;----------------------------------------------------------------------
;Function 15.3 Get mapping array size
;----------------------------------------------------------------------
EMS_15_3 PROC NEAR
ASSUME DS:NOTHING,ES:NOTHING
MOV AX,0012H ;18 bytes in the page array
RET
EMS_15_3 ENDP
;======================================================================
;Function 16. Get/Set Partial Page Map
;======================================================================
EMS_16_TBL DB 2 ;Max value of subfunction
DW OFFSET EMS_16_0 ;Jump table for subfunctions
DW OFFSET EMS_16_1
DW OFFSET EMS_16_2
EMS_16 PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
PUSH BX
PUSH DX
MOV DS,SS:[BP-8] ;Get original DS from stack
ASSUME DS:NOTHING
MOV DI,OFFSET EMS_16_TBL ;Point to jump table structure
CALL EMS_DISPATCHER ;Dispatch routine calls
EMS_16_EXIT: POP DX ; subfunction routine.
POP BX
RET
EMS_16 ENDP
;----------------------------------------------------------------------
;Function 16.0 Get mapping array
;----------------------------------------------------------------------
EMS_16_0 PROC NEAR
ASSUME DS:NOTHING,ES:NOTHING
MOV CX,DS:[SI] ;get count of mappable segs.
MOV ES:[DI],CX ;save count
EMS_16_0_L1: MOV AX,DS:2[SI] ;Get segment to convert
CALL EMS_SEG2LOG ;convert segment onto page #
JC EMS_16_0_EXIT
MOV ES:2[DI],BX ;save physical page number
SAL BX,1 ;Convert page number
SAL BX,1 ; into offset
ADD BX,CS:MAP_ARRAY_PTR
MOV AX,CS:2[BX]
MOV ES:4[DI],AX ;save address low
MOV AX,CS:4[BX]
MOV ES:6[DI],AX ;save address high
ADD DI,6
INC SI ;point to next seg to save
INC SI
LOOP EMS_16_0_L1
XOR AX,AX
EMS_16_0_EXIT: RET
EMS_16_0 ENDP
;----------------------------------------------------------------------
;Function 16.1 Set mapping array
;----------------------------------------------------------------------
EMS_16_1 PROC NEAR
ASSUME DS:NOTHING,ES:NOTHING
MOV CX,DS:[SI] ;get count of pages
EMS_16_1_L1: MOV BX,2[SI] ;get logical page
MOV AX,4[SI] ;get address of page to
MOV DX,6[SI] ; restore
CALL EMS_EXCH_PAG ;Exchange current window page
ADD SI,6 ;Point si to next page
LOOP EMS_16_1_L1 ;No, loop back
XOR AX,AX ;Clear error code
EMS_16_1_EXIT: RET
EMS_16_1 ENDP
;----------------------------------------------------------------------
;Function 16.2 Get partial mapping array size
;----------------------------------------------------------------------
EMS_16_2 PROC NEAR
ASSUME DS:NOTHING,ES:NOTHING
MOV AX,BX ;get number of pages
MOV AH,6 ;6 bytes per page
MUL AH
ADD AX,2 ;add room for count
XOR AH,AH ;zero return code
RET
EMS_16_2 ENDP
;======================================================================
;Function 17. Map Multiple Handle Pages
;======================================================================
EMS_17 PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
MOV ES,SS:[BP-8] ;get pointer to map structure
CALL EMS_17_INTERNAL
RET
EMS_17 ENDP
;----------------------------------------------------------------------
;Function 17 (internal). Used by jump and call routines to map pages.
;----------------------------------------------------------------------
EMS_17_INTERNAL PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
PUSH BX
PUSH DX
JC EMS_17_EXIT ;carry set, invalid handle
CMP AL,1 ;no subfunction > 1.
JA EMS_17_ERR1
CMP CX,4 ;Make sure count < number of
JA EMS_17_ERR2 ; mappable pages.
MOV CH,AL ;save subfunction
EMS_17_L1: MOV AX,ES:[SI+2] ;get physical page number/seg
OR CH,CH
JE EMS_17_S3 ;if seg address mapping,
CALL EMS_SEG2LOG ; convert seg addr to number
JC EMS_17_EXIT ;check for error on conversion
MOV AL,BL
EMS_17_S3: MOV BX,ES:[SI] ;get logical page number
CLC ;handle valid
PUSH CX ;save count
CALL EMS_05 ;map page
POP CX ;restore count
OR AH,AH ;check for error
JNE EMS_17_EXIT
ADD SI,4 ;Move pointers to next
DEC CL ; mapping structure.
JNZ EMS_17_L1
XOR AX,AX ;clear return code
EMS_17_EXIT: POP DX
POP BX
RET
EMS_17_ERR1: MOV AH,8FH ;invalid subfunction
JMP SHORT EMS_17_EXIT
EMS_17_ERR2: MOV AH,8BH ;Number exceeds mappable pages
JMP SHORT EMS_17_EXIT ; in the system
EMS_17_INTERNAL ENDP
;======================================================================
;Function 18. Reallocate Pages
;======================================================================
EMS_18 PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
PUSH BX
PUSH DX
JC EMS_18_EXIT ;carry set, invalid handle
MOV DI,BX ;save reallocation count
PUSH BX
CALL EMS_13 ;get current count
MOV CX,BX
POP BX ;get back new count
SUB BX,CX
JG EMS_18_INCREASE
JL EMS_18_REDUCE
XOR AH,AH ;clear return code
EMS_18_EXIT: POP DX
POP BX
RET
EMS_18_INCREASE:
CALL EMS_ASSIGN
JMP SHORT EMS_18_EXIT
EMS_18_REDUCE: NEG BX ;turn into positive number
CALL EMS_DEALLOC
JMP SHORT EMS_18_EXIT
EMS_18 ENDP
;======================================================================
;Function 19. Get/Set Handle Attribute (Not Supported)
;======================================================================
EMS_19 PROC NEAR
ASSUME CS:CODE,DS:CODE
CMP AL,1
JE EMS_19_1 ;Set handle attribute.
CMP AL,2 ;For subfunctions 0 and 2,
JG EMS_19_ERR1 ; return volatile handle,
EMS_19_GOOD_EXIT:
XOR AX,AX ; non-volatile not supp
EMS_19_EXIT: RET
EMS_19_1: CALL EMS_CHECK_HDL ;See if good handle
JC EMS_19_ERR2
CMP BL,1 ;See if legal attribute type
JG EMS_19_ERR3 ; or if non-volatile.
JL EMS_19_GOOD_EXIT
MOV AH,91H ;function not supported
JMP SHORT EMS_19_EXIT
EMS_19_ERR1: MOV AH,8FH ;subfunction invalid
JMP SHORT EMS_19_EXIT
EMS_19_ERR2: MOV AH,83H ;invalid handle
JMP SHORT EMS_19_EXIT
EMS_19_ERR3: MOV AH,90H ;attribute type not defined.
JMP SHORT EMS_19_EXIT
EMS_19 ENDP
;======================================================================
;Function 20. Get/Set Handle Name
;======================================================================
EMS_20 PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
PUSH BX
PUSH DX
JC EMS_20_EXIT ;carry set, invalid handle
PUSH AX ;find spot for handle
MOV BX,CS ;get code segment
MOV AX,DX ;Compute offset by multipling
MOV AH,9 ; the handle number by the
MUL AH ; size of each entry (9).
MOV DX,AX
ADD DX,HANDLE_ARRAY
INC DX ;point dx past the handle used
POP AX ; flag.
OR AL,AL ;Check for get or set subfun.
JNE EMS_20_S1
;Get Handle Name
MOV SI,DX ;load pointer to handle name
JMP SHORT EMS_20_MOV
;Set Handle Name
EMS_20_S1: CMP AL,1 ;Make sure that subfunction
JNE EMS_20_ERR1 ; = 1.
MOV DS,SS:[BP-8] ;Get original DS
ASSUME DS:NOTHING
PUSH SI
PUSH DX
CALL EMS_21_1 ;First, search for handle
POP DX ; with this name. The
POP SI ; return code must be a0h.
AND AH,0FEH ; or a1h.
CMP AH,0A0H
JNE EMS_20_ERR2
MOV DI,DX ;Get back name pointer
PUSH CS
POP ES
ASSUME ES:CODE
EMS_20_MOV: MOV CX,8 ;copy name. move 8 bytes
REP MOVSB
XOR AX,AX ;clear return code
EMS_20_EXIT: POP DX
POP BX
RET
EMS_20_ERR1: MOV AH,8FH ;Invalid subfunction
JMP SHORT EMS_20_EXIT
EMS_20_ERR2: MOV AH,0A1H ;Handle already used
JMP SHORT EMS_20_EXIT
EMS_20 ENDP
;======================================================================
;Function 21. Get Handle directory
;======================================================================
EMS_21_TBL DB 2 ;Max value of subfunction
DW OFFSET EMS_21_0 ;Jump table for subfunctions
DW OFFSET EMS_21_1
DW OFFSET EMS_21_2
EMS_21 PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
MOV DS,SS:[BP-8] ;Get original DS
ASSUME DS:NOTHING
MOV DI,OFFSET EMS_21_TBL
CALL EMS_DISPATCHER
EMS_21_EXIT: RET
EMS_21 ENDP
;----------------------------------------------------------------------
;Function 21.0 Get Handle Directory
;----------------------------------------------------------------------
EMS_21_0 PROC NEAR
ASSUME DS:NOTHING,ES:NOTHING
PUSH DX
PUSH CS
POP DS
ASSUME DS:CODE
MOV SI,HANDLE_ARRAY
XOR AX,AX ;Clear RC and hndl counter
MOV DX,AX ;Start with handle 0
EMS_21_0_L1: CMP BYTE PTR [SI],0 ;Check flag to see if handle
JE EMS_21_0_S1 ; is used.
MOV ES:[DI],DX ;Store handle value
INC SI ;move SI past handle flag
ADD DI,2 ;move DI past handle
MOV CX,8 ;8 char per handle name
REP MOVSB
INC AL ;add to handle count
JMP SHORT EMS_21_0_S2
EMS_21_0_S1: ADD SI,9 ;move to the next handle
EMS_21_0_S2: INC DX ;check next handle
CMP DX,TOTAL_HANDLES ;last handle?
JB EMS_21_0_L1 ;no, loop back
POP DX
RET
EMS_21_0 ENDP
;----------------------------------------------------------------------
;Function 21.1 Search for Named Handle
;----------------------------------------------------------------------
EMS_21_1 PROC NEAR
ASSUME DS:NOTHING
PUSH BX
PUSH DS ;copy segment of name
POP ES
ASSUME ES:NOTHING
MOV DI,SI
MOV CX,8 ;Check for null string. If
XOR AL,AL ; null, skip scan for dup
REPE SCASB ; strings.
JE EMS_21_1_ERR1
MOV CX,CS:TOTAL_HANDLES ;look at all handles
PUSH CS ;ES:DI -> handle array
POP ES ;DS:SI -> handle name
ASSUME ES:CODE
MOV BX,SI ;bx holds handle name ptr
MOV AX,CS:HANDLE_ARRAY ;ax holds handle array ptr
INC AX ;move ax past handle flag
XOR DX,DX ;start handle count at 0
EMS_21_1_L1: MOV DI,AX ;Compare each of the handle
MOV SI,BX ; names with the new handle
PUSH CX
MOV CX,8
REPE CMPSB
POP CX
JE EMS_21_1_EXIT ;If match found print err msg.
ADD AX,9 ;move AX to next handle
INC DX
LOOP EMS_21_1_L1
MOV AH,0A0H ;handle not found
JMP SHORT EMS_21_1_EXIT1
EMS_21_1_EXIT: XOR AH,AH
EMS_21_1_EXIT1: POP BX
RET
EMS_21_1_ERR1: MOV AH,0A1H ;null handle found
JMP SHORT EMS_21_1_EXIT1
EMS_21_1 ENDP
;----------------------------------------------------------------------
;Function 21.2 Get Total Handles
;----------------------------------------------------------------------
EMS_21_2 PROC NEAR
ASSUME DS:NOTHING
MOV BX,CS:TOTAL_HANDLES ;Get number of allowed hdls
XOR AX,AX ;Clear return code.
RET
EMS_21_2 ENDP
;======================================================================
;Function 22. Alter Page Map and Jump
;======================================================================
EMS_22 PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
JC EMS_22_EXIT ;carry set, invalid handle
;Map new pages into window
MOV DI,SI ; ES:DI = pointer to map and
MOV ES,SS:[BP-8] ; jump data
MOV SI,ES:[DI] ;Modify return address on
MOV SS:[BP+2],SI ; the stack to the address
MOV SI,ES:[DI+2] ; in the jump structure.
MOV SS:[BP+4],SI
MOV SI,ES:[DI+5] ;Get pointer to mapping
MOV ES,ES:[DI+7] ; structure.
MOV CL,ES:[DI+4] ;get mapping count
XOR CH,CH
CALL EMS_17_INTERNAL ;alter page map
EMS_22_EXIT: RET
EMS_22 ENDP
;======================================================================
;Function 23. Alter Page Map and Call
;======================================================================
EMS_23 PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
JC EMS_23_JMP_END ;carry set, invalid handle
CMP AL,2 ;Check for stack size function
JNE EMS_23_S1
MOV BX,28 ;Say we need 28 bytes
XOR AH,AH
EMS_23_JMP_END: JMP EMS_23_EXIT
EMS_23_S1: PUSH AX ;Save subfunction
;Map new pages into window
MOV DI,SI ;get pointer to map and
MOV ES,SS:[BP-8] ; jump data
PUSH ES ;Save pointer to structure
PUSH DI
XOR CH,CH
MOV CL,ES:[DI+4] ;get mapping count
MOV SI,ES:[DI+5] ;get pointer to mapping
MOV ES,ES:[DI+7] ; structure
PUSH AX
CLC ;indicate good handle
CALL EMS_17_INTERNAL ;alter page map
OR AH,AH
POP AX ;Restore AX
JNE EMS_23_EXIT
;Restore values in the registers and call.
MOV AX,SS:[BP+6] ;get flags
PUSH AX
POPF ;load flags
MOV ES,SS:[BP-10] ;restore ES
MOV DS,SS:[BP-8] ;Restore DS
MOV SI,SS:[BP-6] ;Restore SI
MOV DI,SS:[BP-4] ;Restore DI
MOV CX,SS:[BP-2] ;Restore CX
ASSUME DS:NOTHING
PUSH BP ;Save my base pointer
MOV BP,SS:[BP] ;Restore BP
MOV AX,0000 ;Clear return code
CALL DWORD PTR DS:[SI] ;Call.
POP AX ;Get back pointer to stack
PUSH BP ;Save returned BP
MOV BP,AX ;Restore my base pointer
POP AX ;Get back returned BP
PUSHF ;Save returned flags
MOV [BP-10],ES
MOV [BP-8],DS ;Put reg values on stack
MOV [BP-6],SI ; to be restored on return
MOV [BP-4],DI
MOV [BP-2],CX
POP CX ;Get back returned flags
MOV SS:[BP+6],CX
MOV SS:[BP],AX ;Save returned BP
PUSH CS
POP DS
ASSUME DS:CODE
;Map old pages into window
POP DI ;Get back pointer to structure
POP ES
XOR CH,CH
MOV CL,ES:[DI+9] ;get mapping count
MOV SI,ES:[DI+10] ;get pointer to mapping
MOV ES,ES:[DI+12] ; structure
CLC ;indicate good handle
POP AX ;Restore subfunction
CALL EMS_17_INTERNAL ;alter page map
EMS_23_EXIT: RET
EMS_23 ENDP
;======================================================================
;Function 24. Move/Exchange Memory Region
;======================================================================
EMS_24_SUBFUN EQU [BP-1] ;Saved subfunction
EMS_24_DIR EQU [BP-2] ;Direction flag for move
EMS_24_COUNT EQU [BP-6] ;Amount of memory to move
EMS_24_SRC_PTR EQU [BP-10] ;Source move pointer
EMS_24_DEST_PTR EQU [BP-14] ;Destination move pointer
EMS_24_RET_CODE EQU [BP-15] ;RC for non-fatal error codes
EMS_24 PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
PUSH BX ;Save registers
PUSH DX
MOV ES,SS:[BP-8] ;Get DS off original stack
PUSH ES ;Push for local addressability
PUSH SI
PUSH BP
MOV BP,SP ;Set up pointer to local data
SUB SP,18 ;Make room on stack for data
MOV EMS_24_SUBFUN,AL ;Save subfunction
MOV BYTE PTR EMS_24_RET_CODE,0
MOV AX,ES:[SI] ;Get count from move struc
MOV DX,ES:[SI+2]
CMP DX,10H ;see if region size > 1M
JB EMS_24_S0
MOV AH,96H ;region > 1M byte
JMP EMS_24_EXIT
EMS_24_S0: MOV WORD PTR [EMS_24_COUNT],AX ;Save count. Compute
MOV WORD PTR [EMS_24_COUNT+2],DX ; the number of
MOV CX,16384 ; 16K pages needed.
DIV CX
MOV CH,AL ;Save number of pages
MOV CL,DL ;save remainder
;Verify handles have the pages assigned. (If Expanded memory.)
ADD SI,4 ;move pointer to source descr
MOV DI,-10 ;Pointer to src local store
CALL EMS_CHECK_MOV
JC EMS_24_JMP_EXIT
PUSH AX ;Save source end address
PUSH DX
ADD SI,7 ;Point to destination block
MOV DI,-14 ;Pointer to dest local store
CALL EMS_CHECK_MOV
POP DI ;Recover source end address
POP BX
JNC EMS_24_S01 ;If error flag set, exit
EMS_24_JMP_EXIT:
JMP EMS_24_EXIT
EMS_24_S01: MOV BYTE PTR EMS_24_DIR,0 ;Set direction flag bottom up
;Check and adjust for overlap if necessary. If exchange, don't allow overlap.
MOV CL,BYTE PTR ES:[SI] ;Get destination memory type
ADD CL,BYTE PTR ES:[SI-7] ;Compare to source memory type
CMP CL,1 ;0 = both conv, 1 = diff types,
JE EMS_24_MOVEDATA ; 2 = both expanded.
JB EMS_24_S2 ;0, check conv overlap.
MOV CX,ES:[SI+1] ;Get dest handle
CMP CX,ES:[SI-6] ;Compare to source handle
JNE EMS_24_MOVEDATA ;Not the same, no overlap
MOV CX,ES:[SI-2] ;Get source starting page
CMP CX,ES:[SI+5] ;Compare dest starting page
JB EMS_24_S1 ;If source starts first,
JA EMS_24_S02 ; bottom up move.
MOV CX,ES:[SI-4] ;Get source starting offset
CMP CX,ES:[SI+3] ;Get source starting offset
JB EMS_24_S1 ;Source lower, bottom up move
EMS_24_S02: MOV BX,AX ;Copy from top down.
MOV DI,DX ;Put end addr of Dest in DI,BX
SUB SI,7 ;Point to source descriptor
MOV BYTE PTR EMS_24_DIR,1 ;Set direction top down
EMS_24_S1: CMP DI,ES:[SI+5] ;Compare end with start addr
JB EMS_24_MOVEDATA ;No overlap
JA EMS_24_OVERLAP ;Overlap
CMP BX,ES:[SI+3] ;Same pages, check offsets
JB EMS_24_MOVEDATA ;If less, no overlap
JMP SHORT EMS_24_OVERLAP
;Check for overlap of conventional memory regions.
EMS_24_S2: CMP DX,DI ;Compare high word
JB EMS_24_S3 ;dest higher, top down
JA EMS_24_S21 ;Less, bottom up.
CMP AX,BX ;Compare low word of address
JB EMS_24_S3 ;Jmp if dest addr higher
EMS_24_S21: MOV SI,-14 ;Point to dest descriptor
CALL EMS_24_ADR_CNV
XCHG DI,DX ;Exchange starting addresses
XCHG BX,AX
MOV SI,-10 ;Point to source descriptor
CALL EMS_24_ADR_CNV
MOV BYTE PTR EMS_24_DIR,1 ;Set direction flag top down
EMS_24_S3: SUB BX,WORD PTR [EMS_24_COUNT] ;Generate start addr
SBB DI,WORD PTR [EMS_24_COUNT+2]
CMP DX,DI ;Compare starting addr with
JB EMS_24_MOVEDATA ; end of other block
CMP AX,BX
JBE EMS_24_MOVEDATA
EMS_24_OVERLAP: MOV BYTE PTR EMS_24_RET_CODE,92H ;Indicate overlap
CMP BYTE PTR EMS_24_SUBFUN,0 ;If exch. don't allow
JE EMS_24_MOVEDATA ; overlap.
MOV AH,97H ;Error, no overlap
JMP EMS_24_EXIT ; on exchange.
;Move/Exchange the data
EMS_24_MOVEDATA:
MOV BX,MAP_ARRAY_PTR ;Save context of pages 0 & 1
PUSH [BX+8] ;Save address for page 1
PUSH [BX+6]
PUSH [BX+4] ;Save address for page 0
PUSH [BX+2]
STD
CMP BYTE PTR EMS_24_DIR,0 ;If moving from top to bottom
JNE EMS_24_MOVE0 ; set direction flag for move
CLD
MOV AX,ES:[SI-4] ;If move from bottom to top,
MOV DX,ES:[SI-2] ; initialize the
MOV WORD PTR [EMS_24_SRC_PTR],AX ; pointers back to
MOV WORD PTR [EMS_24_SRC_PTR+2],DX ; the starting
MOV AX,ES:[SI+3] ; addresses.
MOV DX,ES:[SI+5]
MOV WORD PTR [EMS_24_DEST_PTR],AX
MOV WORD PTR [EMS_24_DEST_PTR+2],DX
EMS_24_MOVE0: XOR CX,CX ;Clear last move count
EMS_24_MOVELOOP:
MOV ES,[BP+4] ;Restore move structure
MOV BX,[BP+2] ; pointer to ES:BX
MOV DX,ES ;Save ES
MOV AX,CX ;Save last count
ADD BX,4 ;Point to source descriptor
XOR SI,SI ;Indicate source
CALL EMS_24_MOV_SET
PUSH ES ;Save source pointer
PUSH DI
XCHG CX,AX ;save count, restore last cnt
MOV ES,DX ;Restore ES
ADD BX,7 ;Point to dest mem descriptor
MOV SI,1
CALL EMS_24_MOV_SET ;Map extended mem if needed
POP SI ;Get back source pointer
POP BX ;Save segment in BX
CMP AX,CX ;Get lower count
JA EMS_24_MOVE1
MOV CX,AX
EMS_24_MOVE1: MOV AX,WORD PTR [EMS_24_COUNT] ;Get move count
MOV DX,WORD PTR [EMS_24_COUNT+2]
OR DX,DX ;See if at end of
JNE EMS_24_MOVE2 ; count. If so,
CMP AX,CX ; copy only to end
JA EMS_24_MOVE2 ; of count.
MOV CX,AX
EMS_24_MOVE2: SUB AX,CX ;Subtract from count
SBB DX,0
PUSH CX
PUSH AX ;Save count
PUSH DX
CMP BYTE PTR EMS_24_SUBFUN,1 ;See if move or exch
MOV DS,BX ;Time to set DS
ASSUME DS:NOTHING
JE EMS_24_EXCH
REP MOVSB ;Move that data
JMP SHORT EMS_24_MOVE3
EMS_24_EXCH: MOV BL,ES:[DI] ;Get dest byte
MOVSB
CMP BYTE PTR EMS_24_DIR,0 ;Check direction flag to
JNE EMS_24_EXCH1 ; make sure of pointers
MOV DS:[SI-1],BL ;Move dest byte to source
JMP SHORT EMS_24_EXCH2
EMS_24_EXCH1: MOV DS:[SI+1],BL ;Move dest byte to source
EMS_24_EXCH2: LOOP EMS_24_EXCH ;Loop until block exchanged.
EMS_24_MOVE3: PUSH CS ;Restore DS altered by move
POP DS
ASSUME DS:CODE
POP DX ;Get back count
POP AX
POP CX
MOV WORD PTR [EMS_24_COUNT],AX ;Restore count
MOV WORD PTR [EMS_24_COUNT+2],DX
OR DX,DX
JNE EMS_24_MOVE4 ;See if count has expired.
OR AX,AX
JLE EMS_24_LOOP_DONE
EMS_24_MOVE4: JMP EMS_24_MOVELOOP
EMS_24_LOOP_DONE: ;Restore pages 0 and 1.
XOR BX,BX ;set physical page = 0
POP AX ;get address of page to
POP DX ; restore
CALL EMS_EXCH_PAG ;Exchange current window page
MOV BX,1 ;set physical page = 1
POP AX ;get address of page to
POP DX ; restore
CALL EMS_EXCH_PAG ;Exchange current window page
MOV AH,BYTE PTR EMS_24_RET_CODE ;Get return code
EMS_24_EXIT: ADD SP,18 ;Deallocate local storage
POP BP
POP SI
POP ES
POP DX
POP BX
RET
EMS_24 ENDP
;----------------------------------------------------------------------
;Convert address to segment offset form
;Entry: dx ax - address
; si - pointer to local memory descriptor
;----------------------------------------------------------------------
EMS_24_ADR_CNV PROC NEAR
PUSH AX
PUSH DX
MOV CX,16384 ;Convert address to seg:offset
DIV CX
MOV WORD PTR [BP+SI],DX ;Save offset
MOV CL,10
SAL AX,CL
MOV WORD PTR [BP+SI+2],AX ;Save segment
POP DX
POP AX
RET
EMS_24_ADR_CNV ENDP
;----------------------------------------------------------------------
;Setup ems page for move.
;Entry: al - 0 = source page, 1 = destination page.
; es:bx - pointer to external memory descriptor
; cx - Count used on last move
;Exit: ES:DI - pointer to data to move
; cx - max count before crossing boundry.
;----------------------------------------------------------------------
EMS_24_MOV_SET PROC NEAR
ASSUME DS:CODE
PUSH AX
PUSH BX
PUSH DX
MOV DX,SI
MOV SI,-10 ;Use SI as offset to src_ptr
OR DX,DX
JE EMS_24_MOV_SET_S0
SUB SI,4 ;Point SI to dest_ptr
EMS_24_MOV_SET_S0:
MOV DH,BYTE PTR ES:[BX] ;Get memory type
MOV AX,16383 ;Load constants for EMS mem
MOV DI,1
OR DH,DH ;Check type of number
JNE EMS_24_MOV_SET_S1 ;1 = EMS memory
MOV DI,1024 ;Load constants for
; conventional memory.
EMS_24_MOV_SET_S1:
CMP BYTE PTR EMS_24_DIR,0 ;If bottom up move, skip
JE EMS_24_MOV_SET_S3
;Top down.
SUB WORD PTR [BP+SI],CX ;Sub last move from offset
JAE EMS_24_MOV_SET_S2 ;See if end of page
MOV WORD PTR [BP+SI],AX ;Start at top of next page
SUB WORD PTR [BP+SI+2],DI ;Point to next page
EMS_24_MOV_SET_S2:
MOV CX,WORD PTR [BP+SI] ;Get offset for count
INC CX
JMP EMS_24_MOV_SET_S5
;Bottom up
EMS_24_MOV_SET_S3:
ADD WORD PTR [BP+SI],CX ;Add last move to offset
CMP WORD PTR [BP+SI],AX ;See if end of page
JBE EMS_24_MOV_SET_S4
EMS_24_MOV_SET_S31:
MOV WORD PTR [BP+SI],0 ;Start at bottom of page
ADD WORD PTR [BP+SI+2],DI ;Point to next page
EMS_24_MOV_SET_S4:
MOV CX,AX ;Compute count to end of page
SUB CX,WORD PTR [BP+SI]
INC CX
EMS_24_MOV_SET_S5:
OR DH,DH ;Check type of number
JE EMS_24_MOV_SET_CONV1 ;If conventional, don't map
PUSH CX ;Save new count
PUSH DX
MOV AL,DL ;Pass proper phyical page
MOV DX,WORD PTR ES:[BX+1] ;Get handle
MOV BX,WORD PTR [BP+SI+2] ;Put page in proper register
PUSHF ;Save direction flag state
CLD ;Set assumed direction flag
CLC ;Set handle good flag
CALL EMS_05 ;Map page
POPF ;Get back flags
POP DX
POP CX ;Get count back
MOV AX,WINDOW_SEG ;Get window segment
OR DL,DL ;See if source or dest
JE EMS_24_MOV_SET_S6 ;If destination, point to
ADD AX,1024 ; 2nd page. 1024 paragraphs
EMS_24_MOV_SET_S6:
MOV ES,AX ;Set pointer to data
EMS_24_MOV_SET_EXIT:
MOV DI,WORD PTR [BP+SI] ;Load offset
POP DX
POP BX
POP AX
RET
EMS_24_MOV_SET_CONV1:
MOV DI,WORD PTR [BP+SI+2]
MOV ES,DI
JMP SHORT EMS_24_MOV_SET_EXIT
EMS_24_MOV_SET ENDP
;----------------------------------------------------------------------
;Check parameters for move or exchange
;Entry: es:si - pointer to memory descriptor
; bp+di - pointer to local store descriptor
; ch - number of extended pages needed
; cl - number of bytes into last extended page
;Exit: dx,ax - ending address if conventional
; ax - ending page if expanded
; dx - ending offset if expanded
;----------------------------------------------------------------------
EMS_CHECK_MOV PROC NEAR
ASSUME DS:CODE,ES:NOTHING
PUSH BX
PUSH CX
PUSH DI
XOR AX,AX
MOV AL,CH ;Get number of pages needed
MOV DI,AX ;Save number of pages in DI
XOR CH,CH
MOV AX,ES:[SI+5] ;Get segment/page
MOV BX,ES:[SI+3] ;get offset
MOV DL,ES:[SI] ;Get memory type
OR DL,DL ;See if EMS or low memory
JE EMS_CHECK_MOV_CONV ;jump if low memory
CMP DL,1 ;If not low mem make sure
JE EMS_CHECK_MOV_S1 ; EMS memory.
MOV AH,98H ;Invalid memory type
JMP EMS_CHECK_MOV_SET_ERR
EMS_CHECK_MOV_S1:
CMP BX,3FFFH ;Check for offset < 16K
JA EMS_CHECK_MOV_ERR1
;See if the handle owns enough pages to hold the region.
MOV DX,ES:[SI+1] ;Get handle
PUSH CX
CALL EMS_CHECK_HDL ;Verify handle.
CALL EMS_13 ;Get number of pages owned
POP CX ; by handle
OR AH,AH ;If error, set carry and
JNE EMS_CHECK_MOV_SET_ERR ; return.
MOV DX,BX ;save number of pages
MOV BX,ES:[SI+5] ;Get logical page number
MOV AX,DI ;Copy number of pages needed
ADD AX,BX ;Add starting page.
ADD CX,ES:[SI+3] ;Add start offset to remainder
DEC CX ; of the num of pages needed.
CMP CX,16384
JL EMS_CHECK_MOV_S4 ;If rem+offset > 16K add a
INC AX ; page to the num needed.
SUB CX,16384
EMS_CHECK_MOV_S4:
CMP AX,DX ;Compare to total number of
JG EMS_CHECK_MOV_ERR3 ; pages.
MOV DX,CX ;Copy ending offset
XCHG AX,DX ;Exchange offset and segment
EMS_CHECK_MOV_EXIT:
CLC ;Clear error flag
EMS_CHECK_MOV_EXIT1:
POP DI ;Restore registers
MOV [BP+DI],AX ;Save offset
MOV [BP+DI+2],DX ;Save segnent/page
POP CX
POP BX
RET
EMS_CHECK_MOV_CONV:
MOV CX,16 ;convert segment into address
MUL CX
ADD AX,BX ;Add offset
ADC DX,0
ADD AX,WORD PTR [EMS_24_COUNT] ;Add len to start addr
ADC DX,WORD PTR [EMS_24_COUNT+2]
SUB AX,1 ;Decriment count
SBB DX,0
JMP SHORT EMS_CHECK_MOV_EXIT
EMS_CHECK_MOV_ERR1:
MOV AH,95H ;offset too large
EMS_CHECK_MOV_SET_ERR:
STC ;Indicate error
JMP SHORT EMS_CHECK_MOV_EXIT1
EMS_CHECK_MOV_ERR3:
MOV AH,93H ;Not enough pages
JMP SHORT EMS_CHECK_MOV_SET_ERR
EMS_CHECK_MOV ENDP
;======================================================================
;Function 25. Get Mappable Physical Address Array
;======================================================================
EMS_25 PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
CMP AL,1 ;assure subfunction 0 or 1.
JB EMS_25_S1
JE EMS_25_EXIT
MOV AH,8FH ;Unknown subfunction
JMP SHORT EMS_25_EXIT1
EMS_25_S1: MOV AX,WINDOW_SEG
XOR CX,CX
EMS_25_L1: MOV ES:[DI],AX ;write segment
MOV ES:2[DI],CX ;write segment number
ADD AX,1024 ;Point to next segment
ADD DI,4
INC CX ;Indicate next page
CMP CX,3
JLE EMS_25_L1
EMS_25_EXIT: MOV WORD PTR SS:[BP-2],4 ;replace saved CX with 4
XOR AX,AX ;clear return code
EMS_25_EXIT1: RET
EMS_25 ENDP
;======================================================================
;Function 26. Get Expanded Memory Hardware Information
;======================================================================
EMS_26 PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
CMP OS_ENABLED,1 ;Are OS funcctions enabled?
JNE EMS_26_ERR1 ;No, exit
CMP AL,1 ;Subfunction 1, get page cnt
JB EMS_26_0 ;Jmp to subfunction 0
JA EMS_26_ERR2 ;If > 1, invalid subfunction.
EMS_26_1: CALL EMS_03 ;Since raw page = normal page,
JMP SHORT EMS_26_EXIT ; get normal page count.
EMS_26_0: XOR CX,CX
MOV WORD PTR ES:[DI],1024 ;16K pages (1024 paragraphs)
MOV ES:2[DI],CX ;No alternate register sets
CALL EMS_15_3 ;Get context area size
MOV ES:4[DI],AX
MOV ES:6[DI],CX ;No DMA channels
MOV ES:8[DI],CX ;DMA channel operation
XOR AX,AX ;clear return code
EMS_26_EXIT: RET
EMS_26_ERR1: MOV AH,0A4H ;operating system denied
JMP SHORT EMS_26_EXIT ; access.
EMS_26_ERR2: MOV AH,8FH ;Invalid subfunction
JMP SHORT EMS_26_EXIT
EMS_26 ENDP
;======================================================================
;Function 27. Get handle and allocate pages
;======================================================================
EMS_27 PROC NEAR
ASSUME DS:CODE,ES:NOTHING
PUSH BX ;Save register
CMP BX,TOTAL_PAGES ;Make sure request is not out
JLE EMS_27_S1 ; of range.
MOV AH,87H ;Not enough pages in system
JMP SHORT EMS_27_EXIT
EMS_27_S1: PUSH BX ;save num. of pages to alloc
XOR DX,DX ;search for handle =-1 (unaloc)
DEC DX
CLC
CALL EMS_13 ;get unallocated page count.
POP CX
CMP BX,CX ;check for enough free pages
JL EMS_27_ERR1
MOV DI,HANDLE_ARRAY ;Assign handle
XOR AX,AX ;search for free handles
MOV DX,AX ;dx=0 at start of hndl search
EMS_27_L1: CMP AL,[DI] ;if handle id = 0 then that
JE EMS_27_S2 ; hndl has not been allocated.
ADD DI,9 ;Move di to point to next id.
INC DX
CMP DX,TOTAL_HANDLES ;have we searched all handles?
JB EMS_27_L1
MOV AH,85H ;no free handles
JMP SHORT EMS_27_EXIT
EMS_27_S2: DEC BYTE PTR [DI] ;indicate that handle is used
MOV BX,CX
CALL EMS_ASSIGN ;alloc pages, dx = new handle
EMS_27_EXIT: POP BX ;Restore register
RET
EMS_27_ERR1: MOV AH,88H
JMP SHORT EMS_27_EXIT
EMS_27 ENDP
;======================================================================
;Function 28. Alternate Map Register Set
;======================================================================
EMS_28_TBL DB 8 ;Subfunction limit
DW OFFSET EMS_28_0 ;Jump table for subfunctions
DW OFFSET EMS_28_1
DW OFFSET EMS_28_2
DW OFFSET EMS_28_3
DW OFFSET EMS_28_4
DW OFFSET EMS_28_3
DW OFFSET EMS_28_6
DW OFFSET EMS_28_6
DW OFFSET EMS_28_6
EMS_28 PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
CMP OS_ENABLED,1 ;See if function enabled
JNE EMS_28_ERR1
MOV DI,OFFSET EMS_28_TBL
CALL EMS_DISPATCHER
EMS_28_EXIT: RET
EMS_28_ERR1: MOV AH,0A4H ;operating system denied
JMP SHORT EMS_28_EXIT ; access.
EMS_28 ENDP
;----------------------------------------------------------------------
;Function 28.0 Get Alternate Map Register Set
;----------------------------------------------------------------------
EMS_28_0 PROC NEAR
PUSH DX
MOV ES,ALT_MAP_PTRS ;Get pointer
MOV DI,ALT_MAP_PTRO
MOV SS:[BP-10],ES
OR DI,DI ;See if it is zero
JNE EMS_28_0_S1
MOV CX,ES ;If so, exit without saving
OR CX,CX ; page map array.
XOR AX,AX ;Clear return code
JE EMS_28_0_EXIT
EMS_28_0_S1: PUSH DI ;save original pointer
CALL EMS_15_0 ;copy page map
POP DI ;The return code will be
EMS_28_0_EXIT: XOR BL,BL ; set by Function 15.0
POP DX ;Indicate non-support for
RET ; alternate mapping regs.
EMS_28_0 ENDP
;----------------------------------------------------------------------
;Function 28.1 Set Alternate Map Register Set
;----------------------------------------------------------------------
EMS_28_1 PROC NEAR
PUSH BX
PUSH DX
OR BL,BL ;check bl = 0
JNE EMS_28_1_ERR
MOV ALT_MAP_PTRS,ES ;Save mapping pointer
MOV ALT_MAP_PTRO,DI
OR DI,DI ;See if it is zero
JNE EMS_28_1_S1
MOV CX,ES ;If so, exit without restoring
OR CX,CX ; page map array.
JE EMS_28_1_EXIT
EMS_28_1_S1: PUSH DS
MOV SI,ES ;Put pointer into ds:si for
MOV DS,SI ; function 15.1 call.
ASSUME DS:NOTHING
MOV SI,DI ;DS:SI = ES:DI
CALL EMS_15_1 ;Restore page map
POP DS
ASSUME DS:CODE
EMS_28_1_EXIT: POP DX
POP BX
RET
EMS_28_1_ERR: MOV AH,9CH ;Alternate map register
JMP SHORT EMS_28_EXIT ; sets not supported.
EMS_28_1 ENDP
;----------------------------------------------------------------------
;Function 28.2 Get Alternate Map Save Array Size
;----------------------------------------------------------------------
EMS_28_2 PROC NEAR
CALL EMS_15_3 ;Get save array size.
MOV DX,AX
RET
EMS_28_2 ENDP
;----------------------------------------------------------------------
;Function 28.3 and 28.5 Deallocate Map Register Set
;----------------------------------------------------------------------
EMS_28_3 PROC NEAR
XOR BL,BL ;set bl = 0
XOR AX,AX
RET
EMS_28_3 ENDP
;----------------------------------------------------------------------
;Function 28.4 Deallocate Alternate Map Register Set
;----------------------------------------------------------------------
EMS_28_4 PROC NEAR
OR BL,BL ;See if zero page indicated
JNE EMS_28_4_ERR1 ; if not, error
XOR AX,AX ;Clear return code.
MOV ALT_MAP_PTRS,AX ;Clear mapping pointer
MOV ALT_MAP_PTRO,AX
EMS_28_4_EXIT: RET
EMS_28_4_ERR1: MOV AH,9CH ;Alt register sets not
JMP SHORT EMS_28_4_EXIT ; supported
EMS_28_4 ENDP
;----------------------------------------------------------------------
;Function 28.6-28.8 Unsupported Subfunctions
;----------------------------------------------------------------------
EMS_28_6 PROC NEAR
OR BL,BL ;see if zero page indicated
JNE EMS_28_6_ERR1 ;if not, error
XOR AX,AX ;clear return code.
EMS_28_6_EXIT: RET
EMS_28_6_ERR1: MOV AH,9CH ;Alt register sets not
JMP SHORT EMS_28_6_EXIT ; supported
EMS_28_6 ENDP
;======================================================================
;Function 30. OS/E Functions
;======================================================================
EMS_30 PROC NEAR
PUSH DX
CMP OS_PASS_LOW,0
JNE EMS_30_S1
CMP OS_PASS_HIGH,0
JE EMS_30_S2 ;first call, create password.
EMS_30_S1: CMP OS_PASS_LOW,BX ;Check password
JNE EMS_30_ERR1
CMP OS_PASS_HIGH,CX
JNE EMS_30_ERR1
JMP SHORT EMS_30_S3
EMS_30_S2: PUSH AX ;Read the system time using
XOR AH,AH ; bios int 1A function 00.
INT 1AH
MOV AX,DX ;copy low word of time
INC CX ;multiply by high word. Inc
MUL CX ;to assure count <> 0.
MOV OS_PASS_LOW,AX
MOV OS_PASS_HIGH,DX
MOV BX,AX ;Return password in BX,CX
MOV SS:[BP-2],DX ;Update CX on stack
POP AX ;get back subfunction
EMS_30_S3: CMP AL,2 ;return key function
JNE EMS_30_S4
XOR AX,AX ;Clear return code
MOV OS_PASS_LOW,AX ;Clear password
MOV OS_PASS_HIGH,AX
MOV OS_ENABLED,1 ;set op system flag
JMP SHORT EMS_30_EXIT
EMS_30_S4: CMP AL,1 ;Disable op system functions
JNE EMS_30_S5
MOV OS_ENABLED,0 ;Clear flag
JMP SHORT EMS_30_EXIT
EMS_30_S5: OR AL,AL ;Enable op system functions
JNE EMS_30_ERR2
MOV OS_ENABLED,1 ;Set flag
EMS_30_EXIT: XOR AX,AX
EMS_30_EXIT1: POP DX
RET
EMS_30_ERR1: MOV AH,0A4H ;Access denied
JMP SHORT EMS_30_EXIT1
EMS_30_ERR2: MOV AH,8FH ;Subfunction not defined
JMP SHORT EMS_30_EXIT1
EMS_30 ENDP
;======================================================================
;Unsupported Function
;======================================================================
EMS_UNSP PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
MOV AH,91H ;Feature not supported.
RET
EMS_UNSP ENDP
;-----------------------------------------------------------------------------
;Convert segment address into logical page number
;Entry: ax - segment address to convert EXIT: bl - logical page number
;-----------------------------------------------------------------------------
EMS_SEG2LOG PROC NEAR
ASSUME CS:CODE,DS:NOTHING,ES:NOTHING
PUSH CX
PUSH DX
XOR BX,BX ;clear logical sector number
MOV DX,CS:WINDOW_SEG
MOV CX,4
EMS_SEG2_L1: CMP AX,DX
JE EMS_SEG2_FND
ADD DX,400H
INC BX
LOOP EMS_SEG2_L1
MOV AH,8BH ;segment not valid
STC
JMP SHORT EMS_SEG2_EXIT
EMS_SEG2_FND: CLC
EMS_SEG2_EXIT: POP DX
POP CX
RET
EMS_SEG2LOG ENDP
;------------------------------------------------------------------------
;EMS convert logical page to address
;Entry: bx = logical page dx = handle of page owner
;Exit: dx,ax - absolute address of page. carry set - page not found
;------------------------------------------------------------------------
EMS_LOG2PHY PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
PUSH DI
MOV DI,PAG_OWNER_TBL ;Point to page owner table
MOV CX,TOTAL_PAGES ;Check entry for each page
EMS_LOG2P_L1: CMP BYTE PTR [DI],DL ;See if owned by handle
JNE EMS_LOG2P_S1
CMP WORD PTR [DI+1],BX ;See if this is the page
JE EMS_LOG2P_S2 ; we have been looking for.
EMS_LOG2P_S1: ADD DI,3
LOOP SHORT EMS_LOG2P_L1
MOV AH,8AH ;page out of range for handle
STC
JMP SHORT EMS_LOG2PHY_EXIT
EMS_LOG2P_S2: SUB DI,PAG_OWNER_TBL ;compute the phy page address
MOV AX,DI
XOR DX,DX ;Clear high word
MOV CX,3 ;Divide by size of each entry
DIV CX
MOV CX,16384 ;Mul page number by size of
MUL CX ; page.
ADD AX,EXTEND_ADRL ;Add starting address
ADC DL,EXTEND_ADRH
XOR DH,DH
CLC ;clear error flag
EMS_LOG2PHY_EXIT:
POP DI
RET
EMS_LOG2PHY ENDP
;------------------------------------------------------------------------
;EMS Assign pages bx = number of pages needed dx = handle to assign pages.
;------------------------------------------------------------------------
EMS_ASSIGN PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
CMP AX,TOTAL_PAGES ;see if enough total pages
JG EMS_ASSIGN_ERR2
PUSH DX ;save handle
PUSH BX ;save pages to add
MOV DX,0FFFFH ;load unassigned handle
CLC ;Get number of unassigned
CALL EMS_13 ; pages.
POP AX ;Get back number of pages
POP DX ;Get back handle
CMP BX,AX ;are there enough pages?
JL EMS_ASSIGN_ERR1 ;No, return error code.
PUSH AX ;Save number of pages to alloc
CLC ;Set handle found flag
CALL EMS_13 ;Get number of pages assigned
POP AX ;Get back num pages requested
MOV DI,PAG_OWNER_TBL ;point to page owner table
MOV CX,TOTAL_PAGES ;Get size of the array
INC CX ;Make sure loop complete
EMS_ASSIGN_L1: OR AX,AX ;See if we have assigned
JE EMS_ASSIGN_S2 ; enough pages.
CMP BYTE PTR [DI],0FFH ;see if page is unowned
JNE EMS_ASSIGN_S1 ;Page owned, try another.
MOV [DI],DL ;if so, assign it to the hndl
MOV [DI+1],BX ;Assign page number
INC BX ;inc page number to assign
DEC AX ;one less page needed.
EMS_ASSIGN_S1: ADD DI,3 ;point to the next page entry
LOOP EMS_ASSIGN_L1
EMS_ASSIGN_ERR1:
MOV AH,88H ;not enough unallocated pages
STC ;set error flag
JMP SHORT EMS_ASSIGN_EXIT
EMS_ASSIGN_ERR2:
MOV AH,87H ;not enough pages in system
STC ;set error flag
JMP SHORT EMS_ASSIGN_EXIT
EMS_ASSIGN_S2: CLC
XOR AX,AX ;Clear return code.
EMS_ASSIGN_EXIT:
RET
EMS_ASSIGN ENDP
;------------------------------------------------------------------------
;EMS Deallocate pages
;Entry: dx = handle
; bl = number of pages to deallocate
;------------------------------------------------------------------------
EMS_DEALLOC PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
CMP BL,0FFH ;See if clear all
JNE EMS_DEALLOC_S0
XOR BX,BX
JMP SHORT EMS_DEALLOC_S1
EMS_DEALLOC_S0: XOR BH,BH
PUSH BX ;Save num of pages to dealloc
CLC
CALL EMS_13 ;Get num of pages owned
POP AX ;Get back num pages to dealloc
SUB BX,AX ;Sub dealloc from total
EMS_DEALLOC_S1: MOV DI,PAG_OWNER_TBL ;Point to the page owner table
MOV CX,TOTAL_PAGES
EMS_DEALLOC_L1: CMP [DI],DL ;compare handle
JNE EMS_DEALLOC_S2 ;if not, keep looking
CMP [DI+1],BX ;compare page number if above
JB EMS_DEALLOC_S2 ; new limit, erase. Else,
MOV BYTE PTR [DI],0FFH ; keep looking
MOV WORD PTR [DI+1],0FFFFH
EMS_DEALLOC_S2: ADD DI,3 ;Point to next entry
LOOP EMS_DEALLOC_L1
EMS_DEALLOC_EXIT:
XOR AH,AH ;Clear return code.
RET
EMS_DEALLOC ENDP
;-----------------------------------------------------------------------------
;EMS Subfunction dispatcher
;Entry: DI = pointer to jump table structure
;-----------------------------------------------------------------------------
EMS_DISPATCHER PROC NEAR
ASSUME CS:CODE,DS:NOTHING,ES:NOTHING
CMP AL,CS:[DI] ;Compare subfunction to limit
JA EMS_DIS_ERR1 ;If above, error.
PUSH BX ;Save BX
MOV BL,AL ;Convert subfunction to
XOR BH,BH ; jump address.
SHL BX,1
ADD BX,DI ;Add offset into jump table
INC BX ;Skip past limit
MOV DI,BX ;Copy jump address pointer
POP BX ;Restore BX
PUSH CS:[DI] ;Save jump address
MOV DI,SS:[BP-4] ;Restore DI
RETN ;Jump to subfunction code.
EMS_DIS_ERR1: MOV AH,8FH ;Illegal subfunction
STC ;Set error flag
RET
EMS_DISPATCHER ENDP
;-----------------------------------------------------------------------------
;EMS Check Handle
;Entry: dx = handle to check Exit: zero flag set - handle not found, ah = 83h
;-----------------------------------------------------------------------------
EMS_CHECK_HDL PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
PUSH DX
PUSH BX
OR DH,DH ;dh must be 0 for valid handle
JNE EMS_CHECK_ERROR
XCHG AX,DX ;Save ax
MOV AH,9 ;Convert handle into an index
MUL AH ; into the array
MOV BX,AX ;copy to base register
ADD BX,HANDLE_ARRAY ;add base address of array
MOV AX,DX ;restore ax
CMP BYTE PTR [BX],0 ;If byte<>0, then good handle
JE EMS_CHECK_ERROR
CLC ;clear error flag
EMS_CHECK_EXIT: POP BX
POP DX
RET
EMS_CHECK_ERROR:
MOV AH,83H ;load error return code in ah
STC ;set error flag
JMP SHORT EMS_CHECK_EXIT
EMS_CHECK_HDL ENDP
;------------------------------------------------------------------------
;EMS exchange page
;Entry: bl = window page to map dl,ax = absolute address of page to map.
;------------------------------------------------------------------------
EMS_EXCH_PAG PROC NEAR
ASSUME CS:CODE,DS:NOTHING,ES:NOTHING
PUSH CX
PUSH SI
PUSH DS
PUSH ES
PUSH CS ;point DS, ES to code segment
POP DS
ASSUME DS:CODE,ES:CODE
PUSH DEST.BASE_ADRL ;Save GTD data in case a
PUSH SOURCE.BASE_ADRL ; reentrant call is made.
MOV CH,DEST.BASE_ADRH
MOV CL,SOURCE.BASE_ADRH
PUSH CX
MOV DI,OFFSET WINDOW_ADDR_BASE ;Point to window addr
MOV SI,MAP_ARRAY_PTR ;Point to mapping array.
INC SI
INC SI
XOR BH,BH ;Clear high byte of page num
;Check to see if previous process was interrupted. If so, complete last move.
PUSH BX ;Save page number
MOV BL,MOVE_BUSY_FLAG ;If not 0, this flag contains
OR BL,BL ; the page that was being
JE EMS_EXCH_NOT_BUSY ; moved when the driver was
DEC BL ; interrupted.
PUSH AX ;Save new address for a moment
PUSH DX
MOV AX,[DI+BX] ;Load window address into
MOV DL,[DI+BX+2] ; destination registers.
MOV CX,SAVED_ADDR_LOW ;Load physical page address
MOV DH,SAVED_ADDR_HIGH ; into source registers.
CALL EMS_MOVE_DATA ;Move memory
MOV MOVE_BUSY_FLAG,0 ; busy flag.
POP DX ;Get back new address
POP AX
EMS_EXCH_NOT_BUSY:
POP BX ;Get back page number
SAL BX,1 ;Convert page number into
SAL BX,1 ; array index.
MOV DH,1
CMP AX,[SI+BX] ;Check to see if page to be
JNE EMS_EXCH_S1 ; is already mapped in the
CMP DX,[SI+BX+2] ; page.
JE EMS_EXCH_EXIT ;If so, exit.
EMS_EXCH_S1: PUSH AX ;Save new page address
PUSH DX
;Check to see if the address requested has already been mapped.
MOV AX,[SI+BX] ;Load address of current page
MOV DX,[SI+BX+2] ; into destination registers.
OR DH,DH ;See if this is the primary
JE LOAD_PAGE ; page. No, don't save.
XOR DH,DH ;Search for secondary pages
CALL EMS_CHK_LOCAL ;Check for same page locally
JC LOAD_PAGE
;Save page currently mapped.
STORE_PAGE: MOV CX,[DI+BX] ;Load address of window
MOV DH,[DI+BX+2] ; into source registers.
CALL EMS_MOVE_DATA
;Load in page from extended memory.
LOAD_PAGE: POP DX ;Pop new page address
POP AX
MOV DH,1 ;Search for primary page.
CALL EMS_CHK_LOCAL ;See if page mapped elsewhere
MOV CX,BX ;Copy page array index
INC CX ;Make non-zero number
MOV MOVE_BUSY_FLAG,CL ;Busy = page being loaded
MOV DH,1 ;Set primary flag
MOV [SI+BX+2],DX ;Load new address into the
MOV [SI+BX],AX ; page map array.
MOV SAVED_ADDR_LOW,AX ;Save address of page to be
MOV SAVED_ADDR_HIGH,DL ; loaded.
JC EMS_EXCH_EXIT ;If map local, exit
MOV CX,[DI+BX] ;Load window address
MOV DH,[DI+BX+2]
XCHG AX,CX ;Put source and destination
XCHG DL,DH ; addresses in proper place.
CALL EMS_MOVE_DATA ;Move memory
EMS_EXCH_EXIT: MOV MOVE_BUSY_FLAG,0 ;Clear move busy flag
POP CX ;Restore GDT data
MOV SOURCE.BASE_ADRH,CL
MOV DEST.BASE_ADRH,CH
POP SOURCE.BASE_ADRL
POP DEST.BASE_ADRL
POP ES ;Restore registers
POP DS
POP SI
POP CX
RET
EMS_EXCH_PAG ENDP
;-----------------------------------------------------------------------------
;EMS CHK LOCAL compares address to addresses in map array.
; Entry: DL,AX - address
; BX - Index into map array
;-----------------------------------------------------------------------------
EMS_CHK_LOCAL PROC NEAR
PUSH AX
PUSH BX
PUSH DX
PUSH DI
OR AX,AX ;If the current page is
JNE EMS_CHK_LOC0 ; unowned, don't do anything
OR DL,DL ; but set the local flag and
JE EMS_CHK_LOC5 ; exit.
EMS_CHK_LOC0: MOV DI,BX ;Copy page index
XOR BX,BX ;Search the mapping table
MOV CX,4 ; for the address to be
EMS_CHK_LOC1: CMP AX,[SI+BX] ; mapped. If found, use
JNE EMS_CHK_LOC2 ; the data from the mapped
CMP DX,[SI+BX+2] ; page since it may be more
JE EMS_CHK_LOC3 ; accurate than the page
EMS_CHK_LOC2: ADD BX,4 ; in extended memory.
LOOP EMS_CHK_LOC1
JMP SHORT EMS_CHK_LOC6 ;Local page not found
;Local page found. If not the same page, copy data from primary to secondary.
EMS_CHK_LOC3: CMP DI,BX ;Check for same page found
JE EMS_CHK_LOC5 ;Same page, do nothing
OR DH,DH ;See if found primary
JE EMS_CHK_LOC4
XCHG DI,BX
EMS_CHK_LOC4: MOV BYTE PTR [SI+BX+3],1 ;Set primary flag
XCHG DI,BX
MOV BYTE PTR [SI+BX+3],0 ;Reset primary flag
MOV CL,12 ;Convert indices to offsets
SAL BX,CL ; within page frame.
SAL DI,CL
PUSH SI ;Save map array pointer
MOV SI,BX ;Put source offset into SI
PUSH DS
MOV AX,WINDOW_SEG
MOV DS,AX ;Set the segments to the
MOV ES,AX ; page frame.
MOV CX,8192 ;8192 words or 16384 bytes
CLD ;Set direction
REP MOVSW ;Move it
POP DS
POP SI
EMS_CHK_LOC5: STC ;Indicate local page found
EMS_CHK_LOC_EXIT:
POP DI
POP DX
POP BX
POP AX
RET
EMS_CHK_LOC6: CLC ;Indicate local page not fnd
JMP SHORT EMS_CHK_LOC_EXIT
EMS_CHK_LOCAL ENDP
;-----------------------------------------------------------------------------
;EMS MOVE DATA moves blocks of data using BIOS move block function.
; Entry: DL,AX - destination address CX,DH - source address.
;-----------------------------------------------------------------------------
EMS_MOVE_DATA PROC NEAR
PUSH CX
PUSH SI
MOV SI,CS
MOV ES,SI
MOV SI,OFFSET GDT ;ES:SI point to GDT
MOV DEST.BASE_ADRL,AX ;store source address
MOV DEST.BASE_ADRH,DL
MOV SOURCE.BASE_ADRL,CX ;store destination address
MOV SOURCE.BASE_ADRH,DH
MOV AH,87H ;BIOS move extended block
MOV CX,2000H ;move 8192 words
INT 15H ;call BIOS
POP SI
POP CX
RET
EMS_MOVE_DATA ENDP
;-----------------------------------------------------------------------------
;Init1. code initializes memory below this address then returns.
;-----------------------------------------------------------------------------
INITIALIZE1 PROC NEAR
INIT1: ASSUME CS:CODE,DS:CODE,ES:CODE
MOV DI,PAG_OWNER_TBL
MOV AX,TOTAL_PAGES ;Compute size of page owner
MOV DX,3 ; table.
MUL DX
MOV CX,AX
XOR AX,AX ;load ff's into page owner tbl
DEC AX ; because ff is invalid hndl.
REP STOSB
MOV AX,TOTAL_HANDLES ;Compute size of handle array
MOV AH,9 ;9 bytes / handle
MUL AH
MOV CX,AX
XOR AX,AX
REP STOSW
MOV DI,HANDLE_ARRAY ;activate system handle
DEC BYTE PTR [DI]
MOV DI,MAP_ARRAY_PTR
MOV CX,INT_SAVE_SIZE ;Get number of save areas
INC CX ;Add 1 for active map
EMS_INIT_L2:
MOV WORD PTR [DI],0FFFFH ;Mark space as free
INC DI ;Move pointer past free flag
INC DI
PUSH CX
MOV CX,8 ;Clear save area
REP STOSW
POP CX
LOOP EMS_INIT_L2
RET
INITIALIZE1 ENDP
;====================== End of resident Code =============================
DATA_START = $
VDISK_HEADER DB 'VDISK V'
ERRMSG DB 'Not enough memory',13,10,'$'
;===========================================================================
;Initialize. This routine sets up the EMS driver.
;===========================================================================
INITIALIZE PROC NEAR
ASSUME CS:CODE,DS:CODE,ES:NOTHING
PUSH CS ;Parse command line
POP ES
LDS SI,[REQ_HEADADR] ;get back addr of hdr
ASSUME DS:NOTHING,ES:CODE
LDS SI,DS:[SI.CONFIG_PTR] ;Get pointer to config line
MOV BH,1 ;Look for first non-character
MOV CX,80 ;80 characters in line
CALL SCAN_FOR ;Scan for non-character.
OR AH,AH ;see if found
JNE CHK_FOR_VDISK ;not found, skip remainder
XOR BH,BH ;Look for next character
CALL SCAN_FOR ;Scan for character
OR AH,AH ;see if found
JNE CHK_FOR_VDISK ;not found, skip remainder
;-----------------------------------------------------------------------------
;Non-blank line after driver name. Attempt to convert to memory size in Kbytes
;-----------------------------------------------------------------------------
DEC SI ;backup to 1st number
MOV CX,5 ;Max 5 numbers.
XOR AX,AX ;Clear running total
MOV DI,10 ;Decimal conversion constant
INIT_LOOP1: MOV BL,DS:[SI] ;Get number
INC SI ;Point to next number.
SUB BL,'0' ;Convert to number and see
JB INIT_SKIP1 ; if in range for a number.
CMP BL,9
JA INIT_SKIP1
XOR BH,BH
MUL DI ;Mul by 16 to convert to hex
ADD AX,BX ;add to current total
LOOP INIT_LOOP1
;-----------------------------------------------------------------------------
;Compute number of pages available for allocated memory.
;-----------------------------------------------------------------------------
INIT_SKIP1: XOR DX,DX ;Clear high word for divide
MOV DI,16 ;Divide number of Kbytes
DIV DI ; by 16 Kbytes / page.
OR AX,AX ;if number less than 1 page
JE CHK_FOR_VDISK ; use default 24 pages.
MOV CS:TOTAL_PAGES,AX ;Save number of pages.
;-----------------------------------------------------------------------------
;Check for vdisk driver by reading int 19 vector.
;-----------------------------------------------------------------------------
CHK_FOR_VDISK: PUSH CS ;Set DS = CS
POP DS
ASSUME DS:CODE
MOV AX,3519H ;Get interrupt vector 19
INT 21H ;ES points to VDISK segment
MOV DI,12H ;VDISK header at offset 12h
MOV SI,OFFSET VDISK_HEADER
MOV CX,8 ;8 characters in header
XOR BX,BX ;assume no memory used by vdisk
REPE CMPSB ;Compare header
JNE CHK_EXT_MEM
;-----------------------------------------------------------------------------
;If VDISK present, read top of available memory from inside VDISK driver.
;-----------------------------------------------------------------------------
MOV SI,2CH ;load offset of memory used
MOV AX,ES:[SI] ;Get amount of memory used by
MOV DL,ES:[SI+2] ; vdisk
SUB DL,10H ;Subtract 1 Mbyte starting adr
XOR DH,DH
MOV BX,16384 ;Convert to 16k pages
DIV BX
MOV BX,AX ;save result in BX
;-----------------------------------------------------------------------------
;Find upper limit of extended memory.
;-----------------------------------------------------------------------------
CHK_EXT_MEM: PUSH CS ;ES = CS
POP ES
ASSUME ES:CODE
MOV AH,88H ;Get extended memory function
CLC ;clr err flag. (fix IBMCACHE)
INT 15H ;Returns extended memory in
JC EXTEND_ERROR ; 1k pages.
MOV CL,4 ;Convert number of 1k pages
SAR AX,CL ; into number of 16k pages.
SUB AX,TOTAL_PAGES ;See if there is enough room.
JL EXTEND_ERROR
CMP AX,BX ;Subtract memory used by vdisk
JGE EXTEND_MEM_OK1
EXTEND_ERROR: JMP DISP_ERR ;Error, abort instalation.
;-----------------------------------------------------------------------------
;Compute the starting address of the extended memory area for int 15.
;-----------------------------------------------------------------------------
EXTEND_MEM_OK1: PUSH CS ; ES = CS
POP ES ;Convert memory req. to 1k
ASSUME ES:CODE ; pages then store this
MOV CL,4 ; value for use as the new
SAL AX,CL ; extended memory limit.
MOV EXT_MEM_LIMIT,AX
MOV CX,1024 ;Convert number of 1024
MUL CX ; byte pages to absolute adr
ADD DL,10H ;Add starting address of
MOV EXTEND_ADRL,AX ; extended memory and
MOV EXTEND_ADRH,DL ; save.
;-----------------------------------------------------------------------------
;Initialize the variables and pointers needed to emulate the EMS spec.
;-----------------------------------------------------------------------------
MOV CX,OFFSET DATA_START ;Get end of installed code.
MOV PAG_OWNER_TBL,CX ;Save pointer to page table
MOV AX,TOTAL_PAGES ;Get number of pages
MOV AH,3 ;Compute the size of the
MUL AH ; page frame.
ADD CX,AX ;Add to current pointer
MOV HANDLE_ARRAY,CX ;Save pointer to handle array
MOV AX,TOTAL_HANDLES ;compute size of handle
MOV AH,9 ; array using 9 bytes / hdl.
MUL AH
ADD CX,AX
MOV MAP_ARRAY_PTR,CX ;map array 18 bytes. 4 arrays.
MOV AX,INT_SAVE_SIZE ;Get number of save areas
INC AX ;Add 1 for active map
MOV AH,18 ;Compute size of internal
MUL AH ; save array using 18 bytes
ADD AX,CX ; per save area
;-----------------------------------------------------------------------------
;Compute the segment address of the page frame
;-----------------------------------------------------------------------------
ADD AX,15 ;Add 15 to round to next seg
MOV CL,4 ;convert offset into a
SHR AX,CL ;segment value
MOV BX,CS ;get code segment
ADD AX,BX ;add code seg to current ptr
MOV WINDOW_SEG,AX ;store starting segment of ems
PUSH AX ; page frame.
;-----------------------------------------------------------------------------
;Generate and store abolute addresses of window pages.
;-----------------------------------------------------------------------------
MOV DX,16 ;Convert segment into
MUL DX ; absolute address.
MOV DI,OFFSET WINDOW_ADDR_BASE
MOV CX,4
EMS_INIT_L3: MOV [DI],AX ;Save absolute address
MOV [DI+2],DX
ADD AX,16384 ;point to next page address
ADC DX,0
ADD DI,4 ;point to next save address
LOOP EMS_INIT_L3
;-----------------------------------------------------------------------------
;Write the memory requirments to the device driver header
;-----------------------------------------------------------------------------
POP BX ;Get back seg start of window
ADD BX,1000H ;Add 64 Kbytes.
XOR AX,AX ;Start at offset 0
PUSH ES
CALL LOAD_HEADER ;Load memory requirments into
POP ES ; request header.
MOV DX,OFFSET PROGRAM ;Print copyright
MOV AH,9
INT 21H
;-----------------------------------------------------------------------------
;Vector interrupt 15h to reserve the extended memory.
;-----------------------------------------------------------------------------
PUSH ES
MOV AX,3515H ;Get interrupt vector 15
INT 21H
MOV OLD_INT15HO,BX ;save vector
MOV OLD_INT15HS,ES
POP ES
MOV AX,2515H ;Set interrupt vector 15
MOV DX,OFFSET INT_15H
INT 21H ;Call DOS
;-----------------------------------------------------------------------------
;Vector the 67h interrupt to the driver. Jump to final installation code.
;-----------------------------------------------------------------------------
MOV AX,2567H ;Set interrupt vector 67
MOV DX,OFFSET INT_67H
INT 21H ;Call DOS
JMP INIT1 ;jump to final init. code.
;-----------------------------------------------------------------------------
;error routine to abort instalation.
;-----------------------------------------------------------------------------
DISP_ERR: MOV DX,OFFSET ERRMSG ;Tell user that the driver is
MOV AH,9 ; not loaded.
INT 21H
MOV AX,3000H ;Get DOS version
INT 21H
XCHG AL,AH ;Put number in proper order
CMP AX,31EH ;See if DOS 3.3
MOV AX,OFFSET DRIVER_END ;Offset of device driver code
MOV BX,CS ;If >3.3, abort install with
JB ERROR_ABORT_SKIP ; 0 memory. Otherwise leave
XOR AX,AX ; driver stub installed.
ERROR_ABORT_SKIP:
CALL LOAD_HEADER ;Load into request header
MOV AX,8002 ;Indicate error in the
RET ; driver return code.
;-----------------------------------------------------------------------------
;LOADHEADER loads the amount of memory needed into the request header.
;-----------------------------------------------------------------------------
LOAD_HEADER PROC NEAR
LES DI,[REQ_HEADADR] ;get addr of req hdr
MOV WORD PTR ES:[DI.ADDRESS],AX ;Store offset and
MOV WORD PTR ES:[DI.ADDRESS+2],BX ; code segment.
RET
LOAD_HEADER ENDP
;-----------------------------------------------------------------------------
;ScanFor - scans for first (non)occurance of character in line.
; Entry - BH - 0 = scan for non character, 1 = scan for character.
; DS:SI - string to scan. CX - length of string
; Exit - AH - 1 = end of line found.
;-----------------------------------------------------------------------------
SCAN_FOR PROC NEAR
XOR AH,AH ;Clear found flag
SCAN_LOOP1: LODSB ;Get character
OR BH,BH ;see if first match or
JE SCAN_SKIP1 ; mismatch. 0 = match
CMP AL,20H ;Check for noncharacter.
JLE SCAN_SKIP4
JMP SHORT SCAN_SKIP2
SCAN_SKIP1: CMP AL,20H ;Check for character
JG SCAN_SKIP4
SCAN_SKIP2: CMP AL,13 ;Check for CR
JE SCAN_SKIP3
CMP AL,10 ;Check for LF
JE SCAN_SKIP3
LOOP SCAN_LOOP1
SCAN_SKIP3: INC AH ;character not found
SCAN_SKIP4: RET
SCAN_FOR ENDP
END_OF_CODE = $
INITIALIZE ENDP
CODE ENDS
END