Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

598 lines
16 KiB

// TITLE("Spin Locks")
//++
//
// Copyright (c) 1993 IBM Corporation
//
// Module Name:
//
// spinlock.s
//
// Abstract:
//
// This module implements the routines for acquiring and releasing
// spin locks.
//
// Author:
//
// Peter L. Johnston ([email protected]) 28-Jun-93
//
// Environment:
//
// Kernel mode only.
//
// Revision History:
//
//--
#include "ksppc.h"
.extern ..KxReleaseSpinLock
SBTTL("Initialize Executive Spin Lock")
//++
//
// VOID
// KeInitializeSpinLock (
// IN PKSPIN_LOCK SpinLock
// )
//
// Routine Description:
//
// This function initialzies an executive spin lock.
//
// Arguments:
//
// SpinLock (r3) - Supplies a pointer to a executive spinlock.
//
// Return Value:
//
// None.
//
// Remarks:
//
// Equivalent C code for body of function.
// {
// *spinlock = 0;
// }
//
// Why is this in assembly code? I suspect simply so it is bundled
// with the rest of the spin lock code.
//--
LEAF_ENTRY(KeInitializeSpinLock)
li r.0, 0 // clear spin lock value by storing
stw r.0, 0(r.3) // zero at address from parameter.
LEAF_EXIT(KeInitializeSpinLock) // return
SBTTL("Acquire Executive Spin Lock")
//++
//
// VOID
// KeAcquireSpinLock (
// IN PKSPIN_LOCK SpinLock
// OUT PKIRQL OldIrql
// )
//
// Routine Description:
//
// This function raises the current IRQL to DISPATCH_LEVEL and acquires
// the specified executive spinlock.
//
// Arguments:
//
// SpinLock (r3) - Supplies a pointer to an executive spinlock.
//
// OldIrql (r4) - Supplies a pointer to a variable that receives the
// the previous IRQL value.
//
// Return Value:
//
// None.
//
// Remarks:
//
// In the UniProcessor version, we just raise IRQL, the lock address
// is never touched.
//
// In the MultiProcessor version the spinlock is taken after raising
// IRQL.
//
// N.B. The old IRQL must be stored AFTER the lock is acquired.
//
//--
LEAF_ENTRY_S(KeAcquireSpinLock,_TEXT$01)
#if !defined(NT_UP)
DISABLE_INTERRUPTS(r.5, r.6)
lwz r.12, KiPcr+PcCurrentThread(r.0) // addr of current thread
ACQUIRE_SPIN_LOCK(r.3, r.12, r.11, kas.10, kas.15)
#endif
li r.0, DISPATCH_LEVEL // new IRQL = DISPATCH_LEVEL
lbz r.10,KiPcr+PcCurrentIrql(r.0) // get current IRQL
stb r.0, KiPcr+PcCurrentIrql(r.0) // set new IRQL
#if !defined(NT_UP)
ENABLE_INTERRUPTS(r.5)
#endif
stb r.10, 0(r.4) // return old IRQL
blr
#if !defined(NT_UP)
SPIN_ON_SPIN_LOCK_ENABLED(r.3, r.11, kas.10, kas.15, kas.17, r.5, r.6)
#endif
DUMMY_EXIT(KeAcquireSpinLock)
SBTTL("Acquire SpinLock and Raise to DPC")
//++
//
// KIRQL
// KeAcquireSpinLockRaiseToDpc (
// IN PKSPIN_LOCK SpinLock
// )
//
// Routine Description:
//
// This function raises the current IRQL to dispatcher level and acquires
// the specified spinlock.
//
// Arguments:
//
// SpinLock (r3) - Supplies a pointer to the spinlock that is to be
// acquired.
//
// Return Value:
//
// The previous IRQL is returned at the function value.
//
// Remarks:
//
// In the UniProcessor version, we just raise IRQL, the lock address
// is never touched.
//
// In the MultiProcessor version the spinlock is taken after raising
// IRQL.
//
// N.B. The old IRQL must be stored AFTER the lock is acquired.
//
//--
LEAF_ENTRY_S(KeAcquireSpinLockRaiseToDpc,_TEXT$01)
//
// On PPC, synchronization level is the same as dispatch level.
//
ALTERNATE_ENTRY(KeAcquireSpinLockRaiseToSynch)
#if !defined(NT_UP)
DISABLE_INTERRUPTS(r.5, r.6)
lwz r.12, KiPcr+PcCurrentThread(r.0) // addr of current thread
ACQUIRE_SPIN_LOCK(r.3, r.12, r.11, kasrtd.10, kasrtd.15)
#endif
li r.0, DISPATCH_LEVEL // new IRQL = DISPATCH_LEVEL
lbz r.10,KiPcr+PcCurrentIrql(r.0) // get current IRQL
stb r.0, KiPcr+PcCurrentIrql(r.0) // set new IRQL
#if !defined(NT_UP)
ENABLE_INTERRUPTS(r.5)
#endif
ori r.3, r.10, 0 // return old IRQL
blr
#if !defined(NT_UP)
SPIN_ON_SPIN_LOCK_ENABLED(r.3, r.11, kasrtd.10, kasrtd.15, kasrtd.20, r.5, r.6)
#endif
DUMMY_EXIT(KeAcquireSpinLockRaiseToDpc)
SBTTL("Release Executive Spin Lock")
//++
//
// VOID
// KeReleaseSpinLock (
// IN PKSPIN_LOCK SpinLock
// IN KIRQL OldIrql
// )
//
// Routine Description:
//
// This function releases an executive spin lock and lowers the IRQL
// to its previous value.
//
// N.B. This routine is entered at DISPATCH_LEVEL.
//
// Arguments:
//
// SpinLock (r.3) - Supplies a pointer to an executive spin lock.
//
// OldIrql (r.4) - Supplies the previous IRQL value.
//
// Return Value:
//
// None.
//
//--
LEAF_ENTRY_S(KeReleaseSpinLock, _TEXT$01)
cmpwi r.4, DISPATCH_LEVEL // check if new IRQL < DISPATCH
#if !defined(NT_UP)
li r.0, 0
RELEASE_SPIN_LOCK(r.3, r.0)
#endif
bgelr // if target IRQL >= DISPATCH
// just return
DISABLE_INTERRUPTS(r.7,r.10)
lhz r.10, KiPcr+PcSoftwareInterrupt(r.0) // s/w interrupt pending?
stb r.4, KiPcr+PcCurrentIrql(r.0) // set target IRQL
cmpw cr.6, r.10, r.4
srwi. r.5, r.10, 8 // isolate DPC pending
cmpwi cr.7, r.4, APC_LEVEL // compare IRQL to APC_LEVEL
//
// Possible values for SoftwareInterrupt (r.10) are
//
// 0x0101 DPC and APC interrupt pending
// 0x0100 DPC interrupt pending
// 0x0001 APC interrupt pending
// 0x0000 No software interrupt pending (unlikely but possible)
//
// Possible values for current IRQL are zero or one. By comparing
// SoftwareInterrupt against current IQRL (above) we can quickly see
// if any software interrupts are valid at this time.
//
// Calculate correct IRQL for the interrupt we are processing. If DPC
// then we need to be at DISPATCH_LEVEL which is one greater than APC_
// LEVEL. r.5 contains one if we are going to run a DPC, so we add
// APC_LEVEL to r.5 to get the desired IRQL.
//
addi r.4, r.5, APC_LEVEL // calculate new IRQL
ble cr.6,Enable // jif no valid interrupt
//
// A software interrupt is pending and the new IRQL allows it to be
// taken at this time. Branch directly to KxReleaseSpinLock (ctxswap.s)
// to dispatch the interrupt. KxReleaseSpinLock returns directly to
// KeReleaseSpinLock's caller.
//
// WARNING: KxReleaseSpinLock is dependent on the values in r.4, r.7, r.12
// and condition register fields cr.0 and cr.7.
//
b ..KxReleaseSpinLock
Enable: ENABLE_INTERRUPTS(r.7)
LEAF_EXIT(KeReleaseSpinLock) // return
SBTTL("Try To Acquire Executive Spin Lock")
//++
//
// BOOLEAN
// KeTryToAcquireSpinLock (
// IN PKSPIN_LOCK SpinLock
// OUT PKIRQL OldIrql
// )
//
// Routine Description:
//
// This function raises the current IRQL to DISPATCH_LEVEL and attempts
// to acquires the specified executive spinlock. If the spinlock can be
// acquired, then TRUE is returned. Otherwise, the IRQL is restored to
// its previous value and FALSE is returned.
//
// Arguments:
//
// SpinLock (r.3) - Supplies a pointer to a executive spinlock.
//
// OldIrql (r.4) - Supplies a pointer to a variable that receives the
// the previous IRQL value.
//
// Return Value:
//
// If the spin lock is acquired, then a value of TRUE is returned.
// Otherwise, a value of FALSE is returned. UP systems always succeed.
// On MP systems we test if the lock is taken with interrupts disabled,
// so that we don't have to check for any DPCs/APCs that could be queued
// while we have priority at dispatch level.
//
// N.B. The old IRQL must be stored AFTER the lock is acquired.
//
//--
LEAF_ENTRY_S(KeTryToAcquireSpinLock,_TEXT$01)
#if !defined(NT_UP)
//
// Try to acquire the specified spinlock.
//
DISABLE_INTERRUPTS(r.9, r.8)
lwz r.12, KiPcr+PcCurrentThread(r.0) // addr of current thread
TRY_TO_ACQUIRE_SPIN_LOCK(r.3, r.12, r.11, ktas.10, ktas.20)
#endif
//
// Raise IRQL and indicate success.
//
lbz r.10,KiPcr+PcCurrentIrql(r.0) // get current IRQL
li r.0, DISPATCH_LEVEL // new IRQL = DISPATCH_LEVEL
li r.3, TRUE // set return value (success)
stb r.10, 0(r.4) // return old IRQL
stb r.0, KiPcr+PcCurrentIrql(r.0) // set new IRQL
#if !defined(NT_UP)
ENABLE_INTERRUPTS(r.9)
blr // return
//
// The attempt to acquire the specified spin lock failed. Indicate failure.
//
ktas.20:
ENABLE_INTERRUPTS(r.9)
li r.3, FALSE // set return value (failure)
#endif
LEAF_EXIT(KeTryToAcquireSpinLock)
SBTTL("Acquire Kernel Spin Lock")
//++
//
// KIRQL
// KiAcquireSpinLock (
// IN PKSPIN_LOCK SpinLock
// )
//
// Routine Description:
//
// This function acquires a kernel spin lock.
//
// N.B. This function assumes that the current IRQL is set properly.
//
// Arguments:
//
// SpinLock (a0) - Supplies a pointer to a kernel spin lock.
//
// Return Value:
//
// None.
//
//--
LEAF_ENTRY_S(KiAcquireSpinLock,_TEXT$01)
ALTERNATE_ENTRY(KeAcquireSpinLockAtDpcLevel)
#if !defined(NT_UP)
lwz r.12, KiPcr+PcCurrentThread(r.0) // addr of current thread
ACQUIRE_SPIN_LOCK(r.3, r.12, r.11, kas.20, kas.30)
#endif
blr
#if !defined(NT_UP)
SPIN_ON_SPIN_LOCK(r.3, r.11, kas.20, kas.30)
#endif
DUMMY_EXIT(KiAcquireSpinLock)
SBTTL("Release Kernel Spin Lock")
//++
//
// VOID
// KiReleaseSpinLock (
// IN PKSPIN_LOCK SpinLock
// )
//
// Routine Description:
//
// This function releases a kernel spin lock.
//
// N.B. This function assumes that the current IRQL is set properly.
//
// Arguments:
//
// SpinLock (a0) - Supplies a pointer to an executive spin lock.
//
// Return Value:
//
// None.
//
//--
LEAF_ENTRY_S(KiReleaseSpinLock,_TEXT$01)
ALTERNATE_ENTRY(KeReleaseSpinLockFromDpcLevel)
#if !defined(NT_UP)
li r.0, 0
RELEASE_SPIN_LOCK(r.3, r.0)
#endif
LEAF_EXIT(KiReleaseSpinLock) // return
SBTTL("Try To Acquire Kernel Spin Lock")
//++
//
// KIRQL
// KiTryToAcquireSpinLock (
// IN PKSPIN_LOCK SpinLock
// )
//
// Routine Description:
//
// This function attempts to acquires the specified kernel spinlock. If
// the spinlock can be acquired, then TRUE is returned. Otherwise, FALSE
// is returned.
//
// N.B. This function assumes that the current IRQL is set properly.
//
// Arguments:
//
// SpinLock (r.3) - Supplies a pointer to a kernel spin lock.
//
// Return Value:
//
// If the spin lock is acquired, then a value of TRUE is returned.
// Otherwise, a value of FALSE is returned.
//
//--
LEAF_ENTRY_S(KiTryToAcquireSpinLock,_TEXT$01)
#if defined(NT_UP)
li r.3, TRUE // set return value (success)
#else
lwz r.12, KiPcr+PcCurrentThread(r.0) // addr of current thread
TRY_TO_ACQUIRE_SPIN_LOCK(r.3, r.12, r.11, kitas.10, kitas.20)
li r.3, TRUE // set return value (success)
blr // return
kitas.20:
li r.3, FALSE // set return value (failure)
#endif
LEAF_EXIT(KiTryToAcquireSpinLock)
#if !defined(NT_UP)
#if SPINDBG
.struct 0
.space StackFrameHeaderLength
kasdR5: .space 4 // saved R5
kasdR6: .space 4 // saved R6
kasdR7: .space 4 // saved R7
kasdR8: .space 4 // saved R8
.align 3 // 8 byte align
kasdFrameLength:
SPECIAL_ENTRY_S(KiAcquireSpinLockDbg,_TEXT$01)
stwu sp,-kasdFrameLength(sp)
stw r5,kasdR5(sp) // save r5
stw r6,kasdR6(sp) // save r6
stw r7,kasdR7(sp) // save r7
stw r8,kasdR8(sp) // save r8
PROLOGUE_END(KiAcquireSpinLockDbg)
lwz r5,[toc]KiSpinLockLimit(r.toc)
lwz r5,0(r5)
mflr r7
CHKBRK(r6,kasd.05)
CHKLOCK(r6,r3,kasd.10)
DBGSTORE_IRR(r6,r8,0x7711,r4,r7)
kasd.10:
lwarx r6,0,r3 // load word at (r.3) and reserve
cmpwi r6,0 // check if locked
bne- kasd.20 // jif locked (predict NOT taken)
stwcx. r4,0,r3 // set lock owned
bne- kasd.20 // try again if store failed
isync // allow no readahead
CHKLOCK(r6,r3,kasd.11)
DBGSTORE_IRR(r6,r8,0x7712,r4,r7)
kasd.11:
lwz r8,kasdR8(sp) // restore r8
lwz r7,kasdR7(sp) // restore r7
lwz r6,kasdR6(sp) // restore r6
lwz r5,kasdR5(sp) // restore r5
addi sp,sp,kasdFrameLength // deallocate stack frame
blr // return
kasd.20:
subi r5,r5,1
cmpwi r5,0
beq- kasd.30
kasd.25:
lwz r6,0(r3)
cmpwi r6,0
beq+ kasd.10
b kasd.20
kasd.30:
//DBGSTORE_IRRR(r6,r8,0x7713,r3,r4,r7)
twi 31,0,0x16
lwz r5,[toc]KiSpinLockLimit(r.toc)
lwz r5,0(r5)
b kasd.25
DUMMY_EXIT(KiAcquireSpinLockDbg)
SPECIAL_ENTRY_S(KiTryToAcquireSpinLockDbg,_TEXT$01)
stwu sp,-kasdFrameLength(sp)
stw r5,kasdR5(sp) // save r5
stw r6,kasdR6(sp) // save r6
stw r7,kasdR7(sp) // save r7
stw r8,kasdR8(sp) // save r8
PROLOGUE_END(KiTryToAcquireSpinLockDbg)
lwz r5,[toc]KiSpinLockLimit(r.toc)
lwz r5,0(r5)
ori r6,r3,0
mflr r7
CHKBRK(r3,ktasd.05)
CHKLOCK(r3,r6,ktasd.10)
DBGSTORE_IRR(r3,r8,0x7721,r4,r7)
ktasd.10:
lwarx r3,0,r6 // load word at (r.3) and reserve
cmpwi r3,0 // check if locked
bne- ktasd.40 // jif locked (predict NOT taken)
stwcx. r4,0,r6 // set lock owned
bne- ktasd.20 // try again if store failed
isync // allow no readahead
li r3,TRUE
ktasd.15:
CHKLOCK(r8,r6,ktasd.16)
DBGSTORE_IRR(r6,r8,0x7722,r4,r7)
ktasd.16:
lwz r8,kasdR8(sp) // restore r8
lwz r7,kasdR7(sp) // restore r7
lwz r6,kasdR6(sp) // restore r6
lwz r5,kasdR5(sp) // restore r5
addi sp,sp,kasdFrameLength // deallocate stack frame
blr // return
ktasd.20:
subi r5,r5,1
cmpwi r5,0
bne+ ktasd.10
ktasd.30:
//DBGSTORE_IRRR(r3,r8,0x7723,r3,r4,r7)
twi 31,0,0x16
lwz r5,[toc]KiSpinLockLimit(r.toc)
lwz r5,0(r5)
b ktasd.10
ktasd.40:
li r3,FALSE
b ktasd.15
DUMMY_EXIT(KiTryToAcquireSpinLockDbg)
#endif
#endif