1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
|
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
|