/*static char *SCCSID = "@(#)sysentry.h 6.8 92/02/06";*/
/*     SCCSID = @(#)sysentry.h  6.8 92/02/06 */

/***    sysentry.h
 *
 *      IBM/Microsoft Confidential
 *
 *      Copyright (c) IBM Corporation 1987, 1989
 *      Copyright (c) Microsoft Corporation 1987, 1989
 *
 *      All Rights Reserved
 *
 *      Sysentry.inc contains macros used for defining "new" (5.0 sytle)
 *      system call entry points (API).
 *
 *
 *      MACROS  SysEntry  -  Invoked to set up API entry point.
 *              EndEntry  -  Used to close up an entry point definition.
 *              Thop      -  Thread operator - generates a threaded system
 *                           call interpreter "instruction"
 *
 *              Thop instruction macros
 *
 *              uncond_jmp
 *              cmp_je
 *              chk_devioctl
 *              ld_ax
 *              ld_ah
 *              ld_al
 *              ld_bx
 *              ld_bx_0
 *              ld_bx_1
 *              ld_bh
 *              ld_bl
 *              ld_cx
 *              ld_cx_0
 *              ld_dx
 *              ld_dx_0
 *              ld_dl
 *              ld_si
 *              ld_si_0
 *              ld_si_1
 *              ld_di
 *              ld_di_0
 *              ld_ds
 *              ld_ds_norpl
 *              ld_es
 *              ld_es_norpl
 *              ld_disi
 *              ld_dsdx
 *              ld_dsdx_norpl
 *              ld_tcb
 *              ld_tcb_ptr
 *              ld_ind_ax
 *              ld_ind_bx
 *              ld_ind_cx
 *              ld_ind_si
 *              ld_imm_ax
 *              ld_imm_al
 *              ld_imm_ah
 *              ld_imm_cx
 *              ld_imm_dx
 *              ld_parampkt_bx
 *              mv_esdi_dsdx
 *              mv_si_dx
 *              mv_si_si
 *              farcall
 *              st_ax
 *              st_al
 *              st_bx
 *              st_cx
 *              st_dx
 *              st_dxax
 *              st_dxcx
 *              st_edx
 *              st_axdx
 *              st_axbxcx
 *              st_axbxcxdx
 *              stnz_axdx
 *              stnz_cx
 *              stnz_dxax
 *              skip_word
 *              skip_ptr
 *              skip_2ptr
 *              skip_2word
 *              skip_4word
 *              skip_5word
 *              skip_7word
 *              skip_8word
 *              skip_9word
 *              skip_10word
 *              skip_12word
 *              reser_dd_arg
 *              getusrbufz
 *              getusrnzbuf
 *              getusrbufz3
 *              getusrbufz206
 *              enterfscrit
 *              exitfscrit
 *              rplstampsel
 *              rplstampptr
 *            + misc. ras thops
 *
 *      Modification History:
 *
 *      JH      Oct 31, 1988
 *              Changed DefCallGate to include 32 bit gates etc.
 *              Changed SysEntryBegin to invoke AdjustUserESP if odd args
 *      SB      09-Jul-1989
 *              Deleted SysEntryFrame_s,EnterSysFrame,ExitSysFrame,EnterKmode
 *              Modified CALLSCI to support use of new Enter/Exit KMode
 *              interface in sci.
 */


/*      Interface Level equates */

#define IFaceLevel1     1
#define IFaceLevel2     2
#define IFaceLevel3     3
#define IFaceLevel4     4
#define G_COUNTMASK     0x1F

/*ASM
if      NOT RAS
RASpretrace     macro                   ;; Dummy preinvocation thop
                endm

RASposttrace    macro                   ;; Dummy postinvocation thop
                endm
endif

;***    DefCallGate - Define Call Gate
;
;       DefCallGate defines a call gate for a protected mode kernel entry.
;
;       DefCallGate lit,name,parms,ord,gatename
;
;               lit      - String giving name user will call.
;               name     - Name of target entry point.
;               parms    - Number of words of argument to copy from
;                          user stack to kernel stack.
;               ord      - Ordinal number in DOSCALLS entry table.
;                          A VALUE OF ZERO CAUSES A CALL GATE TO
;                          BE DEFINED, BUT SUPPRESSES THE DEFINITION
;                          OF AN ENTRY IN THE DOSCALLS ENTRY TABLE.
;               gatename - Name for GDT entry.  Omitting this parameter
;                          results in no label being generated for the
;                          GDT entry.  This is the common case.
;               cs32bit  - if blank the "name" address is in a 16 bit
;                          code segment (default), otherwise if not
;                          blank the "name" address is in the 32 bit
;                          code segment.  A special call gate entry is
;                          generated with the 32 bit offset in the
;                          g_handler field and the g_extoffset is set
;                          to -1.  During GDT initialization the high
;                          word of the offset in g_handler is moved to
;                          g_extoffset and g_sel is filled in with the
;                          ring 0 32 bit CS selector (R0CS).
;               auxord   - "Auxilliary ordinal", used only in the case
;                          of an indirect entry in the doscalls entry table
;               fring    - Ring flag, used to indicate whether this entry
;                          the ring0 or ring 3 component of an indirect
;                          entry table entry.
;
;       Example:
;
;       DefCallGate DOSGETCURDIR,DOSGETCURDIR,3,ORD_GETCURDIR
;

DefCallGate     macro   lit,name,parms,ord,gatename,cs32bit,auxord,fring
    local x,?parms
    ifndef name
        CODE segment
            extrn name:far
        CODE ends
    endif
    ifb <gatename>
        GDTCGSEG segment
        if1
            ife ord
                %out DefCallGate: lit has zero ordinal
                .err
            endif
        endif
    else
        GDTPUBSEG segment
        public gatename
        gatename label word
    endif
    x label word
    ?parms = ((parms+1)/2)
    .errnz (?parms and not G_COUNTMASK) ;; error if more than G_COUNTMASK parms
    ifb <cs32bit>
        gate <name,?parms,D_GATE332,0>
    else
        gate <offset FLAT:name,?parms,D_GATE332,-1> ;; special flat gate entry
    endif
    ifb <gatename>
        GDTCGSEG ends
    else
        GDTPUBSEG ends
    endif

;       Generate an entry for the API in the DOSCALLS entry table

    if ord ne 0
    ifb <auxord>
        if parms and 1
            GenEntryTbl lit,ord,IS_GATE,<GSEL x+RPL_RING3>
        else
            GenEntryTbl lit,ord,IS_GATE,<GSEL x+RPL_RING2>
        endif
    else
        GenEntryIndirect lit,ord,auxord,fring,IS_INDGATE,<GSEL x+RPL_RING3>
    endif
    endif
endm
*/      /* end of asm section */

/***ET+ ldrdce_t DOSCALLS entry define */

struct dce_s {
        uchar_t         dce_flags;
        ushort_t        dce_gate;
};

typedef struct  dce_s   ldrdce_t;
/*end*/


/*      dce_flags definitions */

#define IS_DOSCALL1     0               /* entry is from DOSCALL1 module */
#define IS_ABSOLUTE     1               /* entry is an absolute symbol */
#define IS_GATE         2               /* entry is a callgate */
#define IS_INDGATE      3               /* entry is aux gate ordinal */
#define IS_INDABSOLUTE  4               /* entry is aux absolute ordinal */

/*      indirect entry ring flags */

#define IND_RING0       1               /* value is for ring 0 fixups */
#define IND_RING3       2               /* value is for ring 2/3 fixups */

/*      dce_gate value if DOSCALL1 */

#define NO_GATE         0

/*ASM
;***    GenEntryTbl - generates an entry in the DOSCALLS entry table
;
;       The parameters to this macro are:
;               lit      - optional name to be placed in resident name table
;               ord      - ordinal number
;               flags    - indicate whether DOSCALLS,DOSCALL1,ABSOLUTE
;               callgate - gate, if flags == IS_GATE
;                          0, if flags == IS_DOSCALL1
;                          symbol value, if flags == IS_ABSOLUTE
;                          offset of struct in , if flags == IS_INDIRECT

GenEntryTbl     macro   lit,ord,flags,callgate
    local a,b
    .386p
    ifnb <lit>
        if (flags eq IS_GATE) or (flags eq IS_ABSOLUTE)
            DOSMTENAME segment
;;              db      b - a
;;          a   label   byte
;;              db      '&lit'
;;          b   label   byte
;;              dw      ord
            DOSMTENAME ends
        endif
    endif
    DOSMTEENTRY segment
        org     ((ord - 1) * (size dce_s))
        dce_s   <flags, &callgate>
    DOSMTEENTRY ends
    CpuMode reset
endm

;***    VDDGenEntryTbl - generates an entry in the MVDM entry table
;
;       The parameters to this macro are:
;               addr     - address entry point/value of absolute
;               ord      - ordinal number
;               fabs     - if blank, addr is an address.
;                          if non-blank, addr is an absolute value.

VDDGenEntryTbl  macro   addr,ord,fabs
    .errb <addr>
    .errb <ord>
    if2
        ifb <fabs>
            ifndef addr
                extrn addr:near
            endif
        endif
    endif
    VDDMTEENTRY segment
        org     ((ord - 1) * 4)         ; 4 bytes for entry point address
        ifb <fabs>
            dd  offset FLAT:addr
        else
            dd  addr
        endif
    VDDMTEENTRY ends
endm

;***    fsh_GenEntryTbl - generates an entry in the FSHELPER entry table
;
;       The parameters to this macro are:
;               addr     - address to the corresponding entry point
;               ord      - ordinal number

fsh_GenEntryTbl macro   addr,ord
    .386p
    FSHMTEENTRY segment
        org     ((ord - 1) * 4)         ; 4 bytes for entry point address
        dw      offset addr
        dw      seg addr
    FSHMTEENTRY ends
    CpuMode reset
endm

;***    GenEntryIndirect - generate an indirect entry
;
;       The parameters to this macro are:
;               lit     - optional name to be placed in resident name table
;               ord     - ordinal number
;               auxord  - auxilliary ordinal, index into aux table
;               fring   - is this the ring0 or ring3 entry?
;               flags   - what kind of entry is this?
;               value   - value to put in the table

GenEntryIndirect macro  lit,ord,auxord,fring,flags,value
    if (fring eq IND_RING0)
        GenEntryTbl lit,ord,flags,auxord
    endif
    GenAuxEntry auxord,fring,<value>
endm


;***    GenAuxEntry - Generate an entry in the auxilliary entry table
;
;       The parameters to this macro are:
;               auxord  - auxilliary ordinal, index into aux table
;               flags   - is this the ring0 or ring3 entry?
;               value   - value to put in the table

GenAuxEntry     macro   auxord,flags,value
    .386p
    DOSMTEAUX segment
    if (flags eq IND_RING0)
        org     ((auxord) * (size adce_s) + offset adce_ring0)
    else
        org     ((auxord) * (size adce_s) + offset adce_ring3)
    endif
    dw  value
    DOSMTEAUX ends
    CpuMode Reset
endm

;***    FSHentry - define a FSHELPER entrypoint
;
;       This macro defines a procedure entry point and calls a macro
;       to generate an entry in the FSHMTE entry table.
;
;       FSHEntry procname,ordinal,testarg
;
;               procname  - String a FSD will use to refer to entry point
;               ordinal   - integer a FSD will use to refer to entry point
;               testarg   - used to ensure correct number of arguments are
;                           present.  This should NOT be used when calling
;                           this macro.
;

FSHentry macro  procname,ordinal,testarg
    ifb <procname>
        if2
            %out Fatal Error - FSHentry called with no arguments.
        endif
        .err2
        exitm
    endif

    ifb <ordinal>
        if2
            %out Fatal Error - FSHentry &procname called with too few args.
        endif
        .err2
        exitm
    endif

    ifnb <testarg>
        if2
            %out Fatal Error - FSHentry &procname called with too many args.
        endif
        .err2
        exitm
    endif
    Procedure procname,far
    fsh_GenEntryTbl procname,ordinal
endm


;*
;*      System call interpreter stack frame and instruction generator macros
;*


;***    sreg  --  Shadow register equates.
;
;       The interpreter itself needs some registers, these registers are
;       "shadowed" in a structure on the user's TCB (PDTA) stack, which looks
;       like this.  After all register values have been set, we load this
;       structure into the real registers and go.
;

sreg            struc
sreg_di         dw      ?       ; the order of these registers (up to sreg_ds)
sreg_si         dw      ?       ; must be kept the same as the order popped
sreg_es         dw      ?
sreg_ds         dw      ?
sreg_tempbuf1   dd      ?       ; first temporary buffer address
sreg_tempbuf2   dd      ?       ; second temporary buffer address
sreg_filler     dw      ?       ; filler - (old RAS record buffer address)
sreg_rpl        dw      ?       ; user RPL (has desired DPL)
sreg            ends

;***    kstk_frame  --  Frame for all the stuff we put on the kernel stack.
;                       Only for efficiency reasons this stack is defined
;                       here and should not be used outside  this file.
;                       Please see SSF kernel stack in kmode.h to refer
;                       variables on SCI stack frame.
;       WARNING: If you change the size of this structure, please
;                update <KSTK_ARGS> in dos\mras.rep; if you do not,
;                you will break all the Dynamic Trace Points in the
;                kernel.

kstk_frame      struc
                db      size sreg dup(?)    ; "include" sreg
kstk_ssf        db      size ssf_s dup(?)   ; "include" ssf stack frame
kstk_args       dw      ?                   ; first word of user argument
kstk_frame      ends


?SCI_OK         equ 0
?SCI_ERROR      equ 1

?SCI_UNKNOWN    equ 0
?SCI_FLAT       equ 1

?SCI_NOT_IN_USE equ 0
?SCI_IN_USE     equ 1
?SCI_SS_RPL     equ 2
?SCI_WKREG      equ 3


sci_init macro
    ?sci_ax = ?SCI_NOT_IN_USE
    ?sci_bx = ?SCI_NOT_IN_USE
    ?sci_cx = ?SCI_NOT_IN_USE
    ?sci_dx = ?SCI_NOT_IN_USE
    ?sci_di = ?SCI_NOT_IN_USE
    ?sci_si = ?SCI_SS_RPL
    ?sci_sreg_si = ?SCI_NOT_IN_USE
    ?sci_sreg_di = ?SCI_NOT_IN_USE
    ?sci_ds = ?SCI_FLAT
    ?sci_es = ?SCI_UNKNOWN
    ?sci_argptr = kstk_args
    endm


;**     WARNING:  if the following constant is increased, then the return code
;                 in SCI.ASM must also be modified to allow for a bigger return
;                 value.  (See rettbl, in SCI.ASM.)

MAXRETN         =       36              ; define maximum number of parm bytes


;***    SysEntryBegin - Begin definition of an API entry point
;
;       SysEntryBegin defines the dynamic link entry in the name table,
;       (via DefCallGate), and generates proper labels.  Unlike SysEntry,
;       it does not generate a call to SCI, the system call interpreter.
;
;       SysEntryBegin usrname,ordinal,argwords,gatename,inline,abase,testarg
;
;       ENTRY   usrname  - String user will use to refer to entry point
;               ordinal  - integer user will use to refer to entry point
;               argwords - Number of words of argument from user stack
;                          call gate will copy onto kernel stack.
;               gatename - if this argument is non-blank, a public label
;                          of the given name is defined to mark the call gate.
;               inline   - System call is in-line and skips SCI if possible.
;               abase    - number of bytes that ArgVar skips when calculating
;                          the argument offsets. If blank, the default is
;                          used which is 6 (4 for the CS:IP and 2 for BP).
;               auxord   - "Auxilliary ordinal", used only in the case
;                          of an indirect entry in the doscalls entry table
;               fring    - Ring flag, used to indicate whether this entry
;                          the ring0 or ring 3 component of an indirect
;                          entry table entry.
;               nozx     - If specified, 'movzx esp,sp' is not produced.
;                          This is used by the 32-bit APIs.
;               noprepost- do not define pre&usrname, post&usrname
;                          procedures.
;               presci   - If the presci entry point of SCI is to be used
;                          so API fixed memory is saved.  This entry point
;                          is used by SysEntry and makes the stack conform
;                          with the sci entry point.
;               testarg  - used to ensure correct number of arguments are
;                          present.  This should NOT be used when calling
;                          this macro.
;
;       EXIT    ?argbytes = rounded up to dword number of arg bytes
;               ?argwords = number of argument words (not rounded)
;

SysEntryBegin   macro   usrname,ordinal,argwords,gatename,inline,abase,auxord,fring,nozx,noprepost,presci,testarg  ;; AA03898
    ?argwords = argwords
    ?argbytes = ((argwords + 1) / 2) * 4
    if1
        if (?argbytes gt MAXRETN)
            %out SysEntry &usrname, number of argument words too high.
            .err
        endif
    endif

    ifb <usrname>       ;; First check if args are ok, usrname MUST be defined
        if2
            %out Fatal Error - SysEntry called with no arguments.
        endif
        .err2
        exitm
    endif

    ifnb <testarg>      ;; If testarg is defined then too many args
        if2
            %out Fatal Error - SysEntry &usrname called with too many arguments.
        endif
        .err2
        exitm
    endif

    ifidn <fring>,<IND_RING0>
        RingEndProc macro usrname2,NoChk        ;; used in EndEntry
            EndProc <R0!&usrname2>,<NoChk>
        endm
    else
        RingEndProc macro usrname2,NoChk        ;; used in EndEntry
            EndProc <usrname2>,<NoChk>
        endm
    endif

if      RAS
    if ?cstype eq ?CS_16bit
        ifb <noprepost>             ;; AA03898
            ifb <inline>            ;; If entry not in-line
                RASpretrace macro   ;; Emit thop
                    if ?sci_sreg_si eq ?SCI_IN_USE
                        mov     si,[bp].sreg_si
                        ?sci_si = ?SCI_IN_USE
                        ?sci_sreg_si = ?SCI_NOT_IN_USE
                    endif
                    if ?sci_sreg_di eq ?SCI_IN_USE
                        mov     di,[bp].sreg_di
                        ?sci_di = ?SCI_IN_USE
                        ?sci_sreg_di = ?SCI_NOT_IN_USE
                    endif
                    public  pre&usrname
                    pre&usrname:
                    ifdef MMPHPre&usrname
                        MMPHPre&usrname ;; Performance Hook
                    endif
                    endm
            else
                RASpretrace macro   ;; Error if used
                    if2
                        %out RASpretrace usage error
                    endif
                    .err
                    endm
            endif
            RASposttrace macro
                if ?sci_sreg_si eq ?SCI_IN_USE
                    mov     si,[bp].sreg_si
                    ?sci_si = ?SCI_IN_USE
                    ?sci_sreg_si = ?SCI_NOT_IN_USE
                endif
                if ?sci_sreg_di eq ?SCI_IN_USE
                    mov     di,[bp].sreg_di
                    ?sci_di = ?SCI_IN_USE
                    ?sci_sreg_di = ?SCI_NOT_IN_USE
                endif
                public  post&usrname
                post&usrname:
                ifdef MMPHPost&usrname
                    MMPHPost&usrname ;; Performance Hook
                endif
                endm
        endif                       ;; AA03898
    endif
endif
    Procedure usrname,far,,,abase
    if (?cstype eq ?CS_16bit)
        DefCallGate usrname,usrname,argwords,<ordinal>,gatename,,auxord,fring
    else
        DefCallGate usrname,usrname,argwords,<ordinal>,gatename,cs32bit,auxord,fring
    endif
    .386p
    ifb <presci>
        ifb <nozx>
            movzx esp,sp
        endif
                                            ;; if odd number of words, then
        if (argwords and 1)                 ;; adjust user ESP for the eventual
            ifnb <nozx>                     ;; RETF n, which is DWORD aligned.
                movzx  esp,sp
            endif
            sub     dword ptr [esp]+size retf32_s+?argbytes,2
        endif
    endif
    CpuMode reset
endm


;***    CallSCI - invoke SCI
;
;       This macro causes SCI to be invoked.  The combination
;       of SysEntryBegin and CallSCI is meant to be equivalent
;       to SysEntry.  The separation allows code to be inserted
;       in the call gate procedure before SCI is invoked.
;

CallSCI macro   usrname
    if2
        ifndef sci
            extrn   sci:near
        endif
    endif
    CpuMode 386
    pushfd                      ; push flags
    PushSCIRet  %?argbytes
    PUSHD       <?argwords * 2> ; push ACTUAL count of bytes of user arguments
                                ; (maintain word-oddness here for debugging)
    CpuMode 286
    call  sci
    sci_init
endm


;***    PushSCIRet  - Push appropriate SCI return address according to the
;                     argument bytes

PushSCIRet macro cbargs
    if2
        ifndef SCIReturn&cbargs
            extrn SCIReturn&cbargs:near
        endif
    endif
    push    offset DOSHIGH3CODE:SCIReturn&cbargs
endm

;***    SysEntry - Define an API entry point
;
;       SysEntry defines the dynamic link entry in the name table,
;       (via Defdyne), generates proper labels, and generates a call
;       to SCI, the system call interpreter.
;
;       SysEntry usrname,ordinal,argwords,gatename,sctmask
;
;               usrname  - String user will use to refer to entry point
;               ordinal  - integer user will use to refer to entry point
;               argwords - Number of words of argument from user stack
;                          call gate will copy onto kernel stack.
;               gatename - if this argument is non-blank, a public label
;                          of the given name is defined to mark the call gate.
;               sctmask  - mask bits for system call tracing - default TRC_OTHER
;               auxord   - "Auxilliary ordinal", used only in the case
;                          of an indirect entry in the doscalls entry table
;               fring    - Ring flag, used to indicate whether this entry
;                          the ring0 or ring 3 component of an indirect
;                          entry table entry.
;               testarg  - used to ensure correct number of arguments are
;                          present.  This should NOT be used when calling
;                          this macro.
;
;

SysEntry macro  usrname,ordinal,argwords,gatename,sctmask,auxord,fring,testarg
        ifidn <fring>,<IND_RING0>
            SysEntryBegin R0&usrname,<ordinal>,argwords,gatename,,,auxord,fring,,,presci,testarg
        else
            SysEntryBegin usrname,<ordinal>,argwords,gatename,,,auxord,fring,,,presci,testarg
        endif
        if2
            ifndef pre_sci
                extrn   pre_sci:near
            endif
        endif
        push    ?argwords * 2  ; push ACTUAL count of bytes of user arguments
        CpuMode 286
        call  pre_sci
        sci_init
        endm

;***    EndEntry - Mark end of API entry point
;
;       EndEntry closes the procedure opened by SysEntry, generating
;       a return thop.
;
;       EndEntry usrname
;
;               usrname  - Name of entry being closed.
;

EndEntry macro  usrname,NoGen,NoChk
        ifb     <NoGen>
            return
        endif
if      RAS
    if ?cstype eq ?CS_16bit
        purge   RASpretrace
        purge   RASposttrace
    endif
endif
        RingEndProc usrname,NoChk
        purge   RingEndProc
        endm

;***    SysEntry32 - Define a 32 bit API entry point
;
;       SysEntry32 defines the dynamic link entry in the name table,
;       generates code to enter and exit kernel mode and calls the
;       worker.
;
;       SysEntry32 usrname,ordinal,argwords,workername,nothunk,pascal,gatename
;
;               usrname  - String user will use to refer to entry point
;               ordinal  - integer user will use to refer to entry point
;               argwords - Number of words of argument from user stack
;                          call gate will copy onto kernel stack.
;               workername - name of worker routine
;               nothunk  - if blank generate code to move the return address
;                          from the thunk to the real eip on the kernel
;                          stack frame.  If not blank, this macro can be
;                          used to generate the call gate for a 16 bit API.
;               pascal   - not blank if entry point will be called with
;                          pascal calling conventions.  Default is C.  Must
;                          be "PASCAL" (upper case) if not blank.
;               gatename - if this argument is non-blank, a public label
;                          of the given name is defined to mark the call
;                          gate.
;
;       WARNING:
;       A subtle point here: To preserve word-oddness of cbargs in
;       PASCAL callgate frames, we use <?argwords*2> instead of <?argbytes>.
;       ?argbytes is <?argwords*2> rounded up to the next DWORD multiple.
;
;       The 2 additional words added to argwords here is due to the far thunk.
;

SysEntry32 macro usrname,ordinal,argwords,workername,nothunk,pascal,gatename

    ifb <nothunk>
        SysEntryBegin <usrname>,<ordinal>,<argwords+2>,<gatename>,,,,,nozx
    else
        SysEntryBegin <usrname>,<ordinal>,<argwords>,<gatename>,,,,,nozx
    endif

    ifb <pascal>
        KMEnterKmodeAPI32 ?argbytes,pascal,nothunk
    else
        KMEnterKmodeAPI32 (?argwords*2),pascal,nothunk
    endif

    if RAS
        ifdef MMPHPre&usrname
            MMPHPre&usrname     ;; Performance Hook
        endif
        Entry pre&usrname,,,nocheck
    endif

    extrn workername:near

;   Call the Security Router.                                        ;@SEC
;   If a security subsystem has hooked 32-bit callgates, the Router  ;@SEC
;   passes the call to the subsystem's callgate handler.  If not,    ;@SEC
;   it simply cleans up the stack and calls the worker routine.      ;@SEC
;                                                                    ;@SEC
;    call workername                                                 ;@SEC
                                                                     ;@SEC
    lea   eax, workername                                            ;@SEC
    push  eax                     ; Push address of worker           ;@SEC
    push  ordinal                 ; Push ordinal number              ;@SEC
                                                                     ;@SEC
    call  Sec32Router             ; Call Security Router             ;@SEC


    if RAS
        ifdef MMPHPost&usrname
            MMPHPost&usrname    ;; Performance Hook
        endif
        Entry post&usrname,,,nocheck
    endif

    KMExitKmodeAPI32 ?argbytes,pascal,nothunk

    EndEntry <usrname>,NoGen
endm


sci_getreg macro reg
    ?sci_rc = ?SCI_OK
    if ?sci_ax eq ?SCI_NOT_IN_USE
        reg equ <ax>
        ?sci_ax = ?SCI_WKREG
    elseif ?sci_cx eq ?SCI_NOT_IN_USE
        reg equ <cx>
        ?sci_cx = ?SCI_WKREG
    elseif ?sci_dx eq ?SCI_NOT_IN_USE
        reg equ <dx>
        ?sci_dx = ?SCI_WKREG
    elseif ?sci_bx eq ?SCI_NOT_IN_USE
        reg equ <bx>
        ?sci_bx = ?SCI_WKREG
    elseif ?sci_di eq ?SCI_NOT_IN_USE
        reg equ <di>
        ?sci_di = ?SCI_WKREG
    elseif ?sci_si eq ?SCI_NOT_IN_USE
        reg equ <si>
        ?sci_si = ?SCI_WKREG
    elseif ?sci_ax eq ?SCI_SS_RPL
        reg equ <ax>
        ?sci_ax = ?SCI_WKREG
    elseif ?sci_cx eq ?SCI_SS_RPL
        reg equ <cx>
        ?sci_cx = ?SCI_WKREG
    elseif ?sci_dx eq ?SCI_SS_RPL
        reg equ <dx>
        ?sci_dx = ?SCI_WKREG
    elseif ?sci_bx eq ?SCI_SS_RPL
        reg equ <bx>
        ?sci_bx = ?SCI_WKREG
    elseif ?sci_di eq ?SCI_SS_RPL
        reg equ <di>
        ?sci_di = ?SCI_WKREG
    elseif ?sci_si eq ?SCI_SS_RPL
        reg equ <si>
        ?sci_si = ?SCI_WKREG
    else
        ?sci_rc = ?SCI_ERROR
    endif
    endm


sci_getbasereg macro reg
    ?sci_rc = ?SCI_OK
    if ?sci_bx eq ?SCI_NOT_IN_USE
        reg equ <bx>
        ?sci_bx = ?SCI_WKREG
    elseif ?sci_di eq ?SCI_NOT_IN_USE
        reg equ <di>
        ?sci_di = ?SCI_WKREG
    elseif ?sci_si eq ?SCI_NOT_IN_USE
        reg equ <si>
        ?sci_si = ?SCI_WKREG
    elseif ?sci_bx eq ?SCI_SS_RPL
        reg equ <bx>
        ?sci_bx = ?SCI_WKREG
    elseif ?sci_di eq ?SCI_SS_RPL
        reg equ <di>
        ?sci_di = ?SCI_WKREG
    elseif ?sci_si eq ?SCI_SS_RPL
        reg equ <si>
        ?sci_si = ?SCI_WKREG
    elseif ?sci_di eq ?SCI_IN_USE
        mov     [bp].sreg_di,di
        ?sci_sreg_di = ?SCI_IN_USE
        reg equ <di>
        ?sci_di = ?SCI_WKREG
    elseif ?sci_si eq ?SCI_IN_USE
        mov     [bp].sreg_si,si
        ?sci_sreg_si = ?SCI_IN_USE
        reg equ <si>
        ?sci_si = ?SCI_WKREG
    else
        ?sci_rc = ?SCI_ERROR
    endif
    endm


sci_setstampreg macro
    ?sci_rc = ?SCI_OK
    if ?sci_si eq ?SCI_SS_RPL
        ?sci_rc = ?SCI_OK
    elseif ?sci_ax eq ?SCI_SS_RPL
        ?sci_rc = ?SCI_OK
    elseif ?sci_bx eq ?SCI_SS_RPL
        ?sci_rc = ?SCI_OK
    elseif ?sci_cx eq ?SCI_SS_RPL
        ?sci_rc = ?SCI_OK
    elseif ?sci_dx eq ?SCI_SS_RPL
        ?sci_rc = ?SCI_OK
    elseif ?sci_di eq ?SCI_SS_RPL
        ?sci_rc = ?SCI_OK
    elseif ?sci_si eq ?SCI_NOT_IN_USE
        mov     si,[bp].sreg_rpl
        ?sci_si = ?SCI_SS_RPL
    elseif ?sci_ax eq ?SCI_NOT_IN_USE
        mov     ax,[bp].sreg_rpl
        ?sci_ax = ?SCI_SS_RPL
    elseif ?sci_cx eq ?SCI_NOT_IN_USE
        mov     cx,[bp].sreg_rpl
        ?sci_cx = ?SCI_SS_RPL
    elseif ?sci_dx eq ?SCI_NOT_IN_USE
        mov     dx,[bp].sreg_rpl
        ?sci_dx = ?SCI_SS_RPL
    elseif ?sci_di eq ?SCI_NOT_IN_USE
        mov     di,[bp].sreg_rpl
        ?sci_di = ?SCI_SS_RPL
    elseif ?sci_bx eq ?SCI_NOT_IN_USE
        mov     bx,[bp].sreg_rpl
        ?sci_bx = ?SCI_SS_RPL
    elseif ?sci_si eq ?SCI_IN_USE
        mov     [bp].sreg_si,si
        mov     si,[bp].sreg_rpl
        ?sci_si = ?SCI_SS_RPL
        ?sci_sreg_si = ?SCI_IN_USE
    elseif ?sci_di eq ?SCI_IN_USE
        mov     [bp].sreg_di,di
        mov     di,[bp].sreg_rpl
        ?sci_di = ?SCI_SS_RPL
        ?sci_sreg_di = ?SCI_IN_USE
    else
        ?sci_rc = ?SCI_ERROR
    endif
    endm


sci_stamprpl macro target
    ?sci_rc = ?SCI_OK
    if ?sci_si eq ?SCI_SS_RPL
        or      target,si
    elseif ?sci_ax eq ?SCI_SS_RPL
        or      target,ax
    elseif ?sci_bx eq ?SCI_SS_RPL
        or      target,bx
    elseif ?sci_cx eq ?SCI_SS_RPL
        or      target,cx
    elseif ?sci_dx eq ?SCI_SS_RPL
        or      target,dx
    elseif ?sci_di eq ?SCI_SS_RPL
        or      target,di
    elseif ?sci_si eq ?SCI_NOT_IN_USE
        mov     si,[bp].sreg_rpl
        or      target,si
        ?sci_si = ?SCI_SS_RPL
    elseif ?sci_ax eq ?SCI_NOT_IN_USE
        mov     ax,[bp].sreg_rpl
        or      target,ax
        ?sci_ax = ?SCI_SS_RPL
    elseif ?sci_cx eq ?SCI_NOT_IN_USE
        mov     cx,[bp].sreg_rpl
        or      target,cx
        ?sci_cx = ?SCI_SS_RPL
    elseif ?sci_dx eq ?SCI_NOT_IN_USE
        mov     dx,[bp].sreg_rpl
        or      target,dx
        ?sci_dx = ?SCI_SS_RPL
    elseif ?sci_di eq ?SCI_NOT_IN_USE
        mov     di,[bp].sreg_rpl
        or      target,di
        ?sci_di = ?SCI_SS_RPL
    elseif ?sci_bx eq ?SCI_NOT_IN_USE
        mov     bx,[bp].sreg_rpl
        or      target,bx
        ?sci_bx = ?SCI_SS_RPL
    elseif target eq ax
        or      ax,[bp].sreg_rpl
    elseif target eq bx
        or      bx,[bp].sreg_rpl
    elseif target eq cx
        or      cx,[bp].sreg_rpl
    elseif target eq dx
        or      dx,[bp].sreg_rpl
    elseif target eq si
        or      si,[bp].sreg_rpl
    elseif target eq di
        or      di,[bp].sreg_rpl
    elseif ?sci_si eq ?SCI_IN_USE
        mov     [bp].sreg_si,si
        mov     si,[bp].sreg_rpl
        or      target,si
        ?sci_si = ?SCI_SS_RPL
        ?sci_sreg_si = ?SCI_IN_USE
    elseif ?sci_di eq ?SCI_IN_USE
        mov     [bp].sreg_di,di
        mov     di,[bp].sreg_rpl
        or      target,di
        ?sci_di = ?SCI_SS_RPL
        ?sci_sreg_di = ?SCI_IN_USE
    else
        push    ax
        mov     ax,[bp].sreg_rpl
        or      target,ax
        pop     ax
    endif
    endm


sci_freereg macro reg
    ?sci_rc = ?SCI_OK
    % ifidni <reg>,<ax>
        ?sci_ax = ?SCI_NOT_IN_USE
    % elseifidni <reg>,<cx>
        ?sci_cx = ?SCI_NOT_IN_USE
    % elseifidni <reg>,<dx>
        ?sci_dx = ?SCI_NOT_IN_USE
    % elseifidni <reg>,<bx>
        ?sci_bx = ?SCI_NOT_IN_USE
    % elseifidni <reg>,<di>
        ?sci_di = ?SCI_NOT_IN_USE
    % elseifidni <reg>,<si>
        ?sci_si = ?SCI_NOT_IN_USE
    else
        ?sci_rc = ?SCI_ERROR
    endif
    endm


gendef  macro   thopinstr
        if2
        ifndef to_&thopinstr
                extrn   to_&thopinstr:near
        endif
        endif
        endm


;***    return  --  jumps to to_return (common return code for system calls)
;
;       Jumps back to sci to effect return from system call
;
;       ENTRY   (ss:bp) -> shadow register frame
;
;       EXIT    (ds) = FLAT Context
;
;       USES    ax, ds

return  macro
        gendef  return
        if ?sci_sreg_di eq ?SCI_IN_USE
           mov     di,[bp].sreg_di
           ?sci_sreg_di = ?SCI_NOT_IN_USE
        endif
        if ?sci_ds eq ?SCI_UNKNOWN
           FlatContext <ds>,ax
           ?sci_ds = ?SCI_FLAT
        endif
        jmp     to_return
        endm


;***    farcall  --  calls to_farcall
;
;       Farcall calls to_farcall after restoring shadowed non segment registers
;       Subsequently, to_farcall calls the kernel routine that actually
;       does the work of the current system call.
;
;       ENTRY   (ss)                =  user's TCB (PTDA) stack segment
;               (ss:bp)             -> shadow register frame
;
;       EXIT    (ax,bx,cx,dx,si,di) =  working values
;               ?sci_argptr will be "rewound" to the base of the user argument
;               stack
;
;               if (worker returned CF = 1)
;                       DI = returned AX
;                       AX = 0
;               else (worker returned CF = 0)
;                       DI = 0
;                       AX = returned AX
;
;               Thus: DI = error status value, AX = work value
;
;       WARNING ?sci_argptr is rewound to the START of the user argument
;               stack, the same place it was when thread program processing
;               began.
;
;       NOTE    The thread program is expected to move AX into the proper
;               return argument location provided by user.
;
;               The return thread op will load AX with DI before returning
;               to the user, thus returning with AX = status value
;
;               We use DI because none of the workers return anything
;               in DI.

farcall macro  worker, securityord                                        ;@SEC
        gendef  farcall
HIGH3CODE ends
        IF2
                EXTRNFAR worker
        ENDIF
HIGH3CODE segment
        if ?sci_sreg_si eq ?SCI_IN_USE
           mov     si,[bp].sreg_si
           ?sci_sreg_si = ?SCI_NOT_IN_USE
        endif
        if ?sci_sreg_di eq ?SCI_IN_USE
           mov     di,[bp].sreg_di
           ?sci_sreg_di = ?SCI_NOT_IN_USE
        endif
        call    to_farcall
        DDFAR   worker
        dw      securityord                                               ;@SEC
        ?sci_ax = ?SCI_IN_USE
        ?sci_bx = ?SCI_IN_USE
        ?sci_cx = ?SCI_IN_USE
        ?sci_dx = ?SCI_IN_USE
        ?sci_di = ?SCI_IN_USE
        ?sci_si = ?SCI_SS_RPL
        ?sci_sreg_si = ?SCI_NOT_IN_USE
        ?sci_sreg_di = ?SCI_NOT_IN_USE
        ?sci_ds = ?SCI_UNKNOWN
        ?sci_es = ?SCI_UNKNOWN
        ?sci_argptr = kstk_args
        endm


;***    chk_devioctl --  validate pointer/length conventions (for DOSDEVIOCTL2)
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    DI = Error Code
;
;       ALGORITHM
;           If (cx == 0)
;               if (sh_es AND NOT RPL3 OR di != 0) {
;                   Error = Invalid parameter
;                   return to error label
;               }
;           If (si == 0)
;               if (sh_ds AND NOT RPL3 OR dx !=0) {
;                   Error = Invalid parameter
;                   return to error label
;               }
;           return to next sequential instruction
;       }
;
;       USES    flags

chk_devioctl  macro   labelarg
        local   cdi1, cdi2, cdi3
        if ?sci_sreg_si eq ?SCI_IN_USE
           mov     si,[bp].sreg_si
           ?sci_si = ?SCI_IN_USE
           ?sci_sreg_si = ?SCI_NOT_IN_USE
        endif
        if ?sci_sreg_di eq ?SCI_IN_USE
           mov     di,[bp].sreg_di
           ?sci_di = ?SCI_IN_USE
           ?sci_sreg_di = ?SCI_NOT_IN_USE
        endif
        sci_getreg reg1                 ; get a work reg

;*      check CX, shadow ES, & DI (parameter packet length, pointer)

        or      cx,cx                   ; 0 length: should have null addr
        jnz     short cdi2              ; not 0, go check other length/pointer
        if ?sci_rc EQ ?SCI_OK           ; if we got a work reg
           mov     reg1,[bp].sreg_es    ; length = 0, reg1 = selector
           .errnz  RPL_RING3-3
           and     reg1,NOT RPL_RING3   ; mask out RPL
           or      reg1,di              ; reg1 = selector OR offset
           jz      short cdi2           ; if pointer = null, go check other
                                        ; pointer is not null
        else
           mov     cx,[bp].sreg_es      ; length = 0, CX = selector
           .errnz  RPL_RING3-3
           and     cx,NOT RPL_RING3     ; mask out RPL
           or      cx,di                ; CX = selector OR offset
           jz      short cdi2           ; if pointer = null, go check other
                                        ; pointer is not null
           xor     cx,cx                ; CX is zero again
        endif

;*      return invalid parameter error code, and jump to error label

cdi1:   mov     di,ERROR_INVALID_PARAMETER  ; DI = error code
        if1
            ifdef labelarg
                %out SCI macro variable error possible after backwards jump
            endif
        endif
        jmp     short labelarg              ; take error return

;*      check SI, shadow DS, & DX (data packet length, pointer)

cdi2:   or      si,si                   ; check other length
        jnz     short cdi3              ; not 0, return normally
        if ?sci_rc EQ ?SCI_OK           ; if we got a work reg
           mov     reg1,[bp].sreg_ds    ; length = 0, reg1 = selector
           .errnz  RPL_RING3-3
           and     reg1,NOT RPL_RING3   ; mask out RPL
           or      reg1,dx              ; reg1 = selector OR offset
           jnz     short cdi1           ; pointer is not null, return error
                                        ; pointer = null
        else
           mov     si,[bp].sreg_ds      ; length = 0, SI = selector
           .errnz  RPL_RING3-3
           and     si,NOT RPL_RING3     ; mask out RPL
           or      si,dx                ; SI = selector OR offset
           mov     si,0                 ; SI is zero again
           jnz     short cdi1           ; pointer is not null, return error
                                        ; pointer = null
        endif

cdi3:                                   ; normal exit
        if ?sci_rc EQ ?SCI_OK           ; if we got a work reg
           sci_freereg reg1             ; free the work reg
        endif
        endm


;***    uncond_jmp  --  uncondition jump
;
;       execute unconditional jump to label
;
;
;       EXIT    A "jump" is made to the thop indicated
;
;       USES    NONE

uncond_jmp  macro   labelarg
        if1
            ifdef labelarg
                %out SCI macro variable error possible after backwards jump
            endif
        endif
        if ?sci_di eq ?SCI_IN_USE
           mov     [bp].sreg_di,di
           ?sci_sreg_di = ?SCI_IN_USE
        endif
        if ?sci_si eq ?SCI_IN_USE
           mov     [bp].sreg_si,si
           ?sci_sreg_si = ?SCI_IN_USE
        endif
        jmp     short labelarg          ; Go execute thread instruction
        endm


;***    cmp_je --  compare word at SS:SI with operand
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    If the operand equals the current user argument, a "jump"
;               is made to the labelled thop indicated, otherwise
;               we continue with the next thop.
;
;       USES    NONE

cmp_je  macro   comparg,labelarg
        if ?sci_di eq ?SCI_IN_USE
           mov     [bp].sreg_di,di
           ?sci_sreg_di = ?SCI_IN_USE
        endif
        if ?sci_si eq ?SCI_IN_USE
           mov     [bp].sreg_si,si
           ?sci_sreg_si = ?SCI_IN_USE
        endif
        cmp     word ptr [bp+?sci_argptr],comparg ; compare op with user argument
        if1
            ifdef labelarg
                %out SCI macro variable error possible after backwards jump
            endif
        endif
        je      short labelarg          ; if equal go to thop indicated
        endm


;*
;*      shadow register load thread operators
;*


;***    ld_dsdx  --  load dword at ss:bp+?sci_argptr into DX, shadow DS
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (dx)           = [(ss:bp+?sci_argptr)]
;               ([bp].sreg_ds) = [(ss:bp+?sci_argptr+2)]
;               (?sci_argptr)  = ?sci_argptr+4
;
;       USES    Current sci_stamprpl work register

ld_dsdx macro
        mov     dx,[bp+?sci_argptr+2]
        ?sci_dx = ?SCI_IN_USE
        sci_stamprpl <dx>               ; adjust the RPL of selector
        mov     [bp].sreg_ds,dx
        mov     dx,[bp+?sci_argptr]
        ?sci_argptr = ?sci_argptr+4
        endm


;***    ld_ds  --  load word at ss:bp+?sci_argptr into shadow ds
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    ([bp].sreg_ds) = [(ss:bp+?sci_argptr)]
;               (?sci_argptr)  = ?sci_argptr+2
;
;       USES    1 work register and current sci_stamprpl work register

ld_ds   macro
        sci_getreg reg1                          ; get a work reg
        if ?sci_rc EQ ?SCI_ERROR
           sci_getbasereg reg1                   ; get a base work reg
        endif
        mov     reg1,word ptr [bp+?sci_argptr]
        sci_stamprpl reg1                        ; adjust the RPL of selector
        mov     [bp].sreg_ds,reg1
        sci_freereg reg1                         ; free the work reg
        ?sci_argptr = ?sci_argptr+2
        endm


;***    ld_dsdxnorpl  --  load dword at ss:bp+?sci_argptr into dx, shadow ds
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (dx)           = first argument word
;               ([bp].sreg_ds) = second argument word
;               (?sci_argptr)  = ?sci_argptr+4
;
;       USES    NONE

ld_dsdx_norpl macro
        mov     dx,word ptr [bp+?sci_argptr+2]
        mov     [bp].sreg_ds,dx
        mov     dx,word ptr [bp+?sci_argptr]
        ?sci_argptr = ?sci_argptr+4
        ?sci_dx = ?SCI_IN_USE
        endm


;***    ld_ds_norpl  --  load word at ss:bp+?sci_argptr into shadow ds
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    ([bp].sreg_ds) = [(ss:bp+?sci_argptr)]
;               (?sci_argptr)  = ?sci_argptr+2
;
;       USES    1 work register

ld_ds_norpl macro
        sci_getreg reg1                          ; get a work reg
        if ?sci_rc EQ ?SCI_ERROR
           sci_getbasereg reg1                   ; get a base work reg
        endif
        mov     reg1,word ptr [bp+?sci_argptr]
        mov     [bp].sreg_ds,reg1
        sci_freereg reg1                         ; free the work reg
        ?sci_argptr = ?sci_argptr+2
        endm


;***    ld_es  --  load word at ss:bp+?sci_argptr into shadow es
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    ([bp].sreg_es) = [(ss:bp+?sci_argptr)]
;               (?sci_argptr)  = ?sci_argptr+2
;
;       USES    1 work register and current sci_stamprpl work register

ld_es   macro
        rplstampsel                              ; adjust the RPL of selector
        sci_getreg reg1                          ; get a work reg
        if ?sci_rc EQ ?SCI_ERROR
           sci_getbasereg reg1                   ; get a base work reg
        endif
        mov     reg1,word ptr [bp+?sci_argptr]
        mov     [bp].sreg_es,reg1
        sci_freereg reg1                         ; free the work reg
        ?sci_argptr = ?sci_argptr+2
        endm


;***    ld_es_norpl  --  load word at ss:bp+?sci_argptr into shadow es
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    ([bp].sreg_es) = [(ss:bp+?sci_argptr)]
;               (?sci_argptr)  = ?sci_argptr+2
;
;       USES    1 work register

ld_es_norpl macro
        sci_getreg reg1                          ; get a work reg
        if ?sci_rc EQ ?SCI_ERROR
           sci_getbasereg reg1                   ; get a base work reg
        endif
        mov     reg1,word ptr [bp+?sci_argptr]
        mov     [bp].sreg_es,reg1
        sci_freereg reg1                         ; free the work reg
        ?sci_argptr = ?sci_argptr+2
        endm


;*
;*      direct (non-shadow) register load thread operators
;*


;***    ld_ax  --  load word at ss:bp+?sci_argptr into ax
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (ax)          = argument value
;               (?sci_argptr) = ?sci_argptr+2
;
;       USES    NONE

ld_ax   macro
        mov     ax,word ptr [bp+?sci_argptr]
        ?sci_argptr = ?sci_argptr+2
        ?sci_ax = ?SCI_IN_USE
        endm


;***    ld_ah  --  load byte at ss:bp+?sci_argptr into ah
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (ah)          = argument value
;               (?sci_argptr) = ?sci_argptr+2
;
;       USES    NONE

ld_ah   macro
        mov     ah,byte ptr [bp+?sci_argptr]
        ?sci_argptr = ?sci_argptr+2
        ?sci_ax = ?SCI_IN_USE
        endm


;***    ld_al  --  load byte at ss:bp+?sci_argptr into al
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (al)          = argument value
;               (?sci_argptr) = ?sci_argptr+2
;
;       USES    NONE

ld_al   macro
        mov     al,byte ptr [bp+?sci_argptr]
        ?sci_argptr = ?sci_argptr+2
        ?sci_ax = ?SCI_IN_USE
        endm


;***    ld_bx  --  load word at ss:bp+?sci_argptr into bx
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (bx)          = argument value
;               (?sci_argptr) = ?sci_argptr+2
;
;       USES    NONE

ld_bx   macro
        mov     bx,word ptr [bp+?sci_argptr]
        ?sci_argptr = ?sci_argptr+2
        ?sci_bx = ?SCI_IN_USE
        endm


;***    ld_bh  --  load byte at ss:bp+?sci_argptr into bh
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (bh)          = argument value
;               (?sci_argptr) = ?sci_argptr+2
;
;       USES    NONE

ld_bh   macro
        mov     bh,byte ptr [bp+?sci_argptr]
        ?sci_argptr = ?sci_argptr+2
        ?sci_bx = ?SCI_IN_USE
        endm


;***    ld_bl  --  load byte at ss:bp+?sci_argptr into bl
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (bl)          = argument value
;               (?sci_argptr) = ?sci_argptr+2
;
;       USES    NONE

ld_bl   macro
        mov     bl,byte ptr [bp+?sci_argptr]
        ?sci_argptr = ?sci_argptr+2
        ?sci_bx = ?SCI_IN_USE
        endm


;***    ld_bx_0  --  load zero into bx
;
;       ENTRY   NONE
;
;       EXIT    (bx) = 0
;
;       USES    NONE

ld_bx_0 macro
        xor     bx,bx
        ?sci_bx = ?SCI_IN_USE
        endm


;***    ld_bx_1  --  load one into bx
;
;       ENTRY   NONE
;
;       EXIT    (bx) = 1
;
;       USES    NONE

ld_bx_1 macro
        mov     bx,1
        ?sci_bx = ?SCI_IN_USE
        endm


;***    ld_cx  --  load word at ss:bp+?sci_argptr into cx
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (cx)          = argument value
;               (?sci_argptr) = ?sci_argptr+2
;
;       USES    NONE

ld_cx   macro
        mov     cx,word ptr [bp+?sci_argptr]
        ?sci_argptr = ?sci_argptr+2
        ?sci_cx = ?SCI_IN_USE
        endm


;***    ld_cx_0  --  load zero into cx
;
;       ENTRY   NONE
;
;       EXIT    (cx) = 0
;
;       USES    NONE

ld_cx_0 macro
        xor     cx,cx
        ?sci_cx = ?SCI_IN_USE
        endm


;***    ld_dx  --  load word at ss:bp+?sci_argptr into dx
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (dx)          = argument value
;               (?sci_argptr) = ?sci_argptr+2
;
;       USES    NONE

ld_dx   macro
        mov     dx,word ptr [bp+?sci_argptr]
        ?sci_argptr = ?sci_argptr+2
        ?sci_dx = ?SCI_IN_USE
        endm


;***    ld_dx_0  --  load zero into dx
;
;       ENTRY   NONE
;
;       EXIT    (dx) = 0
;
;       USES    NONE

ld_dx_0 macro
        xor     dx,dx
        ?sci_dx = ?SCI_IN_USE
        endm


;***    ld_dl  --  load byte at ss:bp+?sci_argptr into dl
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (dl)          = argument value
;               (?sci_argptr) = ?sci_argptr+2
;
;       USES    NONE

ld_dl   macro
        mov     dl,byte ptr [bp+?sci_argptr]
        ?sci_argptr = ?sci_argptr+2
        ?sci_dx = ?SCI_IN_USE
        endm


;***    ld_si  --  load word at ss:bp+?sci_argptr into si
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (si)          = argument value
;               (?sci_argptr) = ?sci_argptr+2
;
;       USES    NONE

ld_si   macro
        mov     si,word ptr [bp+?sci_argptr]
        ?sci_argptr = ?sci_argptr+2
        ?sci_si = ?SCI_IN_USE
        ?sci_sreg_si = ?SCI_NOT_IN_USE
        endm


;***    ld_si_0  --  load zero into si
;
;       ENTRY   NONE
;
;       EXIT    (si) = 0
;
;       USES    NONE

ld_si_0 macro
        xor     si,si
        ?sci_si = ?SCI_IN_USE
        ?sci_sreg_si = ?SCI_NOT_IN_USE
        endm

;***    ld_si_1  --  load one into si
;
;       ENTRY   NONE
;
;       EXIT    (si) = 1
;
;       USES    NONE

ld_si_1 macro
        mov     si,1
        ?sci_si = ?SCI_IN_USE
        ?sci_sreg_si = ?SCI_NOT_IN_USE
        endm


;***    ld_di  --  load word at ss:bp+?sci_argptr into di
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (di)          = argument value
;               (?sci_argptr) = ?sci_argptr+2
;
;       USES    NONE

ld_di   macro
        mov     di,word ptr [bp+?sci_argptr]
        ?sci_argptr = ?sci_argptr+2
        ?sci_di = ?SCI_IN_USE
        ?sci_sreg_di = ?SCI_NOT_IN_USE
        endm


;***    ld_disi  --  load dword at ss:bp+?sci_argptr into si, di
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (si)          = [(ss:bp+?sci_argptr)]
;               (di)          = [(ss:bp+?sci_argptr+2)]
;               (?sci_argptr) = ?sci_argptr+4
;
;       USES    Current sci_stamprpl work register

ld_disi macro
        rplstampptr                            ; adjust the RPL of selector
        mov     si,[bp+?sci_argptr]
        mov     di,[bp+?sci_argptr+2]
        ?sci_argptr = ?sci_argptr+4
        ?sci_si = ?SCI_IN_USE
        ?sci_di = ?SCI_IN_USE
        ?sci_sreg_si = ?SCI_NOT_IN_USE
        ?sci_sreg_di = ?SCI_NOT_IN_USE
        endm


;***    ld_di_0  --  load zero into di
;
;       ENTRY   NONE
;
;       EXIT    (di) = 0
;
;       USES    NONE

ld_di_0 macro
        xor     di,di
        ?sci_di = ?SCI_IN_USE
        ?sci_sreg_di = ?SCI_NOT_IN_USE
        endm


;*
;*      Indirect load thops
;*

;***    ld_ind_ax -- load ax with word pointed to by the double word at
;                    ss:bp+?sci_argptr
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (ax)          = [(ss:bp+?sci_argptr)]
;               (?sci_argptr) = ?sci_argptr+4
;
;       USES    ds, current sci_stamprpl work register, a base work reg
;
;       NOTE:  This thop needs work for verifcation of valid address.

ld_ind_ax macro
        rplstampptr                              ; adjust the RPL of selector
        sci_getbasereg reg1                      ; get a base work reg
        lds     reg1,dword ptr [bp+?sci_argptr]  ; (ds:reg1) -> source word
        mov     ax,[reg1]                        ; (ax) = indirect word
        sci_freereg reg1                         ; free the work reg
        ?sci_argptr = ?sci_argptr+4
        ?sci_ax = ?SCI_IN_USE
        ?sci_ds = ?SCI_UNKNOWN
        endm


;***    ld_ind_bx -- load bx with word pointed to by the double word at
;                    ss:bp+?sci_argptr
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (bx)          = [(ss:bp+?sci_argptr)]
;               (?sci_argptr) = ?sci_argptr+4
;
;       USES    ds
;
;       NOTE:  This thop needs work for verifcation of valid address.

ld_ind_bx macro
        rplstampptr                            ; adjust the RPL of selector
        lds     bx,dword ptr [bp+?sci_argptr]  ; (ds:bx) -> source word
        mov     bx,[bx]                        ; (bx) = indirect word
        ?sci_argptr = ?sci_argptr+4
        ?sci_bx = ?SCI_IN_USE
        ?sci_ds = ?SCI_UNKNOWN
        endm


;***    ld_ind_cx -- load cx with word pointed to by the double word at
;                    ss:bp+?sci_argptr
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (cx)          = [(ss:bp+?sci_argptr)]
;               (?sci_argptr) = ?sci_argptr+4
;
;       USES    ds, current sci_stamprpl work register, a base work reg
;
;       NOTE:  This thop needs work for verifcation of valid address.

ld_ind_cx macro
        rplstampptr                              ; adjust the RPL of selector
        sci_getbasereg reg1                      ; get a base work reg
        lds     reg1,dword ptr [bp+?sci_argptr]  ; (ds:reg1) -> source word
        mov     cx,[reg1]                        ; (cx) = indirect word
        sci_freereg reg1                         ; free the work reg
        ?sci_argptr = ?sci_argptr+4
        ?sci_cx = ?SCI_IN_USE
        ?sci_ds = ?SCI_UNKNOWN
        endm


;***    ld_ind_si -- load si with word pointed to by the double word at
;                    ss:bp+?sci_argptr
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (si)          = [(ss:bp+?sci_argptr)]
;               (?sci_argptr) = ?sci_argptr+4
;
;       USES    ds
;
;       NOTE:  This thop needs work for verifcation of valid address.

ld_ind_si macro
        rplstampptr                            ; adjust the RPL of selector
        lds     si,dword ptr [bp+?sci_argptr]  ; (ds:si) -> source word
        mov     si,[si]                        ; (si) = indirect word
        ?sci_argptr = ?sci_argptr+4
        ?sci_si = ?SCI_IN_USE
        ?sci_sreg_si = ?SCI_NOT_IN_USE
        ?sci_ds = ?SCI_UNKNOWN
        endm


;*
;*      Load Immediate thops
;*


;***    ld_imm_ax -- load ax with the immediate value specified
;
;       ENTRY   NONE
;
;       EXIT    (ax) = immediate value
;
;       USES    NONE

ld_imm_ax macro immedValue
        if immedValue eq 0
           xor     ax,ax
        else
           mov     ax,immedValue
        endif
        ?sci_ax = ?SCI_IN_USE
        endm


;***    ld_imm_al -- load al with the immediate value specified
;
;       ENTRY   NONE
;
;       EXIT    (al) = immediate value
;
;       USES    NONE

ld_imm_al macro immedValue
        if immedValue eq 0
           xor     al,al
        else
           mov     al,immedValue
        endif
        ?sci_ax = ?SCI_IN_USE
        endm

;***    ld_imm_ah -- load ah with the immediate value specified
;
;       ENTRY   NONE
;
;       EXIT    (ah) = immediate value
;
;       USES    NONE

ld_imm_ah macro immedValue
        if immedValue eq 0
           xor     ah,ah
        else
           mov     ah,immedValue
        endif
        ?sci_ax = ?SCI_IN_USE
        endm

;***    ld_imm_cx -- load cx with the immediate value specified
;
;       ENTRY   NONE
;
;       EXIT    (cx) = immediate value
;
;       USES    NONE

ld_imm_cx macro immedValue
        if immedValue eq 0
           xor     cx,cx
        else
           mov     cx,immedValue
        endif
        ?sci_cx = ?SCI_IN_USE
        endm


;***    ld_imm_dx -- load dx with the immediate value specified
;
;       ENTRY   NONE
;
;       EXIT    (dx) = immediate value
;
;       USES    NONE

ld_imm_dx macro immedValue
        if immedValue eq 0
           xor     dx,dx
        else
           mov     dx,immedValue
        endif
        ?sci_dx = ?SCI_IN_USE
        endm


;*
;*      inter-register move thops
;*


;***    mv_esdi_dsdx  --  move shadow ds:real dx to shadow es:real di
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (di)         = (dx)
;               [bp].sreg_es = [bp].sreg_ds
;
;       USES    NONE

mv_esdi_dsdx macro
        mov     di,[bp].sreg_ds
        mov     [bp].sreg_es,di
        mov     di,dx
        ?sci_di = ?SCI_IN_USE
        ?sci_sreg_di = ?SCI_NOT_IN_USE
        endm


;***    mv_si_dx  --  move dx to si
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    si = dx
;
;       USES    NONE

mv_si_dx macro
        mov     si,dx
        ?sci_si = ?SCI_IN_USE
        ?sci_sreg_si = ?SCI_NOT_IN_USE
        endm


;*
;*      provide offsets to user arguments thread ops
;*


;***    mv_si_si  --  load si with offset of current user argument
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (si) = offset of current user argument
;
;       USES    NONE

mv_si_si macro
        lea     si,?sci_argptr[bp]
        ?sci_si = ?SCI_IN_USE
        ?sci_sreg_si = ?SCI_NOT_IN_USE
        endm


;***    ld_parampkt_bx -- load bx with the offset of the user arguments
;
;       ENTRY   (ss:bp) -> shadow register frame
;
;       EXIT    (bx) = offset of user parameters
;
;       USES    NONE

ld_parampkt_bx  macro
        lea     bx,[bp].kstk_args       ; get offset to user arguments
        ?sci_bx = ?SCI_IN_USE
        endm


;*
;*      Load user arguments into tcb variable thops
;*


;***    ld_tcb -- load the tcb variable with the word from user arguments
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    ss:[tcb variable] = [(ss:bp+?sci_argptr)]
;               (?sci_argptr) = ?sci_argptr+2
;
;       USES    2 work registers

ld_tcb  macro   tcboffset
        sci_getbasereg reg1                      ; get a base work reg
        sci_getreg reg2                          ; get a second work reg
        if ?sci_rc EQ ?SCI_ERROR
           sci_getbasereg reg2                   ; get a second base work reg
        endif
        mov     reg1,ss:[TKOPTDA.CurrTCB]
        mov     reg2,word ptr [bp+?sci_argptr]
        mov     word ptr ss:[reg1+tcboffset],reg2
        sci_freereg reg2                         ; free the work reg
        sci_freereg reg1                         ; free the work reg
        ?sci_argptr = ?sci_argptr+2
        endm


;***    ld_tcb_ptr -- load the tcb variable with the ptr from user arguments
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    ss:[tcb variable] = [(ss:bp+?sci_argptr)] (dword)
;               (?sci_argptr) = ?sci_argptr+4
;
;       USES    Current sci_stamprpl work register, and 2 work registers

ld_tcb_ptr macro tcboffset
        rplstampptr                              ; adjust the RPL of selector
        sci_getbasereg reg1                      ; get a base work reg
        sci_getreg reg2                          ; get a second work reg
        if ?sci_rc EQ ?SCI_ERROR
           sci_getbasereg reg2                   ; get again (this will work)
        endif
        mov     reg1,ss:[TKOPTDA.CurrTCB]
        db      66h                              ; load a dword
        mov     reg2,word ptr [bp+?sci_argptr]
        db      66h                              ; store a dword
        mov     word ptr ss:[reg1+tcboffset],reg2
        sci_freereg reg2                         ; free the work reg
        sci_freereg reg1                         ; free the work reg
        ?sci_argptr = ?sci_argptr+4
        endm


;*
;*      store register thread operators
;*


;***    st_ax  --  store ax into word pointed to by ss:bp+?sci_argptr
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    [(ss:bp+?sci_argptr)] = ax
;               (?sci_argptr)         = ?sci_argptr+4
;
;       USES    Current sci_stamprpl work register, ds and 1 work register

st_ax   macro
        rplstampptr                              ; adjust the RPL of selector
        sci_getbasereg reg1                      ; get a base work reg
        lds     reg1,dword ptr [bp+?sci_argptr]  ; (ds:reg1) -> target word
        mov     word ptr [reg1],ax
        sci_freereg reg1                         ; free the work reg
        ?sci_argptr = ?sci_argptr+4
        ?sci_ds = ?SCI_UNKNOWN
        endm


;***    st_al  --  store al into byte pointed to by ss:bp+?sci_argptr
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    [(ss:bp+?sci_argptr)] = al
;               (?sci_argptr)         = ?sci_argptr+4
;
;       USES    Current sci_stamprpl work register, ds and 1 work register

st_al   macro
        rplstampptr                              ; adjust the RPL of selector
        sci_getbasereg reg1                      ; get a base work reg
        lds     reg1,dword ptr [bp+?sci_argptr]  ; (ds:reg1) -> target byte
        mov     byte ptr [reg1],al
        sci_freereg reg1                         ; free the work reg
        ?sci_argptr = ?sci_argptr+4
        ?sci_ds = ?SCI_UNKNOWN
        endm


;***    st_bx  --  store bx into word pointed to by ss:bp+?sci_argptr
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    [(ss:bp+?sci_argptr)] = bx
;               (?sci_argptr)         = ?sci_argptr+4
;
;       USES    Current sci_stamprpl work register, ds and 1 work register

st_bx   macro
        rplstampptr                              ; adjust the RPL of selector
        sci_getbasereg reg1                      ; get a base work reg
        lds     reg1,dword ptr [bp+?sci_argptr]  ; (ds:reg1) -> target word
        mov     word ptr [reg1],bx
        sci_freereg reg1                         ; free the work reg
        ?sci_argptr = ?sci_argptr+4
        ?sci_ds = ?SCI_UNKNOWN
        endm


;***    stnz_cx  --  store cx into word pointed to by ss:bp+?sci_argptr
;                    if ptr not null
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    [(ss:bp+?sci_argptr)] = cx (if pointer not null)
;                                       Only stnz_cx allows a null pointer.
;               (?sci_argptr)         = ?sci_argptr+4
;
;       USES    Current sci_stamprpl work register, ds and 1 work register

stnz_cx macro
        local   stc1
        sci_getbasereg reg1             ; get a base work reg
        sci_setstampreg                 ; make macro state independent of path

        test    word ptr [bp+?sci_argptr+2],NOT RPL_RING3  ; Check for null
        jz      short stc1                       ; selector ignoring RPL field
        rplstampptr                              ; adjust the RPL of selector
        lds     reg1,dword ptr [bp+?sci_argptr]  ; (ds:reg1) -> target word
        mov     word ptr [reg1],cx
stc1:
        sci_freereg reg1                         ; free the work reg
        ?sci_argptr = ?sci_argptr+4
        ?sci_ds = ?SCI_UNKNOWN
        endm


;***    st_cx  --  store cx into word pointed to by ss:bp+?sci_argptr
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    [(ss:bp+?sci_argptr)] = cx
;               (?sci_argptr)         = ?sci_argptr+4
;
;       USES    Current sci_stamprpl work register, ds and 1 work register

st_cx   macro
        rplstampptr                              ; adjust the RPL of selector
        sci_getbasereg reg1                      ; get a base work reg
        lds     reg1,dword ptr [bp+?sci_argptr]  ; (ds:reg1) -> target word
        mov     word ptr [reg1],cx
        sci_freereg reg1                         ; free the work reg
        ?sci_argptr = ?sci_argptr+4
        ?sci_ds = ?SCI_UNKNOWN
        endm


;***    stnz_axdx  --  store dx, then ax into dword pointed to by
;                      ss:bp+?sci_argptr if ptr not null
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    [(ss:bp+?sci_argptr)] = dx, ax (if pointer not null)
;                                       Only stnz_axdx allows a null pointer.
;               (?sci_argptr)         = ?sci_argptr+4
;
;       USES    Current sci_stamprpl work register, ds and 1 work register

stnz_axdx macro
        local   stdad1
        sci_getbasereg reg1             ; get a base work reg
        sci_setstampreg                 ; make macro state independent of path

        test    word ptr [bp+?sci_argptr+2],NOT RPL_RING3  ; Check for null
        jz      short stdad1                     ; selector ignoring RPL field
        rplstampptr                              ; adjust the RPL of selector
        lds     reg1,dword ptr [bp+?sci_argptr]  ; (ds:reg1) -> target word
        mov     word ptr [reg1],dx               ; low order word (dx)
        mov     word ptr [reg1+2],ax             ; high order word (ax)
stdad1:
        sci_freereg reg1                         ; free the work reg
        ?sci_argptr = ?sci_argptr+4
        ?sci_ds = ?SCI_UNKNOWN
        endm


;***    st_axdx  --  store dx, then ax into dword pointed to by
;                    ss:bp+?sci_argptr
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    [(ss:bp+?sci_argptr)] = dx, ax
;               (?sci_argptr)         = ?sci_argptr+4
;
;       USES    Current sci_stamprpl work register, ds and 1 work register

st_axdx macro
        rplstampptr                              ; adjust the RPL of selector
        sci_getbasereg reg1                      ; get a base work reg
        lds     reg1,dword ptr [bp+?sci_argptr]  ; (ds:reg1) -> target word
        mov     word ptr [reg1],dx               ; low order word (dx)
        mov     word ptr [reg1+2],ax             ; high order word (ax)
        sci_freereg reg1                         ; free the work reg
        ?sci_argptr = ?sci_argptr+4
        ?sci_ds = ?SCI_UNKNOWN
        endm


;***    st_dx  --  store dx into word pointed to by ss:bp+?sci_argptr
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    [(ss:bp+?sci_argptr)] = dx
;               (?sci_argptr)         = ?sci_argptr+4
;
;       USES    Current sci_stamprpl work register, ds and 1 work register

st_dx   macro
        rplstampptr                              ; adjust the RPL of selector
        sci_getbasereg reg1                      ; get a base work reg
        lds     reg1,dword ptr [bp+?sci_argptr]  ; (ds:reg1) -> target word
        mov     word ptr [reg1],dx
        sci_freereg reg1                         ; free the work reg
        ?sci_argptr = ?sci_argptr+4
        ?sci_ds = ?SCI_UNKNOWN
        endm


;***    stnz_dxax  --  store ax, dx, into dword pointed to by
;                      ss:bp+?sci_argptr if ptr not null
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    [(ss:bp+?sci_argptr)] = ax, dx (if pointer not null)
;                                       Only stnz_dxax allows a null pointer.
;               (?sci_argptr)         = ?sci_argptr+4
;
;       USES    Current sci_stamprpl work register, ds and 1 work register

stnz_dxax macro
        local   stda1
        sci_getbasereg reg1             ; get a base work reg
        sci_setstampreg                 ; make macro state independent of path

        test    word ptr [bp+?sci_argptr+2],NOT RPL_RING3  ; Check for null
        jz      short stda1    ; selector ignoring RPL field, jump if null
        rplstampptr                              ; adjust the RPL of selector
        lds     reg1,dword ptr [bp+?sci_argptr]  ; (ds:reg1) -> target word
        mov     word ptr [reg1],ax               ; low order word (ax)
        mov     word ptr [reg1+2],dx             ; high order word (dx)
stda1:
        sci_freereg reg1                         ; free the work reg
        ?sci_argptr = ?sci_argptr+4
        ?sci_ds = ?SCI_UNKNOWN
        endm


;***    st_dxax  --  store ax, dx, into dword pointed to by
;                    ss:bp+?sci_argptr
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    [(ss:bp+?sci_argptr)] = ax, dx
;               (?sci_argptr)         = ?sci_argptr+4
;
;       USES    Current sci_stamprpl work register, ds and 1 work register

st_dxax macro
        rplstampptr                              ; adjust the RPL of selector
        sci_getbasereg reg1                      ; get a base work reg
        lds     reg1,dword ptr [bp+?sci_argptr]  ; (ds:reg1) -> target word
        mov     word ptr [reg1],ax               ; low order word (ax)
        mov     word ptr [reg1+2],dx             ; high order word (dx)
        sci_freereg reg1                         ; free the work reg
        ?sci_argptr = ?sci_argptr+4
        ?sci_ds = ?SCI_UNKNOWN
        endm


;***    st_edx  --  store edx into dword pointed to by
;                    ss:bp+?sci_argptr
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    [(ss:bp+?sci_argptr)] = edx
;               (?sci_argptr)         = ?sci_argptr+4
;
;       USES    Current sci_stamprpl work register, ds and 1 work register

st_edx macro
        rplstampptr                              ; adjust the RPL of selector
        sci_getbasereg reg1                      ; get a base work reg
        lds     reg1,dword ptr [bp+?sci_argptr]  ; (ds:reg1) -> target word
        CpuMode 386
        mov     dword ptr [reg1],edx             ;
        CpuMode Reset
        sci_freereg reg1                         ; free the work reg
        ?sci_argptr = ?sci_argptr+4
        ?sci_ds = ?SCI_UNKNOWN
        endm


;***    st_dxcx  --  store dx, cx into dword pointed to by
;                    ss:bp+?sci_argptr
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    [(ss:bp+?sci_argptr)] = dx, cx
;               (?sci_argptr)         = ?sci_argptr+4
;
;       USES    Current sci_stamprpl work register, ds and 1 work register

st_dxcx macro
        rplstampptr                              ; adjust the RPL of selector
        sci_getbasereg reg1                      ; get a base work reg
        lds     reg1,dword ptr [bp+?sci_argptr]  ; (ds:reg1) -> target word
        mov     word ptr [reg1],cx               ; low order word (cx)
        mov     word ptr [reg1+2],dx             ; high order word (dx)
        sci_freereg reg1                         ; free the work reg
        ?sci_argptr = ?sci_argptr+4
        ?sci_ds = ?SCI_UNKNOWN
        endm


;***    st_axbxcx  --  store ax, bx, and cx into ss:bp+?sci_argptr
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    [(ss:bp+?sci_argptr)] = ax, bx, cx
;               (?sci_argptr)         = ?sci_argptr+4
;
;       USES    Current sci_stamprpl work register, ds and 1 work register

st_axbxcx macro
        rplstampptr                              ; adjust the RPL of selector
        sci_getbasereg reg1                      ; get a base work reg
        lds     reg1,dword ptr [bp+?sci_argptr]  ; (ds:reg1) -> target word
        mov     word ptr [reg1],ax               ; low order word (ax)
        mov     word ptr [reg1+2],bx             ; middle word (bx)
        mov     word ptr [reg1+4],cx             ; high order word (cx)
        sci_freereg reg1                         ; free the work reg
        ?sci_argptr = ?sci_argptr+4
        ?sci_ds = ?SCI_UNKNOWN
        endm


;***    st_axbxcxdx  --  store ax, bx, cx, and dx into ss:bp+?sci_argptr
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    [(ss:bp+?sci_argptr)] = ax, bx, cx, dx
;               (?sci_argptr)         = ?sci_argptr+4
;
;       USES    Current sci_stamprpl work register, ds and 1 work register

st_axbxcxdx macro
        rplstampptr                              ; adjust the RPL of selector
        sci_getbasereg reg1                      ; get a base work reg
        lds     reg1,dword ptr [bp+?sci_argptr]  ; (ds:reg1) -> target word
        mov     word ptr [reg1],ax               ; low order word (ax)
        mov     word ptr [reg1+2],bx             ; middle low word (bx)
        mov     word ptr [reg1+4],cx             ; middle high word (cx)
        mov     word ptr [reg1+6],dx             ; high order word (dx)
        sci_freereg reg1                         ; free the work reg
        ?sci_argptr = ?sci_argptr+4
        ?sci_ds = ?SCI_UNKNOWN
        endm


;*
;*      skip thread operators
;*


;***    skip_word  --  "consume" a word argument, do nothing with it
;
;       skip_word advances ss:bp+?sci_argptr past a word argument.
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (?sci_argptr) = ?sci_argptr+2
;
;       USES    NONE

skip_word macro
        ?sci_argptr = ?sci_argptr+2       ; one word, 2 bytes
        endm


;***    skip_2word  --  "consume" 2 words of arguments, do nothing with it
;
;       skip_2word advances ss:bp+?sci_argptr past 2 words of arguments.
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (?sci_argptr) = ?sci_argptr+4
;
;       USES    NONE

skip_2word macro
        ?sci_argptr = ?sci_argptr+4       ; two words, 4 bytes
        endm


;***    skip_ptr  --  "consume" a pointer argument, do nothing with it
;
;       skip_ptr advances ss:bp+?sci_argptr past a DWORD pointer argument.
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (?sci_argptr) = ?sci_argptr+4
;
;       USES    NONE

skip_ptr macro
        ?sci_argptr = ?sci_argptr+4       ; one dword, 4 bytes
        endm


;***    skip_4word  --  "consume" 4 words of arguments, do nothing with them
;
;       skip_4word advances ss:bp+?sci_argptr past 4 words of arguments.
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (?sci_argptr) = ?sci_argptr+8
;
;       USES    NONE

skip_4word macro
        ?sci_argptr = ?sci_argptr+8       ; 4 words, 8 bytes
        endm


;***    skip_2ptr  --  "consume" 2 pointer arguments, do nothing with them
;
;       skip_2ptr advances ss:bp+?sci_argptr past 2 DWORD pointer arguments.
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (?sci_argptr) = ?sci_argptr+8
;
;       USES    NONE

skip_2ptr macro
        ?sci_argptr = ?sci_argptr+8       ; 2 dwords, 8 bytes
        endm


;***    skip_5word  --  "consume" 5 words of arguments, do nothing with them
;
;       skip_5word advances ss:bp+?sci_argptr past 5 words of arguments.
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (?sci_argptr) = ?sci_argptr+10
;
;       USES    NONE

skip_5word macro
        ?sci_argptr = ?sci_argptr+10      ; 5 words, 10 bytes
        endm


;***    skip_7word  --  "consume" 7 words of arguments, do nothing with them
;
;       skip_7word advances ss:bp+?sci_argptr past 7 words of arguments.
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (?sci_argptr) = ?sci_argptr+14
;
;       USES    NONE

skip_7word macro
        ?sci_argptr = ?sci_argptr+14      ; 7 words, 14 bytes
        endm


;***    skip_8word  --  "consume" 8 words of arguments, do nothing with them
;
;       skip_8word advances ss:bp+?sci_argptr past 8 words of arguments.
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (?sci_argptr) = ?sci_argptr+16
;
;       USES    NONE

skip_8word macro
        ?sci_argptr = ?sci_argptr+16      ; 8 words, 16 bytes
        endm


;***    skip_9word  --  "consume" 9 words of arguments, do nothing with them
;
;       skip_9word advances ss:bp+?sci_argptr past 9 words of arguments.
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (?sci_argptr) = ?sci_argptr+18
;
;       USES    NONE

skip_9word macro
        ?sci_argptr = ?sci_argptr+18      ; 9 words, 18 bytes
        endm


;***    skip_10word  -- "consume" 10 words of arguments, do nothing with them
;
;       skip_10word advances ss:bp+?sci_argptr past 10 words of arguments.
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (?sci_argptr) = ?sci_argptr+20
;
;       USES    NONE

skip_10word macro
        ?sci_argptr = ?sci_argptr+20      ; 10 words, 20 bytes
        endm


;***    skip_12word  -- "consume" 12 words of arguments, do nothing with them
;
;       skip_12word advances ss:bp+?sci_argptr past 12 words of arguments.
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (?sci_argptr) = ?sci_argptr+24
;
;       USES    NONE

skip_12word macro
        ?sci_argptr = ?sci_argptr+24      ; 12 words, 24 bytes
        endm

;***    backup_2word  --  "backup" over 2 words of arguments, do nothing with them
;
;       backup_2word backs up ss:bp+?sci_argptr over 2 words of arguments.
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (?sci_argptr) = ?sci_argptr-4
;
;       USES    NONE

backup_2word macro
        ?sci_argptr = ?sci_argptr-4       ; 2 words, 4 bytes
        endm


;*
;*      Test argument thops
;*


;***    reser_dd_arg  -- check that the reserved double word argument is zero.
;
;       reser_dd_arg checks that the next two argument words are both zero.
;       This testing part still has to written.
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (?sci_argptr) = ?sci_argptr+4
;               if error, will NOT return
;
;       USES    NONE

reser_dd_arg macro
        .386p
        cmp     dword ptr [bp+?sci_argptr],0
        ?sci_argptr = ?sci_argptr+4       ; 2 words, 4 bytes
        if2
            ifndef  UsrArgError
                extrn   UsrArgError:near
            endif
        endif
        jne     UsrArgError             ; not zero, complain
        CPUMode reset
        endm


;*
;*      Asciiz string thops
;*


;***    getusrbufz - calls to_getusrbufz
;
;       getusrbufz calls to_getusrbufz.  Returns ERROR_INVALID_NAME if
;       the name is above 128 characters long.
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (ss:bp+?sci_argptr) = pointer to kernel buffer
;
;       USES    NONE

getusrbufz macro
        gendef  getusrbufz
        if ?sci_si eq ?SCI_IN_USE
           mov     [bp].sreg_si,si
           ?sci_sreg_si = ?SCI_IN_USE
        endif
        if ?sci_di eq ?SCI_IN_USE
           mov     [bp].sreg_di,di
           ?sci_sreg_di = ?SCI_IN_USE
        endif
        if ?sci_si ne ?SCI_SS_RPL
           mov     si,[bp].sreg_rpl
        endif
        lea     di,?sci_argptr[bp]      ; DI = current argument pointer
        call    to_getusrbufz           ; transfer to getusrbufz
        ?sci_si = ?SCI_NOT_IN_USE
        ?sci_di = ?SCI_NOT_IN_USE
        ?sci_ds = ?SCI_UNKNOWN
        ?sci_es = ?SCI_UNKNOWN
        endm


;***    getusrnzbuf - calls to_getusrbufz if usr ptr is not null.
;
;       getusrnzbuf verifies that a user's ptr is not a null ptr and
;       calls to_getusrbufz.  If the user's ptr is null no action is
;       taken.  Note that the routine that is passed this pointer
;       must handle null pointers. Returns ERROR_INVALID_NAME is
;       the name is above 128 characters long.
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (ss:bp+?sci_argptr) = pointer to kernel buffer or null pointer
;
;       USES    NONE

getusrnzbuf macro
        local   guz1
        gendef  getusrbufz
        if ?sci_si eq ?SCI_IN_USE
           mov     [bp].sreg_si,si
           ?sci_sreg_si = ?SCI_IN_USE
        endif
        if ?sci_di eq ?SCI_IN_USE
           mov     [bp].sreg_di,di
           ?sci_sreg_di = ?SCI_IN_USE
        endif
        test    word ptr [bp+?sci_argptr+2],RPL_CLR    ; check for null pointer
        jz      short guz1                             ; exit if null
        if ?sci_si ne ?SCI_SS_RPL
           mov     si,[bp].sreg_rpl
        endif
        lea     di,?sci_argptr[bp]      ; DI = current argument pointer
                                        ; SI = User's RPL
        call    to_getusrbufz           ; transfer to getusrbufz
guz1:
        ?sci_si = ?SCI_NOT_IN_USE
        ?sci_di = ?SCI_NOT_IN_USE
        ?sci_ds = ?SCI_UNKNOWN
        ?sci_es = ?SCI_UNKNOWN
        endm


;***    getusrbufz3 - same as getusrbufz except for error return
;
;       getusrbufz3 calls to_getusrbufz3.  Returns ERROR_PATH_NOT_FOUND (3)
;       if the name is above 128 characters long, instead of
;       ERROR_INVALID_NAME.
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (ss:bp+?sci_argptr) = pointer to kernel buffer
;
;       USES    NONE

getusrbufz3 macro
        gendef  getusrbufz3
        if ?sci_si eq ?SCI_IN_USE
           mov     [bp].sreg_si,si
           ?sci_sreg_si = ?SCI_IN_USE
        endif
        if ?sci_di eq ?SCI_IN_USE
           mov     [bp].sreg_di,di
           ?sci_sreg_di = ?SCI_IN_USE
        endif
        if ?sci_si ne ?SCI_SS_RPL
           mov     si,[bp].sreg_rpl
        endif
        lea     di,?sci_argptr[bp]      ; DI = current argument pointer
                                        ; SI = User's RPL
        call    to_getusrbufz3          ; transfer to getusrbufz3
        ?sci_si = ?SCI_NOT_IN_USE
        ?sci_di = ?SCI_NOT_IN_USE
        ?sci_ds = ?SCI_UNKNOWN
        ?sci_es = ?SCI_UNKNOWN
        endm


;### CP20 PTR B721314 ###
;### Add function getusrbufz206
;***    getusrbufz206 - same as getusrbufz except for error return
;
;       getusrbufz206 calls to_getusrbufz206.  Returns
;       ERROR_FILENAME_EXCED_RANGE (206) if the name is above 128 characters
;       long, instead of ERROR_INVALID_NAME.
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    (ss:bp+?sci_argptr) = pointer to kernel buffer
;
;       USES    Current sci_stamprpl work register

getusrbufz206 macro
        gendef  getusrbufz206
        if ?sci_si eq ?SCI_IN_USE
           mov     [bp].sreg_si,si
           ?sci_sreg_si = ?SCI_IN_USE
        endif
        if ?sci_di eq ?SCI_IN_USE
           mov     [bp].sreg_di,di
           ?sci_sreg_di = ?SCI_IN_USE
        endif
        if ?sci_si ne ?SCI_SS_RPL
           mov     si,[bp].sreg_rpl
        endif
        lea     di,?sci_argptr[bp]      ; DI = current argument pointer
                                        ; SI = User's RPL
        call    to_getusrbufz206        ; transfer to getusrbufz206
        ?sci_si = ?SCI_NOT_IN_USE
        ?sci_di = ?SCI_NOT_IN_USE
        ?sci_ds = ?SCI_UNKNOWN
        ?sci_es = ?SCI_UNKNOWN
        endm


;*
;*      Thread Serialization Thops
;*


;***    enterfscrit - enter file system thread critical section
;
;       enterfscrit seizes the semaphore used to serialize thread entry
;       to the file system.
;
;       ENTRY   (ss:bp)   -> shadow register frame
;
;       EXIT    TmpSem = Held by this thread  (see pdata.asm)
;                   or
;               Error Condition due to abnormal wakeup indicating that
;                   we've gotten a kill signal.  Exit via direct jump
;                   to CleanUpReturn, which unwinds from the sci
;                   mechanism and eventually calls Exit_Kmode.
;
;
;       WARNING ** MAY PROCBLOCK **
;
;       USES    None

enterfscrit macro
        gendef  enterfscrit
        if ?sci_di eq ?SCI_IN_USE       ;; make DI available to sci
           mov     [bp].sreg_di,di
           ?sci_sreg_di = ?SCI_IN_USE
        endif
        ?sci_di = ?SCI_NOT_IN_USE
        if ?sci_ax eq ?SCI_IN_USE
           push    ax
        endif
        if ?sci_cx eq ?SCI_IN_USE
           push    cx
        endif
        if ?sci_dx eq ?SCI_IN_USE
           push    dx
        endif
        if ?sci_ds eq ?SCI_UNKNOWN
           FlatContext <ds>,ax
           ?sci_ds = ?SCI_FLAT
        endif
        call    to_enterfscrit
        ?sci_es = ?SCI_FLAT
        if ?sci_dx eq ?SCI_IN_USE
           pop     dx
        endif
        if ?sci_cx eq ?SCI_IN_USE
           pop     cx
        endif
        if ?sci_ax eq ?SCI_IN_USE
           pop     ax
        endif
        endm


;***    exitfscrit - exit file system thread critical section
;
;       exitfscrit releases the semaphore used to serialize thread entry
;       to the file system.
;
;       ENTRY   (ss:bp)   -> shadow register frame
;
;       EXIT    (SS:TmpSem) = 0
;
;       USES    None

exitfscrit macro
        gendef  exitfscrit
        if ?sci_si eq ?SCI_IN_USE       ;; make SI available to sci
           mov     [bp].sreg_si,si
           ?sci_sreg_si = ?SCI_IN_USE
        endif
        ?sci_si = ?SCI_NOT_IN_USE
        call    to_exitfscrit
        ?sci_ds = ?SCI_FLAT
        ?sci_es = ?SCI_FLAT
        endm


;*
;*      RPL stampping thops
;*


;***    rplstampsel --  Set RPL for selector on thop stack
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    [(ss:bp+?sci_argptr)] = selector will have its RPL adjusted
;
;       USES    Current sci_stamprpl work register

rplstampsel macro
        sci_stamprpl <[bp+?sci_argptr]>      ; adjust the RPL of selector
        endm


;***    rplstampptr -- Set RPL for pointer on thop stack
;
;       ENTRY   (ss:bp)             -> shadow register frame
;               (ss:bp+?sci_argptr) -> current argument to perform thread
;                                      operation on
;
;       EXIT    [(ss:bp+?sci_argptr+2)] = selector will have its RPL adjusted
;
;       USES    Current sci_stamprpl work register

rplstampptr macro
        sci_stamprpl <[bp+?sci_argptr+2]>    ; adjust the RPL of selector
        endm


*/      /* end of asm section */

/***    System Call Tracing Mask */


#define TRC_TASK        01              /* tasking calls */
#define TRC_FS          02              /* file system calls */
#define TRC_OTHER       0x8000          /* all other calls */
