page    ,132
TITLE   demsvc - DOS Emulation SVC Entry Points
.386p

;***EM  demsvc.asm
;
;       SCCSID = @(#)demsvc.asm 6.8 92/03/21
;
;       SUMMARY
;           DOS Emulation SVC routines and support
;
;       NOTES
;           These routines are invoked by executing the SVC macro
;           while in Virtual 8086 mode.
;
;       REVISIONS
;
;Local  DCR/PTR
;Tag    PTR            Who          When          What
;                      danno        31-Jan-1989   Created for MVDM
; 6.4   CP20 B722937   Jeff Muir    24-May-1991   DEMGETLOGICALDRIVECNT SVC added
; Bx001 CP20 B723599   Bill Madden  01-Jun-1991   Save segment of doskrnl in
;                                                 DemSetV86KernelAddr
; 1.5   r206 p057183   J. Muir      12/21/92      Set tick count for settime
;62131  r206 62131     C. Romero    03/18/93      Allow winfile to copy EAs
;---------------------------------------------------------------------- ;71744;
; 93Jul16 - G.L.Fulk                                                    ;71744;
; Change DemSleep(0:0) back to calling DosSleep as well as Yield Time   ;71744;
; Slice.  DOSKEY was pegging PULSE because of this.                     ;71744;
;---------------------------------------------------------------------- ;71744;
; 93Aug20 - G.L.Fulk                                                    ;72761;
; Add SVCNOP.                                                           ;72761;
;----------------------------------------------------------------------
; 94Sep19 - bjn
; Change segment names for page tuning
;----------------------------------------------------------------------
;  11/27/95 MLM         Defect 72417                                    ;72417
;  moved from PTDA to TCB:  NoSetDir                                    ;72417
;-----------------------------------------------------------------------;72417
; 04/11/96 - V3.2SEN00   Defect  151783
; Add INT10 service routine
;----------------------------------------------------------------------

INCL_NONE               equ     1
INCL_DEF                equ     1       ; include typedef macros
INCL_MVDMTYPES          equ     1
INCL_NOCOMMON           equ     1
INCL_DOSDATETIME        equ     1
INCL_VDH                equ     1
INCL_VDHVKBD            equ     1
INCL_VKBDINTERFACES     equ     1
INCL_ROMBIOS            equ     1

.xlist
        include dosseg.inc
        include mvdm.inc
        include osmaca.inc
        include dossymc.inc
        include sigdef.inc
        include except.inc
        include kmode.inc
        include demsvc.inc
        include mi.inc
        include infoseg.inc
        include osconst.inc
        include pgexport.inc
        include tkexport.inc
        include screen.inc
        include dirent.inc
        include curdir.inc
        include find.inc
        include sem.inc
        include vmexport.inc
        include tkptda.inc
        include sft.inc
        include error.inc
        include bsedos.inc
        include basemid.inc
        include harderr.inc
        include doshlp.inc
        include struc30.inc
.list

EXTERR_COPY_SIZE        equ     5

        CpuMode 386

        EXTRN32         em86opInvalid
;72761; ReferGlobal     MyNum,WORD
;72761; ReferGlobal     MyName,BYTE
;72761; ReferGlobal     Resched,BYTE
        ReferGlobal     SISData,BYTE
        ReferGlobal     DHF,DWORD
        ReferGlobal     NumIO,BYTE              ;JDM   Block Device SVC call
        ReferFlat       _Int13TCBNumber,WORD                            ;@xxxx
        EXTRN16         RetryWait
        EXTRN16         w_SetDateTime
        EXTRN16         w_Get_Version
        EXTRN16         GetVisDrv
        EXTRN16         w_SetVerify
        EXTRN16         DOS_AbortVDM
        EXTRN16         DOS_Abort
        EXTRN16         HardError
        EXTRN16         w_JSA
        EXTRN16         SFFromHandle

DefCode IMPORT, SWAP
DefFn   demMapESDI
EndCode

DefCode IMPORT, GLOBAL
DefFn   HexToAscii32
EndCode

DefCode IMPORT, GLOBAL, C
;72761; DefFn   TKYield
DefFn   TKYieldTimeslice                                                ;59378;
DefFn   TKDieSoonPTDA
DefFn   VDMInt13Request                                                  ;@xxxx
DefFn   VDMInt10Request                                 ;V3.2SEN00
EndCode

DefCode IMPORT, GLOBAL, PASCAL
DefFn   VDHPopStack
DefFn   VDMMPDBChange
DefFn   VDMMPDBDestroy
DefFn   VDHOpenVDD
DefFn   VDHRequestVDD
DefFn   demProcessEntries
EndCode

DefData IMPORT, GLOBAL, C
PVOID   pPTDACur
PVOID   pTCBCur
PVOID   anpfnVPL                                ; VPL Idle detection
PSZ     pszVpl                                  ; VPL Idle detection
EndData

DefData IMPORT, INSTANCE, C
PVOID   pvheVDM
EndData

DefData EXPORT, SWAPINST, C
USHORT  segV86Kernel,-1                     ; safety check for SVC opcode
EndData

DefData PRIVATE, SWAPINST
_BYTE   DummyExtErr,,EXTERR_COPY_SIZE
_BYTE   DummyPDB,0,2                                                    ;71744;
ALIGN 4
PVOID   pV86ExtErr,<offset FLAT:DummyExtErr>  ;extended error addresses ;71744;
        PUBLIC  _pV86CurrentPDB                                    ;@V3.2SEN00
        _pV86CurrentPDB label dword                                ;@V3.2SEN00
PVOID   pV86CurrentPDB,<offset FLAT:DummyPDB>                           ;71744;
EndData

        FARCODE HIGH32
DefCode PRIVATE, GLOBAL, PASCAL

;***    Dispatch Table Macros
;

SVC_COUNT   =     0

;***    ?ToUpper - Converts string to upper-case, returned in ?upper
;

?ToUpper macro s
          ?upper equ <>
          irpc x,<s>
            if '&x' GE 'a'
              if '&x' LE 'z'
                ?t1 substr <ABCDEFGHIJKLMNOPQRSTUVWXYZ>,'&x'-'a'+1,1
                ?upper catstr ?upper,?t1
              else
                ?upper catstr ?upper,<&x>
              endif
            else
              ?upper catstr ?upper,<&x>
            endif
          endm
        endm

;***    DispSVC - Declare dispatch table entry for 32-bit entry point
;

DDOFF32 macro   name
        DD  OFFSET FLAT:&name
ENDM

DispSVC macro   lbl,lcl,actual
local   act
ifb    <actual>
act EQU <lbl>
else
act EQU <actual>
endif

ifb     <lcl>
        EXTRN32 %&act
endif
        DDOFF32 %&act
if2
?ToUpper    SVC_&lbl
.errnz  ?upper - SVC_COUNT
endif
SVC_COUNT = SVC_COUNT + 1
        endm

;***LD  apdemSVC - DOS Emulation Dispatch Table (0:32)
;
;       This table is an array of flat addresses of the entry
;       points to the various DOS Emulation SVC routines.
;       This table includes only those routines which have
;       0:32 entry points.
;
;       This array is in a code object.
;
;       The format of the macro is:
;
;       DispSVC demName,local
;
;       The procedure must lie in the HIGH32CODE segment and must
;       be a 32-bit NEAR procedure.
;
;       If "local" is omitted, the procedure is assumed to be
;       external.
;       54735
        align  4
Public  _apdemSVC
_apdemSVC        LABEL   DWORD
        DispSVC demDup                          ;00h
        DispSVC demInternalError,local          ;01h
        DispSVC demTerminate,local              ;02h
        DispSVC demClose                        ;03h
        DispSVC demDiskReset                    ;04h
        DispSVC demSetCurrentPDB,local          ;05h
        DispSVC demSetDefaultDrive              ;06h
        DispSVC demSetDTA                       ;07h
        DispSVC demGetVersion,local             ;08h
        DispSVC demWrite                        ;09h
        DispSVC demSetDate,local                ;0Ah
        DispSVC demSetTime,local                ;0Bh
        DispSVC demQueryDate,local              ;0Ch
        DispSVC demQueryTime,local              ;0Dh
        DispSVC demRead                         ;0Eh
        DispSVC demChgFilePtr                   ;0Fh
        DispSVC demDeleteDir                    ;10h
        DispSVC demCreateDir                    ;11h
        DispSVC demQueryCurrentDir              ;12h
        DispSVC demSetCurrentDir                ;13h
        DispSVC demFileTimes                    ;14h
        DispSVC demCommit                       ;15h
        DispSVC demFindFirstFCB                 ;16h
        DispSVC demFindNextFCB                  ;17h
        DispSVC demGetDriveFreespace            ;18h
        DispSVC demFindFirst                    ;19h
        DispSVC demChMod                        ;1Ah
        DispSVC demNameTrans                    ;1Bh
        DispSVC demOpen                         ;1Ch
        DispSVC demDeleteFCB                    ;1Dh
        DispSVC demRenameFCB                    ;1Eh
        DispSVC demDelete                       ;1Fh
        DispSVC demRename                       ;20h
        DispSVC demGSetMediaID                  ;21h
        DispSVC demIOCTL                        ;22h
        DispSVC demGetDriveInfo                 ;23h
        DispSVC demExtInfo                      ;24h
        DispSVC demFCBOpen                      ;25h
        DispSVC demFCBIO                        ;26h
        DispSVC demFCBClose                     ;27h
        DispSVC demFCBLength                    ;28h
        DispSVC demGetBaseName                  ;29h
        DispSVC demDupJFT                       ;2Ah
        DispSVC demGetVisDrv,local              ;2Bh
        DispSVC demSetWriteVerify,local         ;2Ch
        DispSVC demFindNext                     ;2Dh
        DispSVC demCreateNew                    ;2Eh
        DispSVC demCreateTemp                   ;2Fh
        DispSVC demSetV86KernelAddr,local       ;30h
        DispSVC demMakeFcb                      ;31h
        DispSVC demGeneric                      ;32h
        DispSVC demDosAbort,local               ;33h
        DispSVC demYield,local                  ;34h
        DispSVC demSleep,local                  ;35h
        DispSVC demInitNLS                      ;36h
        DispSVC demSetCodePage                  ;37h
        DispSVC demGetCountryInfo               ;38h
        DispSVC demLockOper                     ;39h
        DispSVC demEnumAttrib                   ;3Ah
        DispSVC demQMaxEASize                   ;3Bh
        DispSVC demGetDPB                       ;3Ch
        DispSVC demAbsDrd                       ;3Dh
        DispSVC demAbsDwrt                      ;3Eh
        DispSVC demExtHandle                    ;3Fh
        DispSVC demJSA,local                    ;40h
        DispSVC demVplCallibrate,local          ;41h
        DispSVC demGetMessage,local             ;42h
        DispSVC demSetTitle                     ;43h
        DispSVC demSetEAField                   ;44h
        DispSVC demQNMPInfo                     ;45h
        DispSVC demQNMPHandState                ;46h
        DispSVC demSetNMPHandState              ;47h
        DispSVC demPeekNMP                      ;48h
        DispSVC demTransactNMP                  ;49h
        DispSVC demCallNMP                      ;4Ah
        DispSVC demWaitNMP                      ;4Bh
        DispSVC demRawReadNMP                   ;4Ch
        DispSVC demRawWriteNMP                  ;4Dh
        DispSVC demSpecialEntries,local         ;4Eh
        DispSVC demGetLogicalDriveCnt,local     ;4Fh    ;6.4 added 05/22/91 JDM
        DispSVC demVDMInt13Request,local        ;50h    ;@xxxx
        DispSVC demGetCDS,local                 ;51h
        DispSVC demGetSFT,local                 ;52h
        DispSVC demBlockDD,local                ;53h
        DispSVC demCopyEAs                      ;54h     62131
        DispSVC demSVCNOP,local                 ;55h
        DispSVC demVDMInt10Request,local        ;56h    ;@V3.2SEN00

;***EP  DEMDispatch - Transfer control to the indexed SVC routine
;
;       ENTRY
;           EAX
;               client's EAX register
;           EBX
;               address of the client register frame (VSF)
;           EDX
;               client's EDX register
;           EDI
;               SVC Index
;
;           NOTE: client's CS:IP already adjusted past the "SVC" instruction
;
;       EXIT
;           SUCCESS
;               VSF updated according to SVC
;
;       CONTEXT
;           Called in Kernel from 8086 emulation component
;           Executes in Kernel
;
;       STEPS
;           if (vsf_cs = segV86Kernel)
;               if (AL < cdemSVC32)
;                   call apdemSVC[AL]
;               else
;                   jump to invalid opcode
;           else
;               jump to invalid opcode
;           Copy AX and arithmetic flags to VSF
;
;       CALLS
;           (See dispatch table)
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING
        align  4

Procedure DEMDispatch,near
        .if     <edi ae SVC_COUNT>
          jmp     em86opInvalid                 ; invalid op if bad SVC  ;@xxxx
        .endif
dmd10:
        push    edi
        mov     esi,[pV86ExtErr]
        mov     edi,[pPTDACur]
        cld
        add     edi,ExtErr_Locus
.errnz  EXTERR_COPY_SIZE ne 5
        movsb
        xor     ecx,ecx                         ; (ECX) = 0
        movsd
        pop     edi

;       (EAX) = client's EAX register
;       (EBX) = PVSF
;       (ECX) = 0
;       (EDX) = client's EDX register
;       (EDI) = SVC index
;       (FLAGS) = cld

;------ setup PTDA (Per Task Data Area)
                                                ;72417 moved from PTDA to TCB
        mov     esi,[pTCBCur]                   ; (ESI) = PTDA pointer
        mov     [esi].TCBNoSetDir,cl
                                                ;72417 end

;------ setup TCB (Thread Control Block)
        mov     esi,[pTCBCur]                   ; (ESI) = TCB pointer
        mov     [esi].TCBFailErr,cx
        mov     [esi].TCBJfnFlag,cl
        mov     [esi].TCBMiscFlags,cl

;------ Look for change in user's CurrentPDB
        mov     esi,[pV86CurrentPDB]
        or      cx,[esi]
        .if     nz                      ;skip if == 0
          mov     esi,[pPTDACur]
          .if     <<[esi].CurrentPDB> ne cx>
            call    Change_the_PDB
          .endif
        .endif

;------ dispatch for worker
        push    ebx                             ; save VSF pointer
        push    edi
        call    _apdemSVC[edi*type _apdemSVC]    ; make the call
        assume  ds:nothing,es:nothing
        FlatContext <ds,es>,ecx
        assume  DS:FLAT,ES:FLAT
        pushfd

        mov     esi,[pTCBCur]                                           ;@xxxx
        push    eax                             ; Dont corrupt VSF      ;@xxxx
        mov     ax, [esi].TCBNumber             ; flags & ax on VDM     ;@xxxx
        cmp     ax, _Int13TCBNumber             ; INT 13 requests       ;@xxxx
        pop     eax                                                     ;@xxxx
        .if     z                                                       ;@xxxx
          popfd                                                         ;@xxxx
          pop     edi                                                   ;@xxxx
          pop     ebx                                                   ;@xxxx
          ret                                                           ;@xxxx
        .endif

        mov     esi,[pPTDACur]
        .if     <BIT <[esi].ptda_ForcedActions> nand TK_FF_RTRY>
          popfd
          pop     edi
          pop     ebx
          mov     [ebx].vsf_ax,ax
          lahf
          mov     esi,[pPTDACur]
          mov     [ebx].vsf_flag.lobyte,ah
          mov     edi,[pV86ExtErr]
          add     esi,ExtErr_Locus
          .errnz  EXTERR_COPY_SIZE ne 5
          movsb
          movsd
          ret
        .endif

        and     [esi].ptda_ForcedActions,not TK_FF_RTRY
        CALL16  RetryWait
        popfd
        pop     edi
        pop     ebx
        mov     eax,[ebx].vsf_eax
        mov     edx,[ebx].vsf_edx
        jmp     dmd10
EndProc DEMDispatch
        align 4
Procedure demSVCNOP,near
        ret
EndProc demSVCNOP

;***LP  demVDMInt13Request - Route request from INT_13 mini-VDM          ;@xxxx
;                                                                        ;@xxxx
;       ENTRY                                                            ;@xxxx
;           AX                                                           ;@xxxx
;               Termination code (returned to parent)                    ;@xxxx
;                                                                        ;@xxxx
;       EXIT                                                             ;@xxxx
;           Nothing returned.                                            ;@xxxx
;                                                                        ;@xxxx
;       CONTEXT                                                          ;@xxxx
;           Called from Virtual Mode                                     ;@xxxx
;           Executes in Kernel                                           ;@xxxx
;                                                                        ;@xxxx
;       STEPS                                                            ;@xxxx
;           Flag process for termination                                 ;@xxxx
;                                                                        ;@xxxx
;       NOTES                                                            ;@xxxx
;                                                                        ;@xxxx
;                                                                        ;@xxxx
;       WARNINGS                                                         ;@xxxx
;           None                                                         ;@xxxx
;                                                                        ;@xxxx
;       CALLS                                                            ;@xxxx
;                                                                        ;@xxxx
;       USES                                                             ;@xxxx
;           EAX,ECX,EDX                                                  ;@xxxx
;                                                                        ;@xxxx
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING     ;@xxxx
                                                                         ;@xxxx
Procedure demVDMInt13Request,near                                        ;@xxxx
        movzx   eax,ax                                                   ;@xxxx
        CCALL32 VDMInt13Request, <>                                      ;@xxxx

        clc
        ret                                                         ;@xxxx
EndProc   demVDMInt13Request                                        ;@xxxx
                                                                    ;@xxxx
                                                                    ;@V3.2SEN00
                                                                    ;@V3.2SEN00
;***LP  demVDMInt10Request - Route request from INT_10 mini-VDM     ;@V3.2SEN00
;                                                                   ;@V3.2SEN00
;       ENTRY                                                       ;@V3.2SEN00
;           AX                                                      ;@V3.2SEN00
;               Termination code (returned to parent)               ;@V3.2SEN00
;                                                                   ;@V3.2SEN00
;       EXIT                                                        ;@V3.2SEN00
;           Nothing returned.                                       ;@V3.2SEN00
;                                                                   ;@V3.2SEN00
;       CONTEXT                                                     ;@V3.2SEN00
;           Called from Virtual Mode                                ;@V3.2SEN00
;           Executes in Kernel                                      ;@V3.2SEN00
;                                                                   ;@V3.2SEN00
;       STEPS                                                       ;@V3.2SEN00
;           Flag process for termination                            ;@V3.2SEN00
;                                                                   ;@V3.2SEN00
;       NOTES                                                       ;@V3.2SEN00
;                                                                   ;@V3.2SEN00
;                                                                   ;@V3.2SEN00
;       WARNINGS                                                    ;@V3.2SEN00
;           None                                                    ;@V3.2SEN00
;                                                                   ;@V3.2SEN00
;       CALLS                                                       ;@V3.2SEN00
;                                                                   ;@V3.2SEN00
;       USES                                                        ;@V3.2SEN00
;           EAX,ECX,EDX                                             ;@V3.2SEN00
;                                                                   ;@V3.2SEN00
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING;@V3.2SEN00
                                                                    ;@V3.2SEN00
Procedure demVDMInt10Request,near                                   ;@V3.2SEN00
        movzx   eax,ax                                              ;@V3.2SEN00
        CCALL32 VDMInt10Request, <>                                 ;@V3.2SEN00
                                                                    ;@V3.2SEN00
        clc                                                         ;@V3.2SEN00
        ret                                                         ;@V3.2SEN00
EndProc   demVDMInt10Request                                        ;@V3.2SEN00
                                                                    ;xxxx
EndCode                                                             ;xxxx
                                                                    ;@xxxx
DefCode PRIVATE, SWAP, PASCAL                                       ;@xxxx

SWAP32_27 segment
;***LP  demTerminate - Terminate the VDM
;
;       ENTRY
;           AX
;               Termination code (returned to parent)
;
;       EXIT
;           Nothing returned.
;
;       CONTEXT
;           Called from Virtual Mode
;           Executes in Kernel
;
;       STEPS
;           Flag process for termination
;
;       NOTES
;           The process cleanup is actually performed by demStop, which
;           closes files in the real handle table and releases our
;           GDT selectors.  This routine is also called by demInternalError
;           so we can't accept parameters in the VSF.
;
;       WARNINGS
;           None
;
;       CALLS
;
;       USES
;           EAX,ECX,EDX
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure demTerminate,near
        movzx   eax,ax
        CCALL32 TKDieSoonPTDA, <[pPTDACur], eax, TC_NORMAL, 0>
        ret
EndProc   demTerminate
SWAP32_27 ends

;***LP  demInternalError - Abnormally Terminate the VDM
;
;       ENTRY
;           All V86 registers from the VSF
;           VSF(SS:SP)
;               point to seg:offset of termination message
;               NULL --> no message
;
;       EXIT
;           Nothing returned.
;
;       CONTEXT
;           Called from Virtual Mode
;           Executes in Kernel
;
;       STEPS
;           Display Popup
;           Flag process for termination
;
;       NOTES
;           This routine is called when an inconsistency is detected
;           in the V86 structures.  Such an inconsistency could be
;           caused by an errant application, so we only terminate the
;           VDM and not the entire system.  In the production system,
;           there is no error text produced, except that an internal
;           error is detected.  In a debug system, the specified
;           message text is also displayed.  In both cases, all V86
;           register contents are displayed.
;
;       WARNINGS
;           None
;
;       CALLS
;           demTerminate
;
;       USES
;           EAX,ECX,EDX
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

Procedure demInternalError,near

LocalVar  die_vp, DWORD
LocalVar  die_buf, 100

        EnterProc

;------ Put CS:IP into message buffer
        SSToDS  edi,[die_buf]

        mov     al,'&'
        stosb

        mov     ax,[ebx].vsf_cs
        call    HexToAscii32

        mov     al,':'
        stosb

        mov     ax,[ebx].vsf_ip
        call    HexToAscii32

        xor     al,al
        stosb

;------ Get internal error message address
        SSToDS  esi,[die_vp]

        PCall   VDHPopStack, <4, esi>

        movzx   esi,[die_vp].Segmt
        movzx   ecx,[die_vp].Offst
        shl     esi,4
        add     esi,ecx                 ; (ESI) = source of string
        mov     ecx,80

;------ Copy internal error message
        .repeat
          lodsb
          stosb
          or      al,al
        .loop   nz

        xor     al,al
        stosb

;------ Allow only abort from the hard error daemon

        mov     ebx,[pTCBCur]
        mov     ecx,2
        mov     [ebx].TCBAllowed,ALLOWED_ABORT
        mov     edx,MSG_INTERNAL_ERROR
        SSToDS  esi,[die_buf]

;       (DX) = message number
;       (CX) = number of replacement strings
;       (DS:ESI) = pointer to replacement strings

        mov     eax,HEMessage           ; generate an hard error
        push    ds
        push    es
        CALL16  HardError
        pop     es
        pop     ds
        xor     eax,eax
        call    demTerminate
        LeaveProc
        ret
EndProc   demInternalError

SWAP32_20 segment
;***LP  demSetCurrentPDB - Set Address of Current PDB
;
;       ENTRY
;           EBX
;               Address of VSF
;           VSF(ES)
;               Segment of Current PDB
;
;       EXIT
;           Nothing returned.
;
;       CONTEXT
;           Called from Virtual Mode
;           Executes in Kernel
;
;       STEPS
;
;       NOTES
;           None
;
;       WARNINGS
;           None
;
;       CALLS
;
;       USES
;           ESI, ECX
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

align  4
Procedure demSetCurrentPDB,near
        movzx   ecx,[ebx].vsf_es
        mov     esi,[pPTDACur]
Change_the_PDB:
        mov     [esi].CurrentPDB,cx
        PCall   VDMMPDBChange, <ecx>    ; call VDM Manager for VDM_PDB_CHANGE
        ret
EndProc   demSetCurrentPDB
SWAP32_20 ends


SWAP32_23 segment
;***LP  demGetVersion - Get Current OEM and Version numbers
;
;       ENTRY
;           EBX
;               Address of VSF
;
;       EXIT
;           VSF(AL)
;               Major Number
;           VSF(AH)
;               Minor Number
;           VSF(BH)
;               OEM Serial Number
;           VSF(BL:CX)
;               24 bit user (serial) number
;
;       CONTEXT
;           Called from Virtual Mode
;           Executes in Kernel
;
;       STEPS
;
;       NOTES
;           None
;
;       WARNINGS
;           None
;
;       CALLS
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

align  4
Procedure demGetVersion,near
        push    ds
        push    ebx
        CALL16  w_Get_Version
        mov     edx,ebx
        pop     ebx
        pop     ds
        xchg    ah,al
        mov     [ebx].vsf_bx,dx
        mov     [ebx].vsf_cx,cx
        clc
        ret
EndProc   demGetVersion
SWAP32_23 ends

SWAP32_23 segment
;***LP  demSpecialEntries- Check the special version specific list
;                          and set the fake version if required.
;
;       ENTRY
;            EBX(ds:si)  : File Name being Exec'ed
;            EBX(cx)     : File Length (including NULL)
;
;       EXIT
;            SUCCESS - Entry Matched AX = TRUE
;                      DX = Fake Ver CL = COUNT
;
;            FAILURE - returns FALSE
;
;
;       CONTEXT
;           Called from Virtual Mode
;           Executes in Kernel
;
;       STEPS
;
;       NOTES
;           None
;
;       WARNINGS
;           None
;
;       CALLS
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

align  4
Procedure demSpecialEntries,near
LocalVar  dgv_FakeVer,WORD
LocalVar  dgv_FakeCount,BYTE

        EnterProc
        movzx   eax,[ebx].vsf_ds
        movzx   edx,[ebx].vsf_si
        rol     eax,4                   ; convert seg:off to linear
        movzx   ecx,[ebx].vsf_cx
        add     eax,edx
        push    eax
        push    ecx
        lea     eax,[dgv_FakeVer]
        SSToDS  eax
        push    eax
        lea     eax,[dgv_FakeCount]
        SSToDS  eax
        push    eax
        PCall   demProcessEntries
        or      eax,eax                 ; FALSE means entry not found
        .if     nz
          mov     cx,[dgv_FakeVer]
          mov     [ebx].vsf_dx,cx
          mov     cl,[dgv_FakeCount]
          mov     [ebx].vsf_cl,cl
        .endif
        LeaveProc
        ret
EndProc   demSpecialEntries
SWAP32_23 ends


SWAP32_28 segment
;***LP  demQueryDate - Query System Date
;
;       ENTRY
;           EBX = Address of VSF
;
;       EXIT
;           ALWAYS RETURNS SUCCESSFUL
;               VSF(DH) = Month   (1..12)
;               VSF(DL) = Day     (1..31)
;               VSF(CX) = Year    (1980..2099)
;               VSF(AL) = Weekday (0..6)
;
;       CONTEXT
;           Called from Virtual Mode
;           Executes in Kernel
;
;       STEPS
;           Disable Interrupts
;               Get Fields from SysInfoSeg
;           Restore Interrupts
;           Store results into VSF
;
;       NOTES
;           None
;
;       WARNINGS
;           SIS_DayDate must lie immediately before SIS_MonDate
;
;       CALLS
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

.errnz  (SIS_MonDate - SIS_DayDate) - 1         ; must be adjacent

Procedure demQueryDate,near,local
        pushfd
        cli                                     ; don't allow a clock tick
        mov     ecx,dword ptr SISData.SIS_YrsDate  ; grab date from SysInfoSeg
        mov     edx,dword ptr SISData.SIS_DayDate
        mov     al,SISData.SIS_DOWDate
        popfd
        mov     [ebx].vsf_cx,cx                 ; store results in VSF
        mov     [ebx].vsf_dx,dx
        clc                                     ; AL automatically returned
        ret
EndProc   demQueryDate
SWAP32_28 ends

SWAP32_28 segment
;***LP  demQueryTime - Query System Time
;
;       ENTRY
;           EBX = address of VSF
;
;       EXIT
;           ALWAYS RETURNS SUCCESS
;               AX = 0
;               VSF(CH) = Hour      (0..23)
;               VSF(CL) = Minute    (0..59)
;               VSF(DH) = Second    (0..59)
;               VSF(DL) = Hundredth (0..99)
;
;       CONTEXT
;           Called from Virtual Mode
;           Executes in Kernel
;
;       STEPS
;
;       NOTES
;           None
;
;       WARNINGS
;           SIS_SecTime must lie immediately before SIS_HunTime
;           SIS_HrsTime must lie immediately before SIS_MinTime
;
;       CALLS
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

.errnz  (SIS_HunTime - SIS_SecTime) - 1         ; Must be adjacent
.errnz  (SIS_MinTime - SIS_HrsTime) - 1         ; Must be adjacent
.errnz  (SIS_SecTime - SIS_MinTime) - 1         ; Must be adjacent

Procedure demQueryTime,near,local
        mov     eax,dword ptr SISData.SIS_HrsTime
        xchg    ah,al
        mov     [ebx].vsf_cx,ax                 ; Store results in VSF
        shr     eax,16
        xchg    ah,al
        mov     [ebx].vsf_dx,ax
        xor     eax,eax
        ret
EndProc   demQueryTime
SWAP32_28 ends

;***LP  demSetDate - Set System Date
;
;       ENTRY
;           EBX = address of VSF
;           VSF(CX) = Year   (1980..2099)
;           VSF(DH) = Month  (1..12)
;           VSF(DL) = Day    (1..31)
;
;       EXIT
;           SUCCESS
;               CY = 0
;               AX = 0
;               Date Updated
;           FAILURE
;               CY = 1
;               AX = error code
;
;       CONTEXT
;           Called from Virtual Mode
;           Executes in Kernel
;
;       STEPS
;           Copy Date from registers into DATETIME packet
;           Copy Time from SysInfoSeg into DATETIME packet
;           call w_SetDateTime
;
;       NOTES
;           None
;
;       WARNINGS
;           None
;
;       CALLS
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

.errnz  (SIS_HunTime - SIS_SecTime) - 1         ; must be adjacent
.errnz  (SIS_MinTime - SIS_HrsTime) - 1         ; must be adjacent
.errnz  (SIS_SecTime - SIS_MinTime) - 1         ; must be adjacent
.errnz  (SIS_MonDate - SIS_DayDate) - 1         ; must be adjacent
.errnz  (SIS_YrsDate - SIS_MonDate) - 1         ; must be adjacent

.errnz  (date_hundredths - date_seconds) - 1    ; must be adjacent
.errnz  (date_minutes    - date_hours)   - 1    ; must be adjacent
.errnz  (date_seconds    - date_minutes) - 1    ; must be adjacent
.errnz  (date_month      - date_day)     - 1    ; must be adjacent
.errnz  (date_year       - date_month)   - 1    ; must be adjacent

Procedure demSetDate,near,local

LocalVar  TimeBuf,<SIZE DATETIME>               ; buffer for w_SetDateTime

        EnterProc
        mov     ax,[ebx].vsf_cx                 ; get year
        shl     eax,16
        mov     ax,[ebx].vsf_dx                 ; get month & day
        mov     dword ptr TimeBuf.date_day,eax
        pushfd
        cli
        mov     eax,dword ptr SISData.SIS_HrsTime ; get time of day
        mov     dword ptr TimeBuf.date_hours,eax
        mov     ax,SISData.SIS_TimeZone
        popfd
        mov     TimeBuf.date_timezone,ax
        lea     si,TimeBuf
        mov     bx,ss
        CALL16  w_SetDateTime                   ; (BX:SI) = TimeBuf
        .if     c
          mov     ax,0ffh                       ; Error Translation
        .endif
        LeaveProc
        ret
EndProc   demSetDate

;***LP  demSetTime - Set System Time
;
;       ENTRY
;           EBX = address of VSF
;           VSF(CH) = hour      (0..23)
;           VSF(CL) = minute    (0..59)
;           VSF(DH) = second    (0..59)
;           VSF(DL) = hundredth (0..99)
;
;       EXIT
;           SUCCESS
;               AX = 0
;               Time Updated
;           FAILURE
;               AX = error code
;
;       CONTEXT
;           Called from Virtual Mode
;           Executes in Kernel
;
;       STEPS
;           Copy Time from registers into DATETIME packet
;           Copy Date from SysInfoSeg into DATETIME packet
;           call w_SetDateTime
;
;       NOTES
;           None
;
;       WARNINGS
;           None
;
;       CALLS
;
        ASSUME  DS:FLAT, ES:FLAT, SS:NOTHING, GS:NOTHING, FS:NOTHING

.errnz  (SIS_HunTime - SIS_SecTime) - 1         ; must be adjacent
.errnz  (SIS_MinTime - SIS_HrsTime) - 1         ; must be adjacent
.errnz  (SIS_SecTime - SIS_MinTime) - 1         ; must be adjacent
.errnz  (SIS_MonDate - SIS_DayDate) - 1         ; must be adjacent
.errnz  (SIS_YrsDate - SIS_MonDate) - 1         ; must be adjacent

.errnz  (date_hundredths - date_seconds) - 1    ; must be adjacent
.errnz  (date_minutes    - date_hours)   - 1    ; must be adjacent
.errnz  (date_seconds    - date_minutes) - 1    ; must be adjacent
.errnz  (date_month      - date_day)     - 1    ; must be adjacent
.errnz  (date_year       - date_month)   - 1    ; must be adjacent

Procedure demSetTime,near,local

LocalVar  TimeBuf,<SIZE DATETIME>               ; buffer for w_SetDateTime

        EnterProc
        push    ds
        mov     ax,[ebx].vsf_dx                 ; get seconds/hundredths
        xchg    ah,al
        shl     eax,16
        mov     ax,[ebx].vsf_cx                 ; get hours/minutes
        xchg    ah,al
        mov     dword ptr TimeBuf.date_hours,eax
        pushfd
        cli
        mov     eax,dword ptr SISData.SIS_DayDate ; get date
        mov     dword ptr TimeBuf.date_day,eax
        mov     ax,SISData.SIS_TimeZone
        popfd
        mov     TimeBuf.date_timezone,ax
        lea     si,TimeBuf
        mov     bx,ss
        CALL16  w_SetDateTime                   ; (BX:SI) = TimeBuf
        pop     ds
        .if     c
          mov     ax,0ffh                       ; Error Translation
        .else
          ; 1.5 r206
          ; Convert current time to ticks in BIOS Data area
          mov     ebx,dword ptr TimeBuf.date_hours
          movzx   eax,bl                        ; hours
          imul    eax,60                        ; * 60
          movzx   edx,bh
          add     eax,edx                       ; minutes
          imul    eax,60                        ; * 60
          shr     ebx,16
          movzx   edx,bl
          add     eax,edx                       ; seconds
          imul    eax,100                       ; * 100
          movzx   edx,bh
          add     eax,edx                       ; 100th seconds

          mov     ebx,59659
          mul     ebx                           ; convert to timer ticks
          mov     ebx,327680            ;=0005 0000h
          div     ebx

          xor     ebx,ebx
          mov     dword ptr [ebx].rb_ulTickCount,eax ; save in BIOS data area
          xor     eax,eax
        .endif
        LeaveProc
        ret
EndProc   demSetTime

SWAP32_23 segment
;***    demSetV86KernelAddr - set V86 kernel addresses
;
;       ENTRY   (EBX) = pvsf
;               VSF(DS:DX) = address of extended error variables:
;                       EXTERR_LOCUS    (BYTE)
;                       EXTERR          (WORD)
;                       EXTERR_ACTION   (BYTE)
;                       EXTERR_CLASS    (BYTE)
;               VSF(DS:BX) = address of VHE hard error packet structure
;
;       EXIT    NONE
;
;       USES    ALL
;
        ASSUME  DS:FLAT,ES:FLAT,SS:NOTHING,FS:NOTHING,GS:NOTHING

Procedure demSetV86KernelAddr,near,local
        movzx   eax,[ebx].vsf_ds
        mov     [segV86Kernel],ax       ; store away kernel segment
        shl     eax,4                   ; (EAX) = DS's linear address

        movzx   ecx,[ebx].vsf_dx
        add     ecx,eax                 ; (ECX) = error variables linear address
        mov     [pV86ExtErr],ecx

        movzx   ecx,[ebx].vsf_bx
        add     ecx,eax                 ; (ECX) = VHE structure address
        mov     [pvheVDM],ecx

        ret
EndProc   demSetV86KernelAddr
SWAP32_23 ends

SWAP32_23 segment
;---------------------------------------
;input:  VSF(AL) = drive id (0=default)
;output: CY = invalid drive
;        NC = drive ok
;             AL=drive # (0=A:)
Procedure demGetVisDrv,near,local
LocalVar dummycds,<SIZE curdir>
        EnterProc
        push    eax
        push    ebx
        mov     ebx,[_pTCBCur]
        lea     ax,dummycds
        mov     [ebx].TCBpTmpCDS.Offst,ax      ; Initialize ptda_pCDS
        pop     ebx
        pop     eax

        CALL16  GetVisDrv
        LeaveProc
        ret
EndProc   demGetVisDrv
SWAP32_23 ends

;---------------------------------------
;input:  VSF(AL) = drive id (0=default)
;        VSF(ES:DI) = DOS CDS to be filled in
;output: CY = invalid drive
;        NC = drive ok
Procedure demGetCDS,near,local
LocalVar dummycds,<SIZE curdir>
        EnterProc
        push    eax
        push    ebx
        mov     ebx,[_pTCBCur]
        lea     ax,dummycds
        mov     [ebx].TCBpTmpCDS.Offst,ax      ; Initialize ptda_pCDS
        pop     ebx
        call    demMapESDI              ; (ES:DI) -> destination buffer
        movzx   edi,di
        ASSUME  ES:NOTHING
        pop     eax
        CALL16  GetVisDrv
        lea     esi,dummycds
        push    ss
        pop     ds
        assume  ds:NOTHING
        cld
        .if     nc
          clc
        .else
          stc
        .endif
        LeaveProc
        ret
;-----------------
;curdir_list     STRUC
;curdir_text     db      67 dup(?)
;                                ;+00h text of assignment and curdir
;curdir_flags    dw      ?       ;+43h various flags
;                                ;     bit 15=network
;                                ;     bit 14=physical drive
;                                ;     bit 13=join
;                                ;     bit 12=subst
;curdir_devptr   dd      ?       ;+45h local pointer to DPB or net device
;curdir_ID       dw      ?,?     ;+49h cluster of current dir (net ID)
;curdir_user_word dw     ?       ;+4Dh
;curdir_end      dw      ?       ;+4Fh end of assignment
;                                ;     index to ".." backup limit - see above
;curdir_type     db      ?       ;+51h IFS drive (2=ifs, 4=netuse)
;curdir_ifs_hdr  dd      ?       ;+52h Ptr to File System Header
;curdir_fsda     db      ?,?     ;+56h File System Dependent Data Area
;curdir_list     ENDS            ;=58h
;-----------------
;cd_handle        DW      ?
;cd_pid           DW      ?
;cd_refcnt        DW      ?
;cd_flags         DB      ?
;cd_devptr        DD      ?
;cd_OwnerFSC      DW      ?
;cd_fsd.cdd_work  DB      {8}CDDWORKAREASIZE DUP (?)
;cd_fsi.cdi_hVPB  DW      ?
;cd_fsi.cdi_end   DW      ?
;cd_fsi.cdi_flags DB      ?
;cd_fsi.cdi_text  DB      {260}PMDIRSTRLEN DUP (?)
;-----------------
EndProc   demGetCDS
;******************************************************************************
Procedure demGetSFT,near,local
        call    demMapESDI
        push    es
        push    edi
        movzx   ebx,[ebx].vsf_bx
        CALL16  SFFromHandle                    ; get the SF entry
        pop     esi
        pop     ds
        jc      demGetSFT_error
        movzx   edi,di
;move data from es:edi(real OS/2 SFT) to ds:esi(our fake SFT in VDM)

;------ Reference count
        mov     ax,es:[edi].sf_ref_count
        mov     ds:[esi]+00h,ax
;------ mode, mode of access or high bit on if FCB
        mov     ax,es:[edi].sf_fsi.sfi_mode
        mov     ds:[esi]+02h,ax
;------ attribute, attr of file
        mov     al,es:[edi].sf_fsi.sfi_DOSattr
        mov     ds:[esi]+04h,al
;------ flags
        mov     ax,es:[edi].sf_flags
        mov     ds:[esi]+05h,ax
;------ points to DPB if local file, pts to DD hdr if local device, pts to net hdr if remote
        mov     dword ptr ds:[esi]+07h,0
;------ First cluster of file (bit 15 = 0)
        mov     ax,es:[edi].sf_fsd.sfdFAT_firFILEclus
        mov     ds:[esi]+0Bh,ax
;------ time
        mov     ax,es:[edi].sf_fsi.sfi_mtime
        mov     ds:[esi]+0Dh,ax
;------ date
        mov     ax,es:[edi].sf_fsi.sfi_mdate
        mov     ds:[esi]+0Fh,ax
;------ file size
        mov     eax,es:[edi].sf_fsi.sfi_size
        mov     ds:[esi]+11h,eax
;------ Lseek position
        mov     eax,es:[edi].sf_fsi.sfi_position
        mov     ds:[esi]+15h,eax
;------ last cluster accessed
        mov     ax,es:[edi].sf_fsd.sfdFAT_cluspos
        mov     ds:[esi]+19h,ax
;------ sector number of director
        mov     eax,es:[edi].sf_fsd.sfdFAT_dirsec
        mov     ds:[esi]+1Bh,eax
;------ offset of this entry in the above (dirpos)
        mov     al,es:[edi].sf_fsd.sfdFAT_dirpos
        mov     ds:[esi]+1Fh,al
;------ 8.3 name
        mov     eax,dword ptr es:[edi].sf_fsd.sfdFAT_name
        mov     ds:[esi]+20h,eax
        mov     eax,dword ptr es:[edi].sf_fsd.sfdFAT_name+4
        mov     ds:[esi]+24h,eax
        mov     eax,dword ptr es:[edi].sf_fsd.sfdFAT_name+8
        mov     ds:[esi]+28h,eax
;------ link to next SF
        mov     dword ptr ds:[esi]+2Bh,0
;------ UID
        mov     ax,es:[edi].sf_fsi.sfi_UID
        mov     ds:[esi]+2Fh,ax
;------ PID
        mov     ax,es:[edi].sf_fsi.sfi_PID
        mov     ds:[esi]+31h,ax
;------ MFT
        mov     word ptr ds:[esi]+33h,0
;------ last cluster accessed
        mov     ax,es:[edi].sf_fsd.sfdFAT_lstclus
        mov     ds:[esi]+35h,ax
;------ IFS_HDR
        mov     dword ptr ds:[esi]+37h,0
;------ done
        clc
demGetSFT_error:
        ret
EndProc   demGetSFT
;******************************************************************************
Procedure demBlockDD,near,local
        ret
EndProc   demBlockDD
;******************************************************************************

SWAP32_23 segment
Procedure demSetWriteVerify,near,local
        CALL16  w_SetVerify
        ret
EndProc   demSetWriteVerify
SWAP32_23 ends


SWAP32_27 segment
;***    demDosAbort - do file system clean up
;
;       ENTRY   (EBX) = pvsf
;               VSF(ES) = pdb to clean up for
;
;       EXIT    NONE
;
;       USES    ALL
;
        ASSUME  DS:FLAT,ES:FLAT,SS:NOTHING,FS:NOTHING,GS:NOTHING

Procedure demDosAbort,near,local
        movzx   ecx,[ebx].vsf_es
        PCall   VDMMPDBDestroy, <ecx>   ; call VDMM for VDM_PDB_DESTROY
        CALL16  DOS_AbortVDM
        CALL16  DOS_Abort
        ret
EndProc   demDosAbort
SWAP32_27 ends

;***    demYield - yield to equal or higher priority threads
;
;       ENTRY   NONE
;
;       EXIT    NONE
;
;       USES    ALL
;
        ASSUME  DS:FLAT,ES:FLAT,SS:NOTHING,FS:NOTHING,GS:NOTHING

Procedure demYield,near,local
        CCALL32 TKYieldTimeslice            ; 59378
        ret
EndProc   demYield

SWAP32_15 segment
;***    demSleep - sleep for a specified time
;
;       VPL Idle detection
;
;       ENTRY   (EBX) = pvsf
;               VSF(DX:AX) = specified time, in ms.
;
;       EXIT    NONE
;
;       USES    ALL
;
        ASSUME  DS:FLAT,ES:FLAT,SS:NOTHING,FS:NOTHING,GS:NOTHING

Procedure demSleep,near,local
        mov     eax,[anpfnVPL]          ; get service routine address
        or      eax,eax                 ; VPL address initialized?
        .if     z                       ;   yes, continue
          push    ebx                   ;   no, initialize the address
          call    demGetVplAddr         ; get vpl service address
          pop     ebx
          or      eax,eax               ; VPL address still not valid?
          je      short dsp20           ;   yes, initialization failed
        .endif
        mov     eax,[ebx].vsf_edx
        shl     eax,16
        mov     ax,[ebx].vsf_ax         ; (EAX) = requested sleep time
        or      eax,eax
        push    eax
        .if     z                       ; 59378
          CCALL32 TKYieldTimeslice      ; 59378
          ;71744; ret                   ; 59378
        .endif
        PCall   anpfnVPL[4*VDHVPL_WAIT] ;71744; , <eax>
dsp20:
        ret
EndProc   demSleep
SWAP32_15 ends

SWAP32_23 segment
;***    demVplCallibrate - notify VPL that callibration can start
;
;       VPL Idle detection
;
;       ENTRY   (EBX) = pvsf
;               VSF(DX:AX) = address Dem VPL ulong
;                   low byte is DEMNotBusy boolean
;                   high word is int 28 count
;
;       EXIT    Returns number of peek calls to make
;
;       USES    ALL
;
;       NOTE    DEM calls this routine.  If a nonzero value is
;               returned, DEM performs that many keyboard peeks
;               and then calls again.
;
        ASSUME  DS:FLAT,ES:FLAT,SS:NOTHING,FS:NOTHING,GS:NOTHING

Procedure demVplCallibrate,near,local
        mov     eax,[anpfnVPL]              ; get service routine address
        or      eax,eax                     ; VPL address initialized?
        .if     z                           ;   yes, continue
          push    ebx                       ;   no, initialize the address
          call    demGetVplAddr             ; get vpl service address
          pop     ebx
          or      eax,eax                   ; VPL address still not valid?
          je      short dvc20               ;   yes, initialization failed
        .endif
        movzx   ecx,[ebx].vsf_dx            ; get buffer address dx:ax
        shl     ecx,4
        movzx   eax,[ebx].vsf_ax
        add     eax,ecx                     ; (EAX) = linear address
        PCall   anpfnVPL[4*VDHVPL_BUSY_ADDR], <eax>
dvc20:
        ret
EndProc   demVplCallibrate
SWAP32_23 ends

SWAP32_24 segment
;***    demGetVplAddr - get VPL service address from VKBD
;
;       VPL Idle detection
;
;       ENTRY   NONE
;
;       EXIT    Success AX != 0
;               Global pszVpl is filled in with service address
;
;       USES    ALL
;
;       PSUEDO-CODE
;
;       get handle for vkbd VDD entry
;
        ASSUME  DS:FLAT,ES:FLAT,SS:NOTHING,FS:NOTHING,GS:NOTHING

Procedure demGetVplAddr,near,local
        PCall   VDHOpenVDD, <[pszVpl]>  ; get handle for VKBD
        or      eax,eax                 ; is vkbd registered?
        .if     nz                      ;  no, exit
          PCall   VDHRequestVDD, <eax, 0, 0, 0, (offset FLAT:anpfnVPL)>
        .endif
        ret
EndProc   demGetVplAddr
SWAP32_24 ends

;***    demJSA - do join/subst work
;
;       ENTRY   (EBX) = pvsf
;               (AL) = function code
;               VSF(BX) = drive number (0 based)
;               VSF(ES:DI) = string/buffer pointer
;               VSF(CX) = string/buffer length
;
;       EXIT    AX = error code
;
;       USES    ALL
;
        ASSUME  DS:FLAT,ES:FLAT,SS:NOTHING,FS:NOTHING,GS:NOTHING

Procedure demJSA,near,local
        call    demMapESDI              ; (ES:DI) = string/buffer pointer
        ASSUME  ES:NOTHING
        mov     ebp,[ebx].vsf_ebp       ; (BP) = magic number
        mov     esi,[ebx].vsf_esi       ; (SI) = w_Join/w_Subst signature
        mov     ecx,[ebx].vsf_ecx       ; (CX) = string/buffer length
        mov     ebx,[ebx].vsf_ebx       ; (BX) = drive number
        CALL16  w_JSA
        ret
EndProc   demJSA

SWAP32_23 segment
;***    demGetLogicalDriveCnt - get the number of OS/2 logical block devices
;
;
;       ENTRY   NONE
;
;       EXIT    VSF(AX) = Count of logical block devices
;
;       USES    ALL
;
;       Added SVC Routine   6.4 05/21/91 by Jeff Muir for PTR CP20 B722937
;
        ASSUME  DS:FLAT,ES:NOTHING,SS:NOTHING,FS:NOTHING,GS:NOTHING

Procedure demGetLogicalDriveCnt,near,local
        xor     ah,ah                           ; clear out high byte
        mov     al,NumIO                        ; get logical drive count
                                                ; from the kernel global data
        mov     [ebx].vsf_ax,ax                 ; return in V86 AX register
        ret
EndProc   demGetLogicalDriveCnt
SWAP32_23 ends

;***    demGetMessage - retrieve message from os2ldr
;
;       ENTRY   VSF(AX) = message ID
;               VSF(ES:DI) = message buffer
;               (EBX) = pvsf
;
;       EXIT    Message copied to caller's message buffer
;
;       USE     ALL
;
;       PSEUDO-CODE
;
;               CALL DosHlpProtGetMessage to retrieve the message
;               Copy the message to caller's buffer

        ASSUME  DS:FLAT,ES:FLAT,SS:NOTHING,FS:NOTHING,GS:NOTHING

Procedure demGetMessage,near
        mov     ax, [ebx].vsf_ax                ; (ax) = message number
        CALL16  DosHlpProtGetMessage            ; (ds:si) = ptr to msg
        movzx   esi, si
        push    ds                              ; save DS
        FlatContext <ds>
        movzx   eax, [ebx].vsf_es
        shl     eax, 4
        movzx   edi, [ebx].vsf_di               ; (edi) = caller's msg buf
        add     edi, eax                        ;
        pop     ds
        mov     cx, ds:[si]                     ; (cx) = message length
        add     ecx, 2                          ;  to include the message length
        movzx   ecx, cx
        rep     movsb
        ret
EndProc demGetMessage

EndCode

          FARCODE HIGH3
HIGH3CODE segment

;***LP  DosHlpProtGetMessage - get message
;
;       ENTRY   AX = Message number
;
;       EXIT    (DS:SI) = pointer to message
;
;       USES    None
;
;       PSEUDO-CODE
;
;       call DosHlpGetMessage
;
        ASSUME  DS:NOTHING, ES:NOTHING, SS:NOTHING, FS:NOTHING, GS:NOTHING

Procedure DosHlpProtGetMessage,far16,local
        DosContext <ds>
        call    DHF.DosHlpProtGetMessage
        RETP
EndProc   DosHlpProtGetMessage

HIGH3CODE ENDS

        end
