;*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.;
;*****************************************************************************/
        PAGE    ,132
        TITLE   32CALLBK.ASM
;/*****************************************************************************
;*
;* SOURCE FILE NAME = 32CALLBACK.ASM
;*
;* DESCRIPTIVE NAME = 32 Bit Ring 3 to Ring 2 Calls
;*
;*
;* VERSION      V2.0
;*
;* DATE         07/09/91
;*
;* DESCRIPTION  Contains the routines necessary to perform calls back to
;*              32-bit Ring 3 from 32-bit Ring 2.
;*
;* FUNCTIONS
;*              Vga32Callback -  Makes all GRE calls run at ring 3
;*              Gre16CallBackReturn - returns from 16 bit land
;*
;* NOTES        NONE
;*
;* STRUCTURES   NONE
;*
;* EXTERNAL REFERENCES
;*
;*              NONE
;*
;* EXTERNAL FUNCTIONS
;*
;*              DOS16CALLBACK
;*
;* CHANGE ACTIVITY =
;*   DATE      FLAG        APAR   CHANGE DESCRIPTION
;*   --------  ----------  -----  --------------------------------------
;*   mm/dd/yy  @Vr.mpppxx  xxxxx  xxxxxxx
;*   07/09/91                     Written by Scott T Jones
;*
;*****************************************************************************/

        .386p

        include tune.inc

_CODE16 SEGMENT DWORD USE16 PUBLIC 'CODE'
_CODE16 ENDS

        EXTRN   DOS16CALLBACK:FAR
_TUNE SEGMENT  DWORD USE32 PUBLIC 'CODE'
;/***************************************************************************
;*
;* FUNCTION NAME = Vga32CallBack
;*
;* DESCRIPTION   =
;*      This routine is called only by the 32-bit dispatcher only when the
;*      Graphics Engine has been entered at Ring 2.  Its purpose is to make
;*      all Gre calls run at Ring 3.
;*
;*      It performs a thunk from 32R2 to 16R2, a callback from 16R2 to 16R3,
;*      then a thunk from 16R3 to 32R3 before calling the specified routine.
;*      These thunks are actually mini-thunks, since the fact that we are
;*      going from 32-bit code to 32-bit code eliminates the need to thunk
;*      the parameters.
;*
;*      Since there are not enough registers in which to pass all of the
;*      parameters for every Gre call, the routine will grab a semaphore to
;*      serialize access to the global data used.
;*
;*      Due to the fact that the first parameter is pushed last, a single
;*      routine can handle all of the different numbers of parameters.
;*
;*      Follow the numbers in the comments carefully.  It can be very confusing.
;*
;*      WARNING:  This does not handle stacks > 64K.
;*
;*      The following diagram will attempt to explain this function:
;*
;*                      PMGRE
;*
;*                       #3              #4
;*                      Mini-          Normal
;*                      Thunk           Call
;*         +--->    ----------->    ----------->
;*         |    16R3            32R3            32R3 Dispatch32
;*         | +--    <-----------    <-----------
;*         | |       Mini-Thunk        Normal
;*         | |         Return          Return
;*     #2  | |    #6     #5
;*    Call | | CallBack
;*    Back | |  Return
;*         | |           #7                            #8
;*         | |       Mini-Thunk                      Normal
;*         | |         Return                        Return
;*         | +->    ----------->                  -----------> Original Caller
;*         |    16R2            32R2 Vga32CallBack
;*         +----    <-----------                  <----------- Dispatch32
;*                     Mini-                         Normal
;*                     Thunk                          Call
;*                      #1
;*
;*
;*
;* INPUT         =  Pointer to function
;* OUTPUT        =  NONE
;*
;* RETURN-NORMAL =  NONE
;* RETURN-ERROR  =  NONE
;*
;**************************************************************************/

;_TEXT  SEGMENT DWORD
        ASSUME  DS:FLAT,ES:FLAT,CS:FLAT


;/*
;** #1: The call begins here at 32R2 and picks up the parameters in preparation
;**     before the call back to Ring 2.  It jumps to 16R2 via a Mini-Thunk.
;*/

        PUBLIC  Vga32CallBack
ALIGN 4
Vga32CallBack PROC SYSCALL,
        pfnFunction:DWORD



        mov     eax,cs
        and     eax,1           ;at R3?
        jnz     AlreadyR3       ;Yes

;/*
;**  Save SS:ESP to restore on top of stack
;*/

        push    ss
        push    ebp

;/*
;**  Convert SS:ESP to 16-bit SS:SP via CRMA
;*/

        mov     eax,esp
        shr     eax,16
        shl     eax,3
        or      al,6                    ; R2 LDT selector for stack in AX
        push    eax                     ; Put new SS on stack

        movzx   eax,sp
        add     eax,4
        push    eax                     ; Put new ESP on stack
        mov     ebx,pfnFunction
        lss     esp,[esp]               ; Set the new SS:ESP for 16R2

        jmp     FAR PTR Gre16CallBack   ; Jump to 16R2
ALIGN 4

AlreadyR3:
        call    pfnFunction
        jmp     Vga32CBDone
ALIGN 4


;/*
;** #8: Finally back to 32R2, we can return to the original caller.
;*/

        PUBLIC  Vga32CallBackReturn
ALIGN 4
Vga32CallBackReturn::

        movzx   esp,sp
        lss     esp,[esp]               ; Restore stack for return

Vga32CBDone:
        ret                             ; Return to caller w/o discarding parms

;/*
;** #4: Now at 32R3, we push our parameters on the stack and call the original
;**     routine.
;*/

        PUBLIC  Vga32CallBackR3
ALIGN 4
Vga32CallBackR3::                        ; Return point at R3

;/*
;**  Save the old SS:SP for restoration before return to 16R3
;*/


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

;/*
;**  Convert 16-bit SS:SP to 32-bit SS:ESP via reverse CRMA for other thunks
;*/

        mov     eax,esp
        ror     eax,16
        mov     ax,ss
        shr     ax,3
        rol     eax,16                  ; Get new ESP relative to FLAT

        push    ds                      ; Put new SS on stack
        push    eax                     ; Put new ESP on stack

        lss     esp,[esp]               ; Set the new SS:ESP for 32R3

;/*
;**  Put the parameters on the stack and call the Dispatcher at ring 3
;*/


        push    ebp
        mov     ebp,esp

        call    ebx         ; Call at 32R3

;/*
;** #5: With the call completed, we clean up our stack and return to 16R3 via
;**     a third Mini-Thunk.
;*/

        mov     esp,ebp
        pop     ebp

        lss     esp,[esp]               ; Restore old SS:SP for 16R3

        jmp     FAR PTR Gre16CallBackReturn
ALIGN 4

Vga32CallBack ENDP
_TUNE ENDS
;_TEXT  ENDS

_CODE16 SEGMENT DWORD

;/*
;** #6: Now at 16R3 for the second time, we return to the point of the actual
;**     callback, to allow us to make our fourth Mini-Thunk.
;*/

;/***************************************************************************
;*
;* FUNCTION NAME =  Gre16CallBackReturn
;*
;* DESCRIPTION   =  #6: Now at 16R3 for the second time, we return to the point
;*                      of the actual callback, to allow us to make our
;*                      fourth Mini-Thunk.
;*
;* INPUT         =  NONE
;* OUTPUT        =  NONE
;*
;* RETURN-NORMAL =  NONE
;* RETURN-ERROR  =  NONE
;*
;**************************************************************************/
        PUBLIC  Gre16CallBackReturn
ALIGN 4
Gre16CallBackReturn PROC FAR

        ret                             ; Return from call back to 16R2

Gre16CallBackReturn ENDP

;/*
;** #3: Now at 16R3, we perform the second Mini-Thunk to get to 32R3 so that
;**     we can make the actual call.
;*/

        PUBLIC  Gre16CallBackR3
ALIGN 4
Gre16CallBackR3:

        jmp     FAR PTR FLAT:Vga32CallBackR3 ; Return to 32-bit at R3
ALIGN 4

_CODE16 ENDS

_CODE16 SEGMENT DWORD

;/*
;** #2: Now at 16R2, with parameters in registers, we perform the actual
;**     callback to 16R3.
;*/

        PUBLIC  Gre16CallBack
ALIGN 4
Gre16CallBack LABEL FAR

        push    SEG    Gre16CallBackR3
        push    OFFSET Gre16CallBackR3
        call    DOS16CALLBACK

;/*
;** #7: Now at 16R2 for the second time, we perform our fourth Mini-Thunk to
;**     get to the original callback routine so that we can return to our
;**     caller.
;*/

        jmp     FAR PTR FLAT:Vga32CallBackReturn
ALIGN 4

_CODE16 ENDS

        END
