;       SCCSID = @(#)demproc.asm        6.9 92/04/20
;BN001;
; LINE TAGS BEGINNING WITH 'B' ARE FOR THE CRUISER RELEASE:  OS/2 VERSION 2.0
;BN001;
TITLE   IBMPROC - process maintenance

;**********************************************************************;BN001;
; REVISION HISTORY                                                     ;BN001;
;                                                                      ;BN001;
;  B001  DCR 1329 - 2/16/91 TMB -  Add support for loading DOS device  ;BN001;
;                   drivers and TSRs into UMBs.                        ;BN001;
;                                                                      ;BN001;
;                   Module dependencies:                               ;BN001;
;                   drv6\src\dos\v86code\v86init.asm                   ;BN001;
;                   drv6\src\dos\v86code\demarena.asm                  ;BN001;
;                   drv6\src\dos\v86code\demcnst.asm                   ;BN001;
;                   drv6\src\dos\v86code\demproc.asm                   ;BN001;
;                   drv6\src\dos\v86code\demexec.inc                   ;BN001;
;                   drv6\src\dos\v86code\demumb.inc                    ;BN001;
;                   drv6\src\vdev\vbios.c                              ;BN001;
;                   drv6\src\vdev\propname.h                           ;BN001;
;                   drv6\inc\vdmprop.inc                               ;BN001;
;                   drv6\h\vdmprop.h                                   ;BN001;
;                   drv6\src\dos\mvdm\dem.c                            ;BN001;
;
; 21Feb91 - G.L.Fulk                                                    ;BN002;
; Added code to check if the program product "SpaceMaker" from REALIA   ;BN002;
; was used to compress the load module image.  SpaceMaker has a bug in  ;BN002;
; it that will crash any DOS or OS/2 DOS box if the module loads at a   ;BN002;
; sufficiently low address (below 32K).  The solution is to check the   ;BN002;
; first 25 bytes of the load module.  If the first 25 bytes match that  ;BN002;
; of SpaceMaker, versions 1.03 to 1.09, then call a subroutine to       ;BN002;
; allocate the space up to the 32K line.  This will prevent the         ;BN002;
; applications from destroying memory, and crashing the system.         ;BN002;
;                                                                       ;BN002;
; Source modules affected: v86code\DemExec.inc                          ;BN002;
;                                                                       ;BN002;
;********************************************************************** ;BN002;
; 27Feb91 - G.L.Fulk                                                    ;BC003;
; Fix environment to allow it to be the full 32K.                       ;BC003;
;**********************************************************************
;
;  B004  9/17/91  CP20 AA04039  Mark Rogalski
;        Need to set AX for call to SET_DMA. Need to save new PDB
;        segment in CurrentPDB after doing DUP_PDB.
;
;**********************************************************************
;
;  B005  9/29/91  CP20 AA04143  Mark Rogalski
;        Need to reset indos flag when we exec a program
;
;**********************************************************************
; BN006 - 10/9/91  CP20 AA03991  Mark Rogalski                          ;BN006;
;         Call filter dup_pdb function now instead of going directly    ;BN006;
;         to DOS.                                                       ;BN006;
;***********************************************************************;BN006;
; BN007 - 1/22/92  CP20 B731798  Mark Rogalski                          ;BN007;
;         Since we make calls to DOS from here, the user stack field    ;BN007;
;         in the parent PDB gets wiped out. We need to save this        ;BN007;
;         field upon entry and restore it before jumping to child.      ;BN007;
;***********************************************************************;BN007;
; BN008 - 1/30/92  CP20 AA04471  Mark Rogalski                          ;BN008;
;         Need to call DOS to get CurrentPDB so that FSFILTER may be    ;BN008;
;         re-entrant.                                                   ;BN008
;***********************************************************************;BN008;
; BN009 - 2/10/92  CP20 B732885  Mark Rogalski                          ;BN009;
;         Need to decrement REAL INDOS variable too.                    ;BN009;
;***********************************************************************;BN009;
; 11Mar92 - W. Madden                                                   ;BN010;
; Perform 2 opens.  First, open mode A0h (deny write).  If that fails,  ;BN010;
; then try mode 00h (compatibility mode).                               ;BN010;
;********************************************************************** ;BN010;
; B011 - 4/17/92  CP20 B735532  Mark Rogalski                           ;BN011;
; Do not call DOS functions before saving user stack value              ;BN011;
;********************************************************************** ;BN011;
; BN012 - 9/09/92 CP20 53222  Doug Azzarito                             ;BN012;
; Set AllocMethod in $EXEC so LOADHI works                              ;BN012;
;********************************************************************** ;BN012;
;  29Jul93 - J.M.Hare    defect 71358                                   ;BN040;
; Add propogating of DOSFLAG through files system for exec_only test.   ;BN040;
;***********************************************************************;BN040;
;  29Jul93 - J.M.Hare    defect 71358                                   ;BN040;
; Add propogating of DOSFLAG through files system for exec_only test.   ;BN040;
;***********************************************************************;BN040;
;  09Sep94 - J.M.Hare    defect 90143                                   ;BN044;
; Add code to do low-only if high-only fails.                           ;BN044;
;***********************************************************************;BN044;
;  21Dec94 - ChangeTeam  defect 106942                                  106942;
; PDB_user_stack was being restored to the wrong value in $Exec.        106942;
; Added code to $Exec to save PDB_user_stack before VMcheck_fname call. 106942;
;***********************************************************************106942;
;
; Process related system calls and low level routines for DOS 2.X.
; I/O specs are defined in DISPATCH.
;
;   $WAIT
;   $EXEC
;   $Keep_process
;   Stay_resident
;   $EXIT
;   $ABORT
;   abort_inner
;

.xlist
;
; get the appropriate segment definitions
;
include v86seg.inc

V86CODE SEGMENT
        ASSUME  CS:V86GROUP

;m        EXTRN   $SETBLOCK:NEAR
        EXTRN   Get_User_Stack:NEAR

.xcref
include basemaca.inc
include osmaca.inc
include oldmaca.inc
include demmac.inc
include dossymc.inc
include error.inc
include pdb.inc
include vector.inc
include syscalls.inc
include extattr.inc
include demver.inc
include sft.inc
include exe.inc
include arena.inc
include curdir.inc
include demcd.inc
include filemode.inc
include mvdmexp.inc
include demsvc.inc
.cref
.list
        CpuMode 8086

SAVEXIT         EQU     10

    ReferV86    CurrentPDB,WORD
;m    ReferV86    CreatePDB,BYTE
    ReferV86    Exit_type,BYTE
    ReferV86    INDOS,BYTE                  ;BN005
    ReferV86    REAL_INDOS,DWORD            ;BN009
;m    ReferV86    DidCTRLC,BYTE
    ReferV86    exit_code,WORD
    ReferV86    OpenBuf,128
    ReferV86    EXTERR_LOCUS,BYTE           ; Extended Error Locus
    ReferV86    pOldInt21,DWORD             ;BN008


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 = error_invalid_function
;              = error_bad_format
;              = error_bad_environment
;              = error_not_enough_memory
;              = error_file_not_found
;
;   Revision history:
;
;        A000   version 4.00  Jan. 1988
;

.286p

;exe_valid_old_signature equ exe_valid_oldsignature

        ReferV86    Temp_Var2,WORD              ;AN000;file type from $open
;m        ReferV86    Special_Entries,WORD        ;AN007;address of special entries
;m        ReferV86    Special_Version,WORD        ;AN007;special version number
;m        ReferV86    Fake_Count,BYTE             ;AN008;fake version count
;                                                                        ;BN001;
; UMB support for LOADHIGH command                                       ;BN001;
;                                                                        ;BN001;
;m        ReferV86    AllocMethod,BYTE      ; how to alloc first(best)last ;BN001;

        ReferV86    os2_handled,BYTE      ; mdr

IF      BUFFERFLAG
        extrn   restore_user_map:near
ENDIF

V86TABLE   SEGMENT
        PUBLIC      command_exec

exec_init_SP        DW  ?
exec_init_SS        DW  ?
exec_init_IP        DW  ?
exec_init_CS        DW  ?
exec_user_stack     DD  ?                                              ;106942;
execName            DD  ?

exec_internal_buffer    EQU OpenBuf
                                                                        ;BN002;
;***********************************************************************;BN002;
; SpaceMaker, versions 1.03 to 1.09 all have the following front end.   ;BN002;
;                                                                       ;BN002;
SpaceMaker_entry label  byte                                            ;BN002;
;------ 5 words to check                                                ;BN002;
        DB      9Ch             ; pushf                                 ;BN002;
        DB      55h             ; push  bp                              ;BN002;
        DB      56h             ; push  si                              ;BN002;
        DB      8Ch,0CDh        ; mov   bp,sp                           ;BN002;
        DB      83h,0C5h,10h    ; add   bp,+10h                         ;BN002;
        DB      8Dh,0B6h        ; lea   si,[bp+??]      ;?? module dep  ;BN002;
;------ DB      34h,12h   ;skip the segment value in the check          ;BN002;
;------ 1 word to check                                                 ;BN002;
        DB      56h             ; push  si                              ;BN002;
        DB      0BEh            ; mov   si,??           ;?? module dep  ;BN002;
;------ DB      34h,12h   ;skip the offset value in the check           ;BN002;
;------ 4 words+1 byte to check                                         ;BN002;
        DB      56h             ; push  si                              ;BN002;
        DB      0CBh            ; retf                                  ;BN002;
        DB      4Dh,45h,4Dh,4Fh ; db    "MEMORY$"                       ;BN002;
        DB      52h,59h,24h     ;                                       ;BN002;
;------                                                                 ;BN002;
;***********************************************************************;BN002;

;24-Aug-1990 sudeepb ; full exe header used, to get exec_flags for EA
;                      aware apps.

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_sym_tab        DD  ?               ; offset of symbol table in file
exec_flags          DW  ?               ; flags: EKNOWEAS
exec_res1           DW  ?               ; currently unused
exec_oem_ID         DW  ?               ; Reserved for OEM's
exec_oem_info       DW  ?               ; Reserved for OEM's
exec_pif_info       DD  ?               ; offset to PIF info
exec_pif_len        DW  ?               ; Length of PIF info, 0 if not present
exec_res2           DW  7 DUP (?)       ; Reserved for future use
exec_nhdr_offset    DD  ?               ; offset to new EXE header
Exec_header_len     EQU $-Exec_Signature

exec_internal_buffer_size   EQU (128+128+53+curdirLEN)

command_exec        DB  0               ; command.com pre exec notification

if2
%out    Please make sure that the following are contiguous and of the
%out    following sizes:
%out
%out    OpenBuf     128
%out    RenBuf      128
%out    SearchBuf    53
%out    DummyCDS    CurDirLen
endif

V86TABLE   ENDS

.sall

        EXTRN   $OPEN:NEAR
        EXTRN   $Open_Exec_Only:NEAR                 ; exec_only BN040
        EXTRN   $IOCTL:NEAR
;m        EXTRN   $ALLOC:NEAR
;m        EXTRN   $DEALLOC:NEAR                                           ;BN002;
;m        EXTRN   $SETBLOCK:NEAR                                          ;BN002;
        EXTRN   $CLOSE:NEAR
        EXTRN   $LSEEK:NEAR
        EXTRN   $Dup_PDB:NEAR                    ;BN006
        EXTRN   $READ:NEAR
        EXTRN   ECritMem:NEAR
        EXTRN   LCritMem:NEAR
        EXTRN   GetVisDrv:NEAR
        EXTRN   DStrLen:NEAR
        EXTRN   $SET_DMA:NEAR
        EXTRN   AllocLowMemory:NEAR
        EXTRN   AssignLowMemory:NEAR
        EXTRN   FreeLowMemory:NEAR
        EXTRN   VMcheck_fname:NEAR               ; mdr
        EXTRN   DOS_ABORT:NEAR                   ; mdr
        EXTRN   $INTERNAL_OPEN:NEAR              ; mdr


procedure   $Exec,NEAR
        ASSUME  DS:NOTHING, ES:NOTHING
PUBLIC EXEC001S,EXEC001E
EXEC001S:
        LocalVar    exec_blk,DWORD
        LocalVar    exec_func,BYTE
        LocalVar    exec_load_high,BYTE
        LocalVar    exec_fh,WORD
        LocalVar    exec_rel_fac,WORD
        LocalVar    exec_res_len_para,WORD
        LocalVar    exec_environ,WORD
        LocalVar    exec_size,WORD
        LocalVar    exec_load_block,WORD
        LocalVar    exec_dma,WORD
        LocalVar    execNameLen,WORD
        LocalVar    KNOWEASFLG,WORD
        LocalVar    AllocSave,BYTE          ;save AllocMethod from entry ;BN001;
        LocalVar    WeDidIt,BYTE            ;we changed to hi only+hi first;BN001;
        LocalVar    UMBSave,WORD            ;save UMB chain flag         ;BN012
        LocalVar    Save_ax,WORD            ;save AX for UMB request     ;BN001;
        LocalVar    AllocLow32K,WORD                                    ;BN002;
        LocalVar    exec_parent,WORD                                    ;BN007;
        LocalVar    exec_parent_stack,DWORD                             ;BN007;
        LocalVar    exec_currPDB,WORD                                   ;BN008;

EXEC001E:
        MOV     word ptr cs:[execName],DX     ; mdr save original name string
        MOV     word ptr cs:[execName+2],DS   ; mdr

        PUSH    es                                                     ;106942;
        PUSH    ax                                                     ;106942;
        MOV     es,cs:[CurrentPDB]            ; es = parent PDB        ;106942;
        MOV     ax,word ptr es:[PDB_user_stack]                        ;106942;
        MOV     word ptr cs:[exec_user_stack],ax ; save parent stack   ;106942;
        MOV     ax,word ptr es:[PDB_user_stack+2]                      ;106942;
        MOV     word ptr cs:[exec_user_stack+2],ax                     ;106942;
        POP     ax                                                     ;106942;
        POP     es                                                     ;106942;

        call    VMcheck_fname          ; mdr return if dos drive
        EnterProc
                                                                        ;BN002;
        mov     AllocLow32K,0                                           ;BN002;
                                                                        ;BN002;
;
; validate function
;

        CMP     AL,3                    ; only 0, 1 or 3 are allowed
        JNA     exec_check_2

exec_bad_fun:
        MOV     EXTERR_LOCUS,errLOC_Unk ; Extended Error Locus
        MOV     AX,error_invalid_function

exec_ret_err:
        mov     [command_exec],0        ; No more title work as exec failed
        LeaveProc   NoCheck
        transfer    SYS_RET_ERR

exec_check_2:
        CMP     AL,2
        JZ      exec_bad_fun

        MOV     exec_load_block,0       ; initialize                     ;BN001;
        MOV     exec_blkL,BX            ; stash args
        MOV     exec_blkH,ES
        MOV     exec_func,AL
        MOV     exec_load_high,0

;BD011        mov     ah,51h                  ;BN008 get currentPDB from DOS
;BD011        pushf                           ;BN008
;BD011        call    cs:[pOldInt21]          ;BN008
;BD011        mov     es,bx                   ;BN008 move PDB to ES
        mov     es,cs:[CurrentPDB]      ; save parent PDB in var        ;BN007;BC011
        mov     exec_parent,es                                          ;BN007;
;106942 mov     ax,word ptr es:[PDB_user_stack]  ; save parent user stack        ;BN007;
        mov     ax,word ptr cs:[exec_user_stack] ; save parent stack   ;106942;
        mov     exec_parent_stackL,ax   ;  in local var                 ;BN007;
;106942 mov     ax,word ptr es:[PDB_user_stack+2]                                ;BN007;
        mov     ax,word ptr cs:[exec_user_stack+2]                     ;106942;
        mov     exec_parent_stackH,ax                                   ;BN007;

;                                                                        ;BN001;
;       Set up for UMB allocations                                       ;BN001;
;                                                                        ;BN001;
;m        MOV     AL,AllocMethod          ; get current strategy           ;BN001;
;m        MOV     AllocSave,AL            ; save it away                   ;BN001;
;m        TEST    [AllocMethod], HIGH_FIRST ;LOADHIGH can set this         ;BN001;
;m        JZ      exec_check_3                                             ;BN001;
;m        OR      [AllocMethod], HIGH_ONLY ;ensure high only if requesting ;BN001;
;m                                         ; UMBs                          ;BN001;
;m        OR      [UmbFlag], DOSALLOC      ; indicate kernel call so we    ;BN001;
                                         ; can get to UMBs without       ;BN001;
                                         ; linking them in.              ;BN001;
        mov     ax,5800h                ; get alloc strategy              ;BN012
        pushf                           ; set up for INT 21               ;BN012
        call    cs:[pOldInt21]          ; call DOS's INT 21               ;BN012
        mov     AllocSave,al            ; save strategy                   ;BN012
        mov     WeDidIt, 00h            ; set flag - user requested high-first ;BN044
        test    al, HIGH_FIRST          ; test for high-first flag        ;BN012
        jz      exec_check_3            ; if true then go execute         ;BN012
        or      al, HIGH_ONLY           ; else add high-only flag         ;BN012
        mov     WeDidIt, 01h            ; set flag - we added high-only   ;BN044
        mov     bx,ax                   ; set flag to bx for int21 call   ;BN012
        mov     ax,5801h                ; set alloc strategy              ;BN012
        pushf                           ; set up for INT 21               ;BN012
        call    cs:[pOldInt21]          ; call DOS's INT 21               ;BN012
        mov     ax,5802h                ; get UMB flag                    ;BN012
        pushf                           ; set up for INT 21               ;BN012
        call    cs:[pOldInt21]          ; call DOS's INT 21               ;BN012
        mov     UMBSave,ax              ; save UMB flag for later         ;BN012
        mov     bx,ax                                                     ;BN012
        or      bx,1                    ; add UMB to DOS chain            ;BN012
        mov     ax,5803h                ; set alloc strategy              ;BN012
        pushf                           ; set up for INT 21               ;BN012
        call    cs:[pOldInt21]          ; call DOS's INT 21               ;BN012
        jmp     short exec_check_3                                        ;BN012
                                                                          ;BN012
exec_restore_alloc:                                                       ;BN012
        push    bx                      ; save registers                  ;BN012
        mov     ax,5801h                ; set alloc strategy              ;BN012
        mov     bl,AllocSave            ; get saved strategy              ;BN012
        pushf                           ; set up for INT 21               ;BN012
        call    cs:[pOldInt21]          ; call DOS's INT 21               ;BN012
        mov     ax,5803h                ; set UMB flag                    ;BN012
        mov     bx,UMBSave              ; get saved value                 ;BN012
        pushf                           ; set up for INT 21               ;BN012
        call    cs:[pOldInt21]          ; call DOS's INT 21               ;BN012
        pop     bx                      ; restore registers               ;BN012
        ret                                                               ;BN012


exec_check_3:                                                            ;BN001;
;
; set up length of exec name
;
;m        MOV     execNameL,DX
;m        MOV     execNameH,DS
        MOV     SI,DX                   ; move pointer to convenient place
        invoke  DStrLen
        MOV     ExecNameLen,CX          ; save length

;------ Open the file correctly (deny-write, no inheritance), if that fails
;------ do it the old way (compatibility mode).
        push    bp
        push    ds                                                      ;BN010;
        push    dx                                                      ;BN010;
        mov     al,sharing_deny_write + open_no_inherit ;(AL)=open mode ;BC010;

        xor     bh,bh                   ; exec_only BN040
        or      bh,EXECOPEN             ; exec_only BN040
        call    $Open_Exec_Only         ; is the file there? was $OPEN  exec_only BN040

        pop     dx                                                      ;BN010;
        pop     ds                                                      ;BN010;
        jnc     short EXEC_OPENOK       ; yes, continue                 ;BN010;

        xor     al,al                   ;(AL)=open mode                 ;BN010;

        xor     bh,bh                   ; exec_only BN040
        or      bh,EXECOPEN             ; exec_only BN040
        call    $Open_Exec_Only         ; is the file there? was $OPEN  exec_only BN040

EXEC_OPENOK:
        pop     bp
        JNC     exec_openok2                                            ;BN012

                                        ; it failed to open so                       ;BN044
        cmp     WeDidIt, 01h            ; test flag for we added high-only           ;BN044
        jz      DO_AGAIN                ; if we set high-only try again for low-only ;BN044
        jmp     exec_ret_err            ; if we did not set then this is a failure   ;BN044
                                        ; goto execution error point.                ;BN044
DO_AGAIN:                               ; lets try it again using low-only           ;BN044
        mov     al, AllocSave           ; get the original user request              ;BN044
        and     al, 0fh                 ; remove high-only flag = low-only           ;BN044
        mov     bx,ax                   ; do same strategy setup as before           ;BN044
        mov     ax,5801h                ; set alloc strategy                         ;BN044
        pushf                           ; set up for INT 21                          ;BN044
        call    cs:[pOldInt21]          ; call DOS's INT 21                          ;BN044
        mov     WeDidIt, 00h            ; reset flag that said we set high-only      ;BN044
                                        ; in case this fails                         ;BN044
        jmp     exec_check_3            ; goto try to execute again                  ;BN044


        ; JMP     exec_ret_err          ; old code before BN044 changes              ;BN012


EXEC_OPENOK2:                                                           ;BN012
;File Type Checking
;       CMP     BYTE PTR [Temp_Var2],EAEXISTING      ;AN000;;FT.  old file ?
;       JZ      oldexf                               ;AN000;;FT.  yes
;       TEST    BYTE PTR EXEC_FUNC,EXEC_FUNC_OVERLAY ;AN000;;FT.  exec overlay?
;       JNZ     exovrly                              ;AN000;;FT.  yes
;       CMP     BYTE PTR [Temp_Var2],EAEXECUTABLE    ;AN000;;FT.  only file type
;       JZ      oldexf                               ;AN000;;FT.  3 & 4 will pass
;       CMP     BYTE PTR [Temp_Var2],EAINSTALLABLE   ;AN000;;FT.
;       JZ      oldexf                               ;AN000;;FT.
;exerr:                                               ;AN000;;FT.
;       MOV     AX,error_access_denied               ;AN000;;FT.  error
;       JMP     exec_ret_err                         ;AN000;;FT.
;exovrly:                                             ;AN000;;FT.
;       CMP     BYTE PTR [Temp_Var2],EAOVERLAY       ;AN000;;FT.  only 5,6,7  pass
;       JZ      oldexf                               ;AN000;;FT.
;       CMP     BYTE PTR [Temp_Var2],EADEV_DRIVER    ;AN000;;FT.
;       JZ      oldexf                               ;AN000;;FT.
;       CMP     BYTE PTR [Temp_Var2],EAIFS_DRIVER    ;AN000;;FT.
;       JNZ     exerr                                ;AN000;;FT.
;
;oldexf:                                              ;AN000;
;File Type Checking

        MOV     exec_fh,AX
        MOV     BX,AX
        XOR     AL,AL
        invoke  $IOCTL
        JC      Exec_bombJ
        TEST    AL,devid_ISDEV             ; direct call will return val in AX
        JZ      exec_check_environ
        MOV     AX,error_file_not_found
Exec_bombJ:
        JMP     Exec_Bomb

exec_no_memJ1:
        jmp     exec_no_mem

BadEnv:
        MOV     AX,error_bad_environment
        JMP     exec_bomb

exec_check_environ:
        MOV     exec_load_block,0
        MOV     exec_environ,0

        TEST    BYTE PTR exec_func,exec_func_overlay    ; overlays... no environment
        JNZ     exec_read_header
        LDS     SI,exec_blk             ; get block
        MOV     AX,[SI].Exec1_environ   ; address of environ
        OR      AX,AX
        JNZ     exec_scan_env
        mov     ah,51h                  ;BN008 get currentPDB from DOS
        pushf                           ;BN008
        call    cs:[pOldInt21]          ;BN008
        mov     ds,bx                   ;BN008 move PDB to DS
;BD008        MOV     DS,CurrentPDB
        MOV     AX,DS:[PDB_environ]
        MOV     exec_environ,AX
        OR      AX,AX
        JZ      exec_read_header

exec_scan_env:
        MOV     ES,AX
        XOR     DI,DI
        MOV     CX,8000h                ; at most 32k of environment    ;BC003;
        XOR     AL,AL

exec_get_environ_len:
        REPNZ   SCASB                   ; find that nul byte
        JNZ     BadEnv
        DEC     CX                      ; Dec CX for the next nul byte test
        JS      BadEnv                  ; gone beyond the end of the environment
        SCASB                           ; is there another nul byte?
        JNZ     exec_get_environ_len    ; no, scan some more
        PUSH    DI
        LEA     BX,[DI+0Fh+2]
        ADD     BX,ExecNameLen          ; BX <- length of environment
                                        ; remember argv[0] length
                                        ; round up and remember argc
        MOV     CL,4
        SHR     BX,CL                   ; number of paragraphs needed
        PUSH    ES
;mdr        invoke  $ALLOC                  ; can we get the space?
        mov     ax,486Fh                ;mdr
        int     21h                     ;mdr

        POP     DS
        POP     CX
        JC      exec_no_memj1           ; if not, we're out of mem       ;BN001;

;m        JNC     exec_save_environ
;m        call    ExecCheckMem            ; check if we were looking for   ;BN001;
                                        ; UMBs and need to try again     ;BN001;
;BC001; JMP     exec_no_mem             ; nope... cry and sob

exec_save_environ:
        MOV     ES,AX
        MOV     exec_environ,AX         ; save him for a rainy day
        XOR     SI,SI
        MOV     DI,SI
        REP     MOVSB                   ; copy the environment
        MOV     AX,1
        STOSW
        LDS     SI,execName
        MOV     CX,execNameLen
        REP     MOVSB

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.
;
        Context DS
        MOV     CX,exec_header_len      ; header size
        MOV     DX,OFFSET V86GROUP:exec_signature
        PUSH    ES
        PUSH    DS
        CALL    ExecRead
        POP     DS
        POP     ES
        JC      exec_bad_file
        OR      AX,AX
        JZ      exec_bad_file
        CMP     AX,exec_header_len      ; did we read the right number?
        JNZ     exec_com_filej          ; yep... continue
        TEST    exec_max_BSS,-1         ; indicate load high?
        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:
        MOV     [KNOWEASFLG],0          ; COM files cant be EA aware
        JMP     exec_com_file

;
; We have the program header... determine memory requirements
;
exec_save_start:

; set a variable indicating whether the KNOWEAS flag is set in the
; old exe header (EKNOWEAS)
;
; The linkers can build an exe header with a relocation table offset as
; low as 0x001e.  "exec_flags" is at exe header offset 0x0020.  So, we must
; ensure that we are not reading a relocation record instead of the
; exec_flags field.

        XOR     CX,CX
        MOV     AX,exec_rle_table       ; [exec_rle_table] > exec_flags
        CMP     AX,20h                  ; offset of exec_flags
        JLE     no_knoweas_flag
        MOV     CX,exec_flags           ; store the KNOWEAs bit
no_knoweas_flag:
        MOV     [KNOWEASFLG],CX         ; Store away EA info

        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,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
        JMP     exec_find_res

exec_no_mem:
        MOV     AX,error_not_enough_memory
        JMP     SHORT exec_bomb

exec_bad_file:
        MOV     AX,error_bad_format

exec_bomb:
        ASSUME  DS:NOTHING,ES:NOTHING
        invoke  FreeLowMemory           ; Free AllocLowMemory memory
        call    SpaceMaker_cleanup                                      ;BN002;
        MOV     BX,exec_fh
        CALL    exec_dealloc
        LeaveCrit   CritMem
        SaveReg <AX,BP>
        invoke  $CLOSE
;                                                                        ;BN001;
;       Restore allocation method from entry                             ;BN001;
;                                                                        ;BN001;
;m        MOV     AL,[AllocSave]                                           ;BN001;
;m        MOV     [AllocMethod],AL                                         ;BN001;
        CALL    exec_restore_alloc                                       ;BN012
;                                                                        ;BN001;
;       Deallocate any allocated blocks                                  ;BN001;
;                                                                        ;BN001;
        MOV     AX,exec_load_block      ; block possibly acquired        ;BN001;
        XOR     BX,BX                   ; indicate system owner          ;BN001;
        CALL    ChangeOwner             ; mark it as free                ;BN001;
;                                                                        ;BN001;
        RestoreReg  <BP,AX>
        JMP     Exec_Ret_Err

exec_allocate:

;*** Check for EXEPACK'd EXE.
;
; Versions of EXEPACK prior to Oct, 1988, had a bug.  When an EXEPACK'd
; EXE was loaded below 64K, they issued the error message "Packed file
; is corrupt", and terminated.
;
; Our Solution:
;   When we detect an EXEPACK'd file, we set a flag for $Alloc.
;   When this flag is set, $Alloc will not allocate memory
;   below 64K.  Once the load is complete, we clear this flag.
;
; Detection Algorithm:
;   seek_offset = (hdr.exe_par_dir + hdr.exe_CS)<<4 + hdr.exe_IP - 2;
;   if (word at *seek_offset* in EXE file == "RB")
;       // EXE file is EXEPACK'd

; Compute file seek offset.  Must use long arithmetic!

        SaveReg <ax>
        mov     ax,exec_par_dir
        add     ax,exec_CS              ; ax = # paragraphs

        mov     cx,ax                   ;
        shr     cx,12                   ; cx = high-order word of seek offset

        shl     ax,4                    ; Convert paragraphs to bytes
        add     ax,exec_IP
        adc     cx,0                    ; don't forget carry!

        sub     ax,2                    ; cx:ax = file seek offset
        sbb     cx,0                    ; don't forget carry!

; Seek to ExePack signature

        mov     dx,ax
        mov     bx,exec_fh              ; bx = file handle
        mov     al,0                    ; al = seek from start of file
        SaveReg <ds>
        invoke  $LSEEK                  ; lseek(cx:dx=offset,bx=hndl,al=start)
        RestoreReg <ds>
        jc      exec_pack_done          ;   Seek failed, assume not packed

; Read signature word

;--------------------------------                                       ;BC002;
; Change the number of bytes to read from 2 (for EXEPACK) to            ;BC002;
; 2+25.  2 for EXEPACK, and 25 following that for SPACEMAKER.           ;BC002;
;--------------------------------                                       ;BC002;
        mov     cx,2+25                 ; signature size + SpaceMaker   ;BC002;
        mov     dx,offset V86GROUP:exec_internal_buffer ; only need a word
        SaveReg <ds,es>
        call    ExecRead                ; read signature
        RestoreReg <es,ds>
        jc      exec_pack_done

; Test signature word

        mov     ax,word ptr exec_internal_buffer ; ax = signature
        cmp     ax,4252h                ; signature == "RB"?
        jne     exec_pack_done          ;   NO, not packed file

        invoke  AllocLowMemory          ;   YES, Eat up low memory

exec_pack_done:
;--------------------------------                                       ;BN002;
; Look for SpaceMaker                                                   ;BN002;
;--------------------------------                                       ;BN002;
                                                                        ;BN002;
;m        mov     cx,exec_IP      ;=program's IP                          ;BN002;
;m        mov     si,offset V86GROUP:exec_internal_buffer + 2             ;BN002;
;m        call    Check_for_SpaceMaker                                    ;BN002;
                                                                        ;BN002;
;--------------------------------                                       ;BN002;
        RestoreReg <ax>
        JMP     exec_alloc_150                                           ;BN001;
;
;*** END - Check for EXEPACK'd EXE.

exec_no_memJ2: jmp exec_no_mem
;                                                                        ;BN001;
exec_alloc_100:                                                          ;BN001;
;m        call    ExecCheckMem            ; see if we need to search again ;BN001;
;m        jnc     exec_alloc_140          ; no, we've failed on both chains;BN001;
;m        jmp     exec_no_mem                                              ;BN001;
exec_alloc_140:                                                          ;BN001;
        mov     ax,[Save_ax]            ; restore request amt            ;BN001;
exec_alloc_150:                                                          ;BN001;
;

        DOSAssume   CS,<DS>,"EXEC/exec_allocate"
;BD001; PUSH    AX
        mov     [Save_ax],ax            ; save in case of retry          ;BN001;
        MOV     BX,0FFFFh               ; see how much room in arena
        PUSH    DS
;mdr        invoke  $ALLOC                  ; should have carry set and BX has max
        mov     ax,4870h                  ;mdr
        int     21h                     ;mdr

        POP     DS
;BD001; POP     AX
        MOV     AX,[Save_ax]                                             ;BN001;
        ADD     AX,10h                  ; room for header
        CMP     BX,11h                  ; enough room for a header
        JB      exec_no_memJ2    ;BD001
;m        JB      exec_alloc_100          ; Do we need to check again?     ;BN001;
        CMP     AX,BX                   ; is there enough for bare image?
        JA      exec_no_memJ2    ;BD001
;m        JA      exec_alloc_100          ; Do we need to check again?     ;BN001;
        TEST    exec_load_high,-1       ; if load high, use max
        JNZ     exec_BX_max             ; use max
        ADD     AX,exec_min_BSS         ; go for min allocation
        JC      exec_no_memJ2  ;BD001         ; oops! carry
;m        JC      exec_alloc_100          ; Do we need to check again?     ;BN001;
        CMP     AX,BX                   ; enough space?
        JA      exec_no_memJ2  ;BD001         ; nope...
;m        JA      exec_alloc_100          ; Do we need to check again?     ;BN001;
        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
;mdr        invoke  $ALLOC                  ; get the space
        mov     ax,4871h                  ;mdr
        int     21h                     ;mdr

        POP     DS
        JC      exec_no_memJ2   ;BD001
;m        JC      exec_alloc_100          ; Do we need to check again?     ;BN001;
;                                                                        ;BN001;
        MOV     exec_load_block,AX
        ADD     AX,10h
        TEST    exec_load_high,-1
        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

;
; 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
        XOR     AL,AL
        invoke  $LSEEK                  ; seek to resident
        POP     DS
        jnc     exec_big_read
        jmp     exec_bomb


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
        PUSH    DS
        MOV     DS,exec_dma             ; Set up read buffer
        ASSUME  DS:NOTHING
        XOR     DX,DX
        PUSH    CX                      ; save our count
        CALL    ExecRead
        POP     CX                      ; get old count to verify
        POP     DS
        JC      exec_bad_fileJ
        DOSAssume   CS,<DS>,"EXEC/exec_read_ok"
        CMP     CX,AX                   ; did we read enough?
        POP     BX                      ; get paragraph count back
        JZ      execCheckEnd            ; and do reloc if no more to read
;
; The read did not match the request.  If we are off by 512 bytes or more
; then the header lied and we have an error.
;
        SUB     CX,AX
        CMP     CX,512
        JAE     Exec_Bad_fileJ
;
; We've read in CX bytes... bump DTA location
;
ExecCheckEnd:
        ADD     exec_dma,BX             ; bump dma address
        TEST    exec_res_len_para,-1
        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
        XOR     AX,AX
        invoke  $LSEEK
        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
        MOV     DX,OFFSET V86GROUP:exec_internal_buffer
        MOV     CX,((exec_internal_buffer_size)/4)*4
        PUSH    DS
        CALL    ExecRead
        POP     ES
        POP     DX
        JC      exec_bad_filej
        MOV     CX,(exec_internal_buffer_size)/4
        MOV     DI,OFFSET V86GROUP:exec_internal_buffer ; Pointer to byte location in header
;
; Relocate a single address
;
        MOV     SI,exec_rel_fac

exec_reloc_one:
        OR      DX,DX                   ; Any more entries?
        JE      exec_set_PDBJ

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
        ADD     [BX],SI
        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_set_PDBJ:
        JMP     exec_set_PDB
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_file1                                    ;BC001;
        LDS     SI,exec_blk             ; get arg block
        LODSW                           ; get load address
        MOV     exec_dma,AX
        MOV     AX,0FFFFh
        JMP     SHORT exec_read_block   ; 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_file1:                                                   ;BN001:
;***********************************************************************;BN002;
                                                                        ;BN002;
        mov     cx,0100h        ;=program starting IP                   ;BN002;
        mov     si,offset V86GROUP:exec_signature                       ;BN002;
        call    Check_for_SpaceMaker                                    ;BN002;
        jmp     exec_alloc_com_file                                     ;BN001;
                                                                        ;BN002;
;***********************************************************************;BN002;
;                                                                        ;BN001;
exec_alloc_300:                                                          ;BN001;
;m        call    ExecCheckMem            ; Do we need to check again?     ;BN001;
;m        JC      exec_no_memj            ; No, we've tried both chains.   ;BN001;
exec_alloc_com_file:
        MOV     BX,0FFFFh
;mdr        invoke  $ALLOC                  ; largest piece available as error
        mov     ax,4872h                  ;mdr
        int     21h                     ;mdr

        OR      BX,BX
;BD001; JZ      exec_no_memj
        JZ      exec_alloc_300          ; Do we need to try again       ;BN001;
        MOV     exec_size,BX            ; save size of allocation block
        PUSH    BX
;mdr        invoke  $ALLOC                  ; largest piece available as error
        mov     ax,4873h                  ;mdr
        int     21h                     ;mdr

        POP     BX                      ; get size of block...
        MOV     exec_load_block,AX
        ADD     AX,10h                  ; increment for header
        MOV     exec_dma,AX
        XOR     AX,AX                   ; presume 64K read...
        CMP     BX,1000h                ; 64k or more in block?
        JAE     exec_read_com           ; yes, read only 64k
        MOV     AX,BX                   ; convert size to bytes
        MOV     CL,4
        SHL     AX,CL
exec_read_com:
        SUB     AX,100h                 ; remember size of psp
exec_read_block:
        PUSH    AX                      ; save number to read
        MOV     BX,exec_fh              ; of com file
        XOR     CX,CX                   ; but seek to 0:0
        MOV     DX,CX
        XOR     AX,AX                   ; seek relative to beginning
        invoke  $LSEEK                  ; back to beginning of file
        POP     CX                      ; number to read
        MOV     DS,exec_dma
        XOR     DX,DX
        PUSH    CX
        CALL    ExecRead
        POP     SI                      ; get number of bytes to read
        jnc     OkRead
        jmp     exec_bad_file
OkRead:
        CMP     AX,SI                   ; did we read them all?
;BD001; JZ      exec_no_memj            ; exactly the wrong number... no memory
        JNZ     OkRead_100                                               ;BN001;
        TEST    BYTE PTR exec_func,exec_func_overlay                     ;BN001;
        JNZ     exec_no_memj            ; if overlay, can't attempt      ;BN001;
                                        ;  another allocate, so fail now ;BN001;
        MOV     AX,exec_load_block      ; seg # of block we allocated    ;BN001;
        XOR     BX,BX                                                    ;BN001;
        CALL    ChangeOwner             ; free up this block             ;BN001;
        JMP     exec_alloc_300          ; do we need to alloc again?     ;BN001;
OkRead_100:                                                              ;BN001;

        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 FF00h.  Add FE to account for PSP - word of 0 on stack.
;
        ADD     SI,0FEh                 ; make room for stack
        MOV     exec_init_SP,SI         ; max value for read is also SP!
        MOV     exec_init_SS,AX
        MOV     DS,AX
        MOV     WORD PTR [SI],0         ; 0 for return

exec_set_PDB:
        MOV     BX,exec_fh              ; we are finished with the file.
        CALL    exec_dealloc
        PUSH    BP
        invoke  $CLOSE                  ; release the jfn
        POP     BP
        CALL    exec_alloc
        TEST    BYTE PTR exec_func,exec_func_overlay
        JZ      exec_build_header
        CALL    Scan_Execname           ;MS.;AN007;
;m        CALL    Scan_Special_Entries    ;MS.;AN007;
;                                                                        ;BN001;
;       Restore allocation Method prior to returning.                    ;BN001;
;                                                                        ;BN001;
;m        MOV     AL,[AllocSave]                                           ;BN001;
;m        MOV     [AllocMethod],AL                                         ;BN001;
;m        AND     [UmbFlag], NOT DOSALLOC                                  ;BN001;
        CALL    exec_restore_alloc                                       ;BN012
;                                                                        ;BN001;
        LeaveProc   NoCheck
        transfer    SYS_RET_OK          ; overlay load -> done

exec_build_header:
        MOV     DX,exec_load_block
;
; assign the space to the process

        invoke  AssignLowMemory         ; Assign AllocLowMemory to this PDB!
        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     [SI],DX                 ; assign ownership
NO_OWNER:
        MOV     AX,exec_load_block      ; get load block pointer
        DEC     AX
        MOV     DS,AX                   ; point to header
        MOV     [SI],DX                 ; assign ownership

        PUSH    DS                      ;AN000;MS. make ES=DS
        POP     ES                      ;AN000;MS.
        MOV     DI,ARENA_NAME           ;AN000;MS. ES:DI points to destination
        CALL    Scan_Execname           ;AN007;MS. parse execname
                                        ;          ds:si->name, cx=name length
        PUSH    CX                      ;AN007;;MS. save for fake version
        PUSH    SI                      ;AN007;;MS. save for fake version

movename:                               ;AN000;
        LODSB                           ;AN000;;MS. get char
        CMP     AL,'.'                  ;AN000;;MS. is '.' ,may be name.exe
        JZ      mem_done                ;AN000;;MS. no, move to header
                                        ;AN000;
        STOSB                           ;AN000;;MS. move char
        LOOP    movename                ;AN000;;MS. continue
mem_done:                               ;AN000;
        XOR     AL,AL                   ;AN000;;MS. make ASCIIZ
        CMP     DI,SIZE ARENA           ;AN000;MS. if not all filled
        JAE     fill8                   ;AN000;MS.
        STOSB                           ;AN000;MS.
fill8:                                  ;AN000;
        POP    SI                       ;AN007;MS. ds:si -> file name
        POP    CX                       ;AN007;MS.

;m        CALL   Scan_Special_Entries     ;AN007;MS.

        MOV     SI,exec_size
        ADD     SI,DX
        SaveReg <ds,dx>                 ; save ds,dx over internal call  ;BC006

        mov     ah,55h                  ; set up AH with function number ;BC006
        invoke  $Dup_PDB                ; dup the PDB                    ;BN006
;BD006        int     21h

        RestoreReg <dx,ds>              ; restore those reg now          ;BC006
        mov     es,dx                   ; set up ES - just in case       ;BC006
        mov     exec_currPDB,dx         ;BC008  save new PDB address

        PUSH    exec_environ
        POP     ES:[PDB_environ]
;
; set up proper command line stuff
;
        MOV     CX,[KNOWEASFLG]
        MOV     ES:[PDB_flags],CX       ; Pass EA info in PDB

        LDS     SI,exec_blk             ; get the block
        PUSH    DS                      ; save its location
        PUSH    SI
        LDS     SI,[SI.exec0_5C_FCB]    ; get the 5c fcb
;
; DS points to user space 5C FCB
;
        MOV     CX,12                   ; copy drive, name and ext
        PUSH    CX
        MOV     DI,5Ch
        MOV     BL,[SI]
        REP     MOVSB
;
; DI = 5Ch + 12 = 5Ch + 0Ch = 68h
;
        XOR     AX,AX                   ; zero extent, etc for CPM
        STOSW
        STOSW
;
; DI = 5Ch + 12 + 4 = 5Ch + 10h = 6Ch
;
        POP     CX
        POP     SI                      ; get block
        POP     DS
        PUSH    DS                      ; save (again)
        PUSH    SI
        LDS     SI,[SI.exec0_6C_FCB]    ; get 6C FCB
;
; DS points to user space 6C FCB
;
        MOV     BH,[SI]                 ; do same as above
        REP     MOVSB
        STOSW
        STOSW
        POP     SI                      ; get block (last time)
        POP     DS
        LDS     SI,[SI.exec0_com_line]  ; command line
;
; DS points to user space 80 command line
;
        OR      CL,80h
        MOV     DI,CX
        REP     MOVSB                   ; Wham!
;
; Process BX into default AX (validity of drive specs on args).  We no longer
; care about DS:SI.
;
        DEC     CL                      ; get 0FFh in CL
        MOV     AL,BH
        XOR     BH,BH
        invoke  GetVisDrv
        JNC     exec_BL
        MOV     BH,CL
exec_BL:
        MOV     AL,BL
        XOR     BL,BL
        invoke  GetVisDrv
        JNC     exec_Set_Return
        MOV     BL,CL
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.
        PUSH    DX
        MOV     DS,exec_currPDB
        MOV     DX,80h
        mov     ah,1ah             ;BN004
        invoke  $SET_DMA
        POP     DX
;                                                                        ;BN001;
;       Restore allocation Method prior to returning.                    ;BN001;
;                                                                        ;BN001;
;m        MOV     AL,[AllocSave]                                           ;BN001;
;m        MOV     [AllocMethod],AL                                         ;BN001;
;m        AND     [UmbFlag], NOT DOSALLOC                                  ;BN001;
        CALL    exec_restore_alloc                                       ;BN012
;                                                                        ;BN001;
        TEST    BYTE PTR exec_func,exec_func_no_execute
        JZ      exec_go

        LDS     SI,DWORD PTR exec_init_SP   ; get stack
        LES     DI,exec_blk             ; and block for return
        MOV     ES:[DI].exec1_SS,DS     ; return SS

        DEC     SI                      ; 'push' default AX
        DEC     SI
        MOV     [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
        LeaveProc   NoCheck
        transfer    SYS_RET_OK

exec_go:
        cmp     [command_exec],0
        je      short exec_go1

        LES     DI,execName                 ; Change VDM Title
        SVC     SVC_DEMSETTITLE
        mov     [command_exec],0

exec_go1:
        call    SpaceMaker_cleanup                                      ;BN002;

        mov     es,exec_parent              ;get parent's PDB           ;BN007;
        mov     ax,exec_parent_stackL       ;restore user stack         ;BN007;
        mov     word ptr es:[PDB_user_stack],ax      ; in parent PDB             ;BN007;
        mov     ax,exec_parent_stackH                                   ;BN007;
        mov     word ptr es:[PDB_user_stack+2],ax                                ;BN007;

        LDS     SI,DWORD PTR exec_init_IP   ; get entry point
        LES     DI,DWORD PTR exec_init_SP   ; new stack
        MOV     AX,ES
;
; DS:SI points to entry point
; AX:DI points to initial stack
; DX has PDB pointer
; BX has initial AX value
;
        CLI
        MOV     BYTE PTR INDOS,0        ;BN005 we'll no longer be in filter
        SaveReg <ds,bx>                 ;BN009
        lds     bx,[REAL_INDOS]         ;BN009 get address of real indos flag
        dec     byte ptr ds:[bx]        ;BN009 and dec it
        RestoreReg <bx,ds>              ;BN009
        ASSUME  SS:NOTHING
        MOV     SS,AX                   ; set up user's stack
        MOV     SP,DI                   ; 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

;mIF      BUFFERFLAG
;m        invoke  restore_user_map
;mENDIF

        RET
EndProc exec_long_ret

EndProc $Exec
;------------------------------------------------------------------------;BN001;

;------------------------------------------------------------------------;BN001;
;Procedure ExecCheckMem,NEAR                                              ;BN001;
;                                                                        ;BN001;
;       ExecCheckMem will determine if the allocation method is for      ;BN001;
;       UMB allocations.  If so, it will set up for NON-UMB allocations  ;BN001;
;       and return with no errors.  If not currently requesting UMBs,    ;BN001;
;       we will return with 'C' set.                                     ;BN001;
;                                                                        ;BN001;
;        TEST    [AllocMethod], HIGH_FIRST   ; are we looking for UMBs?   ;BN001;
;        jz      ExecCheckErr                ; no                         ;BN001;
;        and     [AllocMethod], NOT HIGH_FIRST    ; set us back           ;BN001;
;        and     [AllocMethod], NOT HIGH_ONLY     ; to low memory         ;BN001;
;        and     [UmbFlag], NOT DOSALLOC          ; requests              ;BN001;
;        clc                                                              ;BN001;
;        ret                                                              ;BN001;
;ExecCheckErr:                                                            ;BN001;
;        stc                                 ; indicate we weren't UMB    ;BN001;
;ExecCheckRet:                                                            ;BN001;
;        ret                                                              ;BN001;
;                                                                         ;BN001;
;EndProc ExecCheckMem                                                     ;BN001;
;------------------------------------------------------------------------;BN001;

;------------------------------------------------------------------------;BN001;
Procedure   ExecRead,NEAR
        CALL    exec_dealloc
        MOV     bx,exec_fh
        PUSH    BP
        invoke  $READ
        POP     BP
        CALL    exec_alloc
        return
EndProc ExecRead
;------------------------------------------------------------------------;BN001;

;------------------------------------------------------------------------;BN001;
procedure   exec_dealloc,near
        ASSUME      DS:NOTHING,ES:NOTHING
        PUSH        BX
        MOV         BX,arena_owner_system
        EnterCrit   CritMEM
        CALL        ChangeOwners
        POP         BX
        return
EndProc exec_dealloc
;------------------------------------------------------------------------;BN001;

;------------------------------------------------------------------------;BN001;
procedure   exec_alloc,near
        push        ax                  ;BN008
        PUSH        BX
;BD008        MOV         BX,CurrentPDB
        mov     ah,51h                  ;BN008 get currentPDB from DOS
        pushf                           ;BN008
        call    cs:[pOldInt21]          ;BN008
        CALL        ChangeOwners
        LeaveCrit   CritMEM
        POP         BX
        pop         ax                  ;BN008
        return
EndProc exec_alloc
;------------------------------------------------------------------------;BN001;

;------------------------------------------------------------------------;BN001;
procedure   ChangeOwners,NEAR
        pushf
        PUSH    AX
        MOV     AX,exec_environ
        CALL    ChangeOwner
        MOV     AX,exec_load_block
        Call    ChangeOwner
        POP     AX
        popf
        return
EndProc ChangeOwners
;------------------------------------------------------------------------;BN001;

;------------------------------------------------------------------------;BN001;
Procedure   ChangeOwner,near
        OR      AX,AX                   ; is area allocated?
        retz                            ; no, do nothing
        DEC     AX
        PUSH    DS
        MOV     DS,AX
        MOV     DS:[arena_owner],BX
        POP     DS
        return
EndProc ChangeOwner
;------------------------------------------------------------------------;BN001;

;------------------------------------------------------------------------;BN001;
Procedure    Scan_Execname,near         ;AN000;MS.

        LDS     SI,execName             ;AN000;MS. DS:SI points to name
save_begin:                             ;AN000;
        MOV     CX,SI                   ;AN000;MS. CX= starting addr
scan0:                                  ;AN000;
        LODSB                           ;AN000;MS. get char
        CMP     AL,':'                  ;AN000;;MS. is ':' , may be A:name
        JZ      save_begin              ;AN000;;MS. yes, save si
        CMP     AL,'\'                  ;AN000;;MS. is '\', may be A:\name
        JZ      save_begin              ;AN000;;MS. yes, save si
        CMP     AL,0                    ;AN000;;MS. is end of name
        JNZ     scan0                   ;AN000;;MS. no, continue scanning
        SUB     SI,CX                   ;AN000;;MS. get name's length
        XCHG    SI,CX                   ;AN000;;MS. cx= length, si= starting addr

        return                          ;AN000;;MS.
EndProc Scan_Execname                   ;AN000;;MS.
;------------------------------------------------------------------------;BN001;

;------------------------------------------------------------------------;BN001;

IF NOT_FILTER

Procedure    Scan_Special_Entries,near  ;AN000;MS.

; ds:si file name cx = name length

        SaveReg <cx,dx,si>
        CALL   Reset_Version            ; Reset version
        SVC    SVC_DEMSPECIALENTRIES    ; Process Special Entries
        or     ax,ax                    ; if ax = 0 means entry did'nt match
        je     not_found
        mov    [Special_Version],dx     ; Save Fake Version
        mov    [Fake_Count],cl          ; Save Fake count

not_found:
        RestoreReg <si,dx,cx>
        return
EndProc Scan_Special_Entries            ;AN000;;MS.

;------------------------------------------------------------------------;BN001;

;------------------------------------------------------------------------;BN001;
Procedure    Reset_Version,near         ;AN008;MS.

        CMP    [Fake_Count],0FFH        ;AN008;MS.
        JNZ    dont_reset               ;AN008;MS.
        MOV    [Special_Version],0      ;AN008;MS. reset to current version
dont_reset:
        return
EndProc Reset_Version                   ;AN008;;MS.
                                                                        ;BN002;
ENDIF
                                                                        ;BN002;
;***********************************************************************;BN002;
; Check_for_SpaceMaker                                                  ;BN002;
; Subroutine called to scan the first 25 bytes of a load module,        ;BN002;
; comparing it to see if it was compressed using SpaceMaker.  If it     ;BN002;
; was, then call AllocLowMemory32K to allocate space up to the 32K      ;BN002;
; line.                                                                 ;BN002;
;                                                                       ;BN002;
; ENTRY: DS:SI = @1st 25 byte of the file's CS:IP                       ;BN002;
;        CX = file's IP                                                 ;BN002;
;                                                                       ;BN002;
Procedure Check_for_SpaceMaker,near                                     ;BN002;
                                                                        ;BN002;
        cmp     cx, 0100h       ;SpaceMaker modules allows have a       ;BN002;
        jne     not_SpaceMaker  ;starting IP of 100h.                   ;BN002;
                                                                        ;BN002;
        push    cs                                                      ;BN002;
        pop     es                                                      ;BN002;
        mov     di,offset V86GROUP:SpaceMaker_entry                     ;BN002;
                                                                        ;BN002;
        mov     cx,5                                                    ;BN002;
        repe    cmpsw                                                   ;BN002;
        jne     not_SpaceMaker                                          ;BN002;
        inc     si                                                      ;BN002;
        inc     si                                                      ;BN002;
        cmpsw                                                           ;BN002;
        jne     not_SpaceMaker                                          ;BN002;
        inc     si                                                      ;BN002;
        inc     si                                                      ;BN002;
        mov     cx,4                                                    ;BN002;
        repe    cmpsw                                                   ;BN002;
        jne     not_SpaceMaker                                          ;BN002;
        cmpsb                                                           ;BN002;
        je      SpaceMaker_found                                        ;BN002;
not_SpaceMaker:                                                         ;BN002;
        ret                                                             ;BN002;
                                                                        ;BN002;
entry   SpaceMaker_found                                                ;BN002;
;------ allocate 32K                                                    ;BN002;
        mov     bx,4000h                                                ;BN002;
        push    ds                                                      ;BN002;
;mdr        invoke  $ALLOC                                                  ;BN002;
        mov     ah,48h                  ;mdr
        int     21h                     ;mdr
        jnc     spacemaker_alloc_ok                                     ;BN002;
;mdr        invoke  $ALLOC                                                  ;BN002;
        mov     ah,48h                  ;mdr
        int     21h                     ;mdr
        jc      spacemaker_alloc_error                                  ;BN002;
spacemaker_alloc_ok:                                                    ;BN002;
        mov     es,ax                                                   ;BN002;
        mov     bx,ax                                                   ;BN002;
        sub     bx,07F0h                                                ;BN002;
        jns     SpaceMaker_not_needed                                   ;BN002;
                                                                        ;BN002;
        mov     AllocLow32K,ax                                          ;BN002;
        neg     bx                                                      ;BN002;
;mdr        call    $SetBlock                                               ;BN002;
        mov     ah,4ah                  ;mdr
        int     21h                     ;mdr
        jmp     short SpaceMaker_error_check                            ;BN002;
                                                                        ;BN002;
SpaceMaker_not_needed:                                                  ;BN002;
;mdr        call    $DeAlloc                                                ;BN002;
        mov     ah,49h                  ;mdr
        int     21h                     ;mdr
SpaceMaker_error_check:                                                 ;BN002;
        jc      SpaceMaker_alloc_error                                  ;BN002;
        pop     ds                                                      ;BN002;
        ret                                                             ;BN002;
                                                                        ;BN002;
SpaceMaker_alloc_error:                                                 ;BN002;
        pop     ds                                                      ;BN002;
        pop     ax      ;throw away return address                      ;BN002;
        mov     ax,error_bad_environment                                ;BN002;
        jmp     exec_bomb                                               ;BN002;
                                                                        ;BN002;
EndProc Check_for_SpaceMaker                                            ;BN002;
;***********************************************************************;BN002;
Procedure SpaceMaker_cleanup,near                                       ;BN002;
        mov     ax,AllocLow32K                                          ;BN002;
        or      ax,ax                                                   ;BN002;
        je      SpaceMaker_no_alloc                                     ;BN002;
        mov     es,ax                                                   ;BN002;
;mdr        call    $DeAlloc                                                ;BN002;
        mov     ah,49h                  ;mdr
        int     21h                     ;mdr
SpaceMaker_no_alloc:                                                    ;BN002;
        ret                                                             ;BN002;
EndProc SpaceMaker_cleanup                                              ;BN002;
;***********************************************************************;BN002;

CpuMode reset

IF NOT_FILTER

SUBTTL $WAIT - return previous process error code
PAGE
;
; process control data
;
        ReferV86    exit_code,WORD          ; code of exit

;
;   Assembler usage:
;           MOV     AH, WaitProcess
;           INT     int_command
;         AX has the exit code
        procedure   $WAIT,NEAR
        ASSUME  DS:NOTHING,ES:NOTHING
        XOR     AX,AX
        XCHG    AX,exit_code
        transfer    SYS_RET_OK
EndProc $WAIT


SUBTTL Terminate and stay resident handler
PAGE
;
; Input:    DX is  an  offset  from  CurrentPDB  at which to
;           truncate the current block.
;
; output:   The current block is truncated (expanded) to be [DX+15]/16
;           paragraphs long.  An exit is simulated via resetting CurrentPDB
;           and restoring the vectors.
;
        procedure   $Keep_process,NEAR
        ASSUME DS:NOTHING,ES:NOTHING

        PUSH    AX                      ; keep exit code around
        MOV     BYTE PTR [Exit_type],Exit_keep_process
        MOV     ES,[CurrentPDB]
        CMP     DX,6h                   ; keep enough space around for system
        JAE     Keep_shrink             ; info
        MOV     DX,6h
keep_shrink:
        MOV     BX,DX
;mdr        PUSH    BX
;mdr        PUSH    ES
;mdr        invoke  $SETBLOCK               ; ignore return codes.
        mov     ah,4ah                      ;mdr
        int     21h                         ;mdr
;mdr        POP     DS
;mdr        POP     BX
        JC      keep_done               ; failed on modification
        MOV     AX,DS
        ADD     AX,BX
        MOV     DS:[PDB_block_len],AX

keep_done:
        POP     AX
        JMP     SHORT exit_inner        ; and let abort take care of the rest

EndProc $Keep_process

        procedure   Stay_resident,NEAR
        ASSUME  DS:NOTHING,ES:NOTHING
        MOV     AX,(Keep_process SHL 8) + 0 ; Lower part is return code
        ADD     DX,15
        RCR     DX,1
        MOV     CL,3
        SHR     DX,CL

        transfer    COMMAND
EndProc Stay_resident

SUBTTL $EXIT - return to parent process
PAGE
;
;   Assembler usage:
;           MOV     AL, code
;           MOV     AH, Exit
;           INT     int_command
;   Error return:
;           None.
;
        procedure   $EXIT,NEAR
        ASSUME  DS:NOTHING,ES:NOTHING
        XOR     AH,AH
        XCHG    AH,BYTE PTR [DidCTRLC]
        OR      AH,AH
        MOV     BYTE PTR [Exit_type],exit_terminate
        JZ      exit_inner
        MOV     BYTE PTR [Exit_type],exit_ctrl_c

        entry   Exit_inner

        invoke  get_user_stack
        PUSH    [CurrentPDB]
        POP     [SI.user_CS]
        JMP     SHORT abort_inner
EndProc $EXIT

;filter
ENDIF

BREAK <$ABORT -- Terminate a process>

; Inputs:
;       user_CS:00 must point to valid program header block
; Function:
;       Restore terminate and Cntrl-C addresses, flush buffers and transfer to
;       the terminate address
; Returns:
;       TO THE TERMINATE ADDRESS

        procedure   $ABORT,NEAR
ASSUME  DS:NOTHING,ES:NOTHING


        invoke  DOS_ABORT               ; mdr this is all we should do
        mov     cs:os2_handled,0        ; mdr DOS will do rest
        ret                             ; mdr

IF NOT_FILTER

        XOR     AL,AL
        MOV     [exit_type],exit_abort

;
; abort_inner must have AL set as the exit code!  The exit type is retrieved
; from exit_type.  Also, the PDB at user_CS needs to be correct as the one
; that is terminating.
;
        entry   abort_inner

        MOV     AH,[exit_type]
        MOV     [exit_code],AX
        invoke  Get_user_stack
        MOV     DS,[SI.user_CS]         ; set up old interrupts
        XOR     AX,AX
        MOV     ES,AX
        MOV     SI,SAVEXIT
        MOV     DI,addr_int_terminate
        MOVSW
        MOVSW
        MOVSW
        MOVSW
        MOVSW
        MOVSW
        transfer    reset_environment

;filter
ENDIF

EndProc $ABORT


V86CODE ENDS
    END
