;/*static char *SCCSID = "@(#)thkdosh.asm       6.13 93/10/30";*/
;/*static char *SCCSID = "@(#)thkdosh.asm       6.13 92/05/14";*/
;
;       IBM/Microsoft Confidential
;
;       Copyright (c) IBM Corporation 1987, 1989
;       Copyright (c) Microsoft Corporation 1987, 1989
;
;       All Rights Reserved
;
;
; These thunks were generated using the Thunk compiler, then hand
; modified.  DOS32SCANENV was heavily modified to illustrate how the use
; of the macros in thkmacs.inc can simplify the code and make it much more
; maintainable.
;
;
; History:
;
; 04/10/89      Kevinro         Created it
; 12/07/89      JulieB          Changed CODE16 to CODE16C (ring 2 conforming)
; 01/02/90      JeffPar         Added VDD thunks
; 01/23/90      SudeepB         Added new timer thunks
; 09/07/91      Khoa Huynh      Modify the thunk code in DOS32FLATTOSEL
;                               and DOS32SELTOFLAT routines for packed
;                               16-bit segments in the shared arena.
; 02/08/93      PaulDev         mod seltoflat / flattosel to allow
;                               optimisation of thunk compiler
; 11/18/93      Noto            Define which segments for Page Tuning DLL

        TITLE   $dosthkh.asm

        .386
        ?DF     = 1                     ;Disable _TEXT definition in cmacros
        ?QUIET  = 1                     ;turn off cmacros noise
        include error.inc
        include dc1segs.inc             ; DCR 704
        include cmacros.inc
        include thkmacs.inc
        include seldesc.inc

        PUBLIC  DOS32SCANENV
        PUBLIC  DOS32QUERYCP

        EXTRN   DOSSCANENV:FAR
        EXTRN   DOSGETCP:FAR

; External Public Variables for converting pointers in packed region.
        EXTRN   FenceLAddr:dword
        EXTRN   FenceSel:word
        EXTRN   FenceShrLAddr:dword
        EXTRN   FenceShrSel:word
        EXTRN   FencePckLAddr:dword
        EXTRN   FencePckSel:word

CODE32_TUNE1 SEGMENT DWORD USE32 PUBLIC 'CODE'
        EXTRN   DOS32QUERYDOSPROPERTY:NEAR
        EXTRN   DOS32FREEMEM:NEAR
        EXTRN   DOS32ALLOCMEM:NEAR
        EXTRN   THK32FREEBLOCK:NEAR
        EXTRN   THK32HANDLESTRING:NEAR
CODE32_TUNE1 ENDS
CODE32_TUNE2 SEGMENT DWORD USE32 PUBLIC 'CODE'
        EXTRN   THK32DEALLOC:NEAR
        EXTRN   THK32ALLOCVARLEN:NEAR
        EXTRN   THK32ALLOCBLOCK:NEAR
CODE32_TUNE2 ENDS

CODE32_TUNE3 SEGMENT DWORD USE32 PUBLIC 'CODE'
CODE32_TUNE3 ENDS

CODE32_TUNE4 SEGMENT DWORD USE32 PUBLIC 'CODE'
        EXTRN   THK32HANDLEBOUNDARY:NEAR
        EXTRN   THK32FREEALIAS:NEAR
CODE32_TUNE4 ENDS
CODE32  SEGMENT DWORD USE32 PUBLIC 'CODE'
; 546864
        EXTRN   DOS32SETDOSPROPERTY:NEAR
        EXTRN   DOS32QUERYRESOURCESIZE:NEAR
        EXTRN   DosLDTSel:ABS
        EXTRN   THK32ALIASMEM:NEAR
        EXTRN   THK32FREESTACK:NEAR
        EXTRN   THK32ALLOCSTACK:NEAR
        EXTRN   THK32R3DS:ABS
CODE32  ENDS

CODE16C_TUNE1 SEGMENT DWORD USE16 PUBLIC 'CODE'
CODE16C_TUNE1 ENDS
CODE16C_TUNE4 SEGMENT DWORD USE16 PUBLIC 'CODE'
CODE16C_TUNE4 ENDS
CODE16C SEGMENT DWORD USE16 PUBLIC 'CODE'
CODE16C ENDS


DATA32  SEGMENT
DATA32  ENDS



CODE16C_TUNE1 SEGMENT

        ASSUME  CS:CODE16C_TUNE1,DS:NOTHING,ES:NOTHING,SS:NOTHING


;* 16->32 Thunk for DOSSELTOFLAT
;; This routine should only be used by thunks.

        cProc   DOSSELTOFLAT,<PUBLIC,FAR,NONWIN>

        cBegin
        T16Beg  CODE16C_TUNE1,CODE32_TUNE1

        push    ds
        push    THK32R3DS
        pop     ds
        T16Call DOS32SELTOFLAT,noextrn
        pop     ds

        T16End
        cEnd


;* 16->32 Thunk for DOSFLATTOSEL
;; This routine should only be used by thunks.

        cProc   DOSFLATTOSEL,<PUBLIC,FAR,NONWIN>

        cBegin
        T16Beg  CODE16C_TUNE1,CODE32_TUNE1

        push    ds
        push    THK32R3DS
        pop     ds
        T16Call DOS32FLATTOSEL,noextrn
        pop     ds

        T16End
        cEnd

CODE16C_TUNE1 ENDS



;***************************************************************************
; Dos32ScanEnv - Thunks to DosScanEnv
;
; This thunk was hand modified because the call returns a pointer.
;
; The thunk was modified to convert an output pointer.


CODE32_TUNE3 SEGMENT

        ASSUME  CS:FLAT,DS:FLAT,ES:FLAT

DOS32SCANENV PROC

        T32Beg  CODE16C_TUNE3,CODE32_TUNE3
        Parm    pszName
        Parm    ppszValue

        push    ebp
        mov     ebp,esp

        cld                             ;Assume direction flag clear
        sub     eax,eax
        PushVar TmpRC,eax
        PushVar OldESI,esi
        PushVar OldEDI,edi
        PushVar Tmp1,eax                ;temp storage
        PushVar ErrFlag,eax             ;Error flag for cleanup
        PushVar StkFlag,eax             ;temp storage for Stack Allocation Flags
        PushVar BMPFlag,eax             ;temp storage for BMP Flags
        PushVar AlsFlag,eax             ;temp storage for Alias Flags
        PushVar Ptr1,eax                ;temp storage for ptr param #1
        PushVar Ptr2,eax                ;temp storage for ptr param #2

        T32Bump                         ;bump the stack if necessary

        mov     esi,[pszName]           ;base address

;Pointer  -->
        or      esi,esi
        jz      short L4

        mov     [Ptr1],esi
;Handle String Parameters
        mov     edi,esi
        mov     ecx,0ffffh
        xor     ax,ax
        repne   scasb
        or      ecx,ecx
        jz      INVP_Dos32ScanEnv       ;jmp if no zero byte

        neg     cx
        dec     cx
        cmp     cx,61439                ;cmp to max string len
        ja      INVP_Dos32ScanEnv       ;jmp if too long

;Check Boundary Crossing
        mov     eax,esi
        neg     ax
        jz      short L4                ;0=full 64k of room

        cmp     ax,cx
        jae     short L4                ;Enough room

        call    THK32HANDLEBOUNDARY
        or      eax,eax
        jnz     NOMEM_Dos32ScanEnv      ;
        mov     [Ptr1],edi
        or      edx,edx
        js      short L3                ;Alloced Mem
        or      DWORD PTR [ebp+(edx*4)-32],1 ;Set Flag
        dec     edx
        js      short L4                ;Aliases not copied

;Copy ECX bytes from ESI to EDI
L3:     mov     eax,3                   ;Variable Length Copy
        and     eax,ecx
        shr     ecx,2
        rep     movsd
        mov     ecx,eax
        rep     movsb

L4:     fixPtr  esi,[ppszValue],4,null  ;ppszResult base address
        mov     [Ptr2],esi

;Create new call frame, using 16-bit semantics.

L5:     mov     eax,esp                 ;save current esp
        push    ss
        push    eax

        getRPL  dx,ss

        segPtr  eax,[Ptr1],dx,input
        push    eax

        segPtr  eax,[Ptr2],dx
        push    eax

        T32Stack eax,esp,dx             ;switch stacks
        T32Call DOSSCANENV
        T32End

;Functions contain pointers, save return code

L10:    mov     [TmpRC],eax             ;Save return code

;Undo Pointer  -->
        mov     esi,[Ptr1]              ;temp address
        or      esi,esi
        jz      short L13

        mov     edi,[pszName]           ;original address

;Types are identical and no imbedded pointers exist
;This means that we treated the pointer as a buffer
;If temp address == original address then no work required
        cmp     esi,edi
        je      short L13

;Handle String Parameters
;Strings are never copied out
        test    DWORD PTR[StkFlag],1    ;Test Stack Alloc Flag

;DeAllocate space on stack: Done implicitly
        jnz     short L13

        test    DWORD PTR [BMPFlag],1   ;Test BMP Flag
        jz      short L15

;DeAllocate space in BMP area;  ESI holds address of block
        call    THK32FREEBLOCK
        jmp     short L13

INVP_Dos32ScanEnv:
        mov     eax,ERROR_INVALID_PARAMETER
        mov     BYTE PTR [ErrFlag],1    ;Set flag
        jmp     short L10

NOMEM_Dos32ScanEnv:
        mov     eax,ERROR_NOT_ENOUGH_MEMORY
        mov     BYTE PTR [ErrFlag],1    ;Set flag
        jmp     short L10

L15:    call    THK32FREEALIAS          ;Free Linear Alias/ Large Buffer

L13:                                    ;Deallocation Done Label

;**** KWR Modification:
;**** This is always an output parameter.
;**** It is a pointer to a pointer to an ASCIIZ string.
;**** Reverse CRMA the resulting pointer.

;Undo Pointer ppszResult --> ppszResult


        mov     esi,[Ptr2]              ;ppszResult temp address
        or      esi,esi
        jz      short L16

;Since esi is not NULL, then this means that the original PTR was not
;null. No need for a check.

        mov     edi,[ppszValue]         ;ppszResult original address
        flatPtr eax,[esi]
        mov     [edi],eax

L16:    lea     esp,[OldEDI]            ;Any stack space is deallocated implicitly
        pop     edi
        pop     esi
        pop     eax                     ;Pop saved return code
        leave
        ret

DOS32SCANENV ENDP

CODE32_TUNE3 ENDS




CODE16C_TUNE1 SEGMENT

T_DOSGETCP LABEL FAR

CODE16C_TUNE1 ENDS



CODE32_TUNE1 SEGMENT
        ASSUME  CS:FLAT,DS:FLAT,ES:FLAT

DOS32QUERYCP PROC

        push    ebp
        mov     ebp,esp


        cld                             ;Assume direction flag clear
        xor     eax,eax
        push    eax                     ; temp storage for return value
        push    esi
        push    edi
        push    eax                     ; temp storage
        push    eax                     ;Error flag for cleanup
        push    eax                     ; temp storage for Stack Allocation Flags
        push    eax                     ; temp storage for BMP Flags
        push    eax                     ; temp storage for Alias Flags
        push    eax                     ; temp storage for ptr param #1
        push    eax                     ; temp storage for ptr param #2

;* Compare stack selector against FLAT:R3DSB
;* If the selector is not equal, then don't bump stack.

        push    0000                    ;push for stack comparison later
        mov     eax,ss
        cmp     ax,seg FLAT:DATA32      ; standard 32 bit stack?
        jne     short L3001             ; if not, skip bumping code

;* Bump the stack down if too near 64K boundary.

        mov     eax,esp
        cmp     ax,1024
        jae     short L3001
        pop     ecx                     ;old stack comparator
        call    THK32ALLOCSTACK         ; bump the stack down
        push    eax                     ;old stack comparator on old stack
        mov     esp,eax


;Insure that 1 DWORD exists on stack
        push    eax
L3001:


; ****> BEGIN Pointer/Structure Section



        mov     esi,[ebp+12]            ; base address

;Pointer  --> buf
        or      esi,esi
        jz      L3002

        mov     [ebp-36],esi
        mov     ecx,[ebp+8]             ;Get Size Parameter


;DWORD-->WORD sized length. Error if Size > 64k
        cmp     ecx,10000h
        jae     INVP_DOS32QUERYCP       ;jmp if too long
;ECX holds size in bytes
;We need to figure out the number of elements
;that will fit

        shr     ecx,2                   ;Divide by 4

        mov     [ebp-16],ecx            ;Save the count

        shl     ecx,1                   ;target buffer size (count * 2)
        jecxz   L3002                   ;If nothing there, then skip this

;Generate call to allocate ECX bytes

        call    Thk32AllocVarLen
        or      eax,eax                 ;Test error condition
        jnz     NOMEM_DOS32QUERYCP
        mov     [ebp-36],edi

        or      edx,edx
        jb      short L3003             ;Jump if DosAllocMem

        lea     eax,[ebp-28]
        or      BYTE PTR[eax+edx*4],1   ;Set alloc flag

L3003:


;Data item does not have input semantics

L3002:


        mov     esi,[ebp+16]            ; base address

;Pointer  --> retlen
        or      esi,esi
        jz      L3004

        mov     [ebp-40],esi

;Have PU/LONG, want PU/SHORT
;Use the LONG as buffer, only if it doesn't
;cross boundary

;Check Boundary Crossing - fixed size item
        cmp     si,65532
        jbe     L3004                   ;Enough room

; Allocate space on stack
        sub     esp,2                   ;Alloc Mem
        and     esp,0FFFFFFFCh          ;DWORD align
        mov     edi,esp                 ;Points to new data area
        mov     [ebp-40],edi

L3004:

; ****> END Pointer/Structure Section

;* Create new call frame, using 16-bit semantics.

        push    ebp                     ; save ebp
        mov     eax,esp                 ; save current esp
        push    ss
        push    eax


        mov     dx,ss                   ; get cpl bits to use as dpl bits
        and     dx,3                    ; mask off rest of register

        or      dl,4                    ;Force LDT bit on


                                        ;From Name:   Type: unsigned long
        mov     eax,[ebp+8]

        cmp     eax,0ffffh
        ja      INVP_DOS32QUERYCP

        shr     ax,1                    ;Divide it by 2

        push    ax                      ;To:unsigned short


                                        ;From Name:   Type: unsigned long
        mov     eax,DWORD PTR [ebp-36]
        or      eax,eax
        jz      short L3006             ;NULL pointer

        ror     eax,16                  ; CRMA on structure pointer
        shl     ax,3
        or      al,dl
        rol     eax,16
L3006:  push    eax



                                        ;From Name:   Type: unsigned long
        mov     eax,DWORD PTR [ebp-40]
        or      eax,eax
        jz      short L3007             ;NULL pointer

        ror     eax,16                  ; CRMA on structure pointer
        shl     ax,3
        or      al,dl
        rol     eax,16
L3007:  push    eax


;* Convert SS:ESP to 16-bit SS:SP.

        mov     eax,esp                 ; use CRMA on ESP
        ror     eax,16
        shl     ax,3
        or      al,dl
        rol     eax,16

        push    eax                     ; push new stack pointer
        lss     sp,DWORD PTR [esp]      ; ss:sp = 16-bit ptr

;* Jump to 16-bit segment to issue call (so that 16-bit API can RETF).

        jmp     FAR PTR T_DOSGETCP


INVP_DOS32QUERYCP:
        push    87
        pop     eax
        mov     BYTE PTR [ebp-20],1     ;Set flag
        jmp     short L3008

NOMEM_DOS32QUERYCP:
        push    8
        pop     eax

ERR_DOS32QUERYCP:
        mov     BYTE PTR [ebp-20],1     ;Set flag
        jmp     short L3008
R_DOSGETCP:                             ; label defining return jmp location


;* Restore 32-bit SS:ESP - it is on top of stack.

        movzx   esp,sp                  ; make sure that esp is correct
        lss     esp,[esp]
        pop     ebp


;Convert Return Code
;USHORT --> ULONG
        movzx   eax,ax
L3008:
;Functions contain pointers, save return code
        mov     [ebp-4],eax             ;Save return code

; ****> BEGIN Pointer/Structure Unpack Section


;Undo Pointer  --> buf


        mov     esi,[ebp-36]            ; temp address
        or      esi,esi
        jz      L3009



        mov     edi,[ebp+12]            ; original address
        cmp     esi,edi
        je      L3009

;We have two buffers with different types in them

;If the buffer was output, then we need to copy out

        test    BYTE PTR[ebp-20],1      ;Check for errors E
        jnz     L3010                   ;No copy if error
        mov     ecx,[ebp+8]             ;Get Size
;ECX holds size in bytes
;We need to figure out the number of elements
;that will fit

        shr     ecx,2                   ;ecx = count of DWORDS (length passed in)
;-----------------------------------------------------------------------------
;Use the size passed back, if possible.
        push    esi
        mov     esi,[ebp-40]            ; temp address
        or      esi,esi
        jz      L3011a                  ; if null PTR, use length passed in


        movzx   ecx,WORD PTR[esi]
;
; We have size in bytes, need number of elements
;
        shr     ecx,1                   ;

;-----------------------------------------------------------------------------
L3011a:
        pop     esi
L3011:

;USHORT --> ULONG

        movzx   eax,WORD PTR[esi]
        mov     [edi],eax
        add     esi,2
        add     edi,4
        loop    L3011


L3010:                                  ;ErrorLabel E


;Deallocate Variable Size Block
        mov     esi,[ebp-36]
        push    -32                     ;Alloc Flag Offset
        mov     edx,1

        call    THK32DEALLOC


L3009:                                  ;No action required

;Undo Pointer  --> retlen


        mov     esi,[ebp-40]            ; temp address
        or      esi,esi
        jz      L3012



        mov     edi,[ebp+16]            ; original address

;This item is either on the stack, or is still
;in its original position.
;Output semantics convert in place

        movzx   eax,WORD PTR[esi]

;
;
; We have sizeof in WORDs, need sizeof in DWORDS.
;
        shl     eax,1                   ; * 2

        mov     [edi],eax

L3012:                                  ;No action required

; ****> END Pointer/Structure Unpack Section

;* 32-bit return code.

        lea     esp,[ebp-44]            ; get the old stack
        pop     ecx                     ;get the new stack
        cmp     ecx,0                   ;is it new
        jz      @f
        call    THK32FREESTACK          ;deallocate the memory
@@:
        lea     esp,[ebp-12]
        pop     edi
        pop     esi
        pop     eax                     ;Pop saved return code
        leave
        ret                             ; Remove parameters

DOS32QUERYCP endp

CODE32_TUNE1 ENDS




;* 16-bit code to make API call.

CODE16C_TUNE1 SEGMENT

        ASSUME  CS:CODE16C_TUNE1
        .errnz  ($ - T_DOSGETCP)

        call    FAR PTR DOSGETCP        ; call 16-bit version
        jmp     FAR PTR FLAT:R_DOSGETCP ; jump back

CODE16C_TUNE1 ENDS



CODE16C_TUNE4 SEGMENT

        ASSUME  CS:CODE16C_TUNE4,DS:NOTHING,ES:NOTHING,SS:NOTHING

;* 16->32 Thunk for DOSQUERYDOSPROPERTY

        cProc   DOSQUERYDOSPROPERTY,<PUBLIC,FAR,NONWIN>
        parmW   qdp_sgid
        parmD   qdp_psz
        parmW   qdp_cb
        parmD   qdp_pch

        cBegin
        T16Beg  CODE16C_TUNE4,CODE32_TUNE1

        flatPtr eax,qdp_pch             ;parm is 16:16, convert to 0:32
        PushArg eax
        movzx   eax,qdp_cb              ;parm is ushort, so zero-extend first
        PushArg eax
        flatPtr eax,qdp_psz,,input      ;parm is 16:16, convert to 0:32
        PushArg eax
        movzx   eax,qdp_sgid            ;parm is ushort, so zero-extend first
        PushArg eax
        T16Call DOS32QUERYDOSPROPERTY

        T16End
        cEnd


;* 16->32 Thunk for DOSREQUESTVDD

        cProc   DOSREQUESTVDD,<PUBLIC,FAR,NONWIN>
        parmD   hVDD
        parmW   sgid
        parmW   cmdReq
        parmD   cbBuf1
        parmD   pBuf1
        parmD   cbBuf2
        parmD   pBuf2

        cBegin
        T16Beg  CODE16C_TUNE4,CODE32_TUNE1

        flatPtr eax,pBuf2,,input        ;parm is 16:16, convert to 0:32
        PushArg eax
        PushArg cbBuf2                  ;parm is ulong, so push directly
        flatPtr eax,pBuf1,,input        ;parm is 16:16, convert to 0:32
        PushArg eax
        PushArg cbBuf1                  ;parm is ulong, so push directly
        movzx   eax,cmdReq              ;parm is ushort, so zero-extend first
        PushArg eax
        movzx   eax,sgid                ;parm is ushort, so zero-extend first
        PushArg eax
        PushArg hVDD                    ;parm is ulong, so push directly
        T16Call DOS32REQUESTVDD

        T16End
        cEnd


;* 16->32 Thunk for DOSOPENVDD

        cProc   DOSOPENVDD,<PUBLIC,FAR,NONWIN>
        parmD   pszVDD
        parmD   phVDD

        cBegin
        T16Beg  CODE16C_TUNE4,CODE32_TUNE1

        flatPtr eax,phVDD               ;parm is 16:16, convert to 0:32
        PushArg eax
        flatPtr eax,pszVDD,,input       ;parm is 16:16, convert to 0:32
        PushArg eax
        T16Call DOS32OPENVDD

        T16End
        cEnd

CODE16C_TUNE4 ENDS





CODE16C SEGMENT

        ASSUME  CS:CODE16C,DS:NOTHING,ES:NOTHING,SS:NOTHING


;* 16->32 Thunk for DOSCLOSEVDD

        cProc   DOSCLOSEVDD,<PUBLIC,FAR,NONWIN>
        parmD   hVDD

        cBegin
        T16Beg  CODE16C,CODE32

        PushArg hVDD                    ;parm is ulong, so push directly
        T16Call DOS32CLOSEVDD

        T16End
        cEnd


;* 16->32 Thunk for DOSSETDOSPROPERTY

        cProc   DOSSETDOSPROPERTY,<PUBLIC,FAR,NONWIN>
        parmW   sdp_sgid
        parmD   sdp_psz
        parmW   sdp_cb
        parmD   sdp_pch

        cBegin
        T16Beg  CODE16C,CODE32

        flatPtr eax,sdp_pch,,input      ;parm is 16:16, convert to 0:32
        PushArg eax
        movzx   eax,sdp_cb              ;parm is ushort, so zero-extend first
        PushArg eax
        flatPtr eax,sdp_psz,,input      ;parm is 16:16, convert to 0:32
        PushArg eax
        movzx   eax,sdp_sgid            ;parm is ushort, so zero-extend first
        PushArg eax
        T16Call DOS32SETDOSPROPERTY

        T16End
        cEnd

;* 16->32 Thunk for DOSTIMERSTART

        cProc   DOSTIMERSTART,<PUBLIC,FAR,NONWIN>
        parmD   tsr_msTime
        parmD   tsr_hsem
        parmD   tsr_phtimer

        cBegin
        T16Beg  CODE16C,CODE32

        flatPtr eax,tsr_phTimer         ;parm is 16:16, convert to 0:32
        PushArg eax
        PushArg tsr_hsem                ;parm is ulong, so push directly
        PushArg tsr_msTime              ;parm is ulong, so push directly
        T16Call DOSI32STARTTIMER

        T16End
        cEnd

;* 16->32 Thunk for DOSTIMERSTOP

        cProc   DOSTIMERSTOP,<PUBLIC,FAR,NONWIN>
        parmW   tsp_htimer

        cBegin
        T16Beg  CODE16C,CODE32

        movzx   eax,tsp_hTimer          ;parm is ushort, so zero-extend first
        PushArg eax
        T16Call DOS32STOPTIMER

        T16End
        cEnd

;* 16->32 Thunk for DOSTIMERASYNC

        cProc   DOSTIMERASYNC,<PUBLIC,FAR,NONWIN>
        parmD   tas_msTime
        parmD   tas_hsem
        parmD   tas_phtimer

        cBegin
        T16Beg  CODE16C,CODE32

        flatPtr eax,tas_phTimer         ;parm is 16:16, convert to 0:32
        PushArg eax
        PushArg tas_hsem                ;parm is ulong, so push directly
        PushArg tas_msTime              ;parm is ulong, so push directly
        T16Call DOSI32ASYNCTIMER

        T16End
        cEnd

;* 16->32 Thunk for DOSQUERYRESOURCESIZE

        cProc   DOSQUERYRESOURCESIZE,<PUBLIC,FAR,NONWIN>

        parmW   qrs_modhandle
        parmD   qrs_typeid
        parmD   qrs_nameid
        parmD   qrs_size

        cBegin
        T16Beg  CODE16C,CODE32

        flatPtr eax,qrs_size            ;parm is 16:16, convert to 0:32
        PushArg eax
        PushArg qrs_nameid              ;parm is ulong, so push directly
        PushArg qrs_typeid              ;parm is ulong, so push directly
        movzx   eax,qrs_modhandle       ;parm is ushort, so zero-extend first
        PushArg eax
        T16Call DOS32QUERYRESOURCESIZE

        T16End
        cEnd

;* 16->32 Thunk for DOSQUERYPROCTYPE

        cProc   DOSQUERYPROCTYPE,<PUBLIC,FAR,NONWIN>

        parmW   qpt_modhandle
        parmD   qpt_ordinal
        parmD   qpt_procname
        parmD   qpt_proctype

        cBegin
        T16Beg  CODE16C,CODE32

        flatPtr eax,qpt_proctype        ;parm is 16:16, convert to 0:32
        PushArg eax
        flatPtr eax,qpt_procname,,input ;parm is 16:16, convert to 0:32
        PushArg eax
        PushArg qpt_ordinal             ;parm is ulong, so push directly
        movzx   eax,qpt_modhandle       ;parm is ushort, so zero-extend first
        PushArg eax
        T16Call DOS32QUERYPROCTYPE

        T16End
        cEnd

;* 16->32 Thunk for DOSQUERYHEADERINFO

        cProc   DOSQUERYHEADERINFO,<PUBLIC,FAR,NONWIN>

        parmW   qhi_modhandle
        parmD   qhi_index
        parmD   qhi_pbuf
        parmD   qhi_cb
        parmD   qhi_sub

        cBegin
        T16Beg  CODE16C,CODE32

        PushArg qhi_sub                 ;parm is ulong, so push directly
        PushArg qhi_cb                  ;parm is ulong, so push directly
        flatPtr eax,qhi_pbuf            ;parm is 16:16, convert to 0:32
        PushArg eax
        PushArg qhi_index               ;parm is ulong, so push directly
        movzx   eax,qhi_modhandle       ;parm is ushort, so zero-extend first
        PushArg eax
        T16Call DOS32QUERYHEADERINFO

        T16End
        cEnd

;* 16->32 Thunk for DOSINITIALIZEPORTHOLE

        cProc   DOSINITIALIZEPORTHOLE,<PUBLIC,FAR,NONWIN>

        parmD   ip_pfnlibinit
        parmD   ip_enttype

        cBegin
        T16Beg  CODE16C,CODE32

        PushArg ip_enttype              ;parm is ulong, so push directly
        PushArg ip_pfnlibinit           ;parm is ulong, so push directly
        T16Call DOS32INITIALIZEPORTHOLE

        T16End
        cEnd


;* 16->32 Thunk for DOSREGISTERPERFCTRS

        cProc   DOSREGISTERPERFCTRS,<PUBLIC,FAR,NONWIN>
        parmD   pbDataBlk
        parmD   pbTextBlk
        parmD   flFlags

        cBegin
        T16Beg  CODE16C,CODE32
;
;       No need to convert pointers to 32-bit; worker takes care of this.
;
        PushArg flFlags
        PushArg pbTextBlk
        PushArg pbDataBlk
        T16Call DOS32REGISTERPERFCTRS

        T16End
        cEnd


;* 16->32 Thunk for DOSTMRQUERYFREQ

        cProc   DOSTMRQUERYFREQ,<PUBLIC,FAR,NONWIN>
        parmD   pulTmrFreq

        cBegin
        T16Beg  CODE16C,CODE32

        flatPtr eax,pulTmrFreq          ;parm is 16:16, convert to 0:32
        PushArg eax
        T16Call DOS32TMRQUERYFREQ

        T16End
        cEnd


;* 16->32 Thunk for DOSTMRQUERYTIME

        cProc   DOSTMRQUERYTIME,<PUBLIC,FAR,NONWIN>
        parmD   pqwTmrTime

        cBegin
        T16Beg  CODE16C,CODE32

        flatPtr eax,pqwTmrTime          ;parm is 16:16, convert to 0:32
        PushArg eax
        T16Call DOS32TMRQUERYTIME

        T16End
        cEnd

CODE16C ENDS

;=======================================================================
;  The following routines are to be used only by the thunks.
;  These routines will convert a pointer from 32->16 or 16->32 in
;  the packed region of memory.  For any pointer that is in the tiled
;  region of memory, CRMA should be used to do the conversion.  ; 546864
;=======================================================================

;***    DOS32FLATTOSEL
;
;       Convert a flat address to a selector in the packed region of
;       memory.
;
;       ENTRY   EAX = flat address to convert to a selector
;
;       EXIT:   EAX = selector

CODE32_TUNE1 SEGMENT
        ASSUME  CS:FLAT,DS:FLAT,ES:FLAT

        ALIGN   4

        PUBLIC  DOS32FLATTOSEL
DOS32FLATTOSEL PROC

        test    eax,0FFFF0000h          ; Do nothing if high word is 0
        jz      SHORT lts06

        cmp     [FenceLAddr],eax        ; in packed region?
        ja      SHORT lts10             ; jump if so
        cmp     eax,[FenceShrLAddr]     ; below packed region?
        jl      SHORT lts05             ; jump if so
        cmp     eax,[FencePckLAddr]     ; above packed region?
        jl      SHORT lts10             ; in packed region!

;       not packed, so use CRMA

lts05:  push    ax
        mov     ax,ss
        or      al,4
        shl     ax,13
        shl     eax,3
        pop     ax
lts06:  ret

;       we get to here if the given address is within the packed region

lts10:  push    ebx
        push    ecx
        push    edx
        push    ds

        mov     ebx,DosLDTSel           ; (ds) = ldt alias
        mov     ds,ebx

        mov     edx,eax                 ; (edx) = linear address to convert
        shr     eax,13
        and     eax,0fff8h              ; (eax) = selector by tiling (no TI and
                                        ; no privilege bits set.)

        cmp     ax,0dff0h               ; Infosegs are tiled !
        je      SHORT lts30             ; (Privilege bits and TI bits
                                        ;  are not set.)
        cmp     ax,0dff8h               ; Infosegs are tiled !
        je      SHORT lts30             ; (Privilege bits and TI bits
                                        ;  are not set.)

;       Check for the very last descriptor in the LDT.

        mov     ebx,0fff8h              ; (ebx) = very last LDT selector
        mov     ch,[ebx].d_extaddr
        mov     cl,[ebx].d_hiaddr
        shl     ecx,16
        mov     cx,[ebx].d_loaddr       ; (ecx) = base of last descriptor
        test    ecx,ecx                 ; Is it 0 (invalid descriptor) ?
        jz      SHORT lts20             ; If so, resume as normal
        cmp     ecx,edx                 ; is this our match?
        ja      SHORT lts20             ; jump if laddr to convert is lower
        mov     eax,ebx                 ; else return this selector.
        jmp     SHORT lts40             ;


;       Let the search begin.  For now we will do a linear search up from
;       (eax) which is a pointer to the computed descriptor for this address
;       using the tiling algorithm (which is the lowest possible descriptor
;       it could be).

lts20:  add     eax,size desctab        ; (eax) = next higher descriptor

        mov     ch,[eax].d_extaddr
        mov     cl,[eax].d_hiaddr
        shl     ecx,16
        mov     cx,[eax].d_loaddr       ; (ecx) = base of selector
        test    ecx,ecx                 ; Is it 0 (invalid descriptor) ?
        jz      SHORT lts25             ; If so, exit the loop.

        cmp     ecx,edx                 ; is this our match?
        jbe     SHORT lts20             ; jump if still too low

;       if we fall through to here, we hit a descriptor whose base is
;       above what we are looking for.  That means that the previous selector
;       is our answer.

lts25:
        sub     eax,size desctab        ; (eax) = answer selector

lts30:  mov     ch,[eax].d_extaddr
        mov     cl,[eax].d_hiaddr
        shl     ecx,16
        mov     cx,[eax].d_loaddr       ; (ecx) = base of selector

lts40:  sub     edx,ecx                 ; (edx) = offset
        mov     cx,ss
        and     cx,3                    ; (cx) = cpl
        or      cx,4                    ; set TI bit
        or      eax,ecx                 ; (ax) = sel with rpl = cpl
        shl     eax,16                  ; put selector in high word
        mov     ax,dx                   ; (eax) = sel:offset
        pop     ds
        pop     edx
        pop     ecx
        pop     ebx
        ret

DOS32FLATTOSEL endp

CODE32_TUNE1 ENDS

;***    DOS32SELTOFLAT
;
;       Convert a selector to a flat address in the packed region of
;       memory.
;
;       ENTRY   EAX = selector to convert to a flat address
;
;       EXIT:   EAX = flat address

CODE32_TUNE1 SEGMENT
        ASSUME  CS:FLAT,DS:FLAT,ES:FLAT

        ALIGN   4

        PUBLIC  DOS32SELTOFLAT
DOS32SELTOFLAT PROC

        test    eax,0FFFF0000h          ; Do nothing if high word is 0
        jz      SHORT stl06

        ror     eax,16                  ; put selector in low word
        cmp     [FenceSel],ax           ; is selector packed?
        ja      SHORT stl10             ; jump if packed
        cmp     ax,[FenceShrSel]        ; below packed region?
        jl      SHORT stl05             ; jump if so
        cmp     ax,[FencePckSel]        ; above packed region?
        jl      SHORT stl10             ; in packed region!

;       not packed, so use CRMA

stl05:  shr     ax,3
        rol     eax,16
stl06:  ret

;       we get to this code if the selector is in the packed region

stl10:  push    ds                      ; save caller's ds
        push    ebx                     ; svae caller's ebx
        push    ecx                     ; save caller's ecx
        mov     ebx,DosLDTSel
        mov     ds,ebx                  ; (ds) = ldt image
        mov     ecx,eax
        and     ecx,0fff8h              ; (ds:cx) = descriptor pointer

        shr     eax,16                  ; (eax) = offset in segment

        mov     bh,[ecx].d_extaddr
        mov     bl,[ecx].d_hiaddr
        shl     ebx,16
        mov     bx,[ecx].d_loaddr       ; (ebx) = base of selector

        add     eax,ebx                 ; (eax) = base + offset

        pop     ecx                     ; restore caller's ecx
        pop     ebx                     ; restore caller's ebx
        pop     ds                      ; restore caller's ds
        ret

DOS32SELTOFLAT endp

CODE32_TUNE1 ENDS

        END
