MS-DOS/v2.0/source/EXEC.ASM

1036 lines
29 KiB
NASM
Raw Normal View History

1983-08-13 01:53:34 +01:00
SUBTTL $exec - load/go a program
PAGE
;
; Assembler usage:
; LDS DX, name
; LES BX, blk
; MOV AH, Exec
; MOV AL, func
; INT int_command
;
; AL Function
; -- --------
; 0 Load and execute the program.
; 1 Load, create the program header but do not
; begin execution.
; 3 Load overlay. No header created.
;
; AL = 0 -> load/execute program
;
; +---------------------------+
; | WORD segment address of |
; | environment. |
; +---------------------------+
; | DWORD pointer to ASCIZ |
; | command line at 80h |
; +---------------------------+
; | DWORD pointer to default |
; | FCB to be passed at 5Ch |
; +---------------------------+
; | DWORD pointer to default |
; | FCB to be passed at 6Ch |
; +---------------------------+
;
; AL = 1 -> load program
;
; +---------------------------+
; | WORD segment address of |
; | environment. |
; +---------------------------+
; | DWORD pointer to ASCIZ |
; | command line at 80h |
; +---------------------------+
; | DWORD pointer to default |
; | FCB to be passed at 5Ch |
; +---------------------------+
; | DWORD pointer to default |
; | FCB to be passed at 6Ch |
; +---------------------------+
; | DWORD returned value of |
; | CS:IP |
; +---------------------------+
; | DWORD returned value of |
; | SS:IP |
; +---------------------------+
;
; AL = 3 -> load overlay
;
; +---------------------------+
; | WORD segment address where|
; | file will be loaded. |
; +---------------------------+
; | WORD relocation factor to |
; | be applied to the image. |
; +---------------------------+
;
; Returns:
; AX = exec_invalid_function
; = exec_bad_format
; = exec_bad_environment
; = exec_not_enough_memory
; = exec_file_not_found
;
IF IBM
ZEXEC_DATA SEGMENT PUBLIC BYTE
ZERO = $
ENDIF
exec_blk DD ?
exec_func DB ?
exec_fh DW ?
exec_rel_fac DW ?
exec_res_len_para DW ?
exec_init_IP DW ?
exec_init_CS DW ?
exec_init_SP DW ?
exec_init_SS DW ?
exec_environ DW ?
exec_size DW ?
exec_load_block DW ?
exec_load_high DB ?
exec_internal_buffer EQU $
exec_signature DW ? ; must contain 4D5A (yay zibo!)
exec_len_mod_512 DW ? ; low 9 bits of length
exec_pages DW ? ; number of 512b pages in file
exec_rle_count DW ? ; count of reloc entries
exec_par_dir DW ? ; number of paragraphs before image
exec_min_BSS DW ? ; minimum number of para of BSS
exec_max_BSS DW ? ; max number of para of BSS
exec_SS DW ? ; stack of image
exec_SP DW ? ; SP of image
exec_chksum DW ? ; checksum of file (ignored)
exec_IP DW ? ; IP of entry
exec_CS DW ? ; CS of entry
exec_rle_table DW ? ; byte offset of reloc table
exec_iov DW ? ; overlay number (0 for root)
exec_dma DW ?
exec_internal_buffer_size EQU $-exec_internal_buffer
IF IBM
exec_ctrlc DB ? ; state of users ctrlc flag
Exec_low_seg DW ?
CurrentPDB DW ?
NUMIO DB ?
ZEXECDATASIZ = $-ZERO
ZEXECDATAEND LABEL BYTE
PUBLIC ZEXECDATAEND
ZEXEC_DATA ENDS
ZEXEC_CODE SEGMENT PUBLIC PARA
PUBLIC $EXEC
ZERO = $
procedure $EXEC,FAR
ASSUME CS:EGROUP,SS:RESGROUP,ES:NOTHING,DS:NOTHING
ENDIF
IF NOT IBM
procedure $Exec,NEAR
ASSUME DS:NOTHING, ES:NOTHING
ENDIF
;
; validate function
;
IF IBM
PUSH CS
POP DS
ASSUME DS:EGROUP
MOV AX,(Set_Ctrl_C_Trapping SHL 8) + 0 ; Save current ctrl-c
INT int_command
MOV exec_ctrlc,DL
XOR DX,DX
MOV AX,(Set_Ctrl_C_Trapping SHL 8) + 1 ; Turn it off!
INT int_command
MOV AH,Get_current_PDB
INT int_command
MOV [CurrentPDB],BX
;
; set up user return stack info
;
MOV ES,BX
LES BX,DWORD PTR [user_sp]
MOV WORD PTR ES:[PDB_user_stack+2],ES
MOV WORD PTR ES:[PDB_user_stack],BX
MOV AH,Get_Default_Drive
INT int_command
MOV DL,AL
MOV AH,Set_default_drive
INT int_command
MOV [NUMIO],AL
;
; determine lowest seg address for overwrite problem (round DOWN)
;
MOV CL,4
MOV AX,OFFSET ZEXEC_CODE:exec_check
SHR AX,CL
PUSH CS
POP BX
ADD AX,BX
MOV [exec_low_seg],AX
CALL get_user_stack
ASSUME DS:NOTHING
MOV AX,[SI.user_AX]
MOV BX,[SI.user_BX]
MOV DX,[SI.user_DX]
MOV ES,[SI.user_ES]
MOV DS,[SI.user_DS]
ENDIF
CMP AL,3 ; only 0, 1 or 3 are allowed
JNA exec_check_2
exec_bad_fun:
error error_invalid_function
exec_ret_err:
transfer SYS_RET_ERR
exec_check_2:
CMP AL,2
JZ exec_bad_fun
MOV WORD PTR [exec_blk],BX ; stash args
MOV WORD PTR [exec_blk+2],ES
MOV BYTE PTR [exec_func],AL
MOV BYTE PTR [exec_load_high],0
IF IBM
MOV AX,(OPEN SHL 8) + 0
INT int_command
ENDIF
IF NOT IBM
XOR AL,AL ; open for reading
invoke $OPEN ; is the file there?
ENDIF
JC exec_ret_err
MOV [exec_fh],AX
MOV BX,AX
IF IBM
MOV AX,(ioctl SHL 8) ; get device information
INT int_command
ENDIF
IF NOT IBM
XOR AL,AL
invoke $IOCTL
ENDIF
TEST DL,devid_ISDEV
JZ exec_check_environ
MOV AL,exec_file_not_found
transfer SYS_RET_ERR
exec_check_environ:
MOV [exec_load_block],0
TEST BYTE PTR [exec_func],exec_func_overlay ; overlays... no environment
JNZ exec_read_header
LDS SI,DWORD PTR [exec_blk] ; get block
MOV AX,[SI].Exec1_environ ; address of environ
OR AX,AX
JNZ exec_scan_env
MOV DS,[CurrentPDB]
MOV AX,DS:[PDB_environ]
MOV [exec_environ],AX
OR AX,AX
JZ exec_read_header
exec_scan_env:
CLD
MOV ES,AX
XOR DI,DI
MOV CX,07FFFh ; at most 32k of environment
XOR AL,AL
exec_get_environ_len:
REPNZ SCASB ; find that nul byte
JZ exec_check ; CX is out... bad environment
MOV AL,exec_bad_environment
JMP exec_bomb
exec_check:
SCASB ; is there another nul byte?
JNZ exec_get_environ_len ; no, scan some more
PUSH DI
MOV BX,DI ; AX <- length of environment
ADD BX,0Fh
MOV CL,4
SHR BX,CL ; number of paragraphs needed
PUSH ES
IF IBM
MOV AH,ALLOC
INT int_command
ENDIF
IF NOT IBM
invoke $ALLOC ; can we get the space?
ENDIF
POP DS
POP CX
JNC exec_save_environ
JMP exec_no_mem ; nope... cry and sob
exec_save_environ:
MOV ES,AX
MOV [exec_environ],AX ; save him for a rainy day
IF IBM
PUSH CX
MOV CX,ES
ADD CX,BX
CMP BX,[exec_low_seg]
POP CX
JA exec_no_mem
ENDIF
XOR SI,SI
XOR DI,DI
REP MOVSB ; copy the environment
exec_read_header:
;
; We read in the program header into the above data area and determine
; where in this memory the image will be located.
;
IF IBM
PUSH CS
POP DS ; and put it in DS:DX
ASSUME DS:EGROUP
ENDIF
IF NOT IBM
PUSH SS
POP DS ; and put it in DS:DX
ASSUME DS:DOSGROUP
ENDIF
MOV CX,exec_internal_buffer_size; header size
MOV BX,[exec_fh] ; from the handle
IF IBM
MOV DX,OFFSET EGROUP:exec_signature
ENDIF
IF NOT IBM
MOV DX,OFFSET DOSGROUP:exec_signature
ENDIF
PUSH ES
PUSH DS
CALL exec_dealloc
IF IBM
MOV AH,READ
INT int_command
ENDIF
IF NOT IBM
invoke $READ
ENDIF
CALL exec_alloc
POP DS
POP ES
JC exec_bad_file
CMP AX,exec_internal_buffer_size; did we read the right number?
JNZ exec_com_filej ; yep... continue
CMP [exec_max_BSS],0
JNZ exec_check_sig
MOV [exec_load_high],-1
exec_check_sig:
MOV AX,[exec_signature]
CMP AX,exe_valid_signature ; zibo arises!
JZ exec_save_start ; assume com file if no signature
CMP AX,exe_valid_old_signature ; zibo arises!
JZ exec_save_start ; assume com file if no signature
exec_com_filej:
JMP exec_com_file
;
; We have the program header... determine memory requirements
;
exec_save_start:
MOV AX,[exec_pages] ; get 512-byte pages
MOV CL,5 ; convert to paragraphs
SHL AX,CL
SUB AX,[exec_par_dir] ; AX = size in paragraphs
MOV [exec_res_len_para],AX
;
; Do we need to allocate memory? Yes if function is not load-overlay
;
TEST BYTE PTR [exec_func],exec_func_overlay
JZ exec_allocate ; allocation of space
;
; get load address from block
;
LES DI,DWORD PTR [exec_blk]
MOV AX,ES:[DI].exec3_load_addr
MOV [exec_dma],AX
MOV AX,ES:[DI].exec3_reloc_fac
MOV [exec_rel_fac],AX
IF IBM
JMP exec_find_res
ENDIF
IF NOT IBM
JMP SHORT exec_find_res
ENDIF
exec_no_mem:
MOV AL,exec_not_enough_memory
JMP SHORT exec_bomb ; AX should be set by $ALLOC
exec_bad_file:
MOV AL,exec_bad_format
exec_bomb:
ASSUME DS:NOTHING,ES:NOTHING
PUSH AX
MOV BX,[exec_fh]
CALL exec_dealloc
IF IBM
MOV AH,CLOSE
INT int_command
ENDIF
IF NOT IBM
invoke $CLOSE
ENDIF
POP AX
transfer SYS_RET_ERR
exec_allocate:
IF IBM
ASSUME DS:EGROUP
ENDIF
IF NOT IBM
ASSUME DS:DOSGROUP
ENDIF
PUSH AX
MOV BX,0FFFFh ; see how much room in arena
PUSH DS
IF IBM
MOV AH,ALLOC
INT int_command
ENDIF
IF NOT IBM
invoke $ALLOC ; should have carry set and BX has max
ENDIF
POP DS
POP AX
ADD AX,10h ; room for header
CMP BX,11h ; enough room for a header
JB exec_no_mem
CMP AX,BX ; is there enough for bare image?
JA exec_no_mem
CMP [exec_load_high],0 ; if load high, use max
JNZ exec_BX_max ; use max
ADD AX,[exec_min_BSS] ; go for min allocation
JC exec_no_mem ; oops! carry
CMP AX,BX ; enough space?
JA exec_no_mem ; nope...
SUB AX,[exec_min_BSS]
ADD AX,[exec_max_BSS] ; go for the MAX
JC exec_BX_max
CMP AX,BX
JBE exec_got_block
exec_BX_max:
MOV AX,BX
exec_got_block:
PUSH DS
MOV BX,AX
MOV [exec_size],BX
IF IBM
MOV AH,ALLOC
INT int_command
ENDIF
IF NOT IBM
invoke $ALLOC ; get the space
ENDIF
POP DS
JC exec_no_mem
MOV [exec_load_block],AX
ADD AX,10h
CMP [exec_load_high],0
JZ exec_use_ax ; use ax for load info
ADD AX,[exec_size] ; go to end
SUB AX,[exec_res_len_para] ; drop off header
SUB AX,10h ; drop off pdb
exec_use_ax:
MOV [exec_rel_fac],AX ; new segment
MOV [exec_dma],AX ; beginning of dma
IF IBM
CMP AX,[exec_low_seg] ; below loader
JA exec_no_mem_try
ADD AX,[exec_res_len_para] ; go to end
CMP Ax,[exec_low_seg] ; above loader
JBE exec_find_res
exec_try_high:
CMP [exec_load_high],0
JZ exec_no_memj1
exec_try_just_below:
MOV DX,AX
SUB DX,[exec_size] ; get beginning
ADD DX,[exec_res_len_para] ; no space
CMP DX,[exec_low_seg] ; room there?
JA exec_no_memj1
MOV AX,[exec_low_seg]
SUB AX,[exec_res_len_para]
JMP exec_use_ax
exec_no_mem_try:
MOV DX,CS
ADD DX,(zexecdatasiz+zexeccodesize+15)/16
CMP AX,DX
JAE exec_try_high
JMP exec_try_just_below
exec_no_memj1:
JMP exec_no_mem
ENDIF
;
; Determine the location in the file of the beginning of the resident
;
exec_find_res:
MOV DX,[exec_par_dir]
PUSH DX
MOV CL,4
SHL DX,CL ; low word of location
POP AX
MOV CL,12
SHR AX,CL ; high word of location
MOV CX,AX ; CX <- high
;
; Read in the resident image (first, seek to it)
;
MOV BX,[exec_fh]
PUSH DS
IF IBM
MOV AX,(LSEEK SHL 8) + 0
INT int_command
ENDIF
IF NOT IBM
XOR AL,AL
invoke $LSEEK ; seek to resident
ENDIF
POP DS
exec_big_read: ; Read resident into memory
MOV BX,[exec_res_len_para]
CMP BX,1000h ; too many bytes to read?
JB exec_read_ok
MOV BX,0FE0h ; max in one chunk FE00 bytes
exec_read_ok:
SUB [exec_res_len_para],BX ; we read (soon) this many
PUSH BX
MOV CL,4
SHL BX,CL ; get count in bytes from paras
MOV CX,BX ; count in correct register
MOV BX,[exec_fh] ; handle in correct register
PUSH DS
MOV DS,[exec_dma] ; Set up read buffer
ASSUME DS:NOTHING
XOR DX,DX
PUSH CX ; save our count
CALL exec_dealloc
IF IBM
MOV AH,READ
INT int_command
ENDIF
IF NOT IBM
invoke $READ ; WOMP!
ENDIF
CALL exec_alloc
POP CX ; get old count to verify
POP DS
IF IBM
ASSUME DS:EGROUP
ENDIF
IF NOT IBM
ASSUME DS:DOSGROUP
ENDIF
CMP CX,AX ; did we read enough?
POP BX ; get paragraph count back
JNZ exec_do_reloc ; and do reloc if no more to read
;
; We've read in CX bytes... bump DTA location
;
ADD [exec_dma],BX ; bump dma address
CMP [exec_res_len_para],0
JNZ exec_big_read
;
; The image has now been read in. We must perform relocation to
; the current location.
;
exec_do_reloc:
MOV CX,[exec_rel_fac]
MOV AX,[exec_SS] ; get initial SS
ADD AX,CX ; and relocate him
MOV [exec_init_SS],AX
MOV AX,[exec_SP] ; initial SP
MOV [exec_init_SP],AX
LES AX,DWORD PTR [exec_IP]
MOV [exec_init_IP],AX
MOV AX,ES
ADD AX,CX ; relocated...
MOV [exec_init_CS],AX
XOR CX,CX
MOV DX,[exec_rle_table]
MOV BX,[exec_fh]
PUSH DS
IF IBM
MOV AX,(LSEEK SHL 8) + 0
INT int_command
ENDIF
IF NOT IBM
XOR AX,AX
invoke $LSEEK
ENDIF
POP DS
JNC exec_get_entries
exec_bad_filej:
JMP exec_bad_file
exec_get_entries:
MOV DX,[exec_rle_count] ; Number of entries left
exec_read_reloc:
ASSUME DS:NOTHING
PUSH DX
IF IBM
MOV DX,OFFSET EGROUP:exec_signature
ENDIF
IF NOT IBM
MOV DX,OFFSET DOSGROUP:exec_signature
ENDIF
MOV CX,((exec_internal_buffer_size)/4)*4
MOV BX,[exec_fh]
PUSH DS
CALL exec_dealloc
IF IBM
MOV AH,READ
INT int_command
ENDIF
IF NOT IBM
invoke $READ
ENDIF
CALL exec_alloc
POP ES
POP DX
JC exec_bad_filej
MOV CX,(exec_internal_buffer_size)/4
IF IBM
MOV DI,OFFSET EGROUP:exec_signature ; Pointer to byte location in header
ENDIF
IF NOT IBM
MOV DI,OFFSET DOSGROUP:exec_signature ; Pointer to byte location in header
ENDIF
;
; Relocate a single address
;
MOV SI,[exec_rel_fac]
exec_reloc_one:
CMP DX,0 ; Any more entries?
JNE exec_get_addr
JMP Exec_set_PDB
exec_get_addr:
LDS BX,DWORD PTR ES:[DI] ; Get ra/sa of entry
MOV AX,DS ; Relocate address of item
ADD AX,SI
MOV DS,AX
MOV AX,WORD PTR DS:[BX] ; Relocate item
ADD AX,SI
MOV WORD PTR DS:[BX],AX
ADD DI,4
DEC DX
LOOP exec_reloc_one ; End of internal buffer?
;
; We've exhausted a single buffer's worth. Read in the next piece
; of the relocation table.
;
PUSH ES
POP DS
JMP exec_read_reloc
exec_no_memj:
JMP exec_no_mem
;
; we have a .COM file. First, determine if we are merely loading an overlay.
;
exec_com_file:
TEST BYTE PTR [exec_func],exec_func_overlay
JZ exec_alloc_com_file
LDS SI,DWORD PTR [exec_blk] ; get arg block
LODSW ; get load address
MOV [exec_dma],AX
JMP SHORT exec_64k ; read it all!
; We must allocate the max possible size block (ick!) and set up
; CS=DS=ES=SS=PDB pointer, IP=100, SP=max size of block.
;
exec_alloc_com_file:
MOV BX,0FFFFh
IF IBM
MOV AH,ALLOC
INT int_command
ENDIF
IF NOT IBM
invoke $ALLOC ; largest piece available as error
ENDIF
OR BX,BX
JZ exec_no_memj
MOV [exec_size],BX ; save size of allocation block
IF IBM
MOV AH,ALLOC
INT int_command
ENDIF
IF NOT IBM
PUSH BX
invoke $ALLOC ; largest piece available as error
POP BX ; get size of block...
ENDIF
MOV [exec_load_block],AX
ADD AX,10h ; increment for header
MOV [exec_dma],AX
SUB BX,10h ; remember header
IF IBM
;
; need to read up to exec_low_seg (at most)
;
MOV CX,[exec_low_seg]
CMP AX,CX ; is base of allocation above spot
JA exec_check_64k
SUB CX,AX
CMP CX,BX
JA exec_check_64k
MOV BX,CX
exec_check_64k:
ENDIF
CMP BX,1000h ; 64k or more?
JAE exec_64k ; yes, read only 64k
MOV AX,BX ; convert size to bytes
MOV CL,4
SHL AX,CL
JMP SHORT exec_read_com
exec_64k:
MOV AX,0FFFFh ; 64k-1 bytes
exec_read_com:
PUSH AX ; save number to read
MOV BX,[exec_fh] ; of com file
XOR CX,CX ; but seek to 0:0
MOV DX,CX
IF IBM
MOV AX,(LSEEK SHL 8) + 0
INT int_command
ENDIF
IF NOT IBM
XOR AX,AX ; seek relative to beginning
invoke $LSEEK ; back to beginning of file
ENDIF
MOV BX,[exec_fh]
POP CX ; number to read
MOV DS,[exec_dma]
XOR DX,DX
PUSH CX
CALL exec_dealloc
IF IBM
MOV AH,READ
INT int_command
ENDIF
IF NOT IBM
invoke $READ ; read in com file
ENDIF
CALL exec_alloc
POP SI ; get number of bytes to read
CMP AX,SI ; did we read them all?
IF IBM
JNZ exec_skip ; exactly the wrong number... no memory
JMP exec_no_mem
exec_skip:
ENDIF
IF NOT IBM
JZ exec_no_memj ; exactly the wrong number... no memory
ENDIF
TEST BYTE PTR [exec_func],exec_func_overlay
JNZ exec_set_PDB ; no starto, chumo!
MOV AX,[exec_DMA]
SUB AX,10h
MOV [exec_init_CS],AX
MOV [exec_init_IP],100h ; initial IP is 100
; SI is at most FFFFh
DEC SI ; make room for stack
; SI is at most FFFEh, room for a 0!
MOV [exec_init_SP],SI ; max value for read is also SP!
MOV [exec_init_SS],AX
MOV DS,AX
MOV WORD PTR DS:[SI],0 ; 0 for return
exec_set_PDB:
MOV BX,[exec_fh] ; we are finished with the file.
CALL exec_dealloc
IF IBM
MOV AH,CLOSE
INT int_command
ENDIF
IF NOT IBM
invoke $CLOSE ; release the jfn
ENDIF
CALL exec_alloc
TEST BYTE PTR [exec_func],exec_func_overlay
JZ exec_build_header
transfer SYS_RET_OK ; overlay load -> done
exec_build_header:
MOV DX,[exec_load_block]
;
; assign the space to the process
;
MOV SI,arena_owner ; pointer to owner field
MOV AX,[exec_environ] ; get environ pointer
OR AX,AX
JZ NO_OWNER ; no environment
DEC AX ; point to header
MOV DS,AX
MOV DS:[SI],DX ; assign ownership
NO_OWNER:
MOV AX,[exec_load_block] ; get load block pointer
DEC AX
MOV DS,AX ; point to header
MOV DS:[SI],DX ; assign ownership
PUSH DX
IF IBM
MOV AH,DUP_PDB
INT int_command
MOV ES,DX
MOV [CurrentPDB],DX
ENDIF
IF NOT IBM
MOV BYTE PTR [CreatePDB], 0FFH ; indicate a new process
invoke $Dup_PDB ; ES is now PDB
ENDIF
POP DX
PUSH [exec_environ]
POP ES:[PDB_environ]
MOV SI,[exec_size]
ADD SI,DX
MOV ES:[PDB_block_len],SI
;
; set up proper command line stuff
;
LDS SI,DWORD PTR [exec_blk] ; get the block
PUSH DS ; save its location
PUSH SI
LDS SI,DS:[SI.exec0_5C_FCB] ; get the 5c fcb
MOV CX,12 ; copy drive, name and ext
PUSH CX
MOV DI,5Ch
MOV BL,DS:[SI]
REP MOVSB
XOR AX,AX ; zero extent, etc for CPM
STOSW
STOSW
POP CX
POP SI ; get block
POP DS
PUSH DS ; save (again)
PUSH SI
LDS SI,DS:[SI.exec0_6C_FCB] ; get 6C FCB
MOV DI,6Ch ; do same as above
MOV BH,DS:[SI]
REP MOVSB
STOSW
STOSW
POP SI ; get block (last time)
POP DS
LDS SI,DS:[SI.exec0_com_line] ; command line
MOV CX,80h
MOV DI,CX
REP MOVSB ; Wham!
;
; Process BX into default AX (validity of drive specs on args)
;
DEC CL ; get 0FFh in CX
CMP BH,[NUMIO]
JBE exec_BH_good
MOV BH,CL
JMP SHORT exec_BL
exec_BH_good:
XOR BH,BH
exec_BL:
CMP BL,[NUMIO]
JBE exec_BL_good
MOV BL,CL
JMP SHORT exec_set_return
exec_BL_good:
XOR BL,BL
exec_set_return:
invoke get_user_stack ; get his return address
PUSH [SI.user_CS] ; suck out the CS and IP
PUSH [SI.user_IP]
PUSH [SI.user_CS] ; suck out the CS and IP
PUSH [SI.user_IP]
POP WORD PTR ES:[PDB_Exit]
POP WORD PTR ES:[PDB_Exit+2]
XOR AX,AX
MOV DS,AX
POP DS:[addr_int_terminate] ; save them where we can get them later
POP DS:[addr_int_terminate+2] ; when the child exits.
IF NOT IBM
MOV WORD PTR [DMAADD],80h
MOV DS,[CurrentPDB]
MOV WORD PTR [DMAADD+2],DS
ENDIF
IF IBM
PUSH DX
PUSH DS
MOV DS,[CurrentPDB]
MOV DX,80h
MOV AH,SET_DMA
INT int_command
POP DS
POP DX
ENDIF
TEST BYTE PTR [exec_func],exec_func_no_execute
JZ exec_go
LDS SI,DWORD PTR [exec_init_SP] ; get stack
LES DI,DWORD PTR [exec_blk] ; and block for return
MOV ES:[DI].exec1_SS,DS ; return SS
DEC SI ; 'push' default AX
DEC SI
MOV DS:[SI],BX ; save default AX reg
MOV ES:[DI].exec1_SP,SI ; return 'SP'
LDS AX,DWORD PTR [exec_init_IP]
MOV ES:[DI].exec1_CS,DS ; initial entry stuff
MOV ES:[DI].exec1_IP,AX
transfer SYS_RET_OK
exec_go:
IF IBM
CALL restore_ctrlc ; restore value of ctrl-c checker
ENDIF
LDS SI,DWORD PTR [exec_init_IP] ; get entry point
CLI
IF NOT IBM
MOV BYTE PTR INDOS,0
ENDIF
MOV SS,[exec_init_SS] ; set up user's stack
ASSUME SS:NOTHING
MOV SP,[exec_init_SP] ; and SP
STI
PUSH DS ; fake long call to entry
PUSH SI
MOV ES,DX ; set up proper seg registers
MOV DS,DX
MOV AX,BX ; set up proper AX
procedure exec_long_ret,FAR
RET
exec_long_ret ENDP
$Exec ENDP
procedure exec_dealloc,near
ASSUME DS:NOTHING,ES:NOTHING
PUSH BX
MOV BX,arena_owner_system
CALL exec_do_change_owner
POP BX
return
exec_dealloc ENDP
procedure exec_alloc,near
PUSH BX
MOV BX,[CurrentPDB]
CALL exec_do_change_owner
POP BX
return
exec_alloc ENDP
procedure exec_do_change_owner,NEAR
PUSH DS
PUSH AX
MOV AX,[exec_environ]
OR AX,AX
JZ exec_alloc_try_load
DEC AX
MOV DS,AX
MOV DS:[arena_owner],BX
exec_alloc_try_load:
MOV AX,[exec_load_block]
OR AX,AX
JZ exec_alloc_done
DEC AX
MOV DS,AX
MOV DS:[arena_owner],BX
exec_alloc_done:
POP AX
POP DS
RET
exec_do_change_owner ENDP
IF IBM
SYS_RET_ERR:
CALL get_user_stack
PUSH [SI.user_f]
XOR AH,AH
MOV [SI.user_AX],AX
POPF
STC
JMP SYS_RET
SYS_RET_OK:
CALL get_user_stack
PUSH [SI.user_f]
POPF
CLC
SYS_RET:
PUSHF
CALL restore_ctrlc
POP [SI.user_f]
JMP exec_long_ret
;
; get_user_stack returns the user's stack (and hence registers) in DS:SI
;
procedure get_user_stack,NEAR
PUSH SS
POP DS
ASSUME DS:RESGROUP
LDS SI,DWORD PTR [user_SP]
RET
get_user_stack ENDP
;
; restore value of the ctrl-c checker
;
procedure restore_ctrlc
PUSH AX
PUSH DX
MOV DL,CS:[exec_ctrlc]
MOV AX,(Set_Ctrl_C_Trapping SHL 8) + 1 ; Put it back
INT int_command
POP DX
POP AX
RET
restore_ctrlc ENDP
ZEXECCODESIZE EQU $-ZERO
ZEXECCODEEND LABEL BYTE
PUBLIC ZEXECCODEEND
ZEXEC_CODE ENDS
ENDIF