        page    ,132
        title   SrvCall - Server DOS call (int 21h, 5Dh and 5Eh)

;********************************************************************** ;BN001;
; 15Jun91 - G.L.Fulk                                                    ;BN001;
;********************************************************************** ;BN001;
; 11Dec93 - B.Clare (changeteam defect 75460)                           ;75460;
;           Added SrvCallEntFlg to notify DOS that next int 21 was      ;75460;
;           generated by SRV_CALL. Srv_Call sets flag to true           ;75460;
;           if secondary call is to function 41h                        ;75460;
;********************************************************************** ;75460;
.xlist
include v86seg.inc
.xcref
include basemaca.inc
include osmaca.inc
include oldmaca.inc
include demmac.inc
include dpl.inc
include error.inc
include demver.inc
include dossymc.inc
include struc30.inc
include demmult.inc
.cref
.list


        ReferV86 SaveBX,WORD                                            ;BN001;
        ReferV86 SaveDS,WORD                                            ;BN001;
        ReferV86 USER_ID,WORD                                           ;BN001;
        ReferV86 PROC_ID,WORD                                           ;BN001;
        ReferV86 ExtErr_Action, BYTE    ; recommended action
        ReferV86 ExtErr_Locus, BYTE     ; error location
        ReferV86 ExtErrPT, DWORD
        ReferV86 ExtErr, WORD
        ReferV86 SrvCallEntFLG, BYTE    ;                               ;75460;BClare

        EXTRN    SWAP_START:byte
        EXTRN    Swap_Always:byte
        EXTRN    SWAP_END:byte
        EXTRN    SWAP_AREA_TABLE:byte

V86CODE SEGMENT
        assume  cs:V86GROUP, ds:nothing, es:nothing, ss:V86GROUP


        EXTRN   SYS_RET_ERR_AL:near     ;MsCode.asm
        EXTRN   SYS_RET_ERR:near        ;MsCode.asm
        EXTRN   SYS_RET_OK:near         ;MsCode.asm

        EXTRN   TableDispatch:near
        EXTRN   GET_USER_STACK:near
        EXTRN   XCHGP:near                                              ;BN001;

;--------------------------------------
        subttl  Int 21h, AH=5Dh
        page

ServerTab       DW      V86GROUP:Server_Disp
SERVERLEAVE     DW      V86GROUP:ServerReturn
SERVER_DISP     DB      (SERVER_DISP_END-SERVER_DISP-1)/2
                DW      OFFSET V86GROUP:SRV_CALL            ; 0
                DW      OFFSET V86GROUP:COMMIT_ALL          ; 1
                DW      OFFSET V86GROUP:CLOSE_NAME          ; 2
                DW      OFFSET V86GROUP:CLOSE_UID           ; 3
                DW      OFFSET V86GROUP:CLOSE_UID_PID       ; 4
                DW      OFFSET V86GROUP:GET_LIST            ; 5
                DW      OFFSET V86GROUP:GET_DOS_DATA        ; 6
                DW      OFFSET V86GROUP:SPOOL_OPER          ; 7
                DW      OFFSET V86GROUP:SPOOL_OPER          ; 8
                DW      OFFSET V86GROUP:SPOOL_OPER          ; 9
                DW      OFFSET V86GROUP:$setExtendedError   ; 10
SERVER_DISP_END LABEL   BYTE

;       INPUT                           ;       OUTPUT
;
; AX=5D06h Get DOS data area            DS:SI=&start
;       DS:DX=&DPL                      CX=size in bytes of swap if indos
;                                       DX=size in bytes of swap always
;
; AX=5D0Bh Get DOS data area            DS:SI=&swap table
;       DS:DX=&DPL
;

        PUBLIC  $ServerCall
        assume  cs:V86GROUP, ds:nothing, es:nothing, ss:V86GROUP
$ServerCall     proc    near

;------
        .if     <AL eq 11>
          mov     di,offset V86GROUP:SWAP_AREA_TABLE
          push    ss
          pop     es
          call    GET_USER_STACK
          mov     [si].user_DS,es       ;ds:si -> swap tab
          mov     [si].user_SI,di
          jmp     SYS_RET_OK
        .endif

;------ for commands (0..6 & 10) do ? with the DPL input parms
        .if     <AL be 6> or
        .if     <AL eq 10>
          mov     si,dx                 ;DS:SI=&DPL (Dos Parameter List)
          mov     bx,[si].DPL_UID

comment ~ DOS 5
          ; WIN386 updates the USER_ID itself.
          ; If WIN386 is present we skip the updating of USER_ID.
          test    ss:[IsWin386],1
          jnz     skip_win386
~
          mov     ss:[USER_ID],bx     ; Set UID
skip_win386:
          mov     bx,[si].DPL_PID
          mov     ss:[PROC_ID],bx       ; Set process ID
        .endif

;------ dispatch to the sub-function worker
        push    SERVERLEAVE             ; push return address
        push    ServerTab               ; push table address
        push    ax
        call    TableDispatch

;------ if the sub-function is illegal
        mov     ss:[EXTERR_LOCUS],errLoc_Unk ; Extended Error Locus
        mov     al,ERROR_INVALID_FUNCTION
        jmp     SYS_RET_ERR_AL

;------
ServerReturn:
        ret

$ServerCall     endp

;--------------------------------------
        assume  cs:V86GROUP, ds:nothing, es:nothing, ss:V86GROUP
;int 21h ax=5D01h, not supported
COMMIT_ALL proc near
;;;     mov     al,ERROR_INVALID_FUNCTION
;;;     jmp     SYS_RET_ERR_AL
comment ~ DOS 5
        XOR     BX,BX                   ;   for (i=0; ThisSFT=getSFT(i); i++)
        PUSH    SS
        POP     DS
        EnterCrit   critSFT             ; Gonna scan SFT cache, lock it down
        .repeat
          push    BX
          Invoke  SFFromSFN
          .leave  c
          .if     <<ES:[DI].sf_Ref_Count> ne 0> and
            ;if (ThisSFT->refcount != 0)
            .if     <BIT <ES:[DI].sf_Ref_Count> and sf_busy> and
            ;BUSY SFTs have god knows what in them.
            .if     <BIT <ES:[DI].sf_flags> nand sf_isnet>
            ;Skip Network SFTs so the SERVER
            ;doesn't deadlock
              mov     WORD PTR ThisSFT,DI
              mov     WORD PTR ThisSFT+2,ES
              Invoke  DOS_Commit              ;DOSCommit ();
            .endif
            POP     BX
            INC     BX
          .until
          LeaveCrit   critSFT
          POP     BX
          JMP     Sys_Ret_OK
~
COMMIT_ALL endp
;--------------------------------------
;int 21h ax=5D02h, not supported
CLOSE_NAME proc near
;;;     mov     al,ERROR_INVALID_FUNCTION
;;;     jmp     SYS_RET_ERR_AL
comment ~ DOS 5
        call    JShare + 5 * 4    ;36: FF 1E 0014E
CheckReturns:
        .if     nc
          jmp     Sys_ret_ok
        .endif
        jmp     Sys_ret_Err
~
CLOSE_NAME endp
;--------------------------------------
;int 21h ax=5D03h, not supported
CLOSE_UID proc  near
;;;     mov     al,ERROR_INVALID_FUNCTION
;;;     jmp     SYS_RET_ERR_AL
comment ~ DOS 5
        call    JShare + 3 * 4   ;36: FF 1E 000CE
        jmp     CheckReturns
~
CLOSE_UID endp
;--------------------------------------
;int 21h ax=5D04h, not supported
CLOSE_UID_PID proc near
;;;     mov     al,ERROR_INVALID_FUNCTION
;;;     jmp     SYS_RET_ERR_AL
comment ~ DOS 5
        call    JShare + 4 * 4   ;36: FF 1E 0010E
        jmp     CheckReturns
~
CLOSE_UID_PID endp
;--------------------------------------
;int 21h ax=5D05h, not supported
GET_LIST proc near
        mov     al,ERROR_INVALID_FUNCTION
        jmp     SYS_RET_ERR_AL
comment ~ DOS 5
        call    JShare + 9 * 4   ;36: FF 1E 0024E
        .if     c
          jmp     Sys_ret_Err
        .endif
        invoke  get_user_stack
        mov     [SI.user_BX],BX
        mov     [SI.user_DI],DI
        mov     [SI.user_ES],ES
        mov     [SI.user_CX],CX
        jmp     Sys_ret_ok
~
GET_LIST endp
;--------------------------------------
        assume  cs:V86GROUP, ds:nothing, es:nothing, ss:V86GROUP
;int 21h ax=5D00h, not supported
PUBLIC  SRV_CALL                                                        ;BN001;
SRV_CALL proc   near
                                                                        ;BN001;
        pop     ax                      ;get rid of call to $srvcall    ;BN001;
                                                                        ;BN001;
        push    ds                                                      ;BN001;
        push    si                                                      ;BN001;
        invoke  GET_USER_STACK                                          ;BN001;
        pop     di                                                      ;BN001;
        pop     es                                                      ;BN001;
                                                                        ;BN001;
        ;DS:SI = &stack                                                 ;BN001;
        ;ES:DI = &DPL                                                   ;BN001;
                                                                        ;BN001;
        call    XCHGP                                                   ;BN001;
                                                                        ;BN001;
        ;DS:SI = &DPL                                                   ;BN001;
        ;ES:DI = &stack                                                 ;BN001;
                                                                        ;BN001;
        ; We now copy the registers from DPL to save stack              ;BN001;
        push    si                                                      ;BN001;
        mov     cx,6                                                    ;BN001;
        rep     movsw                   ; Put in AX,BX,CX,DX,SI,DI      ;BN001;
        inc     di                                                      ;BN001;
        inc     di                      ; Skip user_BP                  ;BN001;
        movsw                           ; DS                            ;BN001;
        movsw                           ; ES                            ;BN001;
        pop     si                                                      ;BN001;
                                                                        ;BN001;
        MOV     AX,[SI.DPL_AX]                                          ;BN001;
        MOV     BX,[SI.DPL_BX]                                          ;BN001;
        MOV     CX,[SI.DPL_CX]                                          ;BN001;
        MOV     DX,[SI.DPL_DX]                                          ;BN001;
        MOV     DI,[SI.DPL_DI]                                          ;BN001;
        MOV     ES,[SI.DPL_ES]                                          ;BN001;
                                                                        ;BN001;
        PUSH    [SI.DPL_SI]                                             ;BN001;
        MOV     DS,[SI.DPL_DS]                                          ;BN001;
        POP     SI                                                      ;BN001;
                                                                        ;BN001;
        MOV     ss:[SaveDS],DS                                          ;BN001;
        MOV     ss:[SaveBX],BX                                          ;BN001;
;;;     MOV     ss:fSharing,-1  ; set no redirect flag                  ;BN001;
        .if     <ah eq 41h>     ; Function 41h is the only one that     ;75460;
                                ; currently supports SrvCallEntFlg      ;75460;
          MOV     ss:SrvCallEntFlg,TRUE ; Tell DOS that service         ;75460;
                                        ; was called from SRV_CALL      ;75460;
        .endif                                                          ;75460;
                                                                        ;BN001;
        transfer REDISP                                                 ;BN001;
                                                                        ;BN001;
SRV_CALL endp
;--------------------------------------
        page
        subttl  int 21h, AX=5D06h
        PUBLIC  GET_DOS_DATA
GET_DOS_DATA:
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
        push    ss
        pop     es

        mov     di,offset V86GROUP:SWAP_START
        mov     dx,offset V86GROUP:Swap_Always
        mov     cx,offset V86GROUP:SWAP_END

        sub     cx,di
        sub     dx,di
        shr     cx,1                    ; div by 2, remainder in carry
        adc     cx,0                    ; div by 2 + round up
        shl     cx,1                    ; round up to 2 boundary.

        call    GET_USER_STACK
        mov     [si].user_DS,es
        mov     [si].user_SI,di
        mov     [si].user_DX,dx
        mov     [si].user_CX,cx
        jmp     SYS_RET_OK
;--------------------------------------
;int 21h ax=5D07h
;int 21h ax=5D08h
;int 21h ax=5D09h
        PUBLIC  SPOOL_OPER
SPOOL_OPER proc near
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
        push    ax
        mov     ax,1125h
        int     2Fh
        pop     bx
        .if     nc
          jmp     SYS_RET_OK
        .endif
        jmp     SYS_RET_ERR
SPOOL_OPER endp
;--------------------------------------
;int 21h ax=5D0Ah
$setExtendedError proc near
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:V86GROUP
        mov     ax,[si].dpl_ax
        mov     cs:[ExtErr],ax
        mov     ax,[si].dpl_di
        mov     word ptr cs:[ExtErrPt],ax
        mov     ax,[si].dpl_es
        mov     word ptr cs:[ExtErrPt]+2,ax
        mov     ax,[si].dpl_bx
        mov     word ptr cs:[ExtErr_action],ax
        mov     ax,[si].dpl_cx
        mov     cs:[ExtErr_locus],ah
        ret
$setExtendedError endp
;--------------------------------------

V86CODE ENDS

        END
