summaryrefslogtreecommitdiff
path: root/v2.0/source/EXEC.ASM
blob: d41acebe6109bb91673f2695d61668cf9b1bb325 (plain) (blame)
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