mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
475 lines
12 KiB
475 lines
12 KiB
title "Irql Processing"
|
|
;++
|
|
;
|
|
; Copyright (c) 1989 Microsoft Corporation
|
|
;
|
|
; Module Name:
|
|
;
|
|
; ixlock.asm
|
|
;
|
|
; Abstract:
|
|
;
|
|
; This module implements various locking functions optimized for this hal.
|
|
;
|
|
; Author:
|
|
;
|
|
; Ken Reneris (kenr) 21-April-1994
|
|
;
|
|
; Environment:
|
|
;
|
|
; Kernel mode only.
|
|
;
|
|
; Revision History:
|
|
;
|
|
;--
|
|
|
|
.386p
|
|
.xlist
|
|
include hal386.inc
|
|
include callconv.inc ; calling convention macros
|
|
include i386\ix8259.inc
|
|
include i386\kimacro.inc
|
|
include mac386.inc
|
|
.list
|
|
|
|
EXTRNP _KeBugCheck,1,IMPORT
|
|
EXTRNP _KeSetEventBoostPriority, 2, IMPORT
|
|
EXTRNP _KeWaitForSingleObject,5, IMPORT
|
|
|
|
extrn FindHigherIrqlMask:DWORD
|
|
extrn SWInterruptHandlerTable:DWORD
|
|
|
|
EXTRNP _KeRaiseIrql,2
|
|
EXTRNP _KeLowerIrql,1
|
|
|
|
ifdef NT_UP
|
|
LOCK_ADD equ add
|
|
LOCK_DEC equ dec
|
|
else
|
|
LOCK_ADD equ lock add
|
|
LOCK_DEC equ lock dec
|
|
endif
|
|
|
|
page ,132
|
|
subttl "AcquireSpinLock"
|
|
|
|
_TEXT$01 SEGMENT PARA PUBLIC 'CODE'
|
|
ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
|
|
|
|
;++
|
|
;
|
|
; KIRQL
|
|
; KfAcquireSpinLock (
|
|
; IN PKSPIN_LOCK SpinLock
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This function raises to DISPATCH_LEVEL and then acquires a the
|
|
; kernel spin lock.
|
|
;
|
|
; In a UP hal spinlock serialization is accomplished by raising the
|
|
; IRQL to DISPATCH_LEVEL. The SpinLock is not used; however, for
|
|
; debugging purposes if the UP hal is compiled with the NT_UP flag
|
|
; not set (ie, MP) we take the SpinLock.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; (ecx) = SpinLock Supplies a pointer to an kernel spin lock.
|
|
;
|
|
; Return Value:
|
|
;
|
|
; OldIrql
|
|
;
|
|
;--
|
|
|
|
cPublicFastCall KfAcquireSpinLock,1
|
|
cPublicFpo 0,0
|
|
|
|
xor eax, eax ; Eliminate partial stall on return to caller
|
|
mov al, PCR[PcIrql] ; (al) = Old Irql
|
|
mov byte ptr PCR[PcIrql], DISPATCH_LEVEL ; set new irql
|
|
|
|
ifndef NT_UP
|
|
asl10: ACQUIRE_SPINLOCK ecx,<short asl20>
|
|
endif
|
|
|
|
ifdef IRQL_METRICS
|
|
inc HalRaiseIrqlCount
|
|
endif
|
|
if DBG
|
|
cmp al, DISPATCH_LEVEL ; old > new?
|
|
ja short asl99 ; yes, go bugcheck
|
|
endif
|
|
fstRET KfAcquireSpinLock
|
|
|
|
ifndef NT_UP
|
|
asl20: SPIN_ON_SPINLOCK ecx,<short asl10>
|
|
endif
|
|
|
|
if DBG
|
|
cPublicFpo 2,1
|
|
asl99: movzx eax, al
|
|
push eax ; put old irql where we can find it
|
|
stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
|
|
endif
|
|
fstRET KfAcquireSpinLock
|
|
fstENDP KfAcquireSpinLock
|
|
|
|
;++
|
|
;
|
|
; KIRQL
|
|
; KeAcquireSpinLockRaiseToSynch (
|
|
; IN PKSPIN_LOCK SpinLock
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This function acquires the SpinLock at SYNCH_LEVEL. The function
|
|
; is optmized for hoter locks (the lock is tested before acquired.
|
|
; Any spin should occur at OldIrql; however, since this is a UP hal
|
|
; we don't have the code for it)
|
|
;
|
|
; In a UP hal spinlock serialization is accomplished by raising the
|
|
; IRQL to SYNCH_LEVEL. The SpinLock is not used; however, for
|
|
; debugging purposes if the UP hal is compiled with the NT_UP flag
|
|
; not set (ie, MP) we take the SpinLock.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; (ecx) = SpinLock Supplies a pointer to an kernel spin lock.
|
|
;
|
|
; Return Value:
|
|
;
|
|
; OldIrql
|
|
;
|
|
;--
|
|
|
|
cPublicFastCall KeAcquireSpinLockRaiseToSynch,1
|
|
cPublicFpo 0,0
|
|
|
|
mov al, PCR[PcIrql] ; (al) = Old Irql
|
|
mov byte ptr PCR[PcIrql], SYNCH_LEVEL ; set new irql
|
|
|
|
ifndef NT_UP
|
|
asls10: ACQUIRE_SPINLOCK ecx,<short asls20>
|
|
endif
|
|
|
|
ifdef IRQL_METRICS
|
|
inc HalRaiseIrqlCount
|
|
endif
|
|
if DBG
|
|
cmp al, SYNCH_LEVEL ; old > new?
|
|
ja short asls99 ; yes, go bugcheck
|
|
endif
|
|
fstRET KeAcquireSpinLockRaiseToSynch
|
|
|
|
ifndef NT_UP
|
|
asls20: SPIN_ON_SPINLOCK ecx,<short asls10>
|
|
endif
|
|
|
|
if DBG
|
|
cPublicFpo 2,1
|
|
asls99: movzx eax, al
|
|
push eax ; put old irql where we can find it
|
|
stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
|
|
endif
|
|
fstRET KeAcquireSpinLockRaiseToSynch
|
|
fstENDP KeAcquireSpinLockRaiseToSynch
|
|
|
|
PAGE
|
|
SUBTTL "Release Kernel Spin Lock"
|
|
|
|
;++
|
|
;
|
|
; VOID
|
|
; KfReleaseSpinLock (
|
|
; IN PKSPIN_LOCK SpinLock,
|
|
; IN KIRQL NewIrql
|
|
; )
|
|
;
|
|
; Routine Description:
|
|
;
|
|
; This function releases a kernel spin lock and lowers to the new irql
|
|
;
|
|
; In a UP hal spinlock serialization is accomplished by raising the
|
|
; IRQL to DISPATCH_LEVEL. The SpinLock is not used; however, for
|
|
; debugging purposes if the UP hal is compiled with the NT_UP flag
|
|
; not set (ie, MP) we use the SpinLock.
|
|
;
|
|
; Arguments:
|
|
;
|
|
; (ecx) = SpinLock Supplies a pointer to an executive spin lock.
|
|
; (dl) = NewIrql New irql value to set
|
|
;
|
|
; Return Value:
|
|
;
|
|
; None.
|
|
;
|
|
;--
|
|
|
|
align 16
|
|
cPublicFastCall KfReleaseSpinLock ,2
|
|
cPublicFpo 0,0
|
|
ifndef NT_UP
|
|
RELEASE_SPINLOCK ecx ; release it
|
|
endif
|
|
xor ecx, ecx
|
|
if DBG
|
|
cmp dl, PCR[PcIrql]
|
|
ja short rsl99
|
|
endif
|
|
pushfd
|
|
cli
|
|
mov PCR[PcIrql], dl ; store old irql
|
|
mov cl, dl ; (ecx) = 32bit extended OldIrql
|
|
mov edx, PCR[PcIRR]
|
|
and edx, FindHigherIrqlMask[ecx*4] ; (edx) is the bitmask of
|
|
; pending interrupts we need to
|
|
jne short rsl20 ; dispatch now.
|
|
|
|
popfd
|
|
fstRet KfReleaseSpinLock ; all done
|
|
|
|
if DBG
|
|
rsl99: stdCall _KeBugCheck, <IRQL_NOT_LESS_OR_EQUAL> ; never return
|
|
endif
|
|
|
|
cPublicFpo 0,1
|
|
rsl20: bsr ecx, edx ; (ecx) = Pending irq level
|
|
cmp ecx, DISPATCH_LEVEL
|
|
jle short rsl40
|
|
|
|
mov eax, PCR[PcIDR] ; Clear all the interrupt
|
|
SET_8259_MASK ; masks
|
|
rsl40:
|
|
mov edx, 1
|
|
shl edx, cl
|
|
xor PCR[PcIRR], edx ; clear bit in IRR
|
|
call SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int.
|
|
popfd
|
|
|
|
cPublicFpo 0, 0
|
|
fstRet KfReleaseSpinLock ; all done
|
|
|
|
fstENDP KfReleaseSpinLock
|
|
|
|
;++
|
|
;
|
|
; VOID
|
|
; FASTCALL
|
|
; ExAcquireFastMutex (
|
|
; IN PFAST_MUTEX FastMutex
|
|
; )
|
|
;
|
|
; Routine description:
|
|
;
|
|
; This function acquire ownership of the FastMutex
|
|
;
|
|
; Arguments:
|
|
;
|
|
; (ecx) = FastMutex - Supplies a pointer to the fast mutex
|
|
;
|
|
; Return Value:
|
|
;
|
|
; None.
|
|
;
|
|
;--
|
|
|
|
cPublicFastCall ExAcquireFastMutex,1
|
|
cPublicFpo 0,0
|
|
mov al, PCR[PcIrql] ; (cl) = OldIrql
|
|
if DBG
|
|
cmp al, APC_LEVEL ; Is OldIrql > NewIrql?
|
|
ja short afm99 ; Yes, bugcheck
|
|
|
|
mov edx, PCR[PcPrcb]
|
|
mov edx, [edx].PbCurrentThread ; (edx) = Current Thread
|
|
cmp [ecx].FmOwner, edx ; Already owned by this thread?
|
|
je short afm98 ; Yes, error
|
|
endif
|
|
|
|
mov byte ptr PCR[PcIrql], APC_LEVEL ; Set NewIrql
|
|
LOCK_DEC dword ptr [ecx].FmCount ; Get count
|
|
jz short afm_ret ; The owner? Yes, Done
|
|
|
|
inc dword ptr [ecx].FmContention
|
|
|
|
cPublicFpo 0,2
|
|
push eax ; save OldIrql
|
|
push ecx ; Save FAST_MUTEX
|
|
add ecx, FmEvent ; Wait on Event
|
|
|
|
stdCall _KeWaitForSingleObject,<ecx,WrExecutive,0,0,0>
|
|
|
|
pop ecx ; (ecx) = FAST_MUTEX
|
|
pop eax ; (al) = OldIrql
|
|
|
|
cPublicFpo 1,0
|
|
afm_ret:
|
|
|
|
if DBG
|
|
cli
|
|
mov edx, PCR[PcPrcb]
|
|
mov edx, [edx].PbCurrentThread ; (edx) = Current Thread
|
|
sti
|
|
mov [ecx].FmOwner, edx ; Save in Fast Mutex
|
|
endif
|
|
mov byte ptr [ecx].FmOldIrql, al
|
|
fstRet ExAcquireFastMutex
|
|
|
|
if DBG
|
|
afm98: stdCall _KeBugCheck, <eax> ; never return
|
|
afm99: stdCall _KeBugCheck, <IRQL_NOT_LESS_OR_EQUAL> ; never return
|
|
fstRet ExAcquireFastMutex
|
|
endif
|
|
|
|
fstENDP ExAcquireFastMutex
|
|
|
|
|
|
;++
|
|
;
|
|
; VOID
|
|
; FASTCALL
|
|
; ExReleaseFastMutex (
|
|
; IN PFAST_MUTEX FastMutex
|
|
; )
|
|
;
|
|
; Routine description:
|
|
;
|
|
; This function releases ownership of the FastMutex
|
|
;
|
|
; Arguments:
|
|
;
|
|
; (ecx) = FastMutex - Supplies a pointer to the fast mutex
|
|
;
|
|
; Return Value:
|
|
;
|
|
; None.
|
|
;
|
|
;--
|
|
|
|
cPublicFastCall ExReleaseFastMutex,1
|
|
cPublicFpo 0,0
|
|
xor eax, eax
|
|
if DBG
|
|
cli
|
|
mov edx, PCR[PcPrcb]
|
|
mov edx, [edx].PbCurrentThread ; (edx) = CurrentThread
|
|
sti
|
|
cmp [ecx].FmOwner, edx ; Owner == CurrentThread?
|
|
jne short rfm_threaderror ; No, bugcheck
|
|
endif
|
|
or byte ptr [ecx].FmOwner, 1 ; not the owner anymore
|
|
|
|
mov al, byte ptr [ecx].FmOldIrql ; (eax) = OldIrql
|
|
LOCK_ADD dword ptr [ecx].FmCount, 1 ; Remove our count
|
|
js short rfm05 ; if < 0, set event
|
|
jnz short rfm10 ; if != 0, don't set event
|
|
|
|
rfm05:
|
|
cPublicFpo 0,2
|
|
push eax ; Save OldIrql
|
|
add ecx, FmEvent
|
|
stdCall _KeSetEventBoostPriority, <ecx, 0>
|
|
pop eax
|
|
|
|
cPublicFpo 0,0
|
|
rfm10:
|
|
cli
|
|
mov PCR[PcIrql], eax
|
|
mov edx, PCR[PcIRR]
|
|
and edx, FindHigherIrqlMask[eax*4] ; (edx) is the bitmask of
|
|
; pending interrupts we need to
|
|
jne short rfm20 ; dispatch now.
|
|
|
|
sti
|
|
fstRet ExReleaseFastMutex ; all done
|
|
if DBG
|
|
rfm_threaderror:
|
|
stdCall _KeBugCheck, <eax>
|
|
endif
|
|
|
|
rfm20: bsr ecx, edx ; (ecx) = Pending irq level
|
|
cmp ecx, DISPATCH_LEVEL
|
|
jle short rfm40
|
|
|
|
mov eax, PCR[PcIDR] ; Clear all the interrupt
|
|
SET_8259_MASK ; masks
|
|
rfm40:
|
|
mov edx, 1
|
|
shl edx, cl
|
|
xor PCR[PcIRR], edx ; clear bit in IRR
|
|
call SWInterruptHandlerTable[ecx*4] ; Dispatch the pending int.
|
|
sti
|
|
fstRet ExReleaseFastMutex ; all done
|
|
fstENDP ExReleaseFastMutex
|
|
|
|
;++
|
|
;
|
|
; BOOLEAN
|
|
; FASTCALL
|
|
; ExTryToAcquireFastMutex (
|
|
; IN PFAST_MUTEX FastMutex
|
|
; )
|
|
;
|
|
; Routine description:
|
|
;
|
|
; This function acquire ownership of the FastMutex
|
|
;
|
|
; Arguments:
|
|
;
|
|
; (ecx) = FastMutex - Supplies a pointer to the fast mutex
|
|
;
|
|
; Return Value:
|
|
;
|
|
; Returns TRUE if the FAST_MUTEX was acquired; otherwise false
|
|
;
|
|
;--
|
|
|
|
cPublicFastCall ExTryToAcquireFastMutex,1
|
|
cPublicFpo 0,0
|
|
mov al, PCR[PcIrql] ; (al) = OldIrql
|
|
|
|
if DBG
|
|
cmp al, APC_LEVEL ; Is OldIrql > NewIrql?
|
|
ja short tam99 ; Yes, bugcheck
|
|
endif
|
|
|
|
;
|
|
; Try to acquire - but needs to support 386s.
|
|
; *** Warning: This code is NOT MP safe ***
|
|
; But, we know that this hal really only runs on UP machines
|
|
;
|
|
cli
|
|
cmp dword ptr [ecx].FmCount, 1 ; Busy?
|
|
jne short tam20 ; Yes, abort
|
|
|
|
mov dword ptr [ecx].FmCount, 0 ; acquire count
|
|
|
|
if DBG
|
|
mov edx, PCR[PcPrcb]
|
|
mov edx, [edx].PbCurrentThread ; (edx) = Current Thread
|
|
mov [ecx].FmOwner, edx ; Save in Fast Mutex
|
|
endif
|
|
mov PCR[PcIrql], APC_LEVEL
|
|
sti
|
|
mov byte ptr [ecx].FmOldIrql, al
|
|
mov eax, 1 ; return TRUE
|
|
fstRet ExTryToAcquireFastMutex
|
|
|
|
tam20: sti
|
|
xor eax, eax ; return FALSE
|
|
fstRet ExTryToAcquireFastMutex ; all done
|
|
|
|
if DBG
|
|
tam99: stdCall _KeBugCheck, <IRQL_NOT_LESS_OR_EQUAL> ; never return
|
|
xor eax, eax ; return FALSE
|
|
fstRet ExTryToAcquireFastMutex
|
|
endif
|
|
|
|
fstENDP ExTryToAcquireFastMutex
|
|
|
|
_TEXT$01 ends
|
|
|
|
end
|