497 lines
14 KiB
ArmAsm
497 lines
14 KiB
ArmAsm
|
// TITLE("Spin Locks")
|
||
|
//++
|
||
|
//
|
||
|
// Copyright (c) 1990 Microsoft Corporation
|
||
|
//
|
||
|
// Module Name:
|
||
|
//
|
||
|
// spinlock.s
|
||
|
//
|
||
|
// Abstract:
|
||
|
//
|
||
|
// This module implements the routines for acquiring and releasing
|
||
|
// spin locks.
|
||
|
//
|
||
|
// Author:
|
||
|
//
|
||
|
// David N. Cutler (davec) 23-Mar-1990
|
||
|
//
|
||
|
// Environment:
|
||
|
//
|
||
|
// Kernel mode only.
|
||
|
//
|
||
|
// Revision History:
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
#include "ksmips.h"
|
||
|
|
||
|
SBTTL("Initialize Executive Spin Lock")
|
||
|
//++
|
||
|
//
|
||
|
// VOID
|
||
|
// KeInitializeSpinLock (
|
||
|
// IN PKSPIN_LOCK SpinLock
|
||
|
// )
|
||
|
//
|
||
|
// Routine Description:
|
||
|
//
|
||
|
// This function initialzies an executive spin lock.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// SpinLock (a0) - Supplies a pointer to a executive spinlock.
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// None.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
LEAF_ENTRY(KeInitializeSpinLock)
|
||
|
|
||
|
sw zero,0(a0) // clear spin lock value
|
||
|
j ra // return
|
||
|
|
||
|
.end KeInitializeSpinlock
|
||
|
|
||
|
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 (a0) - Supplies a pointer to a executive spinlock.
|
||
|
// OldIrql (a1) - Supplies a pointer to a variable that receives the the previous IRQL value.
|
||
|
// N.B. The Old IRQL MUST be stored after the lock is acquired.
|
||
|
// Return Value:
|
||
|
// None.
|
||
|
|
||
|
LEAF_ENTRY(KeAcquireSpinLock)
|
||
|
|
||
|
//
|
||
|
// Disable interrupts and attempt to acquire the specified spinlock.
|
||
|
//
|
||
|
|
||
|
li a2,DISPATCH_LEVEL // set new IRQL level
|
||
|
|
||
|
10: DISABLE_INTERRUPTS(t2) // disable interrupts
|
||
|
|
||
|
#if !defined(NT_UP)
|
||
|
|
||
|
lw t0,KiPcr + PcCurrentThread(zero) // get address of current thread
|
||
|
20: ll t1,0(a0) // get current lock value
|
||
|
move t3,t0 // set ownership value
|
||
|
bne zero,t1,30f // if ne, spin lock owned
|
||
|
sc t3,0(a0) // set spin lock owned
|
||
|
beq zero,t3,20b // if eq, store conditional failure
|
||
|
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Raise IRQL to DISPATCH_LEVEL and acquire the specified spinlock.
|
||
|
//
|
||
|
// N.B. The raise IRQL code is duplicated here to avoid any extra overhead
|
||
|
// since this is such a common operation.
|
||
|
//
|
||
|
|
||
|
lbu t0,KiPcr + PcIrqlTable(a2) // get translation table entry value
|
||
|
li t1,~(0xff << PSR_INTMASK) // get interrupt enable mask
|
||
|
sll t0,t0,PSR_INTMASK // shift table entry into position
|
||
|
lbu v0,KiPcr + PcCurrentIrql(zero) // get current IRQL
|
||
|
and t2,t2,t1 // clear current interrupt enables
|
||
|
or t2,t2,t0 // set new interrupt enables
|
||
|
sb a2,KiPcr + PcCurrentIrql(zero) // set new IRQL
|
||
|
|
||
|
ENABLE_INTERRUPTS(t2) // enable interrupts
|
||
|
|
||
|
sb v0,0(a1) // store old IRQL
|
||
|
j ra // return
|
||
|
|
||
|
#if !defined(NT_UP)
|
||
|
|
||
|
30: ENABLE_INTERRUPTS(t2) // enable interrupts
|
||
|
|
||
|
b 10b // try again
|
||
|
#endif
|
||
|
|
||
|
.end 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 (a0) - Supplies a pointer to the spinlock that is to be acquired.
|
||
|
// Return Value:
|
||
|
// The previous IRQL is returned at the fucntion value.
|
||
|
|
||
|
LEAF_ENTRY(KiAcquireSpinLockRaiseIrql)
|
||
|
|
||
|
ALTERNATE_ENTRY(KeAcquireSpinLockRaiseToDpc)
|
||
|
|
||
|
li a1,DISPATCH_LEVEL // set new IRQL level
|
||
|
b 10f // finish in common code
|
||
|
|
||
|
|
||
|
SBTTL("Acquire SpinLock and Raise to Synch")
|
||
|
|
||
|
// KIRQL KeAcquireSpinLockRaiseToSynch (IN PKSPIN_LOCK SpinLock)
|
||
|
// Routine Description:
|
||
|
// This function raises the current IRQL to synchronization level and acquires the specified spinlock.
|
||
|
// Arguments:
|
||
|
// SpinLock (a0) - Supplies a pointer to the spinlock that is to be acquired.
|
||
|
// Return Value:
|
||
|
// The previous IRQL is returned at the fucntion value.
|
||
|
|
||
|
ALTERNATE_ENTRY(KeAcquireSpinLockRaiseToSynch)
|
||
|
|
||
|
//
|
||
|
// Disable interrupts and attempt to acquire the specified spinlock.
|
||
|
//
|
||
|
|
||
|
lbu a1,KiSynchIrql // set new IRQL level
|
||
|
|
||
|
10: DISABLE_INTERRUPTS(t2) // disable interrupts
|
||
|
|
||
|
#if !defined(NT_UP)
|
||
|
|
||
|
lw t0,KiPcr + PcCurrentThread(zero) // get address of current thread
|
||
|
20: ll t1,0(a0) // get current lock value
|
||
|
move t3,t0 // set ownership value
|
||
|
bne zero,t1,30f // if ne, spin lock owned
|
||
|
sc t3,0(a0) // set spin lock owned
|
||
|
beq zero,t3,20b // if eq, store conditional failure
|
||
|
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Raise IRQL to synchronization level and acquire the specified spinlock.
|
||
|
//
|
||
|
// N.B. The raise IRQL code is duplicated here to avoid any extra overhead
|
||
|
// since this is such a common operation.
|
||
|
//
|
||
|
|
||
|
lbu t0,KiPcr + PcIrqlTable(a1) // get translation table entry value
|
||
|
li t1,~(0xff << PSR_INTMASK) // get interrupt enable mask
|
||
|
sll t0,t0,PSR_INTMASK // shift table entry into position
|
||
|
lbu v0,KiPcr + PcCurrentIrql(zero) // get current IRQL
|
||
|
and t2,t2,t1 // clear current interrupt enables
|
||
|
or t2,t2,t0 // set new interrupt enables
|
||
|
sb a1,KiPcr + PcCurrentIrql(zero) // set new IRQL
|
||
|
|
||
|
ENABLE_INTERRUPTS(t2) // enable interrupts
|
||
|
|
||
|
j ra // return
|
||
|
|
||
|
#if !defined(NT_UP)
|
||
|
|
||
|
30: ENABLE_INTERRUPTS(t2) // enable interrupts
|
||
|
|
||
|
b 10b // try again
|
||
|
|
||
|
#endif
|
||
|
|
||
|
.end KiAcquireSpinLockRaiseIrql
|
||
|
|
||
|
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.
|
||
|
//
|
||
|
// Arguments:
|
||
|
//
|
||
|
// SpinLock (a0) - Supplies a pointer to an executive spin lock.
|
||
|
//
|
||
|
// OldIrql (a1) - Supplies the previous IRQL value.
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// None.
|
||
|
//
|
||
|
//--
|
||
|
LEAF_ENTRY(KeReleaseSpinLock)
|
||
|
|
||
|
//
|
||
|
// Release the specified spinlock.
|
||
|
//
|
||
|
|
||
|
#if !defined(NT_UP)
|
||
|
|
||
|
sw zero,0(a0) // set spin lock not owned
|
||
|
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// Lower the IRQL to the specified level.
|
||
|
//
|
||
|
// N.B. The lower IRQL code is duplicated here is avoid any extra overhead
|
||
|
// since this is such a common operation.
|
||
|
//
|
||
|
|
||
|
and a1,a1,0xff // isolate old IRQL
|
||
|
lbu t0,KiPcr + PcIrqlTable(a1) // get translation table entry value
|
||
|
li t1,~(0xff << PSR_INTMASK) // get interrupt enable mask
|
||
|
sll t0,t0,PSR_INTMASK // shift table entry into position
|
||
|
|
||
|
DISABLE_INTERRUPTS(t2) // disable interrupts
|
||
|
|
||
|
and t2,t2,t1 // clear current interrupt enables
|
||
|
or t2,t2,t0 // set new interrupt enables
|
||
|
sb a1,KiPcr + PcCurrentIrql(zero) // set new IRQL
|
||
|
|
||
|
ENABLE_INTERRUPTS(t2) // enable interrupts
|
||
|
|
||
|
j ra // return
|
||
|
|
||
|
.end KeReleaseSpinLock
|
||
|
|
||
|
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 (a0) - Supplies a pointer to a executive spinlock.
|
||
|
//
|
||
|
// OldIrql (a1) - Supplies a pointer to a variable that receives the
|
||
|
// the previous IRQL value.
|
||
|
//
|
||
|
// N.B. The Old IRQL MUST be stored after the lock is acquired.
|
||
|
//
|
||
|
// Return Value:
|
||
|
//
|
||
|
// If the spin lock is acquired, then a value of TRUE is returned.
|
||
|
// Otherwise, a value of FALSE is returned.
|
||
|
//
|
||
|
//--
|
||
|
|
||
|
LEAF_ENTRY(KeTryToAcquireSpinLock)
|
||
|
|
||
|
//
|
||
|
// Raise IRQL to DISPATCH_LEVEL and try to acquire the specified spinlock.
|
||
|
//
|
||
|
// N.B. The raise IRQL code is duplicated here to avoid any extra overhead
|
||
|
// since this is such a common operation.
|
||
|
//
|
||
|
|
||
|
li a2,DISPATCH_LEVEL // set new IRQL level
|
||
|
lbu t0,KiPcr + PcIrqlTable(a2) // get translation table entry value
|
||
|
li t1,~(0xff << PSR_INTMASK) // get interrupt enable mask
|
||
|
sll t0,t0,PSR_INTMASK // shift table entry into position
|
||
|
lbu t2,KiPcr + PcCurrentIrql(zero) // get current IRQL
|
||
|
|
||
|
DISABLE_INTERRUPTS(t3) // disable interrupts
|
||
|
|
||
|
and t3,t3,t1 // clear current interrupt enables
|
||
|
or t3,t3,t0 // set new interrupt enables
|
||
|
sb a2,KiPcr + PcCurrentIrql(zero) // set new IRQL
|
||
|
|
||
|
ENABLE_INTERRUPTS(t3) // enable interrupts
|
||
|
|
||
|
//
|
||
|
// Try to acquire the specified spinlock.
|
||
|
//
|
||
|
|
||
|
#if !defined(NT_UP)
|
||
|
|
||
|
lw t0,KiPcr + PcCurrentThread(zero) // get address of current thread
|
||
|
10: ll t1,0(a0) // get current lock value
|
||
|
move v0,t0 // set ownership value
|
||
|
bne zero,t1,20f // if ne, spin lock owned
|
||
|
sc v0,0(a0) // set spin lock owned
|
||
|
beq zero,v0,10b // if eq, store conditional failure
|
||
|
|
||
|
#else
|
||
|
|
||
|
li v0,TRUE // set return value
|
||
|
|
||
|
#endif
|
||
|
|
||
|
//
|
||
|
// The attempt to acquire the specified spin lock succeeded.
|
||
|
//
|
||
|
|
||
|
sb t2,0(a1) // store old IRQL
|
||
|
j ra // return
|
||
|
|
||
|
//
|
||
|
// The attempt to acquire the specified spin lock failed. Lower IRQL to its
|
||
|
// previous value and return FALSE.
|
||
|
//
|
||
|
// N.B. The lower IRQL code is duplicated here is avoid any extra overhead
|
||
|
// since this is such a common operation.
|
||
|
//
|
||
|
|
||
|
#if !defined(NT_UP)
|
||
|
|
||
|
20: lbu t0,KiPcr + PcIrqlTable(t2) // get translation table entry value
|
||
|
li t1,~(0xff << PSR_INTMASK) // get interrupt enable mask
|
||
|
sll t0,t0,PSR_INTMASK // shift table entry into position
|
||
|
|
||
|
DISABLE_INTERRUPTS(t3) // disable interrupts
|
||
|
|
||
|
and t3,t3,t1 // clear current interrupt enables
|
||
|
or t3,t3,t0 // set new interrupt enables
|
||
|
sb t2,KiPcr + PcCurrentIrql(zero) // set new IRQL
|
||
|
|
||
|
ENABLE_INTERRUPTS(t3) // enable interrupts
|
||
|
|
||
|
li v0,FALSE // set return value
|
||
|
j ra // return
|
||
|
|
||
|
#endif
|
||
|
|
||
|
.end 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(KiAcquireSpinLock)
|
||
|
|
||
|
ALTERNATE_ENTRY(KeAcquireSpinLockAtDpcLevel)
|
||
|
|
||
|
#if !defined(NT_UP)
|
||
|
|
||
|
lw t0,KiPcr + PcCurrentThread(zero) // get address of current thread
|
||
|
10: ll t1,0(a0) // get current lock value
|
||
|
move t2,t0 // set ownership value
|
||
|
bne zero,t1,10b // if ne, spin lock owned
|
||
|
sc t2,0(a0) // set spin lock owned
|
||
|
beq zero,t2,10b // if eq, store conditional failure
|
||
|
|
||
|
#endif
|
||
|
|
||
|
j ra // return
|
||
|
|
||
|
.end 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(KiReleaseSpinLock)
|
||
|
|
||
|
ALTERNATE_ENTRY(KeReleaseSpinLockFromDpcLevel)
|
||
|
|
||
|
#if !defined(NT_UP)
|
||
|
|
||
|
|
||
|
sw zero,0(a0) // set spin lock not owned
|
||
|
|
||
|
#endif
|
||
|
|
||
|
j ra // return
|
||
|
|
||
|
.end KiReleaseSpinLock
|
||
|
|
||
|
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 (a0) - 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(KiTryToAcquireSpinLock)
|
||
|
|
||
|
#if !defined(NT_UP)
|
||
|
|
||
|
li v0,FALSE // assume attempt to acquire will fail
|
||
|
lw t0,KiPcr + PcCurrentThread(zero) // get address of current thread
|
||
|
10: ll t1,0(a0) // get current lock value
|
||
|
move t2,t0 // set ownership value
|
||
|
bne zero,t1,20f // if ne, spin lock owned
|
||
|
sc t2,0(a0) // set spin lock owned
|
||
|
beq zero,t2,10b // if eq, store conditional failure
|
||
|
|
||
|
#endif
|
||
|
|
||
|
li v0,TRUE // set return value
|
||
|
20: j ra // return
|
||
|
|
||
|
.end KiTryToAcquireSpinLock
|