1 SUBTTL $exec
- load/go a program
13 ; 0 Load and execute the program.
14 ; 1 Load, create the program header but do not
16 ; 3 Load overlay. No header created.
18 ; AL = 0 -> load/execute program
20 ; +---------------------------+
21 ; | WORD segment address of |
23 ; +---------------------------+
24 ; | DWORD pointer to ASCIZ |
25 ; | command line at 80h |
26 ; +---------------------------+
27 ; | DWORD pointer to default |
28 ; | FCB to be passed at 5Ch |
29 ; +---------------------------+
30 ; | DWORD pointer to default |
31 ; | FCB to be passed at 6Ch |
32 ; +---------------------------+
34 ; AL = 1 -> load program
36 ; +---------------------------+
37 ; | WORD segment address of |
39 ; +---------------------------+
40 ; | DWORD pointer to ASCIZ |
41 ; | command line at 80h |
42 ; +---------------------------+
43 ; | DWORD pointer to default |
44 ; | FCB to be passed at 5Ch |
45 ; +---------------------------+
46 ; | DWORD pointer to default |
47 ; | FCB to be passed at 6Ch |
48 ; +---------------------------+
49 ; | DWORD returned value of |
51 ; +---------------------------+
52 ; | DWORD returned value of |
54 ; +---------------------------+
56 ; AL = 3 -> load overlay
58 ; +---------------------------+
59 ; | WORD segment address where|
60 ; | file will be loaded. |
61 ; +---------------------------+
62 ; | WORD relocation factor to |
63 ; | be applied to the image. |
64 ; +---------------------------+
67 ; AX = exec_invalid_function
69 ; = exec_bad_environment
70 ; = exec_not_enough_memory
71 ; = exec_file_not_found
75 ZEXEC_DATA
SEGMENT PUBLIC BYTE
83 exec_res_len_para
DW ?
94 exec_internal_buffer EQU
$
95 exec_signature
DW ?
; must contain 4D5A (yay zibo!)
96 exec_len_mod_512
DW ?
; low 9 bits of length
97 exec_pages
DW ?
; number of 512b pages in file
98 exec_rle_count
DW ?
; count of reloc entries
99 exec_par_dir
DW ?
; number of paragraphs before image
100 exec_min_BSS
DW ?
; minimum number of para of BSS
101 exec_max_BSS
DW ?
; max number of para of BSS
102 exec_SS
DW ?
; stack of image
103 exec_SP
DW ?
; SP of image
104 exec_chksum
DW ?
; checksum of file (ignored)
105 exec_IP
DW ?
; IP of entry
106 exec_CS
DW ?
; CS of entry
107 exec_rle_table
DW ?
; byte offset of reloc table
108 exec_iov
DW ?
; overlay number (0 for root)
110 exec_internal_buffer_size EQU
$-exec_internal_buffer
113 exec_ctrlc
DB ?
; state of users ctrlc flag
117 ZEXECDATASIZ
= $-ZERO
118 ZEXECDATAEND
LABEL BYTE
121 ZEXEC_CODE
SEGMENT PUBLIC PARA
125 ASSUME
CS:EGROUP
,SS:RESGROUP
,ES:NOTHING
,DS:NOTHING
129 ASSUME
DS:NOTHING
, ES:NOTHING
140 MOV AX,(Set_Ctrl_C_Trapping
SHL 8) + 0 ; Save current ctrl-c
144 MOV AX,(Set_Ctrl_C_Trapping
SHL 8) + 1 ; Turn it off!
147 MOV AH,Get_current_PDB
151 ; set up user return stack info
154 LES BX,DWORD PTR [user_sp
]
155 MOV WORD PTR ES:[PDB_user_stack
+2],ES
156 MOV WORD PTR ES:[PDB_user_stack
],BX
158 MOV AH,Get_Default_Drive
161 MOV AH,Set_default_drive
165 ; determine lowest seg address for overwrite problem (round DOWN)
168 MOV AX,OFFSET ZEXEC_CODE
:exec_check
173 MOV [exec_low_seg
],AX
184 CMP AL,3 ; only 0, 1 or 3 are allowed
188 error error_invalid_function
197 MOV WORD PTR [exec_blk
],BX ; stash args
198 MOV WORD PTR [exec_blk
+2],ES
199 MOV BYTE PTR [exec_func
],AL
200 MOV BYTE PTR [exec_load_high
],0
202 MOV AX,(OPEN
SHL 8) + 0
206 XOR AL,AL ; open for reading
207 invoke $OPEN
; is the file there?
213 MOV AX,(ioctl
SHL 8) ; get device information
221 JZ exec_check_environ
222 MOV AL,exec_file_not_found
226 MOV [exec_load_block
],0
228 TEST BYTE PTR [exec_func
],exec_func_overlay
; overlays... no environment
230 LDS SI,DWORD PTR [exec_blk
] ; get block
231 MOV AX,[SI].Exec1_environ
; address of environ
235 MOV AX,DS:[PDB_environ
]
236 MOV [exec_environ
],AX
244 MOV CX,07FFFh ; at most 32k of environment
247 exec_get_environ_len:
248 REPNZ SCASB ; find that nul byte
249 JZ exec_check
; CX is out... bad environment
250 MOV AL,exec_bad_environment
254 SCASB ; is there another nul byte?
255 JNZ exec_get_environ_len
; no, scan some more
257 MOV BX,DI ; AX <- length of environment
260 SHR BX,CL ; number of paragraphs needed
267 invoke $ALLOC
; can we get the space?
271 JNC exec_save_environ
272 JMP exec_no_mem
; nope... cry and sob
276 MOV [exec_environ
],AX ; save him for a rainy day
281 CMP BX,[exec_low_seg
]
287 REP MOVSB ; copy the environment
291 ; We read in the program header into the above data area and determine
292 ; where in this memory the image will be located.
296 POP DS ; and put it in DS:DX
301 POP DS ; and put it in DS:DX
304 MOV CX,exec_internal_buffer_size
; header size
305 MOV BX,[exec_fh
] ; from the handle
307 MOV DX,OFFSET EGROUP
:exec_signature
310 MOV DX,OFFSET DOSGROUP
:exec_signature
326 CMP AX,exec_internal_buffer_size
; did we read the right number?
327 JNZ exec_com_filej
; yep... continue
330 MOV [exec_load_high
],-1
332 MOV AX,[exec_signature
]
333 CMP AX,exe_valid_signature
; zibo arises!
334 JZ exec_save_start
; assume com file if no signature
335 CMP AX,exe_valid_old_signature
; zibo arises!
336 JZ exec_save_start
; assume com file if no signature
342 ; We have the program header... determine memory requirements
345 MOV AX,[exec_pages
] ; get 512-byte pages
346 MOV CL,5 ; convert to paragraphs
348 SUB AX,[exec_par_dir
] ; AX = size in paragraphs
349 MOV [exec_res_len_para
],AX
352 ; Do we need to allocate memory? Yes if function is not load-overlay
354 TEST BYTE PTR [exec_func
],exec_func_overlay
355 JZ exec_allocate
; allocation of space
357 ; get load address from block
359 LES DI,DWORD PTR [exec_blk
]
360 MOV AX,ES:[DI].exec3_load_addr
362 MOV AX,ES:[DI].exec3_reloc_fac
363 MOV [exec_rel_fac
],AX
368 JMP SHORT exec_find_res
372 MOV AL,exec_not_enough_memory
373 JMP SHORT exec_bomb
; AX should be set by $ALLOC
376 MOV AL,exec_bad_format
379 ASSUME
DS:NOTHING
,ES:NOTHING
401 MOV BX,0FFFFh ; see how much room in arena
408 invoke $ALLOC
; should have carry set and BX has max
412 ADD AX,10h
; room for header
413 CMP BX,11h
; enough room for a header
415 CMP AX,BX ; is there enough for bare image?
417 CMP [exec_load_high
],0 ; if load high, use max
418 JNZ exec_BX_max
; use max
419 ADD AX,[exec_min_BSS
] ; go for min allocation
420 JC exec_no_mem
; oops! carry
421 CMP AX,BX ; enough space?
422 JA exec_no_mem
; nope...
423 SUB AX,[exec_min_BSS
]
424 ADD AX,[exec_max_BSS
] ; go for the MAX
441 invoke $ALLOC
; get the space
445 MOV [exec_load_block
],AX
447 CMP [exec_load_high
],0
448 JZ exec_use_ax
; use ax for load info
449 ADD AX,[exec_size
] ; go to end
450 SUB AX,[exec_res_len_para
] ; drop off header
451 SUB AX,10h
; drop off pdb
453 MOV [exec_rel_fac
],AX ; new segment
454 MOV [exec_dma
],AX ; beginning of dma
456 CMP AX,[exec_low_seg
] ; below loader
458 ADD AX,[exec_res_len_para
] ; go to end
459 CMP Ax,[exec_low_seg
] ; above loader
462 CMP [exec_load_high
],0
466 SUB DX,[exec_size
] ; get beginning
467 ADD DX,[exec_res_len_para
] ; no space
468 CMP DX,[exec_low_seg
] ; room there?
470 MOV AX,[exec_low_seg
]
471 SUB AX,[exec_res_len_para
]
475 ADD DX,(zexecdatasiz
+zexeccodesize
+15)/16
478 JMP exec_try_just_below
484 ; Determine the location in the file of the beginning of the resident
487 MOV DX,[exec_par_dir
]
490 SHL DX,CL ; low word of location
493 SHR AX,CL ; high word of location
494 MOV CX,AX ; CX <- high
497 ; Read in the resident image (first, seek to it)
502 MOV AX,(LSEEK
SHL 8) + 0
507 invoke $LSEEK
; seek to resident
511 exec_big_read: ; Read resident into memory
512 MOV BX,[exec_res_len_para
]
513 CMP BX,1000h
; too many bytes to read?
515 MOV BX,0FE0h ; max in one chunk FE00 bytes
518 SUB [exec_res_len_para
],BX ; we read (soon) this many
521 SHL BX,CL ; get count in bytes from paras
522 MOV CX,BX ; count in correct register
523 MOV BX,[exec_fh
] ; handle in correct register
525 MOV DS,[exec_dma
] ; Set up read buffer
528 PUSH CX ; save our count
538 POP CX ; get old count to verify
546 CMP CX,AX ; did we read enough?
547 POP BX ; get paragraph count back
548 JNZ exec_do_reloc
; and do reloc if no more to read
550 ; We've read in CX bytes... bump DTA location
553 ADD [exec_dma
],BX ; bump dma address
554 CMP [exec_res_len_para
],0
558 ; The image has now been read in. We must perform relocation to
559 ; the current location.
563 MOV CX,[exec_rel_fac
]
564 MOV AX,[exec_SS
] ; get initial SS
565 ADD AX,CX ; and relocate him
566 MOV [exec_init_SS
],AX
568 MOV AX,[exec_SP
] ; initial SP
569 MOV [exec_init_SP
],AX
571 LES AX,DWORD PTR [exec_IP
]
572 MOV [exec_init_IP
],AX
574 ADD AX,CX ; relocated...
575 MOV [exec_init_CS
],AX
578 MOV DX,[exec_rle_table
]
582 MOV AX,(LSEEK
SHL 8) + 0
596 MOV DX,[exec_rle_count
] ; Number of entries left
602 MOV DX,OFFSET EGROUP
:exec_signature
605 MOV DX,OFFSET DOSGROUP
:exec_signature
607 MOV CX,((exec_internal_buffer_size
)/4)*4
622 MOV CX,(exec_internal_buffer_size
)/4
624 MOV DI,OFFSET EGROUP
:exec_signature
; Pointer to byte location in header
627 MOV DI,OFFSET DOSGROUP
:exec_signature
; Pointer to byte location in header
630 ; Relocate a single address
632 MOV SI,[exec_rel_fac
]
635 CMP DX,0 ; Any more entries?
640 LDS BX,DWORD PTR ES:[DI] ; Get ra/sa of entry
641 MOV AX,DS ; Relocate address of item
644 MOV AX,WORD PTR DS:[BX] ; Relocate item
646 MOV WORD PTR DS:[BX],AX
649 LOOP exec_reloc_one
; End of internal buffer?
652 ; We've exhausted a single buffer's worth. Read in the next piece
653 ; of the relocation table.
664 ; we have a .COM file. First, determine if we are merely loading an overlay.
667 TEST BYTE PTR [exec_func
],exec_func_overlay
668 JZ exec_alloc_com_file
669 LDS SI,DWORD PTR [exec_blk
] ; get arg block
670 LODSW ; get load address
672 JMP SHORT exec_64k
; read it all!
674 ; We must allocate the max possible size block (ick!) and set up
675 ; CS=DS=ES=SS=PDB pointer, IP=100, SP=max size of block.
684 invoke $ALLOC
; largest piece available as error
688 MOV [exec_size
],BX ; save size of allocation block
695 invoke $ALLOC
; largest piece available as error
696 POP BX ; get size of block...
698 MOV [exec_load_block
],AX
699 ADD AX,10h
; increment for header
701 SUB BX,10h
; remember header
704 ; need to read up to exec_low_seg (at most)
706 MOV CX,[exec_low_seg
]
707 CMP AX,CX ; is base of allocation above spot
716 CMP BX,1000h
; 64k or more?
717 JAE exec_64k
; yes, read only 64k
718 MOV AX,BX ; convert size to bytes
721 JMP SHORT exec_read_com
724 MOV AX,0FFFFh ; 64k-1 bytes
727 PUSH AX ; save number to read
728 MOV BX,[exec_fh
] ; of com file
729 XOR CX,CX ; but seek to 0:0
732 MOV AX,(LSEEK
SHL 8) + 0
736 XOR AX,AX ; seek relative to beginning
737 invoke $LSEEK
; back to beginning of file
740 POP CX ; number to read
750 invoke $READ
; read in com file
753 POP SI ; get number of bytes to read
754 CMP AX,SI ; did we read them all?
756 JNZ exec_skip
; exactly the wrong number... no memory
761 JZ exec_no_memj
; exactly the wrong number... no memory
763 TEST BYTE PTR [exec_func
],exec_func_overlay
764 JNZ exec_set_PDB
; no starto, chumo!
767 MOV [exec_init_CS
],AX
768 MOV [exec_init_IP
],100h
; initial IP is 100
769 ; SI is at most FFFFh
770 DEC SI ; make room for stack
771 ; SI is at most FFFEh, room for a 0!
772 MOV [exec_init_SP
],SI ; max value for read is also SP!
773 MOV [exec_init_SS
],AX
775 MOV WORD PTR DS:[SI],0 ; 0 for return
778 MOV BX,[exec_fh
] ; we are finished with the file.
785 invoke $CLOSE
; release the jfn
788 TEST BYTE PTR [exec_func
],exec_func_overlay
790 transfer SYS_RET_OK
; overlay load -> done
793 MOV DX,[exec_load_block
]
795 ; assign the space to the process
798 MOV SI,arena_owner
; pointer to owner field
800 MOV AX,[exec_environ
] ; get environ pointer
802 JZ NO_OWNER
; no environment
803 DEC AX ; point to header
805 MOV DS:[SI],DX ; assign ownership
807 MOV AX,[exec_load_block
] ; get load block pointer
809 MOV DS,AX ; point to header
810 MOV DS:[SI],DX ; assign ownership
820 MOV BYTE PTR [CreatePDB
], 0FFH ; indicate a new process
821 invoke $Dup_PDB
; ES is now PDB
828 MOV ES:[PDB_block_len
],SI
830 ; set up proper command line stuff
832 LDS SI,DWORD PTR [exec_blk
] ; get the block
833 PUSH DS ; save its location
835 LDS SI,DS:[SI.exec0_5C_FCB
] ; get the 5c fcb
836 MOV CX,12 ; copy drive, name and ext
841 XOR AX,AX ; zero extent, etc for CPM
847 PUSH DS ; save (again)
849 LDS SI,DS:[SI.exec0_6C_FCB
] ; get 6C FCB
850 MOV DI,6
Ch ; do same as above
855 POP SI ; get block (last time)
857 LDS SI,DS:[SI.exec0_com_line
] ; command line
863 ; Process BX into default AX (validity of drive specs on args)
865 DEC CL ; get 0FFh in CX
876 JMP SHORT exec_set_return
880 invoke get_user_stack
; get his return address
881 PUSH [SI.user_CS
] ; suck out the CS and IP
883 PUSH [SI.user_CS
] ; suck out the CS and IP
885 POP WORD PTR ES:[PDB_Exit
]
886 POP WORD PTR ES:[PDB_Exit
+2]
889 POP DS:[addr_int_terminate
] ; save them where we can get them later
890 POP DS:[addr_int_terminate
+2] ; when the child exits.
892 MOV WORD PTR [DMAADD
],80h
894 MOV WORD PTR [DMAADD
+2],DS
906 TEST BYTE PTR [exec_func
],exec_func_no_execute
909 LDS SI,DWORD PTR [exec_init_SP
] ; get stack
910 LES DI,DWORD PTR [exec_blk
] ; and block for return
911 MOV ES:[DI].exec1_SS
,DS ; return SS
913 DEC SI ; 'push' default AX
915 MOV DS:[SI],BX ; save default AX reg
916 MOV ES:[DI].exec1_SP
,SI ; return 'SP'
918 LDS AX,DWORD PTR [exec_init_IP
]
919 MOV ES:[DI].exec1_CS
,DS ; initial entry stuff
921 MOV ES:[DI].exec1_IP
,AX
926 CALL restore_ctrlc
; restore value of ctrl-c checker
928 LDS SI,DWORD PTR [exec_init_IP
] ; get entry point
933 MOV SS,[exec_init_SS
] ; set up user's stack
935 MOV SP,[exec_init_SP
] ; and SP
937 PUSH DS ; fake long call to entry
939 MOV ES,DX ; set up proper seg registers
941 MOV AX,BX ; set up proper AX
942 procedure exec_long_ret
,FAR
948 procedure exec_dealloc
,near
949 ASSUME
DS:NOTHING
,ES:NOTHING
951 MOV BX,arena_owner_system
952 CALL exec_do_change_owner
957 procedure exec_alloc
,near
960 CALL exec_do_change_owner
965 procedure exec_do_change_owner
,NEAR
968 MOV AX,[exec_environ
]
970 JZ exec_alloc_try_load
973 MOV DS:[arena_owner
],BX
975 MOV AX,[exec_load_block
]
980 MOV DS:[arena_owner
],BX
985 exec_do_change_owner ENDP
1008 ; get_user_stack returns the user's stack (and hence registers) in DS:SI
1010 procedure get_user_stack
,NEAR
1014 LDS SI,DWORD PTR [user_SP
]
1018 ; restore value of the ctrl-c checker
1020 procedure restore_ctrlc
1023 MOV DL,CS:[exec_ctrlc
]
1024 MOV AX,(Set_Ctrl_C_Trapping
SHL 8) + 1 ; Put it back
1031 ZEXECCODESIZE EQU
$-ZERO
1032 ZEXECCODEEND
LABEL BYTE