📄 msspawn.asm
字号:
mov dx,prep.handle ; EMS handle
mov ah,45h ; release EMS pages on error
int EMM_INT
mov ax,RC_MCBERROR
jmp short swapout_error
;
swm_mcberr_file:
mov ah,3eh ; close file
mov bx,prep.handle
int 21h
mov dx,offset prep.swapfilename
mov ah,41h ; delete file
int 21h
mov ax,RC_MCBERROR
;
swapout_error:
ret
;
;
; Swapout complete. Close the handle (EMS/file only),
; then set up low memory.
;
swapout_complete:
cmp prep.swapmethod,USE_FILE
jne swoc_nofile
;
; File swap: Close the swap file to make the handle available
;
mov bx,prep.handle
mov ah,3eh
int 21h ; close file
mov si,offset swapin_file
jnc swoc_ready
mov ax,RC_SWAPERROR
jmp swapout_error
;
swoc_nofile:
cmp prep.swapmethod,USE_EMS
jne swoc_xms
;
; EMS: Unmap page
;
mov ax,4400h
mov bx,-1
mov dx,prep.handle
int EMM_INT
mov si,offset swapin_ems
jmp short swoc_ready
;
swoc_xms:
mov si,offset swapin_xms
jmp short swoc_ready
;
no_swap1:
mov si,offset swapin_none
;
; Copy the appropriate swap-in routine to low memory.
;
swoc_ready:
mov es,pspseg
mov cx,swap_codelen / 2
mov di,codebeg + base_length
push ds
mov ax,cs
mov ds,ax
rep movsw
;
; And while we're at it, copy the MCB allocation routine (which
; also includes the initial MCB release and exec call) down.
;
mov cx,base_length / 2
mov di,param_len
mov si,offset lowcode_begin
rep movsw
;
pop ds
mov bx,es
dec bx
mov es,bx ; let ES point to base MCB
;
; Again set up the base MCB descriptor, and copy it as well as
; the variables set up by prep_swap to low memory.
; This isn't too useful if we're not swapping, but it doesn't
; hurt, either. The only variable used when not swapping is
; lprep.swapmethod.
;
mov ax,es:paras
mov currdesc.msize,ax
sub ax,keep_paras
mov currdesc.swsize,ax
mov currdesc.addr,es
mov currdesc.swoffset,swapbeg + 16
mov ax,prep.total_mcbs
mov currdesc.num_follow,ax
;
mov es,pspseg ; ES points to PSP again
;
mov cx,TYPE prep_block
mov si,offset prep
mov di,lprep
rep movsb
mov cx,TYPE mcbdesc
mov si,offset currdesc
mov di,lcurrdesc
rep movsb
;
; now set up other variables in low core
;
mov es:cgetmcb,getmcboff + codebeg
mov es:eretcode,0
mov es:retflags,0
;
; Prepare exec parameter block
;
mov ax,es
mov es:expar.fcb1seg,ax
mov es:expar.fcb2seg,ax
mov es:expar.pparseg,ax
mov es:expar.envseg,0
;
; The 'zero' word is located at 80h in the PSP, the start of
; the command line. So as not to confuse MCB walking programs,
; a command line length of zero is inserted here.
;
mov es:zero,0d00h ; 00h,0dh = empty command line
;
; Init default fcb's by parsing parameter string
;
IF ptrsize
lds si,params
ELSE
mov si,params
ENDIF
push si
mov di,xfcb1
mov es:expar.fcb1,di
push di
mov cx,16
xor ax,ax
rep stosw ; init both fcb's to 0
pop di
mov ax,2901h
int 21h
mov di,xfcb2
mov es:expar.fcb2,di
mov ax,2901h
int 21h
pop si
;
; move command tail string into low core
;
mov di,progpars
mov es:expar.ppar,di
xor cx,cx
inc di
cmdcpy:
lodsb
or al,al
jz cmdcpy_end
stosb
inc cx
jmp cmdcpy
;
cmdcpy_end:
mov al,0dh
stosb
mov es:progpars,cl
;
; move filename string into low core
;
IF ptrsize
lds si,execfname
ELSE
mov si,execfname
ENDIF
mov di,filename
fncpy:
lodsb
stosb
or al,al
jnz fncpy
;
; Setup environment copy
;
mov bx,keep_paras ; paras to keep
mov cx,envlen ; environment size
jcxz no_environ ; go jump if no environment
cmp swapping,0
jne do_envcopy
;
; Not swapping, use the environment pointer directly.
; Note that the environment copy must be paragraph aligned.
;
IF ptrsize
mov ax,word ptr (envp)+2
mov bx,word ptr (envp)
ELSE
mov ax,ds
mov bx,envp
ENDIF
add bx,15 ; make sure it's paragraph aligned
mov cl,4
shr bx,cl ; and convert to segment addr
add ax,bx
mov es:expar.envseg,ax ; new environment segment
xor cx,cx ; mark no copy
xor bx,bx ; and no shrink
jmp short no_environ
;
; Swapping or EXECing without return. Set up the pointers for
; an environment copy (we can't do the copy yet, it might overwrite
; this code).
;
do_envcopy:
inc cx
shr cx,1 ; words to copy
mov ax,cx ; convert envsize to paras
add ax,7
shr ax,1
shr ax,1
shr ax,1
add bx,ax ; add envsize to paras to keep
IF ptrsize
lds si,envp
ELSE
mov si,envp
ENDIF
;
mov ax,es ; low core segment
add ax,keep_paras ; plus fixed paras
mov es:expar.envseg,ax ; = new environment segment
;
; Save stack regs, switch to local stack
;
no_environ:
mov es:save_ss,ss
mov es:save_sp,sp
mov ax,es
mov ss,ax
mov sp,mystack
;
push cx ; save env length
push si ; save env pointer
push ds ; save env segment
;
; save and patch INT0 (division by zero) vector
;
xor ax,ax
mov ds,ax
mov ax,word ptr ds:0
mov es:div0_off,ax
mov ax,word ptr ds:2
mov es:div0_seg,ax
mov word ptr ds:0,codebeg + iretoff
mov word ptr ds:2,es
;
pop ds ; pop environment segment
pop si ; pop environment offset
pop cx ; pop environment length
mov di,swapbeg ; environment destination
;
; Push return address on local stack
;
push cs ; push return segment
mov ax,offset exec_cont
push ax ; push return offset
mov es:spx,sp ; save stack pointer
;
; Goto low core code
;
push es ; push entry segment
mov ax,codebeg + doexec_entry
push ax ; push entry offset
; ret far ; can't use RET here because
db 0cbh ; of .model
;
;----------------------------------------------------------------
;
; Low core code will return to this location, with DS set to
; the PSP segment.
;
exec_cont:
push ds
pop es
mov ss,ds:save_ss ; reload stack
mov sp,ds:save_sp
;
; restore INT0 (division by zero) vector
;
xor cx,cx
mov ds,cx
mov cx,es:div0_off
mov word ptr ds:0,cx
mov cx,es:div0_seg
mov word ptr ds:2,cx
;
mov ax,es:eretcode
mov bx,es:retflags
mov ds,datseg
;
; Restore overwritten part of program
;
mov si,offset save_dat
mov di,5ch
mov cx,savespace
rep movsb
;
test bx,1 ; carry set?
jnz exec_fault ; return EXEC error code if fault
mov ah,4dh ; else get program return code
int 21h
ret
;
exec_fault:
mov ah,3 ; return error as 03xx
ret
;
do_spawn ENDP
;
;----------------------------------------------------------------------------
;----------------------------------------------------------------------------
;
emm_name db 'EMMXXXX0'
;
; prep_swap - prepare for swapping.
;
; This routine checks all parameters necessary for swapping,
; and attempts to set up the swap-out area in EMS/XMS, or on file.
; In detail:
;
; 1) Check whether the do_spawn routine is located
; too low in memory, so it would get overwritten.
; If this is true, return an error code (-2).
;
; 2) Walk the memory control block chain, adding up the
; paragraphs in all blocks assigned to this process.
;
; 3) Check EMS (if the method parameter allows EMS):
; - is an EMS driver installed?
; - are sufficient EMS pages available?
; if all goes well, the EMS pages are allocated, and the
; routine returns success (1).
;
; 4) Check XMS (if the method parameter allows XMS):
; - is an XMS driver installed?
; - is a sufficient XMS block available?
; if all goes well, the XMS block is allocated, and the
; routine returns success (2).
;
; 5) Check file swap (if the method parameter allows it):
; - try to create the file
; - pre-allocate the file space needed by seeking to the end
; and writing a byte.
; If the file can be written, the routine returns success (4).
;
; 6) Return an error code (-1).
;
prep_swap PROC uses si di,pmethod:word,swapfname:ptr byte
LOCAL totparas: word
;
mov ax,_psp
;
dec ax
mov prep.psp_mcb,ax
mov prep.first_mcb,ax ; init first MCB to PSP
;
; Make a copy of the environment pointer in the PSP
;
inc ax
mov es,ax
mov bx,es:psp_envptr
dec bx
mov prep.env_mcb,bx
mov prep.noswap_mcb,0
test pmethod,DONT_SWAP_ENV
jz can_swap_env
mov prep.noswap_mcb,bx
;
; Check if spawn is too low in memory
;
can_swap_env:
mov bx,cs
mov dx,offset lowcode_begin
mov cl,4
shr dx,cl
add bx,dx ; normalized start of this code
mov dx,keep_paras ; the end of the modified area
add dx,ax ; plus PSP = end paragraph
cmp bx,dx
ja prepswap_ok ; ok if start of code > end of low mem
mov ax,-2
mov prep.swapmethod,al
ret
;
; Walk the chain of memory blocks, adding up the paragraphs
; in all blocks belonging to this process.
; We try to find the first MCB by getting DOS's "list of lists",
; and fetching the word at offset -2 of the returned address.
; If this fails, we use our PSP as the starting point.
;
prepswap_ok:
xor bx,bx
mov es,bx
mov ah,52h ; get list of lists
int 21h
mov ax,es
or ax,bx
jz prep_no_first
mov es,es:[bx-2] ; first MCB
cmp es:id,4dh ; normal ID?
jne prep_no_first
mov prep.first_mcb,es
;
prep_no_first:
mov es,prep.psp_mcb ; ES points to base MCB
mov cx,es ; save this value
mov bx,es:owner ; the current process
mov dx,es:paras ; memory size in the base block
sub dx,keep_paras ; minus resident paragraphs
mov si,0 ; number of MCBs except base
mov di,prep.noswap_mcb
mov ax,prep.first_mcb
mov prep.first_mcb,0
;
prep_mcb_walk:
mov es,ax
cmp ax,cx ; base block?
je prep_walk_next ; then don't count again
cmp ax,di ; Non-swap MCB?
je prep_walk_next ; then don't count
;
cmp bx,es:owner ; our process?
jne prep_walk_next ; next if not
inc si
mov ax,es:paras ; else get number of paragraphs
add ax,2 ; + 1 for descriptor + 1 for MCB
add dx,ax ; total number of paras
cmp prep.first_mcb,0
jne prep_walk_next
mov prep.first_mcb,es
;
prep_walk_next:
cmp es:id,4dh ; normal block?
jne prep_mcb_ready ; ready if end of chain
mov ax,es
add ax,es:paras ; start + length
inc ax ; next MCB
jmp prep_mcb_walk
;
prep_mcb_ready:
mov totparas,dx
mov prep.total_mcbs,si
;
test pmethod,XMS_FIRST
jnz check_xms
;
; Check for EMS swap
;
check_ems:
test pmethod,USE_EMS
jz prep_no_ems
;
push ds
mov al,EMM_INT
mov ah,35h
int 21h ; get EMM int vector
mov ax,cs
mov ds,ax
mov si,offset emm_name
mov di,10
mov cx,8
repz cmpsb ; EMM name present?
pop ds
jnz prep_no_ems
;
mov ah,40h ; get EMS status
int EMM_INT
or ah,ah ; EMS ok?
jnz prep_no_ems
;
mov ah,46h ; get EMS version
int EMM_INT
or ah,ah ; AH must be 0
jnz prep_no_ems
;
cmp al,30h ; >= version 3.0?
jb prep_no_ems
;
mov ah,41h ; Get page frame address
int EMM_INT
or ah,ah
jnz prep_no_ems
;
; EMS present, try to allocate pages
;
mov prep.ems_pageframe,bx
mov bx,totparas
add bx,ems_paramask
mov cl,ems_shift
shr bx,cl
mov ah,43h ; allocate handle and pages
int EMM_INT
or ah,ah ; success?
jnz prep_no_ems
;
; EMS pages allocated, swap to EMS
;
mov prep.handle,dx
mov ax,USE_EMS
mov prep.swapmethod,al
ret
;
; No EMS allowed, or EMS not present/full. Try XMS.
;
prep_no_ems:
test pmethod,XMS_FIRST
jnz check_file ; don't try again
;
check_xms:
test pmethod,USE_XMS
jz prep_no_xms
;
mov ax,4300h ; check if XMM driver present
int 2fh
cmp al,80h ; is XMM installed?
jne prep_no_xms
mov ax,4310h ; get XMM entrypoint
int 2fh
mov word ptr prep.xmm,bx ; save entry address
mov word ptr prep.xmm+2,es
;
mov dx,totparas
add dx,xms_paramask ; round to nearest multiple of 1k
mov cl,xms_shift
shr dx,cl ; convert to k
mov ah,9 ; allocate extended memory block
call prep.xmm
or ax,ax
jz prep_no_xms
;
; XMS block allocated, swap to XMS
;
mov prep.handle,dx
mov ax,USE_XMS
mov prep.swapmethod,al
ret
;
; No XMS allowed, or XMS not present/full. Try File swap.
;
prep_no_xms:
test pmethod,XMS_FIRST
jz check_file
jmp check_ems
;
check_file:
test pmethod,USE_FILE
jnz prep_do_file
jmp prep_no_file
;
prep_do_file:
push ds
IF ptrsize
lds dx,swapfname
ELSE
mov dx,swapfname
ENDIF
mov cx,2 ; hidden attribute
test pmethod,HIDE_FILE
jnz prep_hide
xor cx,cx ; normal attribute
;
prep_hide:
mov ah,3ch ; create file
test pmethod,CREAT_TEMP
jz prep_no_temp
mov ah,5ah
;
prep_no_temp:
int 21h ; create/create temp
jnc prep_got_file
jmp prep_no_file
;
prep_got_file:
mov bx,ax ; handle
;
; save the file name
;
pop es
push es
mov di,offset prep.swapfilename
mov cx,81
mov si,dx
rep movsb
;
pop ds
mov prep.handle,bx
;
; preallocate the file
;
test pmethod,NO_PREALLOC
jnz prep_noprealloc
test pmethod,CHECK_NET
jz prep_nonetcheck
;
; check whether file is on a network drive, and don't preallocate
; if so. preallocation can slow down swapping significantly when
; running on certain networks (Novell)
;
mov ax,440ah ; check if handle is remote
int 21h
jc prep_nonetcheck ; assume not remote if function fails
test dh,80h ; DX bit 15 set ?
jnz prep_noprealloc ; remote if yes
;
prep_nonetcheck:
mov dx,totparas
mov cl,4
rol dx,cl
mov cx,dx
and dx,0fff0h
and cx,0000fh
sub dx,1
sbb cx,0
mov si,dx ; save
mov ax,4200h ; move file pointer, absolute
int 21h
jc prep_file_err
cmp dx,cx
jne prep_file_err
cmp ax,si
jne prep_file_err
mov cx,1 ; write 1 byte
mov ah,40h
int 21h
jc prep_file_err
cmp ax,cx
jne prep_file_err
;
mov ax,4200h ; move file pointer, absolute
xor dx,dx
xor cx,cx ; rewind to beginning
int 21h
jc prep_file_err
;
prep_noprealloc:
mov ax,USE_FILE
mov prep.swapmethod,al
ret
;
prep_file_err:
mov ah,3eh ; close file
int 21h
mov dx,offset prep.swapfilename
mov ah,41h ; delete file
int 21h
;
prep_no_file:
mov ax,-1
mov prep.swapmethod,al
ret
;
prep_swap endp
;
end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -