📄 process.a86
字号:
mov word ptr [bx],0 ; zero on user stack
pop ds
lea si,EXE_IP[si] ; point at IP
lodsw ! stosw ; copy it, and get in AX for return
movsw ; copy EXE_CS too
jmp return_AX_CLC ; all went OK
start_child_go:
;--------------
;
; Set the initial registers conditions for a DOS process
; Check the validity of the drives specified in FCB 1 and FCB 2
; of the loading PSP and initialise the AX register accordingly.
;
xor dx,dx ; start with valid drives
mov es,current_psp ; Get the PSP Address and check
push dx
mov al,PSP_FCB1 ; if the drive specifier for FCB1
call valid_drive ; is invalid set AL to FF
pop dx
jz reg_s10
mov dl,0FFh
reg_s10:
push dx
mov al,PSP_FCB2 ; if the drive specifier for FCB2
call valid_drive ; is invalid set AH to FF
pop dx
jz reg_s20
mov dh,0FFh
reg_s20:
mov di,EXE_SP[si] ; Get the new stack address
push di ; save it
mov cl,4
shr di,cl ; convert SP to para's
jnz reg_s30
mov di,1000h ; if 0k make it 64k
reg_s30:
mov ax,load_max ; find top of prog area
sub ax,EXE_SS[si] ; find para's left for stack
cmp di,ax ; SP too high ?
pop di ; assume OK
jb reg_s40
mov di,ax ; no, so lower SP
shl di,cl ; convert to bytes
reg_s40:
mov cx,EXE_SS[si] ; CX:DI -> initial stack
les si,dword ptr EXE_IP[si] ; get initial CS:IP
cli
mov ax,current_psp ; AX = PSP we are going to use
xchg ax,dx
mov indos_flag,0 ; zap the indos flag
if 0
mov ss,cx ; switch to new USER stack
mov sp,di
push es
push si ; CS:IP on USER stack
mov ds,dx ; DS = ES = PSP we are exec'ing
mov es,dx
xor bx,bx ; BX = zero, set flags
sti
retf ; lets go!
else
jmpf exec_stub
endif
eject
; *****************************
; *** DOS Function 00 ***
; *** Terminate Process ***
; *****************************
;
; This code is executed for both INT 20 and INT 21/00 and they both
; implicitly set the current PSP to the users calling CODE segment.
; This overwrites the correct value held in CURRENT_PSP.
;
Public func00
func00:
mov byte ptr int21AX,0 ; force return code of zero
les di,int21regs_ptr
mov bx,es:reg_CS[di] ; normally users CS is current_psp
mov ax,current_psp ; but application call here
cmp ax,bx ; with an Int 20 at funny moments
je func4c ; (I have "NOW!" in mind)
mov es,bx ; fiddle CS PSP parent so we return to
mov PSP_PARENT,ax ; current_psp then fiddle current_psp
mov current_psp,bx ; to be user CS
; *****************************
; *** DOS Function 4C ***
; *** Terminate Process ***
; *****************************
;
Public func4C
func4c:
mov ax,current_psp ; the current PSP is terminating
mov term_psp,ax ; so set term_psp and load_psp
mov load_psp,ax ; to that value
f31_term: ; INT27 and INT21/31 Entry Point
push ds
mov ds,term_psp
xor ax,ax
mov es,ax ; Copy the Three interrupt vectors
mov si,offset PSP_TERM_IP ; saved on process creation from the
mov di,INT22_OFFSET ; termination PSP to the interrupt
mov cx,6 ; vector table.
rep movsw
mov ax,8200h ; call the REDIR hooks to clean up
int 2ah ; first the server hook
mov ax,I2F_PTERM ; then call cleanup code
int 2fh ; via magic INT 2F call
pop ds ; back to PCMODE data
mov al,byte ptr int21AX ; Get the User Return Code
mov user_retcode,al ; Save the User Ret Code and Set the
mov al,TERM_NORMAL ; Now get the Termination Type
xchg al,exit_type ; and exchange with the default value
mov system_retcode,al ; EXIT_TYPE is set so Non-Zero values
; when a Special Form of termination
; takes place. ie INT 27h
; But thence came VTERM, and it looked upon terminating the ROOT process,
; and saw that it was good.
;
; VTERM gives access to the cmdline by doing func31 and becoming a TSR. You can
; then re-invoke it with a hot-key but the next time you invoke the cmdline
; option does a func4C in whatever context it was re-invoked in. This will
; either blow away an application, or try and terminate the ROOT process.
mov es,term_psp ; make the terminating PSP's
mov ax,es:PSP_PARENT ; parental PSP into the
mov bx,current_psp
cmp ax,bx ; Is the user trying to terminate
jz f4C_20 ; the ROOT DOS process if YES then
; skip freeing resources (VTERM)
mov cx,load_psp ; if we are TSR'ing
jcxz f4C_20 ; skip the free
push ax ; save parental PSP
mov es,bx ; ES = current PSP
xor bx,bx ; start with handle zero
f4C_10:
mov ah,MS_X_CLOSE ; close this handle
call dos_entry ; so freeing up PSP entry
inc bx ; onto next handle
cmp bx,PSP_XFNMAX ; done them all yet?
jb f4C_10
mov FD_FUNC,FD_EXIT ; Must Close all Open FCB's
call fdos_nocrit
push ds ; We have already closed all the
pop es ; open MSNET files we know about
mov ax,I2F_PCLOSE ; but we will call the MSNET
int 2fh ; extention's cleanup code anyway
push ss ! pop ds ; reload DS with data segment
mov bx,current_psp ; free all memory associated
call free_all ; with this PSP
pop ax ; recover parental PSP
f4C_20:
mov current_psp,ax ; make current PSP = parental PSP
;
; Function 4C requires a different termination technique. It needs
; to return to the parent process on the stack that was used on the
; function 4B. The interrupt structure has been forced to contain
; the interrupt 22 vector. Therefore all registers will contain
; their original values unless the stack has been overlayed
;
;
cli ; Stop anybody interfering
mov indos_flag,0 ; Force the INDOS_FLAG to 0 for PCTOOLS
mov error_flag,0 ; and SideKick Plus.
mov ax,retcode
mov ds,current_psp
mov ss,ds:PSP_USERSS ; Retrieve the entry SS and SP from
mov sp,ds:PSP_USERSP ; the PSP and return with all
mov bp,sp ; registers as on user entry
mov ss:reg_AX[bp],ax ; Set AX to the Process RETCODE
xor ax,ax
mov ds,ax
mov ax,ds:word ptr .INT22_OFFSET
mov ss:reg_IP[bp],ax ; PSP_TERM_IP
mov ax,ds:word ptr .INT22_OFFSET+WORD
mov ss:reg_CS[bp],ax ; PSP_TERM_CS
mov ss:reg_FLAGS[bp],0b202h ; force flags to 0F202h
; ie Interrupts enabled and
; NEC processor Mode Switch SET
; changed to B202 to have clear
; NT flag (DPMS doesn't like it)
jmp int21_exit ; Jump to the Exit routine
eject
; *****************************
; *** DOS Function 4D ***
; *** Get Sub-Func Ret-Code ***
; *****************************
;
Public func4D
func4D:
xor ax,ax ; Zero the return code for
xchg ax,retcode ; subsequent calls and return the
jmp return_AX_CLC ; saved value to the caller
eject
;****************************************
;* *
;* Process Control Subroutines *
;* *
;****************************************
;
; We need a full pathname for the application to inherit in it's environment.
; MS_X_EXPAND can't do the job - it returns a PHYSICAL path which may be
; unreachable (bug circa DRDOS 3.41).
; On Entry:
; ES:DX Points to the Original FileName
; On Exit:
; None
;
get_filename:
push ds
push es ; swap ES and DS
pop ds
pop es
mov si,dx ; DS:SI -> filename
mov di,offset load_file ; ES:DI -> local buffer
mov cx,MAX_PATHLEN-4 ; max length (allow for d:\,NUL)
lodsw ; get 1st two chars in filename
cmp ah,':' ; is a drive specified ?
je get_filename10
dec si ! dec si ; forget we looked
mov al,ss:current_dsk ; and use the default drive
add al,'A'
get_filename10:
stosb ; put in the drive
and al,1fh ; convert from ASCII to 1 based
xchg ax,dx ; keep in DL for ms_x_curdir
mov ax,':'+256*'\' ; make it "d:\"
stosw
lodsb ; do we start at the root ?
cmp al,'\'
je get_filename20
cmp al,'/'
je get_filename20
dec si ; forget we looked for a root
push si ; save where we were
mov ah,MS_X_CURDIR
mov si,di ; ES:SI -> buffer
call dos_entry ; get current directory
xor ax,ax
repne scasb ; look for NUL
xchg ax,si ; AX = start of path
pop si ; recover pointer to source
jne get_filename30
dec di ; point at NUL
cmp ax,di ; are we at the root ?
je get_filename20
mov al,'\'
stosb ; no, append a '\'
get_filename20:
rep movsb ; copy the remainder of the string
get_filename30:
xor ax,ax
stosb ; ensure we are terminated
push es
pop ds ; DS back to nornal
ret
;
; BUILD_ENV determines the size of the Source environment and
; allocates memory and finally copies it.
;
; ON entry AX contains the segment address of the environment
; to be used or zero if the parents is to be copied.
build_env:
mov es,ax ; Assume user has specified the
or ax,ax ; environment to be used. If AX is
jnz b_e10 ; 0000 then use the current environment
mov es,current_psp
mov cx,PSP_ENVIRON ; Current Environment Segment
mov es,cx ; If the current environment segment
mov di,cx ; is zero then return a size of
jcxz b_e35 ; zero bytes
b_e10:
xor ax,ax ; Now determine the Environment size
mov cx,32*1024 ; CX is maximum size
mov di,ax
b_e20:
repnz scasb ; Look for two zero bytes which
jcxz b_e40 ; mark the end of the environment
cmp al,es:byte ptr [di] ; continue search till the end is found
jnz b_e20
dec di ; DI == Environment Size - 2
b_e30:
mov si,offset load_file ; Get the Load pathname length
call strlen ; String length returned in CX
inc cx ; Add in the terminator
push bx
mov bx,cx ; Get the String Length
add bx,di ; Add the environment size
add bx,15 + 4 ; and convert to paragraphs
shr bx,1 ! shr bx,1
shr bx,1 ! shr bx,1
mov load_envsize,bx ; Save the Environment Size
call mem_alloc ; allocate the memory
pop bx
jc b_e50
mov load_env,ax ; Save the Environment location
push cx ! push di ; Save STRLEN and Offset
push ds ; Save DS
push es
mov es,ax ; Point ES at the NEW environment
pop ds ; Point DS at the Old environment
mov cx,di ; Get the environment size
xor si,si ! mov di,si ; Initialize the pointers
rep movsb ; and copy. Nothing moves if CX == 0
pop ds
pop di ! pop cx ; Get the string pointers
xor ax,ax ! stosw ; Add terminating zeros
inc ax ! stosw ; Initialise the String COUNT field
mov si,offset load_file ; and size information and
rep movsb ; copy the load filename.
b_e35:
clc ; Return with no errors
ret
b_e40:
mov ax,ED_ENVIRON ; Invalid environment
b_e50:
stc
ret
; Calculate the new program segment prefix
; save: bx -> Handle
calc_psp:
push bx
mov si,offset exe_buffer ; Calculate the Minimum and Maximum
; amount of memory required to load
call image_size ; the program image (Returned in DX)
add dx,PSPLEN/16 ; Do not forget the PSP
mov cx,dx ; Save the Load Image Size
mov bx,dx ; BX will be memory required
mov ax,ED_MEMORY
add dx,EXE_MINPARA[si] ; force DX to be the minimum and if
jc cp_exit ; more than 1 MByte exit with error
add bx,EXE_MAXPARA[si] ; add the maximum amount of memory
jnc c_p10 ; to the load image size
mov bx,0FFFFh ; clipping to 1 MByte
c_p10:
if HILOAD
test mem_strategy,80h ; HILOAD ON ?
jz c_p15
mov bx,dx ; use minimum amount of memory
add bx,40h ; add 1 K extra for luck (stack etc)
call mem_alloc ; Allocate the requested block
jc cp_exit ; if alloc fails exit with error
push ds
mov ds,ax
mov bx,0ffffh ; find how much we can grow this block
call mem_setblock
call mem_setblock ; then grow it to that size
mov ax,ds ; ax = base of the block again
pop ds
jmps c_p20
c_p15:
endif
call mem_alloc ; allocate size and if error occurs
jnc c_p20 ; then the maximum size is greater
cmp bx,dx ; than the minimum required
jc cp_exit ; if not exit with error
call mem_alloc ; Allocate what we've got
jc cp_exit ; Exit on error
c_p20:
mov load_psp,ax ; Save the load paragraph == PSP
add bx,ax ; Save the block top
mov load_top,bx
mov load_max,bx ; save top of block for SP adjust
add ax,PSPLEN/16 ; Set AX to be the Relocation Paragraph
cmp exe_loadhigh,0 ; Should the Load Image be
jz c_p30 ; forced into to High Memory with the
mov ax,bx ; data area and PSP loaded low.
sub ax,cx ; Subtract the Load Image Size from
mov cx,PSPLEN/16 ; the top of allocated memory and
add ax,cx ; load at that address.
c_p30:
mov load_image,ax ; Save the Address of the Load Image
cp_exit:
pop bx
ret
eject
;LOADIMAGE:
;
; This function reads in the load image of the file into memory
; (Paragraph DI) asserting the relocation factor (SI) if any relocation
; items exist in the file. The size of the load image is calculated
; using the EXE_SIZE and EXE_FINAL fields enough memory exists at DI
; to load the image. The valid .EXE header has been moved to exe_buffer.
;
; Read in and relocate the EXE image
; entry: bx -> handle
; di = load segment
; si = reloc segment
; exit: cf = 1, ax = Error Code if load fails
;
loadimage:
;---------
call readfile ; Read the load image into memory
jc load_error ; Exit if error
mov cx,exe_buffer+EXE_RELCNT
; get number of reloc entries
jcxz load_done ; if none there, forget it .COM's
; drop out here because RELCNT is zero
push cx ; seek to 1st relocation entry
xor cx,cx ; in the file
mov dx,exe_buffer+EXE_RELOFF
mov ax,(MS_X_LSEEK*256)+0
call dos_entry
pop cx
jc load_error ; stop on error
xchg ax,cx ; AX = # items to relocate
call reloc_image ; relocate the image
jc load_error
load_done:
mov load_handle,-1
mov ah,MS_X_CLOSE ; and close the loadfile
jmp dos_entry ; close the com file
load_error: ; Error exit from relocation
push ax ; save error code
call load_done ; close the file
pop ax ; recover error code
stc ; say we had an error
ret
;
; The following code will relocate CX items from the open handle BX
;
reloc_image:
; On Entry:
; BX = handle
; AX = # items to relocate
; SI = relocation segment
; DI = relocation fixup
;
; On Exit:
; CY clear if OK, else AX = error code
push ds ! pop es ; ES -> Local Buffer Segment
mov dx,offset reloc_buf ; DX -> Local Buffer Offset
mov cx,RELOC_CNT ; AX -> Buffer Size
shl cx,1 ; convert reloc size from paras
shl cx,1 ; to an item count
sub ax,cx ; buffer. which contains a maximum
jnc reloc_i10 ; of RELOC_SIZE items.
add cx,ax ; CX contains # of items to Read
xor ax,ax ; AX contains # left to read
reloc_i10:
push ax ; save # items left to read
push cx ; and # reloc to read
shl cx,1 ! shl cx,1 ; calculate # byte to read
mov ah,MS_X_READ ; relocation buffer.
call dos_entry
pop cx
jnc reloc_i20 ; Exit on Error
pop cx ; clean up stack
ret ; return with error
reloc_i20:
push bx ; save handle
xchg ax,di ; AX = reloc fixup
mov bx,dx ; Get buffer offset
reloc_i30:
add word ptr 2[bx],ax ; Correct segment to Load Seg
les di,dword ptr [bx] ; es:di = reloc entry
add es:[di],si ; add reloc seg into image
add bx,4 ; and update for next entry
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -