;*DDK*************************************************************************/
;
; COPYRIGHT    Copyright (C) 1995 IBM Corporation
;
;    The following IBM OS/2 WARP source code is provided to you solely for
;    the purpose of assisting you in your development of OS/2 WARP device
;    drivers. You may use this code in accordance with the IBM License
;    Agreement provided in the IBM Device Driver Source Kit for OS/2. This
;    Copyright statement may not be removed.;
;*****************************************************************************/
;/*****************************************************************************
;*
;* SOURCE FILE NAME = TGRRING2.ASM
;*
;* DESCRIPTIVE NAME = Ring transition code
;*
;*
;* VERSION      V2.1
;*
;* DATE
;*
;* DESCRIPTION
;*
;*      Call here when we need to get to functions which are 32-bit and need
;*      to run at ring 2. There is no means of calling through a 32-bit
;*      callgate directly so we use the same method as GRE32. This consists
;*      of a partial thunk to 16-bit ring 3 where we go through a callgate to
;*      16-bit ring 2, and then on to 32-bit ring 2. The return then takes
;*      the reverse route.  The thunk is partial in that the source and
;*      destination are both in 32-bit code, therefore the parameters don't
;*      need to be converted, just a bit of mucking with the stack. The
;*      diagram below describes the basic operation, parenthesised names are
;*      code labels or procs.
;*
;*              (GRADD32Ring3Return)  (GRADD32CALLR2)
;*
;*                Part-Thunk Return    Return to caller
;*        +--->    --------------->    --------------->
;*        |         16-bit Ring 3       32-bit Ring 3
;*        | +--   <---------------    <---------------
;*        | |        Part-Thunk        Function Call
;*        | |
;*        | |   (GRADD16Ring3Entry)   (GRADD32CALLR2)
;*        | |
;*  Call  | |
;*  Gate  | |  Call via Callgate
;* Return | | (GRADD16RING2PROC)
;*        | |
;*        | |
;*        | |   (GRADD32Ring2Entry)
;*        | |
;*        | |       Part-Thunk           Call to HW*()
;*        | +->    --------------->     --------------->
;*        |         16-bit Ring 2        32-bit Ring 2
;*        +----   <---------------     <---------------
;*                 Part-Thunk Return     Return from HW*()
;*
;*              (GRADD16Ring2Return)
;*
;*
;*
;* FUNCTIONS
;*
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              NONE
;*
;* CHANGE ACTIVITY =
;*  DATE      FLAG        APAR   CHANGE DESCRIPTION
;*  --------  ----------  -----  --------------------------------------
;*  mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*
;*****************************************************************************/

.386p

;/*
;**  Include files
;*/

;*
;*  Segment definitions
;*

CODE16   SEGMENT dword PUBLIC USE16 'CODE'
CODE16   ENDS

CODE32   SEGMENT dword PUBLIC USE32 'CODE'
CODE32   ENDS

CODE16R2 SEGMENT dword PUBLIC USE16 'CODE'
CODE16R2 ENDS


;/*
;**  Externals and Publics
;*/

                PUBLIC  HWCallIOPL
                PUBLIC  GRADD16RING2PROC

THK32R2SS       EQU     04ah

;************************************************************************
;*
;* FUNCTION NAME = HWCallIOPL
;*
;* DESCRIPTION   = Make call to HWCmd function, at Ring 2.
;*
;* INPUT         = NONE
;* OUTPUT        = NONE
;*
;* RETURN-NORMAL = NONE
;* RETURN-ERROR  = NONE
;*
;*************************************************************************


CODE32          SEGMENT
                ASSUME CS:FLAT, DS:FLAT, ES:NOTHING

                ALIGN 4

HWCallIOPL      PROC

                mov     ax,cs                   ;Do quick test to see if
                test    al,1                    ; we aren't at ring 3.
                jz      short CallNoThunk       ; 

                mov     eax,esp                 ;Save SS:ESP on top of stack
                push    ss                      ; 
                push    eax                     ; 

                mov     eax,esp                 ;Convert SS:ESP to 16-bit
                shr     eax,16                  ; 
                shl     eax,3                   ; 
                or      al,7                    ;AX = R3 stack selector
                push    eax                     ; 
                movzx   eax,sp                  ; 
                add     eax,4                   ; 
                push    eax                     ; 
                lss     esp,[esp]               ;Reload with 16-bit stack

;*
;* Jump to 16-bit ring 3
;*

                jmp     FAR PTR CODE16:GRADD16Ring3Entry

;*
;* Return here from 16-bit ring 2, now 32-bit ring 2.
;*

                ALIGN 4
GRADD32Ring2Entry::

                mov     eax,esp                 ; 
                push    ss                      ;Save previous
                push    eax                     ;  SS and ESP.
                mov     eax,esp                 ; 
                ror     eax,16                  ;Translate 16-bit
                mov     ax,ss                   ;  SS:SP to 32-bit
                shr     ax,3                    ;  SS:ESP
                rol     eax,16                  ; 

                push    THK32R2SS               ; 
                push    eax                     ; 
                lss     esp,[esp]               ;Load ring 2 32-bit SS:ESP
                push    ebp                     ;Save EBP
                mov     ebp,esp                 ; 
                                                ;Push parameters for call
                push    [ebp+36]                ;pOut
                push    [ebp+32]                ;pIn
                mov     eax,[ebp+28]            ; 
                call    eax                     ; 
                add     esp,8                   ; 

                pop     ebp                     ;Restore EBP
                lss     esp,[esp]               ;Switch back to 16-bit SS:SP

                jmp     FAR PTR CODE16R2:GRADD16Ring2Return

;*
;* Return here from 16-bit ring 3, now 32-bit ring 3 again.
;*

                ALIGN 4
GRADD32Ring3Return::

                lss     esp,[esp]               ;Switch back to 32-bit stack
                ret                             ;Back to caller

;*
;* Jump here if this routine was called at other than ring 3.
;*
                ALIGN 4

CallNoThunk:
                pop     eax                     ;Get return address
                xchg    eax,[esp]               ;Put it back, get address
                jmp     eax                     ;Go there...

HWCallIOPL      ENDP

CODE32          ENDS

;*************************************************************************
;*
;* DESCRIPTION   =  Ring 3, 16-bit code segment
;*
;* NOTES:
;*
;*      Arrive here from a jump out of 32-bit ring 3 code.
;*      Make a call, via callgate to ring 2 proc.
;*      On return, jump back to 32-bit ring 3 code.
;*
;*      Stack (32-bit, all entries DWORDS) on arrival here is as follows:
;*
;*              +-----------------------+
;*              | ulFun                 |
;*              +-----------------------+
;*              | pOut                  |
;*              +-----------------------+
;*              | pIn                   |
;*              +-----------------------+
;*              | 32-bit Return address |
;*              +-----------------------+
;*              | Saved 32-bit SS       |
;*              +-----------------------+
;*              | Saved 32-bit ESP      |
;*              +-----------------------+
;*
;*      We need to be able to get at the top four parameters to make the
;*      function call to HW*(), so all 6 DWORDS will be copied
;*      to the ring 2 stack as part of the callgate mechanism.
;*
;*      See also the fixup on return from callgate (GRADD16Ring2Return).
;*
;*************************************************************************


CODE16          SEGMENT
                ASSUME  CS:CODE16

                ALIGN 4
GRADD16Ring3Entry       LABEL FAR

                call    FAR PTR CODE16R2:GRADD16RING2PROC
                jmp     FAR PTR FLAT:GRADD32Ring3Return

CODE16          ENDS

;*************************************************************************
;*
;* DESCRIPTION   = Ring 2, 16-bit code segment
;*
;* NOTES:
;*
;*      Called here from 16-bit ring 3 code, via callgate.
;*      Jump into 32-bit segment, which now runs as ring 2 code.
;*      Once 32-bit ring 2 execution complete, return here via
;*      jump to FAR LABEL.
;*      Clean up stack and return to caller in 16-bit ring 3 code.
;*
;*************************************************************************


CODE16R2        SEGMENT
                ASSUME  CS:CODE16R2

                ALIGN 4
GRADD16RING2PROC        PROC FAR

                jmp     FAR PTR FLAT:GRADD32Ring2Entry

GRADD16Ring2Return      LABEL FAR

                pop     ecx                     ;Get return address
                add     esp,24                  ;Remove parms and saved SS:ESP
                push    ecx                     ;Restore return address
                ret                             ; 

GRADD16RING2PROC        ENDP

CODE16R2        ENDS

                END


