;*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

CHECKR3 EQU 1
;;;-------------------------------Module Prologue------------------------------
;;;
;;;     Module Name: 32CALLBK.ASM
;;;
;;;     Contains the routines necessary to perform calls back to 32-bit Ring 3
;;;     from 32-bit Ring 2.
;;;
;;;     Created: 07 Septempber 1991
;;;     Author:  Scott T Jones
;;;
;;;
;;;
;;;----------------------------------------------------------------------------

        .386p

_TEXT  SEGMENT PARA USE32 PUBLIC 'CODE'
        PUBLIC  _DMS32CallBack
_TEXT  ENDS

CODE16 SEGMENT PARA USE16 PUBLIC 'CODE'
CODE16 ENDS

        EXTRN   DOS16CALLBACK:FAR
;
;;;------------------------------Routine Prologue------------------------------
;;;
;;;     Gre(32/16)CallBack
;;;
;;;     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.
;;;
;;;     Created: 26 Septempber 1991
;;;     Author:  Scott T Jones
;;;
;;;     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
;;;
;;;----------------------------------------------------------------------------

_TEXT  SEGMENT PARA
        ASSUME  CS:FLAT,DS:FLAT,ES:FLAT

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

ALIGN 4
_DMS32CallBack PROC NEAR

ifdef CHECKR3
        mov     eax,cs
        and     eax,1           ;at R3?
        jnz     AlreadyR3       ;Yes
endif
;;;     Save SS:ESP to restore on top of stack

        push    ebx
        push    ss
        push    esp

;;;     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,[esp+18h]           ; get function pointer in ebx
        lss     esp,[esp]               ; Set the new SS:ESP for 16R2

        jmp     FAR PTR Gre16CallBack   ; Jump to 16R2
ALIGN 4
ifdef CHECKR3
AlreadyR3:
        call    [esp+4]                 ; call function pointer
        jmp     Vga32CBDone
ALIGN 4
endif
;;;----------------------------------------------------------------------------
;;; #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
        pop     eax                ; must pop of this dword
        pop     ebx
        xor     eax,eax
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

;        ASSUME  CS:R3CODE16
        jmp     FAR PTR Gre16CallBackReturn
ALIGN 4
;        ASSUME  CS:FLAT

_DMS32CallBack ENDP

_TEXT  ENDS

CODE16 SEGMENT PARA

;;;----------------------------------------------------------------------------
;;; #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.
;;;----------------------------------------------------------------------------

        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 PARA

;;;----------------------------------------------------------------------------
;;; #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
