;       SCCSID = @(#)msctrlc.asm        6.2 92/05/29
;
; Low level routines for detecting special characters on CON input,
;       the ^C exit/int code, the Hard error INT 24 code, the
;       process termination code, and the INT 0 divide overflow handler.
;
;   FATAL
;   FATAL1
;   reset_environment
;   DSKSTATCHK
;   SPOOLINT
;   STATCHK
;   CNTCHAND
;   DIVOV
;   CHARHARD
;   HardErr
;
;   Revision history:
;
;       AN000   version 4.0   Jan 1988
;       A002    PTM    -- dir >lpt3 hangs
;       A003    PTM 3957- fake version for IBMCAHE.COM
;********************************************************************** ;BN001;
; 29May92 - G.L.Fulk                                                    ;BN001;
; Reset_version is nolonger needed.                                     ;BN001;
;********************************************************************** ;BN001;
; 11Jan93 - G.L.Fulk                                                    ;59983;
; CurrentPDB can be corrupted if a timer tick occurs between the real   ;59983;
; and protect mode alterations of the variable.  The CLI will prevent   ;59983;
; timer ticks from this corruption.                                     ;59983;
;********************************************************************** ;59983;

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

.xcref
include basemaca.inc
include osmaca.inc
include oldmaca.inc
include demmac.inc
include dossymc.inc
include devsym.inc
include demver.inc
include demdbcs.inc
include sft.inc
include demdev.inc
include mi.inc
include syscalls.inc
include error.inc
include vector.inc
include pdb.inc
include exe.inc
include mvdmexp.inc
include demsvc.inc
include demmult.inc
include harderr.inc
include basemid.inc
include utilmid2.inc
include struc30.inc
.cref
.list

; from 4.0 filemode.inc
ext_open_I24_off        EQU 02H

        CpuMode 286

        I_Need  SFN,WORD
        I_Need  pJFN,DWORD
        I_Need  DevIOBuf,BYTE
        I_Need  DidCTRLC,BYTE
        I_Need  INDOS,BYTE
        I_Need  DSKSTCOM,BYTE
        I_Need  DSKSTCALL,BYTE
        I_Need  DSKSTST,WORD
        I_Need  BCON,DWORD
        I_Need  DSKCHRET,BYTE
        I_Need  DSKSTCNT,WORD
        I_Need  IDLEINT,BYTE
        I_Need  CONSWAP,BYTE
        I_Need  user_SS,WORD
        I_Need  user_SP,WORD
        I_Need  User_In_AX,WORD
        I_Need  ERRORMODE,BYTE
        I_Need  ConC_spsave,WORD
        I_Need  Exit_type,BYTE
        I_Need  PFLAG,BYTE
        I_Need  ExitHold,DWORD
        I_Need  WPErr,BYTE
        I_Need  CONTSTK,WORD
        I_Need  Exit_Code,WORD
        I_Need  CurrentPDB,WORD
        I_Need  ALLOWED,BYTE
        I_Need  FAILERR,BYTE
        I_Need  EXTERR,WORD
        I_Need  ERR_TABLE_24,BYTE
        I_Need  ErrMap24,BYTE
        I_Need  ErrMap24End,BYTE
        I_Need  fAborting,BYTE
        I_Need  AUXStack,BYTE
        I_Need  SCAN_FLAG,BYTE
        I_Need  EXTOPEN_ON,BYTE               ;AN000; DOS 4.0
        I_Need  InterCon,BYTE                 ;AN000; DOS 4.0
        I_Need  DOS34_FLAG,WORD               ;AN000; DOS 4.0
        I_Need  Special_Version,WORD          ;AN007; DOS 4.0
        I_Need  SaveDS,WORD
        I_Need  SaveBX,WORD
        I_Need  Message_Buffer,BYTE
        I_Need  vheVDM,BYTE


V86CODE    SEGMENT
        ASSUME  CS:V86GROUP
        EXTRN   $Get_Interrupt_Vector:NEAR
        EXTRN   BUFOUT:NEAR
        EXTRN   CAL_LK:NEAR
        EXTRN   CRLF:NEAR
        EXTRN   DEVIOCALL2:NEAR
        EXTRN   DOS_ABORT:NEAR
        EXTRN   GET_IO_SFT:NEAR
        EXTRN   IOFUNC:NEAR
        EXTRN   SWAPBACK:NEAR
        EXTRN   arena_free_process:NEAR
        EXTRN   restore_world:NEAR
        EXTRN   ECritDisk:NEAR
        EXTRN   LCritDisk:NEAR
        EXTRN   get_user_stack:NEAR
        EXTRN   RMDevOpen:NEAR
        EXTRN   RMDevClose:NEAR
        EXTRN   exit_inner: near
        EXTRN   COMMAND:near
        EXTRN   REDISP:near

subttl  Checks for ^C in CON I/O
page

        ASSUME  DS:NOTHING,ES:NOTHING

public DskStatChk
DskStatChk proc near ; Check for ^C if only one level in
        .if     <<byte ptr cs:[INDOS]> ne 1>
          ret
        .endif
        PUSH    CX
        PUSH    ES
        PUSH    BX
        PUSH    DS
        PUSH    SI

        push    cs
        pop     es
;;;;    assume  es:V86GROUP

        push    ss
        pop     ds
        assume  ds:V86GROUP

        MOV     BYTE PTR [DSKSTCOM],CMDNDR
        MOV     BYTE PTR [DSKSTCALL],LENNDR
        MOV     [DSKSTST],0
        MOV     AL, [InterCon]          ;AN000;get type of status read 2/13/KK
        MOV     BYTE PTR [DSKCHRET],AL  ;AN000; load interim flag into packet
        MOV     BX,OFFSET V86GROUP:DSKSTCALL
        LDS     SI,[BCON]
        assume  ds:nothing
        call    DEVIOCALL2
        .if     <BIT <cs:[DSKSTST]> and STBUI>
          xor     al,al                 ; No characters available, set zero
RET36:
          POP     SI
          POP     DS
          POP     BX
          POP     ES
          POP     CX
          ret
        .endif
        mov     al,byte ptr cs:[DSKCHRET]
DSK1:
        CMP     AL,"C"-"@"
        JNZ     RET36

        MOV     BYTE PTR cs:[DskStCom],CMDINPUT
        MOV     BYTE PTR cs:[DskStCall],LENIO
        MOV     BYTE PTR cs:[DskChRet],CL
        MOV     cs:[DskStSt],0
        MOV     cs:[DskStCnt],1
        call    DEVIOCALL2              ; Eat the ^C
        POP     SI
        POP     DS
        POP     BX                      ; Clean stack
        POP     ES
        POP     CX
        JMP     CNTCHAND

NOSTOP:
        .if     <AL eq <"P"-"@">>
          CMP     BYTE PTR cs:[Scan_Flag],0    ; ALT_Q ?
          JZ      INCHK                   ; no
          ret
        .endif

        cmp     AL,"C"-"@"
        je      INCHK

check_end: ret

DskStatChk endp

;
; SpoolInt - signal processes that the DOS is truly idle.  We are allowed to
; do this ONLY if we are working on a 1-12 system call AND if we are not in
; the middle of an INT 24.
;

public SpoolInt
SpoolInt proc   near
        pushf
        .if     <<cs:[IdleInt]> ne 0>

;*************************************************************************
;**     WARNING WARNING                                                  *
;                                                                        *
;       Sidekick (and possibly others) looks for this specific code      *
;       sequence relative to the INT 28 to determine the location        *
;       of the ErrorMode variable.  Sidekick inspects this variable      *
;       to determine if it is running at INT 24h time (in which case     *
;       it cannot come up because it cannot issue any system calls).     *
;                                                                        *
sint1:    .if     <BIT <cs:[ErrorMode]> nand -1>                         *
;                                                                        *
; Note that we are going to allow an external program to issue system calls
; at this time.  We MUST preserve IdleInt across this.                   *
;                                                                        *
            push    word ptr cs:[IdleInt] ;                              *
            int     28h                   ;                              *
            .errnz      (($-0fh)-sint1)   ; special Sidekick support     *
;*************************************************************************

            pop     word ptr cs:[IdleInt]
          .endif
        .endif
        popf
        ret
SpoolInt endp

public  StatChk
StatChk proc    near

        call    DskStatChk              ; Allows ^C to be detected under
                                        ; input redirection
        PUSH    BX
        XOR     BX,BX
        call    GET_IO_SFT
        POP     BX
        .if     c
          ret
        .endif
        MOV     AH,1
        call    IOFUNC
        JZ      SPOOLINT
        CMP     AL,"S"-"@"
        JNZ     NOSTOP


        CMP     BYTE PTR [SCAN_FLAG],0        ;AN000; ALT_R ?
        JNZ     check_end                     ;AN000; yes
        XOR     AH,AH
        call    IOFUNC                  ; Eat Cntrl-S
        JMP     SHORT PAUSOSTRT


PRINTON:
        NOT     BYTE PTR [PFLAG]
        PUSH    BX
        MOV     BX,4
        call    GET_IO_SFT
        POP     BX
        .if     c
          ret
        .endif

;dos6?  PUSH    ES
;dos6?  PUSH    DI
;dos6?  PUSH    DS
;dos6?  POP     ES
;dos6?  MOV     DI,SI                   ; ES:DI -> SFT
;dos6?  TEST    ES:[DI.sf_flags],sf_net_spool
;dos6?  JZ      NORM_PR                 ; Not redirected, echo is OK
;dos6?  Callinstall NetSpoolEchoCheck,MultNet,38,<AX>,<AX> ; See if allowed
;dos6?  JNC     NORM_PR                 ; Echo is OK
;dos6?  MOV     BYTE PTR [PFLAG],0      ; If not allowed, disable echo
;dos6?  Callinstall NetSpoolClose,MultNet,36,<AX>,<AX> ; and close
;dos6?  JMP     SHORT RETP6

NORM_PR:
        CMP     BYTE PTR [PFLAG],0
        JNZ     PRNOPN
        call    RMDevClose
        JMP     SHORT RETP6

PRNOPN:
        call    RMDevOpen

RETP6:
;dos6?  POP     DI
;dos6?  POP     ES
        ret

PAUSOLP:
        CALL    SPOOLINT
PAUSOSTRT:
        MOV     AH,1
        call    IOFUNC
        JZ      PAUSOLP
INCHK:
        PUSH    BX
        XOR     BX,BX
        call    GET_IO_SFT
        POP     BX
        .if     c
          ret
        .endif
        XOR     AH,AH
        call    IOFUNC
        CMP     AL,"P"-"@"
        JZ      PRINTON                       ; no! must be CTRL_P
        .if     <AL ne "C"-"@">
          ret
        .endif
StatChk endp

public  CNTCHAND
CNTCHAND proc   near
; Ctrl-C handler.
; "^C" and CR/LF is printed.  Then the user registers are restored and the
; user CTRL-C handler is executed.  At this point the top of the stack has 1)
; the interrupt return address should the user CTRL-C handler wish to allow
; processing to continue; 2) the original interrupt return address to the code
; that performed the function call in the first place.  If the user CTRL-C
; handler wishes to continue, it must leave all registers unchanged and RET
; (not IRET) with carry CLEAR.  If carry is SET then an terminate system call
; is simulated.
        .if     <BIT <[DOS34_FLAG]> nand CTRL_BREAK_FLAG> ;AN002; from RAWOUT
          MOV     AL,3                    ; Display "^C"
          call    BUFOUT
          call    CRLF
        .endif
        push    cs
        pop     ds
        ASSUME  DS:V86GROUP
        .if     <<BYTE PTR [CONSWAP]> ne 0>
          call    SWAPBACK
        .endif
        CLI                             ; Prepare to play with stack
        MOV     SS,[user_SS]            ; User stack now restored
        MOV     SP,[user_SP]
        call    restore_world           ; User registers now restored
        ASSUME  DS:NOTHING
        MOV     BYTE PTR [INDOS],0      ; Go to known state
        MOV     BYTE PTR [ERRORMODE],0
        MOV     [ConC_spsave],SP        ; save his SP
        clc
        int     23h                     ; Execute user Ctrl-C handler
;
; The user has returned to us.  The circumstances we allow are:
;
;   IRET        We retry the operation by redispatching the system call
;   CLC/RETF    POP the stack and retry
;   ...         Exit the current process with ^C exit
;
; User's may RETURN to us and leave interrupts on.  Turn 'em off just to be
; sure
;
        CLI
        MOV     [user_IN_AX],ax         ; save the AX
        PUSHF                           ; and the flags (maybe new call)
        POP     AX
;
; See if the input stack is identical to the output stack
;
        CMP     SP,[ConC_spsave]
        JNZ     ctrlc_try_new           ; current SP not the same as saved SP
;
; Repeat the operation by redispatching the system call.
;
ctrlc_repeat:
        MOV     AX,User_In_AX
        jmp     COMMAND
;
; The current SP is NOT the same as the input SP.  Presume that he RETF'd
; leaving some flags on the stack and examine the input
;
ctrlc_try_new:
        ADD     SP,2                    ; pop those flags
        TEST    AX,f_carry              ; did he return with carry?
        JZ      Ctrlc_Repeat            ; no carry set, just retry
;
; Well...  time to abort the user.  Signal a ^C exit and use the EXIT system
; call..
;
ctrlc_abort:
        mov     AX,4C00h
        mov     cs:[DidCTRLC],-1
        jmp     COMMAND             ; give up by faking $EXIT

CNTCHAND endp


subttl  DIVISION OVERFLOW INTERRUPT
page

; Default handler for division overflow trap
public  DIVOV
DIVOV   proc    near
        assume  ds:NOTHING,es:NOTHING,ss:NOTHING
        mov     ax, MSG_CMD_DIV_0
        mov     di, offset V86GROUP:Message_Buffer
        push    cs
        pop     es                      ; (es:di) = message buffer
        svc     SVC_DEMGETMESSAGE
        MOV     SI,DI
        LODS    WORD PTR CS:[SI]        ; (AX) = length
        MOV     BX,AX                   ; (BX) = length
        MOV     AX,CS
        MOV     SS,AX
        MOV     SP,OFFSET V86GROUP:AUXSTACK ; Enough stack for interrupts
        CALL    OutMes
        JMP     ctrlc_abort             ; Use Ctrl-C abort on divide overflow
DIVOV   endp

;
; OutMes: perform message output
; Inputs:   SS:SI points to message
;           BX has message length
; Outputs:  message to BCON
;
public OutMes
OutMes  proc    near

        push    ss
        pop     es
        push    ss
        pop     ds
        assume  ds:V86GROUP,es:V86GROUP

        MOV     BYTE PTR [DskStCom],CMDOUTPUT
        MOV     BYTE PTR [DskStCall],LENIO
        MOV     [DskSTST],0
        MOV     [DskStCnt],BX
        MOV     BX,OFFSET V86GROUP:DskStCall
        MOV     WORD PTR [DskChRet+1],SI    ; transfer address (need an EQU)
        LDS     SI,[BCON]
        assume  DS:NOTHING
        call    DEVIOCALL2
        MOV     WORD PTR es:[DskChRet+1],OFFSET V86GROUP:DevIOBuf
        MOV     es:[DskStCnt],1
        ret
OutMes  endp

subttl  CHARHRD,HARDERR,ERROR -- HANDLE DISK ERRORS AND RETURN TO USER
page

public CHARHARD
CHARHARD proc   near
        ASSUME  DS:NOTHING,ES:NOTHING

; Character device error handler
; Same function as HARDERR

        push    BX
        push    cx
        push    dx
        push    bp
        push    si
        push    di
        push    ds
        push    es
        OR      AH,allowed_FAIL + allowed_IGNORE + allowed_RETRY
        MOV     Allowed,AH
        MOV     WORD PTR [EXITHOLD+2],ES
        MOV     WORD PTR [EXITHOLD],BP
        AND     DI,STECODE
        MOV     BP,DS                   ; Device pointer is BP:SI
        call    FATALC
        pop     es
        pop     ds
        pop     di
        pop     si
        pop     bp
        pop     dx
        pop     cx
        pop     bx
        ret
CHARHARD endp

;***    CheckHardError - check for hard error
;
;       This routine checks for hard error that might have happened
;       in a SVC call.  It dispatches to the int 24 handler if a hard
;       error occured.
;
;       ENTRY   NONE
;
;       EXIT    if carry set, fail
;               if carry clear, ignore
;
;       USES    Flags
;
;       Retry and Abort responses are automaticly taken care of.
;
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING

public  CheckHardError
CheckHardError proc near
        .if     <BIT <cs:[vheVDM.vhe_fbMisc]> nand VHE_FLAG_ACTIVE> ; pending hard errors?
                                          ;  yes, jump to dispatch code
          stc                             ;  no, return fail
          ret
        .endif
        push    ds
        push    es
        pusha
        push    ss
        pop     ds
        assume  ds:V86GROUP
        mov     bp,ds                   ; (BP:SI) = device driver header
        mov     si,offset V86GROUP:vheVDM.vhe_abDeviceHeader
        and     [vheVDM.vhe_fbMisc],not VHE_FLAG_ACTIVE
        mov     di,[vheVDM.vhe_usPacketErr]
        mov     ah,[vheVDM.vhe_fbInt24]
        mov     al,[vheVDM.vhe_fbAllowed]
        mov     [ALLOWED],al
        mov     al,[vheVDM.vhe_bDriveNum]

;       Set the extended error fields with the OS2 kernel error
;       code.  We lose info if the error code returned by
;       SET_I24_EXTENDED_ERROR is used.

        push    si
        mov     si,[vheVDM.vhe_usFailErr]
        mov     [EXTERR],si
        mov     si,offset V86GROUP:ERR_TABLE_24
        call    CAL_LK                  ; set other extended error fields
        pop     si

;       (AX) = drive number and flags
;       (DI) = packet error code
;       (BP:SI) = device driver address
;       [ALLOWED] = allowed flags

        call    NET_I24_ENTRY           ; (AL) = response
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING
        .if     <al eq HDERR_RETRY>
                                        ; jmp if ignore or fail
          call    get_user_stack        ; (DS:SI) = user stack frame
          mov     ax,[si].user_AX
          mov     bx,[si].user_BX
          mov     cx,[si].user_CX
          mov     dx,[si].user_DX
          mov     di,[si].user_DI
          mov     bp,[si].user_BP
          mov     es,[si].user_ES
          push    [si].user_SI
          push    [si].user_DS
          pop     ds
          pop     si
          MOV     [SaveDS],DS           ; PTR B787305
          MOV     [SaveBX],BX
          jmp     REDISP               ; retry system call
        .endif
        popa
        pop     es
        pop     ds
        cmc                             ; make fail carry set/ignore carry clear
        ret
CheckHardError endp

; DI has the INT-24-style extended error.  We now map the error code for this
; into the normalized get extended error set by using the ErrMap24 table as an
; translate table.  Note that we translate ONLY the device returned codes and
; leave all others beyond the look up table alone.
;
        ASSUME  DS:NOTHING, ES:NOTHING
public FATALC
FATALC:
        call    SET_I24_EXTENDED_ERROR
        .if     <DI a error_I24_gen_failure> ;Error codes above gen_failure get
          mov     di,error_I24_gen_failure   ;mapped to gen_failure. Real codes
        .endif                               ;Only come via GetExtendedError



;**
;
; Entry point used by REDIRector on Network I 24 errors.
;
;       ASSUME  DS:NOTHING,ES:NOTHING,SS:DOSDATA
;
; ALL I 24 regs set up. ALL Extended error info SET. ALLOWED Set.
;     EXITHOLD set for restore of ES:BP.
;

public NET_I24_ENTRY
NET_I24_ENTRY:
        assume  ds:nothing,es:nothing

        .if     <<BYTE PTR cs:[ERRORMODE]> ne 0> ; No INT 24s if already INT 24
          mov     al,3
          jmp     short FailRet
        .endif
        mov     cs:[CONTSTK],SP
        push    ss
        pop     es
        assume  ds:nothing,es:V86GROUP

        ; Wango!!!  We may need to free some user state info...  In
        ; particular, we may have locked down a JFN for a user and he may
        ; NEVER return to us.  Thus, we need to free it here and then
        ; reallocate it when we come back.

        .if     <SFN ne -1>
          push    ds
          push    si
          LDS     SI,es:[pJFN]
          mov     byte ptr [SI],-1
          pop     si
          pop     ds
        .endif
        CLI                             ; Prepare to play with stack
        INC     BYTE PTR es:[ERRORMODE] ; Flag INT 24 in progress
        DEC     BYTE PTR es:[INDOS]     ; INT 24 handler might not return
;; Extneded Open hooks
        .if     <BIT <es:[DOS34_FLAG]> and Force_I24_Fail> or ;form IFS Call Back
        .if     <BIT <es:[EXTOPEN_ON]> and EXT_OPEN_I24_OFF>  ;I24 error disabled
          mov     al,3                  ;IFS.fake fail
        .else
          ;; Extended Open hooks
          mov     ss,es:[user_SS]
          mov     sp,es:[user_SP]       ; User stack pointer restored
          int     24h                   ; Fatal error interrupt vector, must preserve ES
          mov     es:[user_SP],SP       ; restore our stack
          mov     es:[user_SS],SS
          MOV     BP,ES
          MOV     SS,BP
        .endif
        MOV     SP,es:[CONTSTK]
        INC     BYTE PTR es:[INDOS]        ; Back in the DOS
        MOV     BYTE PTR es:[ERRORMODE],0  ; Back from INT 24
        STI

FAILRET:
        LES     BP,es:[EXITHOLD]
        assume  es:NOTHING

;------ Triage the user's reply.
        CMP     AL,1
        JB      short CheckIgnore       ; 0 => ignore
        JZ      short CheckRetry        ; 1 => retry
        CMP     AL,3                    ; 3 => fail
        JNZ     short DoAbort           ; 2, invalid => abort

;------ The reply was fail.  See if we are allowed to fail.
        TEST    cs:[ALLOWED],allowed_FAIL  ; Can we?
        JZ      short DoAbort           ; No, do abort

public DoFail ;public only for debugging
DoFail:
        MOV     AL,3                    ; just in case...
        .if     <BIT <[EXTOPEN_ON]> nand EXT_OPEN_I24_OFF> ;I24 error disabled
          inc     cs:[FAILERR]            ; Tell everybody
        .endif
CleanUp:
        mov     cs:[WpErr],-1
        .if     <<cs:[SFN]> ne -1>
          push    ds
          push    si
          push    ax
          mov     ax,cs:[SFN]
          LDS     SI,cs:[pJFN]
          MOV     [SI],AL
          pop     ax
          pop     si
          pop     ds
        .endif
        ret
;
; The reply was IGNORE.  See if we are allowed to ignore.
;
CheckIgnore:
        TEST    cs:[ALLOWED],allowed_IGNORE ; Can we?
        JZ      DoFail                  ; No, do fail
        JMP     CleanUp
;
; The reply was RETRY.  See if we are allowed to retry.
;
CheckRetry:
        TEST    cs:[ALLOWED],allowed_RETRY ; Can we?
        JZ      DoFail                  ; No, do fail
        JMP     CleanUp
;
; The reply was ABORT.
;
public DoAbort ;public only for debugging
DoAbort:
        push    ss
        pop     ds
        assume  ds:V86GROUP
        .if     <<BYTE PTR [CONSWAP]> ne 0>
          call    SWAPBACK
        .endif
;
; See if we are to truly abort.  If we are in the process of aborting, turn
; this abort into a fail.
;
        cmp     [fAborting],0
        JNZ     DoFail
;
; Set return code
;
        MOV     BYTE PTR [exit_Type],Exit_hard_error
        XOR     AL,AL
;
; we are truly aborting the process.  Go restore information from the PDB as
; necessary.
;
        jmp     exit_inner
;
; reset_environment checks the DS value against the CurrentPDB.  If they are
; different, then an old-style return is performed.  If they are the same,
; then we release jfns and restore to parent.  We still use the PDB at DS:0 as
; the source of the terminate addresses.
;
; Some subtlety:  We are about to issue a bunch of calls that *may* generate
; INT 24s.  We *cannot* allow the user to restart the abort process; we may
; end up aborting the wrong process or turn a terminate/stay/resident into a
; normal abort and leave interrupt handlers around.  What we do is to set a
; flag that will indicate that if any abort code is seen, we just continue the
; operation.  In essence, we dis-allow the abort response.
;
; output:   none.
;
public reset_environment
reset_environment:
        ASSUME  DS:NOTHING,ES:NOTHING

        PUSH    DS                      ; save PDB of process

;
; There are no critical sections in force.  Although we may enter here with
; critical sections locked down, they are no longer relevant.  We may safely
; free all allocated resources.
;
        MOV     AH,82h
        INT     2Ah

        MOV     cs:[fAborting],-1       ; signal abort in progress

;;;;;;;;CallInstall NetResetEnvironment, multNet, 34  ;DOS 4.00 doesn't need it
                                        ; Allow REDIR to clear some stuff
                                        ;   On process exit.
        mov     ax,1122h
        int     2Fh
;;;;;;;;

        mov     al,22h
        call    $Get_interrupt_vector   ; and who to go to

        pop     cx                      ; get ThisPDB
        push    es
        push    bx                      ; save return address

        MOV     BX,cs:[CurrentPDB]      ; get currentPDB
        MOV     DS,BX
        MOV     AX,DS:[PDB_Parent_PID]  ; get parentPDB

;
; AX = parentPDB, BX = CurrentPDB, CX = ThisPDB
; Only free handles if AX <> BX and BX = CX and [exit_code].upper is not
; Exit_keep_process
;
        .if     <AX ne BX> and          ; parentPDB = CurrentPDB
        .if     <BX eq CX>              ; CurrentPDB <> ThisPDB
          PUSH    AX                    ; save parent
          .if     <<byte ptr cs:[exit_type]> ne Exit_keep_process>
                                        ; keeping this process
            ; We are truly removing a process.  Free all allocation blocks
            ; belonging to this PDB
            call    arena_free_process

            ; Kill off remainder of this process.  Close file handles and
            ; signal to relevant network folks that this process is dead.
            ; Remember that CurrentPDB is STILL the current process!
            call    DOS_ABORT

          .endif

          pop     es
          assume  es:nothing
          pushf                                                         ;59983;
          cli                                                           ;59983;
          MOV     CurrentPDB,ES                                         ;59983;
          SVC     SVC_DEMSETCURRENTPDB                                  ;59983;
          popf                                                          ;59983;
        .endif

                                        ; come here for normal return
        PUSH    CS
        POP     DS
        ASSUME  DS:V86GROUP
        MOV     AL,-1
;
; make sure that everything is clean In this case ignore any errors, we cannot
; "FAIL" the abort, the program being aborted is dead.
;
;dos6?  EnterCrit   critDisk
;dos6?  invoke  FLUSHBUF
;dos6?  LeaveCrit   critDisk
;
; Decrement open ref. count if we had done a virtual open earlier.
;
;dos6?  invoke  CHECK_VIRT_OPEN

        CLI
        MOV     BYTE PTR [INDOS],0      ; Go to known state
        MOV     BYTE PTR [WPERR],-1     ; Forget about WP error
        MOV     [fAborting],0           ; let aborts occur
        POP     WORD PTR [ExitHold]
        POP     WORD PTR [ExitHold]+2

;------ Snake into multitasking... Get stack from CurrentPDB person
        MOV     DS,[CurrentPDB]
        ASSUME  DS:NOTHING
        MOV     SS,WORD PTR DS:[PDB_user_stack+2]
        MOV     SP,WORD PTR DS:[PDB_user_stack]
        assume  ss:nothing

        call    restore_world
        ASSUME  ES:NOTHING
;dos6?  push    ax                      ; set up ds, but save ds in TEMPSEG
;dos6?  mov     ax, ds                  ; and not on stack.
;dos6?  getdseg <ds>                    ; ds ->dosdata
;dos6?  mov     TempSeg, ax
;dos6?  pop     ax
        MOV     cs:[User_SP],AX
        POP     AX                      ; suck off CS:IP of interrupt...
        POP     AX
        POP     AX

;------ Force a STI
        LAHF
        XCHG    AH, AL
        AND     AL, 02
        MOV     AH, 0F2h
        PUSH    AX

        PUSH    WORD PTR cs:[EXITHOLD+2]
        PUSH    WORD PTR cs:[EXITHOLD]
        MOV     AX,cs:[User_SP]
;dos6?  mov     ds,TempSeg              ; restore ds
;dos6?  assume  ds:NOTHING
        IRET                            ; Long return back to user terminate address
;---------------------------------------------------------------------
;
; This routine handles extended error codes.
; Input : DI = error code from device
; Output: All EXTERR fields are set
;
assume  ds:nothing,es:nothing,ss:nothing
public SET_I24_EXTENDED_ERROR
SET_I24_EXTENDED_ERROR proc near
        PUSH    AX
        MOV     AX,OFFSET V86GROUP:ErrMap24End
        SUB     AX,OFFSET V86GROUP:ErrMap24
;
; AX is the index of the first unavailable error.  Do not translate if
; greater or equal to AX.
;
        CMP     DI,AX
        MOV     AX,DI
        .if     b
          MOV     AL,cs:[ErrMap24][DI]
          XOR     AH,AH
        .endif
        MOV     cs:[EXTERR],AX
        POP     AX
;
; Now Extended error is set correctly.  Translate it to get correct error
; locus class and recommended action.
;
        push    si
        mov     si,OFFSET V86GROUP:ERR_TABLE_24
        call    CAL_LK                  ; Set other extended error fields
        pop     si
        ret
SET_I24_EXTENDED_ERROR endp

subttl IntCharIO - interrupt char I/O for SPOOLINT and possible freeze/resched
page
;***    IntCharIO - interrupt char I/O for SPOOLINT and possible freeze/resched
;
;   This function is called by at least once during the execution of all
;   character I/O system calls.  The DOS is polling to do character I/O
;   instead of having interrupt driven I/O.  This is done so that tasks
;   which are doing character I/O can be "quickly" frozen if need be and
;   so that SPOOLINTs can be issued.
;
;   Int_spooler (usually Int 28h) handlers are invoked if IdleInt is set and
;   the foreground task is running.  The handlers are allowed to issue ALL
;   system calls except $Std_Con_String_Input.
;
;
;       ENTRY   none
;
;       EXIT    none
;
;       USES    none

        assume DS:NOTHING,ES:NOTHING,SS:NOTHING

public IntCharIO
IntCharIO proc near

        PUSHF
        .286p
        PUSHA
        CpuMode reset
        push    ds
        push    es

;*  Issue INT 28, if it is okay to do so

        .if     <<cs:[IdleInt]> ne 0>   ; Are spoolints ok?
                                        ; No, skip the int
          call    SPOOLINT
        .endif
        pop     es
        pop     ds
        assume  DS:NOTHING,ES:NOTHING
        .286p
        popa
        CpuMode reset
        popf
        ret

IntCharIO endp

V86CODE ENDS

        END
