;++
;
; File Name:
;
;       macro.inc
;
; Author:
;
;       Thomas Parslow [tomp]
;
; Created:
;
;       27-Feb-91
;
; Abstract:
;
;       The macros used for creating the exported entry points the
;       OS loader will use for basic h/w dependent services. These
;       services are:
;
;       o       Disk I/O
;       o       Character I/O
;
;
;--


;++
;
; EXPORT_ENTRY_MACRO
; We arrive here from the OS loader with a 32bit CS. That is, we're
; executing the code with cs:eip where cs contains a selector for a
; 32bit flat segment. We want to get to a 16bit cs. That is, cs:ip.
; The entry points are exported as 32bit near pointers to the OS loader.
; All code in the SU module is identity mapped so the flat 32bit offset
; is equal to the physical address.
;
; Therefore, we export the 32bit physical address as the
; entry point and the code may be executed with either the 32bit
; flat cs or the SU module's 16bit based cs.  Before we can switch
; modes we must load all of the segment registers with selectors for
; 16bit segments.  We start by pushing a far pointer to a label in
; the macro and then doing a retf. This allows us to fall through
; to the next instruction, but we're now executing through cs:ip
; with a 16bit CS.
;
; Output:
;
;       (ebx) = pointer to stack frame (and top of 32bit stack).
;

EXPORT_ENTRY_MACRO  macro entryname
        LOCAL    exp1
_TEXT32 segment para use32 public 'CODE'
        ASSUME CS:_TEXT32
ALIGN 4
Public  EntryName
EntryName LABEL near
;
; We've go a 32bit CS:EIP - go to a 16bit CS:IP

        push     dword ptr SuCodeSelector
        push     dword ptr (offset exp1)

        retf
_TEXT32 ends
        ASSUME CS:_TEXT
ALIGN 4
exp1:
;
; Save caller's EBP register and stack pointer (ESP)
;

        push     ebp
        push     ebx
        push     esi
        push     edi
        mov      ebx,esp
;
; Load all the segment registers with 16bit segment selectors
;
        mov      ax,SuDataSelector
        mov      ds,ax
        mov      ss,ax
;
; Set the stack to the top of the segment. We can do this now since
; all of the OS loader's code has already be relocated. Also, we need
; plenty of stack since we'll be calling BIOS routines.
;
        mov      esp,EXPORT_STACK
        push     ebx                  ; save the caller's esp
        endm
;
; EXPORT_ENTRY_MACRO end
;



;++
;
; Name:
;
;       ExportExit
;
; Arguments:
;
;
; Notes:
;
;       EAX = return code and MUST be preserved by this macro.
;
;--

EXPORT_EXIT_MACRO macro
;
; Next get caller's esp that we saved upon entry on the 16bit stack
;
        pop      ebx                    ; get caller's esp
;
; Restore flat selectors in segment registers.
;
        mov      dx,KeDataSelector
        mov      ds,dx
        mov      ss,dx
        mov      es,dx
        mov      esp,ebx


;
; Restore callers' ebp that we saved on the 32bit stack
;
        pop      edi
        pop      esi
        pop      ebx
        pop      ebp      ; (ebp) = caller's ebp

;
; Pull callers flat return address off stack and push the
; flat code selector followed by the return offset, then
; execute a far return and we'll be back in the OS loaders code space.
;
        pop      edx      ; (edx) = caller's return address
        push     dword ptr KeCodeSelector
        push     edx
        db OVERRIDE
        retf
        endm

;++
;
;
;
;--

RE_ENABLE_PAGING_MACRO macro
extrn _EnableProtectPaging:near
        push     RE_ENABLING
        call     _EnableProtectPaging
        add      sp,2
        endm

ENTER_REALMODE_MACRO macro
extrn _RealMode:near
        call    _RealMode
        endm



WAIT_FOREVER_MACRO macro
        LOCAL wf1
wf1:    jmp     wf1
        endm

;++
;
; MAKE_STACK_FRAME_MACRO
;
; Arguments:
;
;    _FrameName_ - is the name of the structure defining the
;                  stack frame layout.
;
;    _PointerRegister_ - is the register containing the linear pointer to
;                        the top of the stack frame.
; ProtectMode ONLY
;
;--

MAKE_STACK_FRAME_MACRO macro _FrameName_ , _PointerRegister_
Local msf1
        mov     ecx, (size _FrameName_)/2
        mov     esi,_PointerRegister_   ; (esi) = offset of argument frame
        add     esi,20                  ; account for ebp, ebx, esi, edi and
                                        ; return address
        push    KeDataSelector          ; (ax) = Flat 32bit segment selector
        pop     ds                      ; (ds:esi) points to argument frame
        push    ss                      ;
        pop     es                      ; (es) = 16bit stack selector
        sub     sp, size _FrameName_    ; make room for the arguments
        xor     edi,edi                 ; clear out upper 16bits of edi
        mov     di,sp                   ; (es:edi) points to top of stack
msf1:
        mov     ax,[esi]
        mov     es:[edi],ax
        add     esi,2
        add     edi,2
        loop    msf1
        push    es                      ;
        pop     ds                      ; put 16bit selector back into ds
        endm


REMOVE_STACK_FRAME_MACRO macro _FrameName_

        add     sp, size _FrameName_
        endm


;BuildDescriptor macro   Base,Limit,Access,Dpl,Stype
;        dw       (Limit AND 0ffffh)
;        dw       (Base AND 0ffffh)
;        db       ((Base SHR 16) AND 0ffh)
;        db       (Gran + Dpl + Stype)
;        db       ((Limit SHR 16) AND 0ffh)
;        db       ((Base SHR 24) AND 0ffh)
;        endm



;
;
;
RETURNCODE_IN_EAX_MACRO macro

        shl      edx,16
        mov      dx,ax
        mov      eax,edx
        endm