home *** CD-ROM | disk | FTP | other *** search
- IFNDEF __TPINC
- NAME swap_ems
- TITLE SPAWNO EMS swapping code
- PAGE 60,132
-
- ;-----------------------------------
- ; (c) Copyright 1990,1991 Ralf Brown All Rights Reserved
- ; This file may be redistributed as a part of the complete SPAWNO package,
- ; under its distribution conditions
- ;
- ; SPAWNO v4.00
- ; Overlaying spawnv()
- ;
- ; File: SWAP_EMS
- ;-----------------------------------
-
- __BSS__ equ 1 ; yes, we are using uninitialized storage
- INCLUDE RULES.ASI ; define the various standard macros
- INCLUDE SPAWNO.INC
-
- Header@ ; set up segment and group definitions
- ENDIF ;ndef __TPINC
-
- ;-----------------------------------------------------------
- ; data with relocatable items
-
- JSeg@
-
- public@ __SPAWNO_FUNCS_EMS
- __SPAWNO_FUNCS_EMS label byte
- dw spawno_init_ems ; called to determine whether to swap to EMS
- dw write_block_ems ; called to write out memory
- dw spawno_swapdone_ems ; called when all memory written out
- dw spawno_swapin_ems ; called when ready to read back memory
- dw read_ems ; called to read back a section of memory
- dw spawno_finish_ems ; called to clean up at very end of swap
- dw $ems_overlay ; address of code to append to resident stub
- dw ems_overlay_size ; total size of code to be appended
- dw ems_overlay_res ; number of bytes which must stay resident
-
- JSegEnd@
-
- ;-----------------------------------------------------------
- ; initialized data
-
- DSeg@
-
- EMM_name DB "EMMXXXX0"
-
- IFNDEF RBcomm
- PubSym@ __spawn_ems,<DB 1>,__CDECL__ ; are we allowed to swap to EMS?
- ELSE
- ExtSym@ __spawn_ems,BYTE,__CDECL__
- ENDIF ;RBcomm
- DSegEnd@
-
- ;----------------------------------------------------------------
- ; uninitialized data storage area
-
- BSeg@
-
- ems_page_num dw ? ; current page number for EMS handle
- ems_page_offset dw ? ; offset (in para) withing page
-
- ems_page_num$ dw ? ; page number after reading in PSP
- ems_page_offset$ dw ? ; offset (in bytes) after reading in PSP
-
- BSegEnd@
-
- ;----------------------------------------------------------------
-
- CSeg@
-
- ;----------------------------------------------------------------
- ; section of code to append to the common code when using EMS for
- ; swapping
- ;
- ; on entry,
- ; DX = segment at which to start reloading memory
- ; CS = DS = segment of program's PSP
- ; AX, BX, CX, SI, DI, ES unpredictable
- ; at exit:
- ; SS:SP must be preserved, but all other registers can be destroyed
- ; The device-specific code is always entered at the very beginning and
- ; must exit either by falling off the end or by branching to "abort_offset"
- ; bytes prior to its beginning with DS=CS (the latter only if it detects
- ; an error from which it cannot recover).
- ;
- $ems_overlay proc far
- ems_reloc_factor equ (offset $ems_overlay - resident_addr)
- ASSUME DS:NOTHING
- mov es,dx ; ES <- seg at which to start loading
- ASSUME ES:NOTHING
- xor bx,bx ; start on logical page 0
- mov dx,0 ; DX <- EMS handle (will be patched)
- $ems_handle equ word ptr ($-2)
- ems_reload_loop:
- mov ax,4400h ; map logical page into physical page 0
- int 67h
- or ah,ah ; was "map" call successful?
- jnz short ($ems_overlay - abort_offset) ; quit if not
- mov ax,0 ; AX <- EMS page frame seg (will patch)
- page_frame_seg equ word ptr ($-2)
- mov ds,ax ; DS -> page frame
- ASSUME DS:NOTHING
- mov cx,2000h ; 16K bytes = 8K words
- $ems_partial equ word ptr ($-2)
- xor si,si ; source offset is 0
- xor di,di ; dest offset is 0
- rep movsw
- jmp short copied_page ; flush prefetch queue
- ems_overlay_res equ $ - $ems_overlay
- ;
- ; everything beyond this point may be overwritten by the child program, since
- ; the first read above will restore it back to memory
- ;
- $ems_pages dw 0 ; number of pages, excluding partial last
- ; will be filled in before copy to PSP
- copied_page:
- inc bx ; go to next logical page
- mov ax,es ; move 16K higher in memory
- add ax,400h
- mov es,ax
- dec word ptr cs:($ems_pages - ems_reloc_factor)
- jg ems_reload_loop ; if not yet last, go do another full page
- mov word ptr cs:($ems_partial - ems_reloc_factor),0
- $ems_partial_size equ word ptr ($-2)
- jz ems_reload_loop ; loop one last time if count reached 0
- ;
- ; exit by falling out of this subroutine
- ;
- $ems_overlay endp
-
- ems_overlay_size equ $ - $ems_overlay
-
- ;----------------------------------------------------------------
- ; entry: AX = start segment within EMS page frame
- ; ES = conventional-memory transfer segment
- ; exit: DS, ES = source, destination of copy
- ; DX = new conventional-memory transfer address
- ;----------------------------------------------------------------
- set_segment_read proc near
- mov ds,ax ; AX = start segment in EMS page frame
- ASSUME DS:NOTHING
- mov dx,es
- ret
- set_segment_read endp
-
- set_segment_write proc near
- mov dx,es
- mov ds,dx
- mov es,ax ; AX = start segment in EMS page frame
- ret
- set_segment_write endp
-
- ;----------------------------------------------------------------
- ; enter: AX=starting segment
- ; BX = handle
- ; DX=num paras
- ; return: CF clear on success, set if failed
- ; AX, BX, CX, DX, ES destroyed
- ;----------------------------------------------------------------
- read_ems proc near
- ASSUME DS:DGROUP
- mov cx,offset __TEXT:set_segment_read
- jmp short transfer_EMS
- read_ems endp
-
- ;----------------------------------------------------------------
- ; entry: AX = starting segment
- ; BX = handle
- ; DX = number of paragraphs
- ; return: CF clear on success, set if failed
- ; AX, BX, CX, DX, ES destroyed
- ;----------------------------------------------------------------
- write_block_ems proc near
- mov cx,offset __TEXT:set_segment_write
- transfer_EMS:
- push bp
- mov bp,bx ; store handle
- ASSUME DS:DGROUP
- mov es,ax
- ASSUME ES:NOTHING
- push di
- push si
- xchg cx,dx
- xfer_ems_loop:
- push dx
- mov ax,4400h ; map physical page 0
- mov bx,ems_page_num
- mov dx,bp ; DX <- handle
- int 67h ; map in the appropriate EMS page
- or ah,ah
- jnz EMS_mapping_failed
- mov bx,ems_page_offset
- mov dx,bx
- sub bx,400h ; 1024 paragraphs in a 16K EMS page
- neg bx ; adjust for doing sub the wrong way
- cmp bx,cx
- jbe xfer_ems_fullpage
- mov bx,cx
- add ems_page_offset,bx
- jmp short xfer_ems_do_it
- xfer_ems_fullpage:
- xor ax,ax
- mov ems_page_offset,ax
- inc ems_page_num
- xfer_ems_do_it:
- mov ax,page_frame_seg
- add ax,dx
- cmp ax,ax ; set ZF to indicate success
- EMS_mapping_failed:
- pop dx
- jnz xfer_ems_failed
- push ds
- push dx
- call dx ; set DS, ES, and DX
- ASSUME DS:NOTHING,ES:NOTHING
- xor si,si
- xor di,di
- push cx
- mov cx,bx
- shl cx,1
- shl cx,1
- shl cx,1 ; paragraphs to words
- cld
- rep movsw ; copy as much memory as we can
- pop cx
- add dx,bx
- mov es,dx ; move higher in mem by amount copied
- pop dx
- pop ds
- ASSUME DS:DGROUP
- sub cx,bx ; update amount remaining
- jnz xfer_ems_loop
- clc ; tell caller we succeeded
- xfer_ems_done:
- pop si
- pop di
- pop bp
- ret
-
- xfer_ems_failed:
- stc ; tell caller we failed
- jmp xfer_ems_done
- write_block_ems endp
-
- ;----------------------------------------------------------------
- ; return the number of EMS pages which are available (0 if no EMS) in AX
- ;
- IFDEF RBcomm
- public _EMS_available
- ENDIF ;RBcomm
-
- _EMS_available proc near
- ASSUME DS:DGROUP
- push es
- push si
- push di
- mov ax,3567h
- int 21h ; get vector for EMS driver
- mov di,10 ; ES:DI -> driver name
- mov si,offset DGROUP:EMM_name
- mov cx,8 ; length EMM_name
- cld
- xor ax,ax ; assume no match
- repz cmps EMM_name,byte ptr es:[di]
- jnz EMS_avail_done
- mov ah,42h
- int 67h
- or ah,ah ; was call successful?
- mov ax,bx ; assume yes, return # of pages available
- jz EMS_avail_done
- xor ax,ax ; nope, so return zero
- EMS_avail_done:
- pop di
- pop si
- pop es
- ret
- _EMS_available endp
-
- ;----------------------------------------------------------------
- ; Determine whether able to swap to EMS, and prepare for swapping to EMS
- ; if able.
- ; on entry:
- ; AX = total number of paragraphs to swap out
- ; DX = number of paragraphs in PSP block to swap out
- ; return: CF set on error
- ; CF clear if able to swap
- ; AX = handle
- ;----------------------------------------------------------------
- spawno_init_ems proc near
- ASSUME DS:DGROUP
- cmp __spawn_ems@,0 ; are we allowed to use EMS?
- je no_EMS ; if not, try next method
- push ax ; remember total paragraphs required
- mov cx,(16*1024) ; 16K per page, but 16 bytes per para
- mov ax,16 ; 16 bytes per paragraph
- push ax
- mul dx ; paragraphs to bytes
- div cx ; DX:AX bytes to EMS pages
- mov ems_page_num$,ax
- mov ems_page_offset$,dx
- or dx,dx ; partial last page?
- jne got_last_page
- dec ax ; if not, say we have a "partial" last
- mov dx,(16*1024) ; page of 16K
- got_last_page:
- mov $ems_pages,ax
- mov $ems_partial_size,dx
- xor ax,ax
- mov ems_page_num,ax
- mov ems_page_offset,ax
- pop dx ; DX <- 16
- pop ax ; get back total paragraphs required
- mul dx ; paragraphs to bytes
- div cx ; DX:AX bytes to EMS pages
- or dx,dx
- jz no_partial_page_ems
- inc ax
- no_partial_page_ems:
- push ax ; remember required number of pages
- call _EMS_available ; find out how many EMS pages are free
- pop cx ; get back required number of pages
- cmp ax,cx ; enough EMS memory for swapping?
- jb no_EMS ; if not, swap to disk
- mov ah,41h ; get EMS page frame segment
- int 67h
- or ah,ah ; was call successful
- jnz no_EMS ; swap to disk if not
- mov page_frame_seg,bx ; store page frame seg in swap-in code
- mov ah,43h ; allocate EMS for swapping
- mov bx,cx ; BX <- total number of EMS pages needed
- int 67h
- or ah,ah
- jnz no_EMS ; if error, try next method
- mov ah,47h ; save mapping context for handle DX
- int 67h
- mov ax,dx ; return the EMS handle
- mov $ems_handle,ax
- clc
- ret
- no_EMS:
- stc
- ret
- spawno_init_ems endp
-
- ;----------------------------------------------------------------
- ; Clean up at end of spawn.
- ; entry: AX = handle returned by spawno_init_*
- ;----------------------------------------------------------------
- spawno_finish_ems proc near
- assume DS:DGROUP,ES:NOTHING
- mov dx,ax ; DX <- handle
- mov ah,48h ; restore mapping context
- int 67h
- mov ah,45h
- int 67h ; free EMS handle and memory
- ;
- ; assume the free works, since there's not much we can do if it doesn't
- ;
- spawno_swapdone_ems: ; don't need to do anything after
- ; writing out the memory, so piggy-
- ; back an empty subroutine onto an
- ; existing return instruction
- ret
- spawno_finish_ems endp
-
- ;----------------------------------------------------------------
- ; Prepare to read back the swapped-out program's memory
- ; entry: AX = handle returned by spawno_init_ems
- ;----------------------------------------------------------------
- spawno_swapin_ems proc near
- ASSUME DS:DGROUP
- mov ax,ems_page_num$
- mov ems_page_num,ax
- mov ax,ems_page_offset$
- mov cl,4
- shr ax,cl
- mov ems_page_offset,ax
- ret
- spawno_swapin_ems endp
-
- CSegEnd@
-
- IFNDEF __TPINC
- NOWARN OPI
- END
- ENDIF
-