📄 cwswapr.asm
字号:
.386
;*****************************
;* Equates *
;*****************************
SWAPPERERROR EQU 9999
WEDGEOFFSET EQU 180h
;*****************************
;* Public declarations *
;*****************************
PUBLIC CWSwap_
;PUBLIC SWPRUNCMD
;PUBLIC OverLay
;PUBLIC O_RUNX
;PUBLIC Done
;*****************************
;* External data *
;*****************************
;EXTRN __retni:FAR
;EXTRN __parclen:FAR
;EXTRN __parc:FAR
;*****************************
;* SPAWN Structures *
;*****************************
;
; --- Version 3.3 92-03-30 21:39 ---
;
; SPAWN.ASM - Main function for memory swapping spawn call.
;
; Public Domain Software written by
; Thomas Wagner
; Ferrari electronic GmbH
; Beusselstrasse 27
; D-1000 Berlin 21
; Germany
;
;
; Assemble with
;
; tasm /DPASCAL spawn,spawnp - Turbo Pascal (Tasm only), near
; tasm /DPASCAL /DFARCALL spawn,spawnp - Turbo Pascal (Tasm only), far
; ?asm spawn; - C, default model (small)
; ?asm /DMODL=large spawn - C, large model
;
; NOTE: For C, change the 'model' directive below according to your
; memory model, or define MODL=xxx on the command line.
;
; For Turbo C Huge model, you must give /DTC_HUGE on the
; command line, or define it here.
;
;
; Main function:
;
; C:
; int do_spawn (int swapping,
; char *execfname,
; char *cmdtail,
; unsigned envlen,
; char *envp,
; char *stdin,
; char *stdout,
; char *stderr)
;
; Parameters:
;
; swapping - swap/spawn/exec function:
; < 0: Exec, don't swap
; 0: Spawn, don't swap
; > 0: Spawn, swap
; in this case, prep_swap must have
; been called beforehand (see below).
;
; cmdtail - command tail for EXEC.
;
; execfname - name and path of file to execute.
;
; envlen - length of environment copy (may be 0).
;
; envp - pointer to environment block (must be aligned on
; paragraph boundary). Unused if envlen is 0.
;
; 'cmdtail' and 'execfname' must be zero terminated, even when
; calling from Pascal. For Pascal, the length byte of the string
; is ignored.
;
; Returns:
; 0000..00ff: Returncode of EXECed program
; 03xx: DOS-Error xx calling EXEC
; 0500: Swapping requested, but prep_swap has not
; been called or returned an error
; 0501: MCBs don't match expected setup
; 0502: Error while swapping out
; 06xx: DOS-Error xx on redirection
;
;
; For swapping, the swap method must be prepared before calling do_spawn.
;
; C:
; int prep_swap (unsigned method, char *swapfname)
;
; Parameters:
;
; method - bit-map of allowed swap devices:
; 01 - Allow EMS
; 02 - Allow XMS
; 04 - Allow File swap
; 10 - Try XMS first, then EMS
; 40 - Create file as "hidden"
; 80 - Use "create temp" call for file swap
; 100 - Don't preallocate file
; 200 - Check for Network, don't preallocate if net
; 4000 - Environment block will not be swapped
;
; swapfname - swap file name (may be undefined if the
; "method" parameters disallows file swap).
; The string must be zero terminated, even
; when calling from Pascal. For Pascal, the
; length byte of the string is ignored.
;
; Returns:
;
; A positive integer on success:
; 1 - EMS swap initialized
; 2 - XMS swap initialized
; 4 - File swap initialized
; A negative integer on failure:
; -1 - Couldn't allocate swap space
; -2 - The spawn module is located too low in memory
;
;--------------------------------------------------------------------------
;
;
; Set NO_INHERIT to FALSE if you don't want do_exec to mess with
; the handle table in the PSP, and/or you do want the child process
; to inherit all open files.
; If NO_INHERIT is TRUE, only the first five handles (the standard
; ones) will be inherited, all others will be hidden. This allows
; the child to open more files, and also protects you from the child
; messing with any open handles.
; NO_INHERIT should always be TRUE if you use functions to extend
; the handle table (for more than 20 open files).
;
; Set REDIRECT to FALSE if you do not want do_spawn to support redirection.
;
;
;
FALSE = 0
TRUE = NOT FALSE
;
NO_INHERIT = TRUE
REDIRECT = FALSE
;
;
;
; IFNDEF MODL
; .model small,c
; %out small model
; ELSE
;% .model MODL,c
;% %out MODL model
; ENDIF
;
;ptrsize = @DataSize
ptrsize = 1
;
; extrn _psp: word
;
; public do_spawn
; public prep_swap
; public swap_prep
;
stacklen = 256 ; local stack
;
; "ems_size" is the EMS block size: 16k.
;
ems_size = 16 * 1024 ; EMS block size
ems_parasize = ems_size / 16 ; same in paragraphs
ems_shift = 10 ; shift factor for paragraphs
ems_paramask = ems_parasize-1 ; block mask
;
; "xms_size" is the unit of measurement for XMS: 1k
;
xms_size = 1024 ; XMS block size
xms_parasize = xms_size / 16 ; same in paragraphs
xms_shift = 6 ; shift factor for paragraphs
xms_paramask = xms_parasize-1 ; block mask
;
; Method flags
;
USE_EMS = 01h
USE_XMS = 02h
USE_FILE = 04h
XMS_FIRST = 10h
HIDE_FILE = 40h
CREAT_TEMP = 80h
NO_PREALLOC = 100h
CHECK_NET = 200h
DONT_SWAP_ENV = 4000h
;
; Return codes
;
RC_TOOLOW = 0102h
RC_BADPREP = 0500h
RC_MCBERROR = 0501h
RC_SWAPERROR = 0502h
RC_REDIRFAIL = 0600h
;
EMM_INT = 67h
;
; The EXEC function parameter block
;
exec_block struc
envseg dw ? ; environment segment
ppar dw ? ; program parameter string offset
pparseg dw ? ; program parameter string segment
fcb1 dw ? ; FCB offset
fcb1seg dw ? ; FCB segment
fcb2 dw ? ; FCB offset
fcb2seg dw ? ; FCB segment
exec_block ends
;
; Structure of an XMS move control block
;
xms_control struc
lenlo dw ? ; length to move (doubleword)
lenhi dw ?
srchnd dw ? ; source handle (0 for standard memory)
srclo dw ? ; source address (doubleword or seg:off)
srchi dw ?
desthnd dw ? ; destination handle (0 for standard memory)
destlo dw ? ; destination address (doubleword or seg:off)
desthi dw ?
xms_control ends
;
; The structure of the start of an MCB (memory control block)
;
mcb struc
id db ?
owner dw ?
paras dw ?
mcb ends
;
; The structure of an internal MCB descriptor.
; CAUTION: This structure is assumed to be no larger than 16 bytes
; in several places in the code, and to be exactly 16 bytes when
; swapping in from file. Be careful when changing this structure.
;
mcbdesc struc
addr dw ? ; paragraph address of the MCB
msize dw ? ; size in paragraphs (excluding header)
swoffset dw ? ; swap offset (0 in all blocks except first)
swsize dw ? ; swap size (= msize + 1 except in first)
num_follow dw ? ; number of following MCBs
dw 3 dup(?) ; pad to paragraph (16 bytes)
mcbdesc ends
;
; The variable block set up by prep_swap
;
prep_block struc
xmm dd ? ; XMM entry address
first_mcb dw ? ; Segment of first MCB
psp_mcb dw ? ; Segment of MCB of our PSP
env_mcb dw ? ; MCB of Environment segment
noswap_mcb dw ? ; Env MCB that may not be swapped
noswap2_mcb dw ? ; Wedge MCB that may not be swapped
noswap3_mcb dw ? ; File handle MCB that may not be swapped
ems_pageframe dw ? ; EMS page frame address
handle dw ? ; EMS/XMS/File handle
total_mcbs dw ? ; Total number of MCBs
swapmethod db ? ; Method for swapping
sp_swapfilename db 81 dup(?) ; Swap file name if swapping to file
prep_block ends
;
;----------------------------------------------------------------------
;
; Since we'll be moving code and data around in memory,
; we can't address locations in the resident block with
; normal address expressions. MASM does not support
; defining variables with a fixed offset, so we have to resort
; to a kludge, and define the shrunk-down code as a structure.
; It would also be possible to use an absolute segment for the
; definition, but this is not supported by the Turbo Pascal linker.
;
; All references to low-core variables from low-core itself
; are made through DS, so we define a text macro "lmem" that
; expands to "ds:". When setting up low core from the normal
; code, ES is used to address low memory, so this can't be used.
;
lmem equ <ds:>
;
; The memory structure for the shrunk-down code, excluding the
; code itself. The code follows this block.
; The start of this block is the PSP.
;
parseg struc
db 18h dup(?)
psp_handletab db 20 dup(?) ; Handle Table
psp_envptr dw ? ; Environment Pointer
dd ?
psp_handlenum dw ? ; Number of Handles (DOS >= 3.3)
psp_handleptro dw ? ; Handle Table Pointer (DOS >= 3.3)
psp_handleptrs dw ? ; Handle Table Pointer Segment
db 5ch-38h dup(?) ; start after PSP
;
save_ss dw ? ; 5C - saved global ss
save_sp dw ? ; 5E - saved global sp
xfcb1 db 16 dup(?) ; 60..6F - default FCB
xfcb2 db 16 dup(?) ; 70..7F - default FCB
zero dw ? ; 80 Zero command tail length (dummy)
;
expar db TYPE exec_block dup (?) ; exec-parameter-block
spx dw ? ; saved local sp
div0_off dw ? ; divide by zero vector save
div0_seg dw ?
lhandlesave db 26 dup(?) ; saved handle table and pointer
IF REDIRECT
lredirsav db 6 dup(?) ; saved redirection handles
lstdinsav dw 3 dup(?) ; duped redirection handles
ENDIF
filename db 82 dup(?) ; exec filename
progpars db 128 dup(?) ; command tail
db stacklen dup(?) ; local stack space
mystack db ?
lprep db TYPE prep_block dup(?) ; the swapping variables
lcurrdesc db TYPE mcbdesc dup(?) ; the current MCB descriptor
lxmsctl db TYPE xms_control dup(?)
eretcode dw ? ; EXEC return code
retflags dw ? ; EXEC return flags
cgetmcb dw ? ; address of get_mcb
dtasave DD ? ; address of original DTA
GoToWedge DD ? ; address of wedge code
;
parseg ends
;
param_len = ((TYPE parseg + 1) / 2) * 2 ; make even
codebeg = param_len
;
;*****************************
;* Code begins *
;*****************************
SWAP_TEXT SEGMENT PARA PRIVATE USE16 'CODE'
ASSUME cs:SWAP_TEXT
CodeStart = $
;lookie DW keep_paras
;
;------------------------------------------------------------------------
;
lowcode_begin:
;
; The following parts of the program code will be moved to
; low core and executed there, so there must be no absolute
; memory references.
; The call to get_mcb must be made indirect, since the offset
; from the swap-in routine to get_mcb will not be the same
; after moving.
;
;
; get_mcb allocates a block of memory by modifying the MCB chain
; directly.
;
; On entry, lcurrdesc has the mcb descriptor for the block to
; allocate.
;
; On exit, Carry is set if the block couldn't be allocated.
;
; Uses AX, BX, CX, ES
; Modifies lprep.first_mcb
;
get_mcb proc near
;
mov ax,lmem lprep.first_mcb
mov bx,lmem lcurrdesc.addr
;
getmcb_loop:
mov es,ax
cmp ax,bx
ja gmcb_abort ; halt if MCB > wanted
je mcb_found ; jump if same addr as wanted
add ax,es:paras ; last addr
inc ax ; next mcb
cmp ax,bx
jbe getmcb_loop ; Loop if next <= wanted
;
;
; The wanted MCB starts within the current MCB. We now have to
; create a new MCB at the wanted position, which is initially
; free, and shorten the current MCB to reflect the reduced size.
;
cmp es:owner,0
jne gmcb_abort ; halt if not free
mov bx,es ; current
inc bx ; + 1 (header doesn't count)
mov ax,lmem lcurrdesc.addr
sub ax,bx ; paragraphs between MCB and wanted
mov bx,es:paras ; paras in current MCB
sub bx,ax ; remaining paras
dec bx ; -1 for header
mov es:paras,ax ; set new size for current
mov cl,es:id ; old id
mov es:id,4dh ; set id: there is a next
mov ax,lmem lcurrdesc.addr
mov es,ax
mov es:id,cl ; and init to free
mov es:owner,0
mov es:paras,bx
;
; We have found an MCB at the right address. If it's not free,
; abort. Else check the size. If the size is ok, we're done
; (more or less).
;
mcb_found:
mov es,ax
cmp es:owner,0
je mcb_check ; continue if free
;
gmcb_abort:
stc
ret
;
mcb_check:
mov ax,es:paras ; size
cmp ax,lmem lcurrdesc.msize ; needed size
jae mcb_ok ; ok if enough space
;
; If there's not enough room in this MCB, check if the next
; MCB is free, too. If so, coalesce both MCB's and check again.
;
cmp es:id,4dh
jnz gmcb_abort ; halt if no next
push es ; save current
mov bx,es
add ax,bx
inc ax ; next MCB
mov es,ax
cmp es:owner,0 ; next free ?
jne gmcb_abort ; halt if not
mov ax,es:paras ; else load size
inc ax ; + 1 for header
mov cl,es:id ; and load ID
pop es ; back to last MCB
add es:paras,ax ; increase size
mov es:id,cl ; and store ID
jmp mcb_check ; now try again
;
; The MCB is free and large enough. If it's larger than the
; wanted size, create another MCB after the wanted.
;
mcb_ok:
mov bx,es:paras
sub bx,lmem lcurrdesc.msize
jz mcb_no_next ; ok, no next to create
push es
dec bx ; size of next block
mov ax,es
add ax,lmem lcurrdesc.msize
inc ax ; next MCB addr
mov cl,es:id ; id of this block
mov es,ax ; address next
mov es:id,cl ; store id
mov es:paras,bx ; store size
mov es:owner,0 ; and mark as free
pop es ; back to old MCB
mov es:id,4dh ; mark next block present
mov ax,lmem lcurrdesc.msize ; and set size to wanted
mov es:paras,ax
;
mcb_no_next:
mov es:owner,cx ; set owner to current PSP
;
; Set the 'first_mcb' pointer to the current one, so we don't
; walk through all the previous blocks the next time.
; Also, check if the block we just allocated is the environment
; segment of the program. If so, restore the environment pointer
; in the PSP.
;
mov ax,es
mov lmem lprep.first_mcb,ax
; cmp lmem lprep.env_mcb,ax
; jne getmcb_finis
; inc ax
; mov lmem psp_envptr,ax
;
getmcb_finis:
clc
ret ; all finished (whew!)
;
get_mcb endp
;
;
ireti:
iret
;
;
; The actual EXEC call.
; Registers on entry:
; BX = paragraphs to keep (0 if no swap)
; CX = length of environment to copy (words) or zero
; DS:SI = environment source
; ES:DI = environment destination
; (ES = our low core code segment)
;
;
; copy environment buffer down if present
;
doexec:
; jcxz noenvcpy
; rep movsw
;
noenvcpy:
push es ; DS = ES = low core = PSP
pop ds
or bx,bx
jz no_shrink
;
; first, shrink the base memory block down.
;
; int 3
IFDEF SHRINKPSP
mov ah,04ah
int 21h ; resize memory block
ENDIF
;
; Again walk all MCBs. This time, all blocks owned by the
; current process are released.
;
mov si,lmem lprep.first_mcb
or si,si
jz no_shrink
mov dx,lmem lprep.psp_mcb
mov bx,dx
inc bx ; base PSP (MCB owner)
mov di,lmem lprep.noswap_mcb
mov cx,lmem lprep.noswap2_mcb
;
free_loop:
cmp si,dx
je free_next ; don't free base block
cmp si,di
je free_next
cmp si,cx
je free_next
cmp si,lmem lprep.noswap3_mcb
je free_next
mov es,si
cmp bx,es:owner ; our process?
jne free_next ; next if not
; cmp si,lmem lprep.env_mcb ; is this the environment block?
; jne free_noenv
; mov ds:psp_envptr,0 ; else clear PSP pointer
;
free_noenv:
inc si
mov es,si
dec si
mov ah,049h ; free memory block
int 21h
;
free_next:
mov es,si
cmp es:id,4dh ; normal block?
jne free_ready ; ready if end of chain
add si,es:paras ; start + length
inc si ; next MCB
jmp free_loop
;
free_ready:
no_shrink:
mov ah,2fh ; get DTA address
int 21h
mov WORD PTR lmem dtasave,bx ; save original DTA
mov WORD PTR lmem dtasave+2,es
mov ax,ds
mov es,ax
mov WORD PTR lmem GoToWedge,0
mov WORD PTR lmem GoToWedge+2,fs
;
; int 3
mov dx,filename ; params for exec
mov bx,expar
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -