windows-nt/Source/XPSP1/NT/base/ntos/ex/ia64/intrlock.s
2020-09-26 16:20:57 +08:00

974 lines
26 KiB
ArmAsm
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//++
//
// Module Name:
//
// intrlock.s
//
// Abstract:
//
// This module implements the functions to support interlocked
// operations. Interlocked operations can only operate on
// nonpaged data and the specified spinlock cannot be used for
// any other purpose.
//
// Author:
//
// William K. Cheung (wcheung) 27-Sep-95
//
// Revision History:
//
// 07-Jul-97 bl Updated to EAS2.3
//
// 02-Feb-96 Updated to EAS2.1
//
//--
#include "ksia64.h"
.file "intrlock.s"
//++
//
// LARGE_INTEGER
// ExInterlockedAddLargeInteger (
// IN PLARGE_INTEGER Addend,
// IN LARGE_INTEGER Increment,
// IN PKSPIN_LOCK Lock
// )
//
// Routine Description:
//
// This function performs an interlocked add of an increment value to an
// addend variable of type large integer. The initial value of the addend
// variable is returned as the function value.
//
// Arguments:
//
// Addend (a0) - Supplies a pointer to a variable whose value is to be
// adjusted by the increment value.
//
// Increment (a1) - Supplies the increment value to be added to the
// addend variable.
//
// Lock (a2) - Supplies a pointer to a spin lock to be used to synchronize
// access to the addend variable.
//
// Return Value:
//
// The initial value of the addend variable is stored at the address
// supplied by v0.
//
//--
#if !defined(NT_UP)
LEAF_ENTRY(ExInterlockedAddLargeInteger)
//
// disable interrupt and then acquire the spinlock
//
rsm 1 << PSR_I // disable interrupt
cmp.eq pt0, pt1 = zero, zero
cmp.eq pt2 = zero, zero
;;
Eiali10:
.pred.rel "mutex",pt0,pt1
(pt0) xchg8 t0 = [a2], a2
(pt1) ld8.nt1 t0 = [a2]
;;
(pt0) cmp.ne pt2 = zero, t0
cmp.eq pt0, pt1 = zero, t0
;;
(pt1) ssm 1 << PSR_I // enable interrupt
(pt0) rsm 1 << PSR_I // disable interrupt
(pt2) br.dpnt Eiali10
;;
ld8 v0 = [a0]
;;
add t1 = a1, v0 // do the add
;;
st8 [a0] = t1 // save result
st8.rel.nta [a2] = zero // release spinlock
ssm 1 << PSR_I // enable interrupt
br.ret.sptk.clr brp // return
;;
LEAF_EXIT(ExInterlockedAddLargeInteger)
#else
LEAF_ENTRY(ExInterlockedAddLargeInteger)
rsm 1 << PSR_I // disable interrupt
;;
ld8.acq v0 = [a0]
;;
add t0 = a1, v0
;;
st8.rel [a0] = t0
ssm 1 << PSR_I // enable interrupt
br.ret.sptk brp
;;
LEAF_EXIT(ExInterlockedAddLargeInteger)
#endif // !defined(NT_UP)
//++
//
// VOID
// ExInterlockedAddLargeStatistic (
// IN PLARGE_INTEGER Addend,
// IN ULONG Increment
// )
//
// Routine Description:
//
// This function performs an interlocked add of an increment value to an
// addend variable of type large integer.
//
// Arguments:
//
// Addend (a0) - Supplies a pointer to a variable whose value is to be
// adjusted by the increment value.
//
// Increment (a1) - Supplies the increment value to be added to the
// addend variable.
//
// Return Value:
//
// None.
//
//--
LEAF_ENTRY(ExInterlockedAddLargeStatistic)
ld8.nt1 v0 = [a0]
extr.u a1 = a1, 0, 32 // sanitize the top 32 bits
;;
Eials10:
nop.m 0
mov ar.ccv = v0
add t0 = a1, v0
;;
//
// If the addend has been modified since the last load, pt8 will be set
// to TRUE and need to branch back to Eiali10 to retry the operation again.
//
cmpxchg8.rel t1 = [a0], t0, ar.ccv
;;
cmp.ne pt8, pt7 = v0, t1
mov v0 = t1
;;
nop.m 0
(pt8) br.cond.spnt Eials10 // if failed, then try again
(pt7) br.ret.sptk.clr brp // otherwise, return
;;
LEAF_EXIT(ExInterlockedAddLargeStatistic)
//++
//
// ULONG
// ExInterlockedAddUlong (
// IN PULONG Addend,
// IN ULONG Increment,
// IN PKSPIN_LOCK Lock
// )
//
// Routine Description:
//
// This function performs an interlocked add of an increment value to an
// addend variable of type unsigned long. The initial value of the addend
// variable is returned as the function value.
//
// Arguments:
//
// Addend (a0) - Supplies a pointer to a variable whose value is to be
// adjusted by the increment value.
//
// Increment (a1) - Supplies the increment value to be added to the
// addend variable.
//
// Lock (a2) - Supplies a pointer to a spin lock to be used to synchronize
// access to the addend variable.
//
// Return Value:
//
// The initial value of the addend variable.
//
//--
#if !defined(NT_UP)
LEAF_ENTRY(ExInterlockedAddUlong)
//
// disable interrupt and then acquire the spinlock
//
rsm 1 << PSR_I // disable interrupt
zxt4 a1 = a1 // sanitize the top 32 bits
cmp.eq pt0, pt1 = zero, zero
cmp.eq pt2 = zero, zero
;;
Eiau10:
.pred.rel "mutex",pt0,pt1
(pt0) xchg8 t0 = [a2], a2
(pt1) ld8.nt1 t0 = [a2]
;;
(pt0) cmp.ne pt2 = zero, t0
cmp.eq pt0, pt1 = zero, t0
;;
(pt1) ssm 1 << PSR_I // enable interrupt
(pt0) rsm 1 << PSR_I // disable interrupt
(pt2) br.dpnt Eiau10
;;
//
// lock acquired; load the addend, perform the addition and write it back.
// then release the lock and enable interrupts.
//
ld4 v0 = [a0]
;;
add t0 = a1, v0 // do the add
;;
st4 [a0] = t0 // save result
st8.rel.nta [a2] = zero // release spinlock
ssm 1 << PSR_I // enable interrupt
br.ret.sptk.clr brp // return
LEAF_EXIT(ExInterlockedAddUlong)
#else
LEAF_ENTRY(ExInterlockedAddUlong)
rsm 1 << PSR_I // disable interrupt
;;
ld4.acq v0 = [a0]
zxt4 a1 = a1 // sanitize the top 32 bits
;;
add t0 = a1, v0
;;
st4.rel [a0] = t0
ssm 1 << PSR_I // enable interrupt
br.ret.sptk brp
;;
LEAF_EXIT(ExInterlockedAddUlong)
#endif // !defined(NT_UP)
//++
//
// ULONG
// ExInterlockedExchangeUlong (
// IN PULONG Source,
// IN ULONG Value,
// IN PKSPIN_LOCK Lock
// )
//
// Routine Description:
//
// This function performs an interlocked exchange of a longword value with
// a longword in memory and returns the memory value.
//
// N.B. There is an alternate entry point provided for this routine which
// is IA64 target specific and whose prototype does not include the
// spinlock parameter. Since the routine never refers to the spinlock
// parameter, no additional code is required.
//
// Arguments:
//
// Source (a0) - Supplies a pointer to a variable whose value is to be
// exchanged.
//
// Value (a1) - Supplies the value to exchange with the source value.
//
// Lock (a2) - Supplies a pointer to a spin lock to be used to synchronize
// access to the source variable.
//
// Return Value:
//
// The source value is returned as the function value.
//
// Implementation Note:
//
// The specification of this function does not require that the given lock
// be used to synchronize the update as long as the update is synchronized
// somehow. On Alpha a single load locked-store conditional does the job.
//
//--
LEAF_ENTRY(ExInterlockedExchangeUlong)
ALTERNATE_ENTRY(ExIa64InterlockedExchangeUlong)
mf
zxt4 a1 = a1 // sanitize the upper 32 bits
;;
xchg4 v0 = [a0], a1
br.ret.sptk.clr brp
LEAF_EXIT(ExInterlockedExchangeUlong)
//++
//
// LONG
// InterlockedExchangeAdd (
// IN OUT PLONG Addend,
// IN LONG Increment
// )
//
// Routine Description:
//
// This function performs an interlocked add of an increment value to an
// addend variable of type unsinged long. The initial value of the addend
// variable is returned as the function value.
//
// It is NOT possible to mix ExInterlockedDecrementLong and
// ExInterlockedIncrementong with ExInterlockedAddUlong.
//
//
// Arguments:
//
// Addend - Supplies a pointer to a variable whose value is to be
// adjusted by the increment value.
//
// Increment - Supplies the increment value to be added to the
// addend variable.
//
// Return Value:
//
// (r8) - The initial value of the addend.
//
//--
LEAF_ENTRY(InterlockedExchangeAdd)
ld4.nt1 v0 = [a0]
;;
Iea10:
mov ar.ccv = v0
add t1 = a1, v0
mov t0 = v0
;;
cmpxchg4.acq v0 = [a0], t1, ar.ccv
nop.m 0
nop.i 0
;;
cmp.ne pt7, pt8 = v0, t0
(pt7) br.cond.spnt Iea10
(pt8) br.ret.sptk.clr brp
;;
LEAF_EXIT(InterlockedExchangeAdd)
//++
//
// PVOID
// InterlockedCompareExchange (
// IN OUT PVOID *Destination,
// IN PVOID Exchange,
// IN PVOID Comperand
// )
//
// Routine Description:
//
// This function performs an interlocked compare of the destination
// value with the comperand value. If the destination value is equal
// to the comperand value, then the exchange value is stored in the
// destination. Otherwise, no operation is performed.
//
// Arguments:
//
// Destination - Supplies a pointer to destination value.
//
// Exchange - Supplies the exchange value.
//
// Comperand - Supplies the comperand value.
//
// Return Value:
//
// (r8) - The initial destination value.
//
//--
LEAF_ENTRY(InterlockedCompareExchange)
mf
mov ar.ccv = a2
;;
cmpxchg4.acq v0 = [a0], a1, ar.ccv
br.ret.sptk.clr brp
;;
LEAF_EXIT(InterlockedCompareExchange)
//++
//
// INTERLOCKED_RESULT
// ExInterlockedDecrementLong (
// IN PLONG Addend,
// IN PKSPIN_LOCK Lock
// )
//
// Routine Description:
//
// This function performs an interlocked decrement on an addend variable
// of type signed long. The sign and whether the result is zero is returned
// as the function value.
//
// N.B. There is an alternate entry point provided for this routine which
// is IA64 target specific and whose prototype does not include the
// spinlock parameter. Since the routine never refers to the spinlock
// parameter, no additional code is required.
//
// Arguments:
//
// Addend (a0) - Supplies a pointer to a variable whose value is to be
// decremented.
//
// Lock (a1) - Supplies a pointer to a spin lock to be used to synchronize
// access to the addend variable.
//
// Return Value:
//
// RESULT_NEGATIVE is returned if the resultant addend value is negative.
// RESULT_ZERO is returned if the resultant addend value is zero.
// RESULT_POSITIVE is returned if the resultant addend value is positive.
//
// RESULT_ZERO = 0
// RESULT_NEGATIVE = 1
// RESULT_POSITIVE = 2
//
// Implementation Notes:
//
// The specification of this function does not require that the given lock
// be used to synchronize the update as long as the update is synchronized
// somehow. On Alpha a single load locked-store conditional does the job.
//
//--
LEAF_ENTRY(ExInterlockedDecrementLong)
ALTERNATE_ENTRY(ExIa64InterlockedDecrementLong)
fetchadd4.acq t1 = [a0], -1
mov v0 = 0 // assume result is zero
;;
cmp4.le pt7, p0 = 2, t1
cmp4.ge pt8, p0 = 0, t1
;;
.pred.rel "mutex",pt7,pt8
(pt8) mov v0 = 1 // negative result
(pt7) mov v0 = 2 // positive result
br.ret.sptk.clr brp // return
;;
LEAF_EXIT(ExInterlockedDecrementLong)
//++
//
// INTERLOCKED_RESULT
// ExInterlockedIncrementLong (
// IN PLONG Addend,
// IN PKSPIN_LOCK Lock
// )
//
// Routine Description:
//
// This function performs an interlocked increment on an addend variable
// of type signed long. The sign and whether the result is zero is returned
// as the function value.
//
// N.B. There is an alternate entry point provided for this routine which
// is IA64 target specific and whose prototype does not include the
// spinlock parameter. Since the routine never refers to the spinlock
// parameter, no additional code is required.
//
// Arguments:
//
// Addend (a0) - Supplies a pointer to a variable whose value is to be
// incremented.
//
// Lock (a1) - Supplies a pointer to a spin lock to be used to synchronize
// access to the addend variable.
//
// Return Value:
//
// RESULT_NEGATIVE is returned if the resultant addend value is negative.
// RESULT_ZERO is returned if the resultant addend value is zero.
// RESULT_POSITIVE is returned if the resultant addend value is positive.
//
// Implementation Notes:
//
// The specification of this function does not require that the given lock
// be used to synchronize the update as long as the update is synchronized
// somehow. On Alpha a single load locked-store conditional does the job.
//
//--
LEAF_ENTRY(ExInterlockedIncrementLong)
ALTERNATE_ENTRY(ExIa64InterlockedIncrementLong)
fetchadd4.acq t1 = [a0], 1
mov v0 = 0 // assume result is zero
;;
cmp4.le pt7, p0 = 0, t1
cmp4.ge pt8, p0 = -2, t1
;;
.pred.rel "mutex",pt7,pt8
(pt8) mov v0 = 1 // negative result
(pt7) mov v0 = 2 // positive result
br.ret.sptk.clr brp // return
;;
LEAF_EXIT(ExInterlockedIncrementLong)
//++
//
// PLIST_ENTRY
// ExInterlockedInsertHeadList (
// IN PLIST_ENTRY ListHead,
// IN PLIST_ENTRY ListEntry,
// IN PKSPIN_LOCK Lock
// )
//
// Routine Description:
//
// This function inserts an entry at the head of a doubly linked list
// so that access to the list is synchronized in a multiprocessor system.
//
// Arguments:
//
// ListHead (a0) - Supplies a pointer to the head of the doubly linked
// list into which an entry is to be inserted.
//
// ListEntry (a1) - Supplies a pointer to the entry to be inserted at the
// head of the list.
//
// Lock (a2) - Supplies a pointer to a spin lock to be used to synchronize
// access to the list.
//
// Return Value:
//
// Pointer to entry that was at the head of the list or NULL if the list
// was empty.
//
//--
LEAF_ENTRY(ExInterlockedInsertHeadList)
//
// disable interrupt and then try to acquire the spinlock
//
add t3 = LsFlink, a0
add t5 = LsBlink, a1
add t4 = LsFlink, a1
rsm 1 << PSR_I // disable interrupt
#if !defined(NT_UP)
cmp.eq pt0, pt1 = zero, zero
cmp.eq pt2 = zero, zero
;;
Eiihl10:
.pred.rel "mutex",pt0,pt1
(pt0) xchg8 t0 = [a2], a2
(pt1) ld8.nt1 t0 = [a2]
;;
(pt0) cmp.ne pt2 = zero, t0
cmp.eq pt0, pt1 = zero, t0
;;
(pt1) ssm 1 << PSR_I // enable interrupt
(pt0) rsm 1 << PSR_I // disable interrupt
(pt2) br.dpnt Eiihl10
#endif // !defined(NT_UP)
;;
LDPTR(v0, t3) // get address of next entry
STPTR(t5, a0) // store previous link in next
STPTR(t3, a1) // store next link in head
;;
STPTR(t4, v0) // store next link in entry
add t6 = LsBlink, v0
;;
STPTR(t6, a1) // store previous link in next
#if !defined(NT_UP)
st8.rel.nta [a2] = zero // release the spinlock
#endif // !defined(NT_UP)
cmp.eq pt4, p0 = v0, a0 // if v0 == a0, list empty
;;
ssm 1 << PSR_I // enable interrupt
(pt4) mov v0 = zero
br.ret.sptk.clr brp // return
;;
LEAF_EXIT(ExInterlockedInsertHeadList)
//++
//
// PLIST_ENTRY
// ExInterlockedInsertTailList (
// IN PLIST_ENTRY ListHead,
// IN PLIST_ENTRY ListEntry,
// IN PKSPIN_LOCK Lock
// )
//
// Routine Description:
//
// This function inserts an entry at the tail of a doubly linked list
// so that access to the list is synchronized in a multiprocessor system.
//
// Arguments:
//
// ListHead (a0) - Supplies a pointer to the head of the doubly linked
// list into which an entry is to be inserted.
//
// ListEntry (a1) - Supplies a pointer to the entry to be inserted at the
// tail of the list.
//
// Lock (a2) - Supplies a pointer to a spin lock to be used to synchronize
// access to the list.
//
// Return Value:
//
// Pointer to entry that was at the tail of the list or NULL if the list
// was empty.
//
//--
LEAF_ENTRY(ExInterlockedInsertTailList)
//
// disable interrupt and then try to acquire the spinlock
//
add t3 = LsBlink, a0
add t4 = LsFlink, a1
add t5 = LsBlink, a1
rsm 1 << PSR_I // disable interrupt
#if !defined(NT_UP)
cmp.eq pt0, pt1 = zero, zero
cmp.eq pt2 = zero, zero
;;
Eiitl10:
.pred.rel "mutex",pt0,pt1
(pt0) xchg8 t0 = [a2], a2
(pt1) ld8.nt1 t0 = [a2]
;;
(pt0) cmp.ne pt2 = zero, t0
cmp.eq pt0, pt1 = zero, t0
;;
(pt1) ssm 1 << PSR_I // enable interrupt
(pt0) rsm 1 << PSR_I // disable interrupt
(pt2) br.dpnt Eiitl10
#endif // !defined(NT_UP)
;;
LDPTR(v0, t3) // get address of previous entry
STPTR(t4, a0) // store next link in entry
STPTR(t3, a1) // store previous link in head
;;
STPTR(t5, v0) // store previous link in entry
add t6 = LsFlink, v0
;;
STPTR(t6, a1) // store next in previous entry
#if !defined(NT_UP)
st8.rel.nta [a2] = zero // release the spinlock
#endif // !defined(NT_UP)
cmp.eq pt4, p0 = v0, a0 // if v0 == a0, list empty
;;
ssm 1 << PSR_I // enable interrupt
(pt4) mov v0 = zero
br.ret.sptk.clr brp // return
;;
LEAF_EXIT(ExInterlockedInsertTailList)
//++
//
// PLIST_ENTRY
// ExInterlockedRemoveHeadList (
// IN PLIST_ENTRY ListHead,
// IN PKSPIN_LOCK Lock
// )
//
// Routine Description:
//
// This function removes an entry from the head of a doubly linked list
// so that access to the list is synchronized in a multiprocessor system.
// If there are no entries in the list, then a value of NULL is returned.
// Otherwise, the address of the entry that is removed is returned as the
// function value.
//
// Arguments:
//
// ListHead (a0) - Supplies a pointer to the head of the doubly linked
// list from which an entry is to be removed.
//
// Lock (a1) - Supplies a pointer to a spin lock to be used to synchronize
// access to the list.
//
// Return Value:
//
// The address of the entry removed from the list, or NULL if the list is
// empty.
//
//--
LEAF_ENTRY(ExInterlockedRemoveHeadList)
//
// disable interrupt and then acquire the spinlock
//
rsm 1 << PSR_I // disable interrupt
add t3 = LsFlink, a0
#if !defined(NT_UP)
cmp.eq pt0, pt1 = zero, zero
cmp.eq pt2 = zero, zero
;;
Eirhl10:
.pred.rel "mutex",pt0,pt1
(pt0) xchg8 t0 = [a1], a1
(pt1) ld8.nt1 t0 = [a1]
;;
(pt0) cmp.ne pt2 = zero, t0
cmp.eq pt0, pt1 = zero, t0
;;
(pt1) ssm 1 << PSR_I // enable interrupt
(pt0) rsm 1 << PSR_I // disable interrupt
(pt2) br.dpnt Eirhl10
#endif // !defined(NT_UP)
;;
LDPTR(v0, t3) // get address of next entry
;;
cmp.eq pt4, pt3 = v0, a0 // if v0 == a0, list is empty
add t5 = LsFlink, v0
;;
PLDPTR(pt3, t6, t5) // get address of next in next
;;
PSTPTR(pt3, t3, t6) // store address of next in head
(pt3) add t7 = LsBlink, t6
;;
PSTPTR(pt3, t7, a0) // store addr of prev in next
#if !defined(NT_UP)
st8.rel.nta [a1] = zero // release the spinlock
#endif // !defined(NT_UP)
ssm 1 << PSR_I // enable interrupt
(pt4) mov v0 = zero
br.ret.sptk.clr brp // return
;;
LEAF_EXIT(ExInterlockedRemoveHeadList)
//++
//
// PSINGLE_LIST_ENTRY
// ExInterlockedPopEntryList (
// IN PSINGLE_LIST_ENTRY ListHead,
// IN PKSPIN_LOCK Lock
// )
//
// Routine Description:
//
// This function removes an entry from the head of a singly linked list
// so that access to the list is synchronized in a multiprocessor system.
// If there are no entries in the list, then a value of NULL is returned.
// Otherwise, the address of the entry that is removed is returned as the
// function value.
//
// Arguments:
//
// ListHead (a0) - Supplies a pointer to the head of the singly linked
// list from which an entry is to be removed.
//
// Lock (a1) - Supplies a pointer to a spin lock to be used to synchronize
// access to the list.
//
// Return Value:
//
// The address of the entry removed from the list, or NULL if the list is
// empty.
//
//--
LEAF_ENTRY(ExInterlockedPopEntryList)
//
// disable interrupt and then acquire the spinlock
//
rsm 1 << PSR_I // disable interrupt
#if !defined(NT_UP)
cmp.eq pt0, pt1 = zero, zero
cmp.eq pt2 = zero, zero
;;
Eipopel10:
.pred.rel "mutex",pt0,pt1
(pt0) xchg8 t0 = [a1], a1
(pt1) ld8.nt1 t0 = [a1]
;;
(pt0) cmp.ne pt2 = zero, t0
cmp.eq pt0, pt1 = zero, t0
;;
(pt1) ssm 1 << PSR_I // enable interrupt
(pt0) rsm 1 << PSR_I // disable interrupt
(pt2) br.dpnt Eipopel10
#endif // !defined(NT_UP)
;;
LDPTR(v0, a0) // get address of next entry
;;
cmp.ne pt4, p0 = zero, v0 // if v0 == NULL, list is empty
;;
PLDPTR(pt4, t6, v0) // get address of next entry
;;
PSTPTR(pt4, a0, t6) // store address of next in head
#if !defined(NT_UP)
st8.rel.nta [a1] = zero // release the spinlock
#endif // !defined(NT_UP)
ssm 1 << PSR_I // enable interrupt
br.ret.sptk.clr brp // return
;;
LEAF_EXIT(ExInterlockedPopEntryList)
//++
//
// PSINGLE_LIST_ENTRY
// ExInterlockedPushEntryList (
// IN PSINGLE_LIST_ENTRY ListHead,
// IN PSINGLE_LIST_ENTRY ListEntry,
// IN PKSPIN_LOCK Lock
// )
//
// Routine Description:
//
// This function inserts an entry at the head of a singly linked list
// so that access to the list is synchronized in a multiprocessor system.
//
// Arguments:
//
// ListHead (a0) - Supplies a pointer to the head of the singly linked
// list into which an entry is to be inserted.
//
// ListEntry (a1) - Supplies a pointer to the entry to be inserted at the
// head of the list.
//
// Lock (a2) - Supplies a pointer to a spin lock to be used to synchronize
// access to the list.
//
// Return Value:
//
// Previous contents of ListHead. NULL implies list went from empty
// to not empty.
//
//--
LEAF_ENTRY(ExInterlockedPushEntryList)
//
// disable interrupt and then acquire the spinlock
//
rsm 1 << PSR_I // disable interrupt
#if !defined(NT_UP)
cmp.eq pt0, pt1 = zero, zero
cmp.eq pt2 = zero, zero
;;
Eipushel10:
.pred.rel "mutex",pt0,pt1
(pt0) xchg8 t0 = [a2], a2
(pt1) ld8.nt1 t0 = [a2]
;;
(pt0) cmp.ne pt2 = zero, t0
cmp.eq pt0, pt1 = zero, t0
;;
(pt1) ssm 1 << PSR_I // enable interrupt
(pt0) rsm 1 << PSR_I // disable interrupt
(pt2) br.dpnt Eipushel10
#endif // !defined(NT_UP)
;;
LDPTR(v0, a0) // get address of next entry
STPTR(a0, a1) // set address of first entry
;;
STPTR(a1, v0) // set addr of next in new entry
#if !defined(NT_UP)
st8.rel.nta [a2] = zero // release the spinlock
#endif // !defined(NT_UP)
ssm 1 << PSR_I // enable interrupt
br.ret.sptk brp // return
;;
LEAF_EXIT(ExInterlockedPushEntryList)