;++
;
; Copyright (c) 1989  Microsoft Corporation
;
; Module Name:
;
;    mac386.inc - 386 machine specific assembler macros
;
; Abstract:
;
;   This module contains 386 machine specific (assembler) macros
;   applicable to code outside the kernel.  Note that
;   ACQUIRE_SPINLOCK_DIRECT assumes the PCR is handy, so it won't
;   work in user mode (with debugging turned on.)
;
; Author:
;
;   Bryan Willman (bryanwi)  1 Aug 90
;

if NT_INST
else

;++
;
;  ACQUIRE_SPINLOCK LockAddress, SpinLabel
;
;  Macro Description:
;
;     This macro acquires a kernel spin lock.
;
;     N.B. This macro assumes that the current IRQL is set properly.
;        It neither raises nor lowers IRQL.
;
;  Arguments:
;
;     (KSPIN_LOCK) LockAddress - address of SpinLock value
;     SpinLabel   - if acquire spinlock fail, the label to perform the
;                   spin checking.  It could be simply a "label" or
;                   "short label" which means the label is within 128
;                   bytes in distant.
;
;     NoChecking - Not blank, if no debugging code should be generated.
;--

ACQUIRE_SPINLOCK macro   LockAddress, SpinLabel, NoChecking

.errb <LockAddress>
.errb <SpinLabel>

ifndef NT_UP

;
; Attempt to assert the lock
;

        lock bts dword ptr [LockAddress], 0     ; test and set the spinlock
        jc      SpinLabel               ; spinlock owned, go SpinLabe

if    DBG
ifb   <NoChecking>
        push    edi                     ; save edi
        mov     edi,fs:PcPrcb
        mov     edi, [edi].PbCurrentThread
        or      edi, 1                  ; spinlock owned
        mov     [LockAddress], edi      ; remember current thread
        pop     edi                     ; restore edi
endif ; NoChecking
endif ; DBG
endif ; NT_UP

endm

;++
;
;  SPIN_ON_SPINLOCK   LockAddress, AcquireLabel
;
;  Macro Description:
;
;     This macro spins on a kernel spin lock.
;
;     N.B. This macro assumes that the current IRQL is set properly.
;        It neither raises nor lowers IRQL.
;
;  Arguments:
;
;     (KSPIN_LOCK) LockAddress - address of a SpinLock value
;
;     SpinLabel    - if the test on cleared spinlock sucess, the label
;                    to assert the spin lock.  It could be simply a
;                    "label" or  "short label" which means the label is
;                    within 128 bytes in distance.
;
;     NoChecking - Not blank, if no debugging code should be generated.
;--

SPIN_ON_SPINLOCK macro   LockAddress, AcquireLabel, NoChecking, PollDebugger, NoTimeout
local   a,flag                          ; define a local label

.errb <LockAddress>
.errb <AcquireLabel>

ifndef NT_UP
if    DBG

EXTRNP  Kii386SpinOnSpinLock,2
        flag = 0

ifb   <NoChecking>
        flag = flag + 1
endif

ifnb  <Polldebugger>
        flag = flag + 2
endif

ifb   <NoTimeout>
        flag = flag + 4
endif
        stdCall Kii386SpinOnSpinLock,<LockAddress,flag>
        jmp     AcquireLabel

else    ; DBG

;
; Non-Debug version
;

a:      test    dword ptr [LockAddress], 1 ; Was spinlock cleared?
        jz      AcquireLabel            ; Yes, go get it
        jmp     short a

endif   ; DBG
endif   ; NT_UP

endm


;++
;
;  TEST_SPINLOCK   LockAddress, BusyLabel
;
;  Macro Description:
;
;     This macro tests a kernel spin lock to see if it's busy.
;     If it's not busy, ACQUIRE_SPINLOCK still needs to be called
;     to obtain the spinlock in a locked manner.
;
;  Arguments:
;
;     (KSPIN_LOCK) LockAddress - address of a SpinLock value


TEST_SPINLOCK macro   LockAddress, BusyLabel
        test    dword ptr [LockAddress], 1 ; spinlock clear?
        jnz     BusyLabel                  ; No, then busy
endm




;++
;
;  RELEASE_SPINLOCK  LockAddress
;
;  Macro Description:
;
;     This macro releases a kernel spin lock.
;
;     N.B. This macro assumes that the current IRQL is set properly.
;        It neither raises nor lowers IRQL.
;
;  Arguments:
;
;     (KSPIN_LOCK) LockAddress - Supplies an address to a spin lock value
;     NoChecking - Not blank, if no debugging code should be generated.
;--

RELEASE_SPINLOCK macro   LockAddress, NoChecking
local a
.errb <LockAddress>
ifndef NT_UP
if    DBG
ifb   <NoChecking>
EXTRNP  _KeBugCheck,1

        push    edi                     ; save edi
        mov     edi,fs:PcPrcb
        mov     edi,[edi].PbCurrentThread
        or      edi, 1                  ; assume current thread owns the lock
        cmp     edi, [LockAddress]      ; Does current thread own the lock?
        pop     edi                     ; restore edi
        jz      short a                 ; if z, yes, goto a and release lock
        stdCall _KeBugCheck,<LockAddress>    ; Never return ...
a:
endif
        mov     dword ptr [LockAddress], 0
else
        mov     byte ptr [LockAddress], 0

endif   ; DBG
endif   ; NT_UP
endm


endif
if NT_INST

;
; These are the instrumentation version of the above functions.
; internal use only
;

ACQUIRE_SPINLOCK macro   LockAddress, SpinLabel, NoChecking
EXTRNP  KiInst_AcquireSpinLock,0
ifidni  <&LockAddress>, <eax>
        stdCall KiInst_AcquireSpinLock
else
        push    eax
        mov     eax, LockAddress
        stdCall KiInst_AcquireSpinLock
        pop     eax
endif
        jc      SpinLabel
endm

SPIN_ON_SPINLOCK macro   LockAddress, AcquireLabel, NoChecking, PollDebugger
EXTRNP  KiInst_SpinOnSpinLock,0
ifidni  <&LockAddress>, <eax>
        stdCall KiInst_SpinOnSpinLock
else
        push    eax
        mov     eax, LockAddress
        stdCall KiInst_SpinOnSpinLock
        pop     eax
endif
        jmp     AcquireLabel
endm

TEST_SPINLOCK macro   LockAddress, BusyLabel
EXTRNP  KiInst_TestSpinLock,0
ifidni  <&LockAddress>, <eax>
        stdCall KiInst_TestSpinLock
else
        push    eax
        mov     eax, LockAddress
        stdCall KiInst_TestSpinLock
        pop     eax
endif
        jnc     AcquireLabel
endm

RELEASE_SPINLOCK macro   LockAddress, NoChecking
EXTRNP  KiInst_ReleaseSpinLock,0
ifidni  <&LockAddress>, <eax>
        stdCall KiInst_ReleaseSpinLock
else
        push    eax
        mov     eax, LockAddress
        stdCall KiInst_ReleaseSpinLock
        pop     eax
endif
endm

endif


