        page    80,132                  ;0
        title   MSDISP - System call entry points and dispatcher

;
; Dispatcher code
;
;   Revision history:
;
;**********************************************************************
; danno   16-Nov-1988 Modified for MVDM
;**********************************************************************
; dcr 1330 - 02\07\91 EMK-ADD SUBFUNCTION 6 (GET REAL DOS VERSION)
;                TO $SET_CTRL_C_TRAPPING (INT 21H, AH=33H).
;**********************************************************************
; 23Jan92 - G.L.Fulk
; Enable the Swappable DOS data area feature.
;**********************************************************************
; 15Jun92 - G.L.Fulk
; Preserve the AX register.
;**********************************************************************
; 29Nov94 - ChangeTeam   Defect 105913 - Roll defect 82929 into r207 sparse tree.
; Add hex 00 to COMMAND_EXIT to prevent session hang in RAPRATER
; application, which scans forward for 00 from int 1 handler.
; Change is flagged with "82929".
;**********************************************************************

.xlist
.xcref
include basemaca.inc
include osmaca.inc
include oldmaca.inc
include demmac.inc
include demver.inc
include dossymc.inc
include v86seg.inc
include demdbcs.inc
include syscalls.inc
include vector.inc
include error.inc
include pdb.inc
include mi.inc
include mvdmexp.inc
include demsvc.inc
include harderr.inc
include struc30.inc
include version.inc
include devsym.inc
include demdev.inc
.cref
.list
        CpuMode 8086

AsmVars <Kanji, Debug>



;-----------------------------------------------------------------------
V86TABLE SEGMENT
        EXTRN   MaxCom:  ABS
        EXTRN   MaxCall: ABS
        EXTRN   command_exec: byte      ;MsProc
        EXTRN   Dispatch: word          ;MsTable & i21.inc
        EXTRN   DosDseg: word           ;MsTable
V86TABLE ENDS
;-----------------------------------------------------------------------
V86LoL  SEGMENT
        EXTRN   DOS_FLAG: byte
        EXTRN   CDSCount: byte
        EXTRN   BOOTDRIVE: byte
V86LoL  ENDS
;-----------------------------------------------------------------------
V86DATA SEGMENT
        EXTRN   IsWIN386: byte
        EXTRN   InterCon: byte
        EXTRN   vheVDM: byte
        EXTRN   VDMNotBusy: word        ;MsInit, VPL Idle detection
V86DATA ENDS
;-----------------------------------------------------------------------
V86SDA  SEGMENT
        EXTRN   Errormode: byte         ;+000
        EXTRN   InDos: byte             ;+001
        EXTRN   WPERR: byte             ;+002
        EXTRN   EXTERR_LOCUS: byte      ;+003
        EXTRN   CurrentPDB: word        ;+010
        EXTRN   CntCFlag: byte          ;+017
        EXTRN   CPSWFLAG: byte          ;+018
        EXTRN   CPSWSAVE: byte          ;+019
        EXTRN   User_In_AX: word        ;+01A
        EXTRN   Proc_ID: word           ;+01C
        EXTRN   User_ID: word           ;+01E
        EXTRN   FailERR: byte           ;+02A
        EXTRN   NoSetDir: byte          ;+02C
        EXTRN   ConSwap: byte           ;+037
        EXTRN   IdleInt: byte           ;+038
        EXTRN   fSharing: byte          ;+252
        EXTRN   User_SP: word           ;+264
        EXTRN   User_SS: word           ;+266
        EXTRN   SaveBX: word            ;+2CA
        EXTRN   SaveDS: word            ;+2CC
        EXTRN   restore_tmp: word       ;+2CE
        EXTRN   NSS: word               ;+2D0
        EXTRN   NSP: word               ;+2D2
        EXTRN   EXTOPEN_ON: byte        ;+2D6
        EXTRN   DOS34_FLAG: word        ;+2F1
        EXTRN   AuxStack: byte          ;+480
        EXTRN   DSKSTACK: byte          ;+600
        EXTRN   IOSTACK: byte           ;+780
        EXTRN   Printer_Flag: byte      ;+780
V86SDA  ENDS
;-----------------------------------------------------------------------
V86CODE SEGMENT
        assume  CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING

        EXTRN   DskStatChk:NEAR         ;MsCtrlc
        EXTRN   Sys_Return:NEAR         ;MsCode
        EXTRN   RMDevCheck:NEAR         ;Dev
        EXTRN   pJFNFromHandle:NEAR     ;Util
        EXTRN   $OpenExtended:NEAR      ;File


subttl  $Set_CTRL_C_Trapping -- En/Disable ^C check in dispatcher
page

; Inputs:
;       AL = 0 read ^C status, returns DL=0|1 break status
;       AL = 1 Set ^C status, DL = 0/1 for ^C off/on
;                       DL=0, BREAK=OFF
;                       DL=1, BREAK=ON
;       AL = 2 Set ^C status to contents of DL.  Output is old state.
;       AL = 3 Get CPSW state to DL        DOS 3.4  (accepted, does nothing)
;       AL = 4 Set CPSW state from DL      DOS 3.4  (accepted, does nothing)
;       AL = 5 get DOS boot drive to DL
;       AL = 6 Get version number
;        RETURNS:
;           BH = Minor version number
;           BL = Major version number
;           DL = DOS internal revision
;           DH = DOS type flags:
;              Bit 3   - DOS in ROM
;              Bit 4   - DOS in HMA
;              Bit 0-2, 5-7 - Reserved
;       AL > 6 invalid, returns AL=-1

;Note: the DOS version returned when AL=6 is the TRUE version of the
; operating system.  The INT 21H, AH=30H (GET DOS VERSION), can be told
; to report a "false" DOS version via setting the EXTENDED PROPERTIES
; for a specific application.


;               RESPONSE TO OPTION 0, GET BREAK STATUS
BREAK_BIT             EQU 1               ; LOW BIT IN DL
;                                         ; DL=1,BREAK=ON. DL=0,BREAK=OFF


public  $SET_CTRL_C_TRAPPING
$SET_CTRL_C_TRAPPING proc near
        ASSUME  CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
        .if     <AL a 6>
          mov     al,-1
        .else
          push    ds
          mov     ds,cs:[DosDseg]
          assume  ds:V86GROUP

          .select
          .when   <ZERO al> short         ;3300
            mov     dl,[CntCFlag]         ;Return the current break status

          .when   <AL eq 1> short         ;3301
            and     dl,BREAK_BIT          ;Save only the "break" bit
            mov     [CntCFlag],dl         ;3301h must preserve entry DL

          .when   <AL eq 2> short         ;3302
            and     dl,BREAK_BIT          ;Save only the "break" bit
            xchg    [CntCFlag],dl         ;Set new state as requested
                                          ;and return in DL the old value
;
;         .when   <AL eq 3> short         ;3303
;           MOV     DL,[CPSWSAVE]         ; DOS 3.4
;           MOV     [CPSWFLAG],DL         ; DOS 3.4 in case ABORT
;           mov     dl,CPSWFLAG           ; return CPSW state
;         .when   <AL eq 4> short         ;3304
;           PUSH    AX
;           MOV     AL,[CPSWSAVE]         ; DOS 3.4
;           MOV     [CPSWFLAG],AL         ; DOS 3.4 in case ABORT
;           POP     AX
;           PUSH    AX
;           CallInstall NLSInstall,NLSFUNC,0  ; NLSFUNC installed ?
;           CMP     al,-1
;           POP     AX
;           .if     nz                    ; not loaded,therefore ignore
;             mov     al,-1
;           .else
;             AND     DL,1                ; only 0 or 1
;             MOV     [CPSWFLAG],DL       ; set the flag
;             MOV     [CPSWSAVE],DL       ; save one copy
;           .endif
;

          .when   <AL eq 5> short         ;3305
            mov     dl,[BootDrive]        ;put boot drive in DL

          .when   <AL eq 6> short         ;3306
.errnz  rmm ge 0800h   ;internal revision must be less than 2048
            mov     dx,rmm                ; DL = DOS internal revision
                                          ;     also use DH bits 0,1,2.
      ;dos; .if <[DosHasHMA] ne 0> ;dos;
            mov     bx,cs          ;mvdm; ; DH = DOS type flags:
            .if     <bx eq -1>     ;mvdm; ; Bit 3=DOS in ROM (we have none)
              or      dh,10h              ; Bit 4=DOS in HMA
            .endif                        ; Bit 0-2, 5-7=Reserved (0)
            mov     bx,(MINOR_VERSION SHL 8) + MAJOR_VERSION
                                          ; BH=MINOR VERSION
                                          ; BL=MAJOR VERSION
          .endselect

          pop     ds
          assume  ds:nothing
        .endif

        jmp     command_exit

SetCtrlShortEntry:
        jmp     $SET_CTRL_C_TRAPPING

$SET_CTRL_C_TRAPPING endp
;----------------------------------------------------------------------



;----------------------------------------------------------------------
subttl  $Get_current_PDB -- Set/Get PDB value
page
;
; The following two routines are dispatched to directly with ints disabled
; immediately after the int 21h entry.  no DIS state is set.
;
; $Set_current_PDB takes BX and sets it to be the current process
;   *** THIS FUNCTION CALL IS SUBJECT TO CHANGE!!! ***

public  $SET_CURRENT_PDB
$SET_CURRENT_PDB proc near
        ASSUME  CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING

;------ Change OS/2 protect mode data
        push    es
        push    ax
        mov     es,BX
        SVC     SVC_DEMSETCURRENTPDB
        pop     ax
        pop     es

;------ Change V86 mode data
        push    ds
        mov     ds,cs:[DosDseg]
        assume  ds:V86GROUP
        mov     [CurrentPDB],BX
        pop     ds
        assume  ds:nothing
        jmp     Command_exit

$SET_CURRENT_PDB endp
;----------------------------------------------------------------------



;----------------------------------------------------------------------
;
; $get_current_PDB returns in BX the current process
;   *** THIS FUNCTION CALL IS SUBJECT TO CHANGE!!! ***
;
public  $GET_CURRENT_PDB
$GET_CURRENT_PDB proc near
        ASSUME  CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
        push    ds
        mov     ds,cs:[DosDseg]
        assume  ds:V86GROUP
        mov     BX,[CurrentPDB]
        pop     ds
        assume  ds:nothing
        jmp     Command_exit
$GET_CURRENT_PDB endp
;----------------------------------------------------------------------



subttl  SYSTEM_CALL proc - DosKrnl entry points
page
public  SYSTEM_CALL
SYSTEM_CALL proc near
        assume  cs:v86group,ds:nothing,es:nothing,ss:nothing


subttl  CALL_ENTRY - CPM call 5 worker
page
;----------------------------------------------------------------------
; An alternative method of entering the system is to perform a CALL 5
; in the program segment prefix with the contents of CL indicating what
; system call the user would like.  A subset of the possible system
; calls is allowed here; only the CPM-compatible calls may get
; dispatched.
;
; Sample usage:
;   mov  CL,0
;   call near [5]
;
; At PSP:[5] is a "CALL FAR" to here (CALL_ENTRY).  The stack looks
; like this:
;   return offset to user
;   return segment to users PSP (must be the same as user code).
;   return offset to users PSP
;
        public  CALL_ENTRY
CALL_ENTRY:                             ;System call entry point and dispatcher
        assume  cs:v86group,ds:nothing,es:nothing,ss:nothing

;------ Aviod interrupt problems because of the improper use of [User_SP]
        cli

;------ Fill in SaveDS
        push    ds
        mov     ds,cs:[DosDseg]
        assume  ds:V86GROUP
        pop     [SaveDS]

;------ get old values off stack
        pop     ax                      ; IP from the long call at 5
        pop     ax                      ; Segment from the long call at 5
        pop     [User_SP]               ; IP from the user call to CALL 5
; Note: Using [User_SP] as a temporary storage variable is very bad
; form.  If a LAN timer tick, or other event occurs this variable does
; not correctly reflect the state of affairs.  It is highly recommended
; that another, more appropriate variable be used instead.

;------ Re order the stack to simulate an interrupt 21.
        pushf                           ; Start re-ordering the stack
;dos;   cli     ;move above
        push    ax                      ; Save segment
        push    [User_SP]               ; Stack now ordered as if INT had been
                                        ; used.

;------ restore entry DS
        push    [SaveDS]
        pop     ds
        assume  ds:nothing

;------ Check for valid entry and continue if ok.
        .if     <CL be MAXCALL>
          mov     ah,cl
;dos;     jmp     short SavRegs
          jmp     short Command
        .endif

; The system call in AH is out of the range that we know how to handle.
; We arbitrarily set the contents of AL to 0 and IRET.  Note that we
; CANNOT set the carry flag to indicate an error as this may break some
; programs compatability.
;
BadCall:
        assume  cs:v86group,ds:nothing,es:nothing,ss:nothing
        xor     al,al
        jmp     COMMAND_EXIT
;----------------------------------------------------------------------

;----------------------------------------------------------------------
subttl  QUIT - Int 20h worker
page
; The Quit entry point is where all INT 20h's come from.  These are
; old-style exit system calls.  The CS of the caller indicates which
; Process is dying.  The error code is presumed to be 0.  We simulate
; an ABORT system call.
;
        public  QUIT
QUIT:
        assume  cs:v86group,ds:nothing,es:nothing,ss:nothing
        xor     ah,ah
;dos;   jmp     short SavRegs

;Real DOS jumps to "SavRegs".  I've chosen to jump to "Command" instead
;to include ALL proper int 21 processing steps.  At this time the only
;key statement we need is the CLI.  If someone has hooked int 20h and
;the interrupt flag is enabled when control reaches here, then the
;DosKrnl can crash below while changing the SS and SP if a timer tick
;(or any other interrupt event) occurs.
;----------------------------------------------------------------------

subttl  COMMAND - int 21h worker
page
;==============================================================================
;
; This is the normal INT 21 entry point.  We first perform a quick test
; to see if we need to perform expensive DOS-entry functions.  Certain
; system calls are done without interrupts being enabled.
;

        assume  CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
        public  COMMAND
COMMAND:                                ; Interrupt call entry point (INT 21H)

        cli

        cmp     ah,MaxCom
        ja      BadCall

        ; The following set of calls are issued by the server at
        ; *arbitrary* times and, therefore, must be executed on
        ; the user's entry stack and executed with interrupts off.

;dos;SavRegs:
        .if     <AH ae 33h>             ;=Set_CTRL_C_Trapping
          je      SetCtrlShortEntry

          .if     <AH be 62h>           ;=GetCurrentPSP
            je      $GET_CURRENT_PDB

            cmp     ah,51h              ;=GET_CURRENT_PDB
            je      $GET_CURRENT_PDB

            cmp     ah,50h              ;=SET_CURRENT_PDB
            je      $SET_CURRENT_PDB

          .endif
        .endif

;------ Preserve all user's registers on his own stack.
;dos4;  call    save_world
        push    es
        push    ds
        push    bp
        push    di
        push    si
        push    dx
        push    cx
        push    bx
        push    ax

;------ User's stack=
; flags  ÄÄ¿
; far     INT
;  retn  ÄÄÙ
; entry ES
; entry DS
; entry BP
; entry DI
; entry SI
; entry DX
; entry CX
; entry BX
; entry AX

;------ DS points to DosKrnl data
        mov     ax,ds
        mov     ds,cs:[DosDseg]
        assume  ds:V86GROUP
        mov     [SaveDS],AX
        mov     [SaveBX],BX

;------ Make a backup copy of User_SS,User_SP
        ; M043
        ; Note: Nsp and Nss have to be unconditionally initialized here
        ; even if InDOS is zero. Programs like CROSSTALK 3.7 depend on this!!!

        mov     AX,[User_SP]            ; Provide one level of reentrancy for
        mov     [Nsp],AX                ; int 24 recallability.
        mov     AX,[User_SS]
        mov     [Nss],AX

;------ allow redirection
        xor     AX,AX
        mov     [fSharing],AL

;------
        .if     <BIT <[IsWIN386]> nand 1> ; WIN386 patch.
          mov     [User_Id],ax         ;Do not update USER_ID if win386 present
        .endif

;------ Flag that we're in the DOS
        inc     [INDOS]

;------ Save user's stack
        mov     [user_SP],SP
        mov     [user_SS],SS

;------ Assign process id
        mov     ax,[CurrentPDB]         ; current process
        mov     [PROC_ID],ax            ; Assume local machine for the moment
        mov     ds,ax
        assume  ds:nothing              ;DS=CurrentPDB

;------ get the original entry AX in AX
        pop     ax
        push    ax

;------ save user stack in his area for later returns (possibly from EXEC)
        mov     word ptr ds:[PDB_User_stack],SP
        mov     word ptr ds:[PDB_User_stack]+2,SS

;------ Assign new SS, SP is now invalid (must have CLI above)
        mov     ss,cs:[DosDseg]
        assume  ss:V86GROUP






        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:V86GROUP
        ;ds=CurrentPDB
        ;es=entry ES
public  REDISP
REDISP:


        mov     sp,offset V86GROUP:AUXSTACK ; Enough stack for interrupts
        sti                             ; stack is in our space now...


;------ DBCS
        mov     bh,ds:[PDB_InterCon]
        mov     cs:[InterCon],bh        ;DOS uses SS: instead of CS: ???

;------ Assign DS the code segment
        MOV     BX,CS                   ;DOS 5 & 6 use SS instead of CS ???
        MOV     DS,BX
        assume  cs:V86GROUP,ds:V86GROUP,es:nothing,ss:V86GROUP

;------ AX=0, BX=entry AX
        xchg    ax,bx
;dos34; mov     al,[CPSWSAVE]           ;DOS 3.4 in case of ABORT
;dos34; mov     [CPSWFLAG],al           ;Code Page switching removed in DOS 4
        xor     ax,ax

;------ init some vars
;dos4;  mov     [Disk_full],al          ;not used since DOS 4
;dos4;  mov     [Act_page],-1           ;not used since DOS 4
        mov     [EXTOPEN_ON],al         ;clear extended open flag
        and     [DOS34_Flag], EXEC_AWARE_REDIR

        mov     [ConSwap],al            ; random clean up of possibly mis-set flags
        mov     [NoSetDir],al           ; set directories on search
        mov     [FailErr],al            ; FAIL not in progress

;------ MVDM specific hard error init
        mov     [vheVDM].vhe_fbMisc,al  ; no pending hard errors

        inc     ax
        mov     [IdleInt],al      ;=1   ; presume that we can issue INT 28
        xchg    AX,BX                   ; Restore Entry AX and BX = 1
        MOV     BL,AH
        SHL     BX,1                    ; 2 bytes per call in table
        CLD


; Since the DOS maintains mucho state information across system calls,
; we must be very careful about which stack we use.
;
; First, all abort operations must be on the disk stack.  This is due
; to the fact that we may be hitting the disk (close operations, flushing)
; and may need to report an INT 24.

        .if     <NONZERO AH>            ;=ABORT

          ; Second, PRINT and PSPRINT and the server issue GetExtendedError calls
          ; at INT 28 and INT 24 time.  This call MUST, therefore, use the AUXSTACK.

          CMP     AH,59h        ;=GetExtendedError
          JZ      short DISPCALL

          ; Old 1-12 system calls may be either on the IOSTACK (normal operation) or
          ; on the AUXSTACK (at INT 24 time).


          .if     <AH be 12>
            CMP     [ERRORMODE],0           ; Are we in an INT 24?
            JNZ     short DISPCALL          ; Stay on AUXSTACK if INT 24.
            MOV     SP,OFFSET V86GROUP:IOSTACK
            JMP     SHORT DISPCALL
          .endif

        .endif

        ; We are on a system call that is classified as "the rest".  We place
        ; ourselves onto the DSKSTACK and away we go.  We know at this point:
        ;
        ;   o   An INT 24 cannot be in progress.  Therefore we reset errormode and
        ;       wperr
        ;   o   That there can be no critical sections in effect.  We signal the
        ;       server to remove all the resources.

DSKROUT:
        MOV     [USER_IN_AX],AX         ; Remember what user is doing
        MOV     [EXTERR_LOCUS],errLOC_Unk ; Default
        MOV     [ERRORMODE],0           ; Cannot make non 1-12 calls in
        MOV     [WPERR],-1              ; error mode, so good place to make

;------ Release all resource information
        push    ax
        mov     ah,82h
        int     2Ah  ;=int_IBM
        pop     ax


; Since we are going to be running on the DSKStack and since INT 28 people
; will use the DSKStack, we must turn OFF the generation of INT 28's.

        mov     [IdleInt],0
        mov     sp,offset V86GROUP:DSKSTACK
        .if     <<[CNTCFLAG]> ne 0>     ; Extra ^C checking is disabled
          push    ax
          call    DskStatChk
          pop     ax
        .endif



DISPCALL:

;------ VPL Idle detection, Note useful work when not polling
        .if     <BX a  <2*0Ch>> and     ; bx = 2*function number
        .if     <BX ne <2*2Ch>> and     ; get time call?
        .if     <BX ne <2*2Ah>>         ; get date call?
          mov     [VDMNotBusy],0        ; Avoid idle detection sleep
        .endif

;------
        mov     bx,Dispatch[BX]
        xchg    bx,[SaveBX]
        mov     ds,[SaveDS]
        assume  ds:nothing

        call    cs:[SaveBX]

        ;
        ; M068
        ;
        ; The EXEXA20OFF bit of DOS_FLAG will now be unconditionally cleared
        ; here. Please see under M003, M009 and M068 tags in dossym.inc
        ; for explanation. Also NOTE that a call to ExecReady (ax=4b05) will
        ; return to LeaveDos and hence will not clear this bit. This is
        ; because this bit is used to indicate to the next int 21 call that
        ; the previous int 21 was an exec.
        ;
        ; So do not add any code between the call above and the label
        ; LeaveDOS if it needs to be executed even for ax=4b05
        ;

        and     cs:[DOS_FLAG], NOT EXECA20OFF


public  LeaveDos
LeaveDos:
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
        cli

        mov     ds,cs:[DosDseg]
        assume  ds:V86GROUP

;dos6;  .if     <[A20OFF_COUNT] ne 0>
;dos6;    mov     bx,[A20OFF_PSP]
;dos6;    .if     <BX eq [CurrentPDB]>
;dos6;      dec     [A20OFF_COUNT]
;dos6;      push    ds
;dos6;      mov     bx,offset disa20_iret
;dos6;      push    bx
;dos6;      retf
;dos6;    .endif
;dos6;  .endif

        dec     [INDOS]
        mov     SS,[user_SS]
        mov     SP,[user_SP]

        mov     BP,SP
        mov     byte ptr [BP].user_AX,AL

;------ restore User_SS,User_SP to entry values
        mov     AX,[NSP]
        mov     [user_SP],AX
        mov     AX,[NSS]
        mov     [user_SS],AX

;------ restore registers
        POP     AX
        POP     BX
        POP     CX
        POP     DX
        POP     SI
        POP     DI
        POP     BP
        POP     DS
        POP     ES

;------ return to the caller
public  COMMAND_EXIT
COMMAND_EXIT:
        iret
        db      00                     ;add hex zero for raprater app   ;82929;

SYSTEM_CALL endp
;-----------------------------------------------------------------------


;-----------------------------------------------------------------------
; restore_world restores all registers ('cept SS:SP, CS:IP, flags) from
; the stack prior to giving the user control
public  restore_world
restore_world   proc    near
        ASSUME  cs:v86group,DS:NOTHING,ES:NOTHING,SS:NOTHING
        POP     cs:[restore_tmp]
        POP     AX
        POP     BX
        POP     CX
        POP     DX
        POP     SI
        POP     DI
        POP     BP
        POP     DS
        POP     ES
        jmp     cs:[restore_tmp]
restore_world   endp


public  restore_user_world
restore_user_world proc near
        ASSUME  cs:v86group,DS:NOTHING,ES:NOTHING,SS:NOTHING
;dos5;;;        mov     es,cs:[DosDseg]
;dos5;;;        assume  es:V86GROUP
;dos5;;;        POP     es:[restore_tmp]
;dos5;;;        POP     AX
;dos5;;;        POP     BX
;dos5;;;        POP     CX
;dos5;;;        POP     DX
;dos5;;;        POP     SI
;dos5;;;        POP     DI
;dos5;;;        POP     BP
;dos5;;;        POP     DS
;dos5;;;        jmp     es:[restore_tmp]
restore_user_world endp
;-----------------------------------------------------------------------



;-----------------------------------------------------------------------
; save_world saves complete registers on the stack
public  save_world
save_world proc near
        ASSUME  cs:v86group,DS:NOTHING,ES:NOTHING,SS:NOTHING
        POP     cs:[restore_tmp]
        PUSH    ES
        PUSH    DS
        PUSH    BP
        PUSH    DI
        PUSH    SI
        PUSH    DX
        PUSH    CX
        PUSH    BX
        PUSH    AX
        jmp     cs:[restore_tmp]
save_world endp


public  save_user_world
save_user_world proc near
        ASSUME  cs:v86group,DS:NOTHING,ES:NOTHING,SS:NOTHING
;dos5;;;        mov     es,cs:[DosDseg]
;dos5;;;        assume  es:V86GROUP
;dos5;;;        POP     es:[restore_tmp]
;dos5;;;        PUSH    DS                      ;bp+18
;dos5;;;        PUSH    BP                      ;bp+16
;dos5;;;        PUSH    DI                      ;bp+14
;dos5;;;        PUSH    SI                      ;bp+12
;dos5;;;        PUSH    DX                      ;bp+10
;dos5;;;        PUSH    CX                      ;bp+8
;dos5;;;        PUSH    BX                      ;bp+6
;dos5;;;        PUSH    AX                      ;bp+4
;dos5;;;        PUSH    es:[restore_tmp]        ;bp+2
;dos5;;;
;dos5;;;        push    bp                      ;bp+0
;dos5;;;        mov     bp,sp
;dos5;;;        mov     es,[bp+20]              ;ES was pushed before call
;dos5;;;        assume  es:nothing
;dos5;;;        pop     bp
;dos5;;;        ret
save_user_world endp
;-----------------------------------------------------------------------




;-----------------------------------------------------------------------
; get_user_stack returns the user's stack (and hence registers) in DS:SI
public  get_user_stack
get_user_stack  proc    near
        ASSUME  cs:v86group,DS:NOTHING,ES:NOTHING,SS:NOTHING
        mov     ds,cs:[DosDseg]
        assume  ds:V86GROUP
        LDS     SI,dword ptr cs:[user_SP]
        assume  ds:nothing
        ret
get_user_stack  endp
;-----------------------------------------------------------------------



;-----------------------------------------------------------------------
;***    $Generic - Make calls to selected OS/2 workers
;
;       $Generic calls selected OS/2 workers to perform services for
;       OS/2 utilities via utilapi.
;       This is an Int21 dispatcher routine.
;
;       ENTRY   BX = ordinal (see ordinal.inc)
;               CX = signature (636Ch or 'cl')
;               DS = callers data segment
;               ES:DI -> Stack frame
;
;       EXIT    'NC'  - No Error
;
;               'C'   - Error
;
;       NOTE
;               $Generic is also a MVDM generic function. For such a case
;               BX should be zero and DX gives the sub function.Following
;               is the current usage:
;
; AH=64h CX='cl' BX=0   DX=0                Pre-Exec notify
; AH=64h CX='cl' BX=0   DX=1 ES:DI=title    Set VDM title
; AH=64h CX='cl' BX=0   DX=2 ES:DI=title    Get VDM title
; AH=64h CX='cl' BX=0   DX=3                Get last drive value         ret:AL
; AH=64h CX='cl' BX=0   DX=4                Get JFT size, FILES parm.    ret:AX
; AH=64h CX='cl' BX=0   DX=5   DI=handle    Get SFT_flags2               ret:AX
; AH=64h CX='cl' BX=0   DX=6 ES:DI=file DS=base load a new symbol file
; AH=64h CX='cl' BX=0   DX=7                Get WinOS2 call gate addr    ret:AX
; AH=64h CX='cl' BX=0   DX=8                Display WinOs2 black hole msg
;
; AH=64h CX='cl' BX=ord DS=seg ES:DI=frame  DosQFSAttach
; AH=64h CX='cl' BX=ord DS=seg ES:DI=frame  DosEditName
; AH=64h CX='cl' BX=ord DS:DX=asciiz        DosForceDelete
; AH=64h CX='cl' BX=ord (DS:SI,ES:DI,DX,AL) Dos32CreateEventSem
; AH=64h CX='cl' BX=ord (DS:SI,ES:DI)       Dos32OpenEventSem
; AH=64h CX='cl' BX=ord (DX:SI)             Dos32CloseEventSem
; AH=64h CX='cl' BX=ord (DX:SI,ES:DI)       Dos32ResetEventSem
; AH=64h CX='cl' BX=ord (DX:SI)             Dos32PostEventSem
; AH=64h CX='cl' BX=ord (DS:SI,ES:DI)       Dos32OpenMuxWaitSem
; AH=64h CX='cl' BX=ord (DX:SI)             Dos32WaitMuxWaitSem
; AH=64h CX='cl' BX=ord (DX:SI,ES:DI,AL)    Dos32CloseMuxWaitSem
;
;
;


public  $Set_Printer_Flag
$Set_Printer_Flag proc near
        ASSUME  cs:V86group,DS:NOTHING,ES:NOTHING,SS:NOTHING

        .if     <CX ne 'cl'>
          ;This is a serious bug caused by FAPI.  FAPI issues an int 21h
          ;ah=64h instead of int 21h ah=6Ch when doing a DosOpen API call.
          ;Defect #56652 has been openned against FAPI to fix this bug.
          jmp     $OpenExtended

          ;push   ds
          ;mov    ds,cs:[DosDseg]
          ;assume ds:V86GROUP
          ;mov    [Printer_flag],al
          ;pop    ds
          ;assume ds:nothing
          ;ret
        .endif

        .if     <ZERO bx>

          .if     <ZERO dx>
            ;BX=0, DX=0, CX='cl'
            mov     [command_exec],1        ; PRE_EXEC notification
            clc
            jmp     short end_special
          .endif

          .if     <DX eq 3>
            ;BX=0, DX=3, CX='cl'
            mov     al,[CDScount]           ; al = lastdrive value
            clc
            jmp     short end_special
          .endif

          .if     <DX eq 5>
            mov     bx,di
            call    pJFNFromHandle          ; get address of JFN entry
            jc      short end_special
            mov     bl,byte ptr es:[di]     ; get the VSFN
            xor     bh,bh
            call    RMDevCheck        ; (BX) = real handle if OS2 dev or file
            ;return ZF CY = file
            ;       ZF NC = OS/2 device
            ;       NZ NC = DOS device
            .if     nz
              mov     ax,1
              stc
              jmp     short end_special
            .endif
            mov     di,bx
            xor     bx,bx
          .endif

          .if     <DX eq 8>
            EXTRN   TXT_MSG_STAND_BY: byte
            call    Get_user_stack
            assume  ds:nothing
            mov     [si].user_DS,cs
            mov     [si].user_DX,offset V86GROUP:TXT_MSG_STAND_BY
          .endif

        .endif

        SVC     SVC_DEMGENERIC

end_special:
        jmp     Sys_Return              ; exit processing

$Set_Printer_Flag endp



V86CODE ENDS
        END
