diff options
Diffstat (limited to 'private/ntos/ex/i386/intrlfst.asm')
-rw-r--r-- | private/ntos/ex/i386/intrlfst.asm | 1531 |
1 files changed, 1531 insertions, 0 deletions
diff --git a/private/ntos/ex/i386/intrlfst.asm b/private/ntos/ex/i386/intrlfst.asm new file mode 100644 index 000000000..11d8ef8dd --- /dev/null +++ b/private/ntos/ex/i386/intrlfst.asm @@ -0,0 +1,1531 @@ + title "Interlocked Support" +;++ +; +; Copyright (c) 1989 Microsoft Corporation +; +; Module Name: +; +; intrlfst.asm +; +; Abstract: +; +; This module implements functions to support interlocked operations. +; Interlocked operations can only operate on nonpaged data. +; +; This module implements the fast call version of the interlocked +; fuctions. +; +; Author: +; +; Ken Reneris (kenr) 5-May-1994 +; +; Environment: +; +; Any mode. +; +; Revision History: +; +;-- +.386p + .xlist +include ks386.inc +include callconv.inc ; calling convention macros +include mac386.inc + .list + + +_TEXT$00 SEGMENT DWORD PUBLIC 'CODE' + ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING + +;++ +; +; General Notes on Interlocked Procedures: +; +; These procedures assume that neither their code, nor any of +; the data they touch, will cause a page fault. +; +; They use spinlocks to achieve MP atomicity, iff it's an MP machine. +; (The spinlock macros generate zilch if NT_UP = 1, and +; we if out some aux code here as well.) +; +; They turn off interrupts so that they can be used for synchronization +; between ISRs and driver code. Flags are preserved so they can +; be called in special code (Like IPC interrupt handlers) that +; may have interrupts off. +; +;-- + + +;; align 512 + + page ,132 + subttl "ExInterlockedAddLargeStatistic" +;++ +; +; VOID +; FASTCALL +; 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 unsigned large integer. +; +; Arguments: +; +; (ecx) Addend - Supplies a pointer to the variable whose value is +; adjusted by the increment value. +; +; (edx) Increment - Supplies the increment value that is added to the +; addend variable. +; +; Return Value: +; +; None. +; +;-- + +cPublicFastCall ExInterlockedAddLargeStatistic, 2 +cPublicFpo 0,0 + +ifdef NT_UP + + add dword ptr [ecx], edx ; add low part of large statistic + adc dword ptr [ecx+4], 0 ; add carry to high part + +else + + lock add dword ptr [ecx], edx ; add low part of large statistic + jc short Eils10 ; if c, add generated a carry + fstRET ExInterlockedAddLargeStatistic ; return + +Eils10: lock adc dword ptr [ecx+4], 0 ; add carry to high part + +endif + + fstRET ExInterlockedAddLargeStatistic ; return + +fstENDP ExInterlockedAddLargeStatistic + + page , 132 + subttl "Interlocked Add Unsigned Long" +;++ +; +; ULONG +; FASTCALL +; ExfInterlockedAddUlong ( +; 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 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: +; +; (ecx) Addend - Supplies a pointer to a variable whose value is to be +; adjusted by the increment value. +; +; (edx) Increment - Supplies the increment value to be added to the +; addend variable. +; +; (esp+4) Lock - 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. +; +;-- + +cPublicFastCall ExfInterlockedAddUlong, 3 +cPublicFpo 1, 1 + +ifdef NT_UP +; +; UP version of ExInterlockedAddUlong +; + + pushfd + cli ; disable interrupts + + mov eax, [ecx] ; (eax)= initial addend value + add [ecx], edx ; [ecx]=adjusted value + + popfd ; restore flags including ints + fstRET ExfInterlockedAddUlong + +else + +; +; MP version of ExInterlockedAddUlong +; + pushfd + mov eax, [esp+8] ; (eax) = SpinLock +Eial10: cli ; disable interrupts + ACQUIRE_SPINLOCK eax, <short Eial20> + + mov eax, [ecx] ; (eax)=initial addend value + add [ecx], edx ; [ecx]=adjusted value + + mov edx, [esp+8] ; (edx) = SpinLock + RELEASE_SPINLOCK edx + popfd + fstRET ExfInterlockedAddUlong + +Eial20: popfd + pushfd + SPIN_ON_SPINLOCK eax, <short Eial10> +endif + +fstENDP ExfInterlockedAddUlong + + page , 132 + subttl "Interlocked Insert Head List" +;++ +; +; PLIST_ENTRY +; ExfInterlockedInsertHeadList ( +; 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. +; +; N.B. The pages of data which this routine operates on MUST be +; present. No page fault is allowed in this routine. +; +; Arguments: +; +; (ecx) = ListHead - Supplies a pointer to the head of the doubly linked +; list into which an entry is to be inserted. +; +; (edx) = ListEntry - Supplies a pointer to the entry to be inserted at the +; head of the list. +; +; (esp+4) Lock - 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. +; +;-- + +cPublicFastCall ExfInterlockedInsertHeadList , 3 +cPublicFpo 1, 1 + +ifndef NT_UP +cPublicFpo 1, 2 + push esi + mov esi, [esp+8] ; Address of spinlock +endif + pushfd + +Eiih10: cli + ACQUIRE_SPINLOCK esi,<short Eiih20> + + mov eax, LsFlink[ecx] ; (eax)->next entry in the list + mov [edx]+LsFlink, eax ; store next link in entry + mov [edx]+LsBlink, ecx ; store previous link in entry + mov [ecx]+LsFlink, edx ; store next link in head + mov [eax]+LsBlink, edx ; store previous link in next + + RELEASE_SPINLOCK esi + popfd +ifndef NT_UP + pop esi +endif + xor eax, ecx ; return null if list was empty + jz short Eiih15 + xor eax, ecx +Eiih15: fstRET ExfInterlockedInsertHeadList + +ifndef NT_UP +Eiih20: popfd + pushfd + SPIN_ON_SPINLOCK esi, <short Eiih10> +endif + +fstENDP ExfInterlockedInsertHeadList + + page , 132 + subttl "Interlocked Insert Tail List" +;++ +; +; PLIST_ENTRY +; FASTCALL +; ExfInterlockedInsertTailList ( +; 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. +; +; N.B. The pages of data which this routine operates on MUST be +; present. No page fault is allowed in this routine. +; +; Arguments: +; +; (ecx) = ListHead - Supplies a pointer to the head of the doubly linked +; list into which an entry is to be inserted. +; +; (edx) = ListEntry - Supplies a pointer to the entry to be inserted at the +; tail of the list. +; +; (esp+4) Lock - 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. +; +;-- + +cPublicFastCall ExfInterlockedInsertTailList, 3 +cPublicFpo 1, 1 + +ifndef NT_UP +cPublicFpo 1, 2 + push esi + mov esi, [esp+8] ; Address of spinlock +endif + pushfd + +Eiit10: cli + ACQUIRE_SPINLOCK esi,<short Eiit20> + + mov eax, LsBlink[ecx] ; (eax)->prev entry in the list + mov [edx]+LsFlink, ecx ; store next link in entry + mov [edx]+LsBlink, eax ; store previous link in entry + mov [ecx]+LsBlink, edx ; store next link in head + mov [eax]+LsFlink, edx ; store previous link in next + + RELEASE_SPINLOCK esi + popfd + +ifndef NT_UP + pop esi +endif + xor eax, ecx ; return null if list was empty + jz short Eiit15 + xor eax, ecx +Eiit15: fstRET ExfInterlockedInsertTailList + +ifndef NT_UP +Eiit20: popfd + pushfd + SPIN_ON_SPINLOCK esi, <short Eiit10> +endif + +fstENDP ExfInterlockedInsertTailList + + + page , 132 + subttl "Interlocked Remove Head List" +;++ +; +; PLIST_ENTRY +; FASTCALL +; ExfInterlockedRemoveHeadList ( +; 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. +; +; N.B. The pages of data which this routine operates on MUST be +; present. No page fault is allowed in this routine. +; +; Arguments: +; +; (ecx) ListHead - Supplies a pointer to the head of the doubly linked +; list from which an entry is to be removed. +; +; (edx) Lock - 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. +; +;-- + +cPublicFastCall ExfInterlockedRemoveHeadList , 2 +cPublicFpo 0, 1 +ifdef NT_UP +; +; UP version +; + pushfd + cli + + mov eax, [ecx]+LsFlink ; (eax)-> next entry + cmp eax, ecx ; Is list empty? + je short Eirh20 ; if e, list is empty, go Eirh20 + + mov edx, [eax]+LsFlink ; (ecx)-> next entry(after deletion) + mov [ecx]+LsFlink, edx ; store address of next in head + mov [edx]+LsBlink, ecx ; store address of previous in next +if DBG + mov [eax]+LsFlink, 0baddd0ffh + mov [eax]+LsBlink, 0baddd0ffh +endif + popfd ; restore flags including interrupts + fstRET ExfInterlockedRemoveHeadList + +Eirh20: popfd + xor eax,eax ; (eax) = null for empty list + fstRET ExfInterlockedRemoveHeadList + +else +; +; MP version +; + +Eirh40: pushfd + cli + ACQUIRE_SPINLOCK edx, <short Eirh60> + + mov eax, [ecx]+LsFlink ; (eax)-> next entry + cmp eax, ecx ; Is list empty? + je short Eirh50 ; if e, list is empty, go Eirh50 + +cPublicFpo 0,2 + push esi + mov esi, edx + + mov edx, [eax]+LsFlink ; (ecx)-> next entry(after deletion) + mov [ecx]+LsFlink, edx ; store address of next in head + mov [edx]+LsBlink, ecx ; store address of previous in next +if DBG + mov [eax]+LsFlink, 0baddd0ffh + mov [eax]+LsBlink, 0baddd0ffh +endif + RELEASE_SPINLOCK esi + +cPublicFpo 0, 0 + pop esi + popfd ; restore flags including interrupts + fstRET ExfInterlockedRemoveHeadList + +Eirh50: RELEASE_SPINLOCK edx + popfd + xor eax,eax ; (eax) = null for empty list + fstRET ExfInterlockedRemoveHeadList + +cPublicFpo 0, 0 +Eirh60: popfd + SPIN_ON_SPINLOCK edx, <Eirh40> + fstRET ExfInterlockedRemoveHeadList + +endif ; nt_up + +fstENDP ExfInterlockedRemoveHeadList + + page , 132 + subttl "Interlocked Pop Entry List" +;++ +; +; PSINGLE_LIST_ENTRY +; FASTCALL +; ExfInterlockedPopEntryList ( +; IN PSINGLE_LIST_ENTRY ListHead, +; IN PKSPIN_LOCK Lock +; ) +; +; Routine Description: +; +; This function removes an entry from the front 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: +; +; (ecx) = ListHead - Supplies a pointer to the head of the singly linked +; list from which an entry is to be removed. +; +; (edx) = Lock - 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. +; +;-- + +cPublicFastCall ExfInterlockedPopEntryList , 2 + +ifdef NT_UP +; +; UP version +; +cPublicFpo 0,1 + pushfd + cli ; disable interrupts + + mov eax, [ecx] ; (eax)-> next entry + or eax, eax ; Is it empty? + je short Eipe05 ; if e, empty list, go Eipe05 + mov edx, [eax] ; (edx)->next entry (after deletion) + mov [ecx], edx ; store address of next in head +if DBG + mov [eax], 0baddd0ffh +endif +cPublicFpo 0,0 + popfd ; restore flags including interrupts + fstRET ExfInterlockedPopEntryList ; cReturn (eax)->removed entry + +Eipe05: popfd + xor eax,eax + fstRET ExfInterlockedPopEntryList ; cReturn (eax)=NULL + +else ; nt_up + +; +; MP Version +; + +cPublicFpo 0,1 + +Eipe10: pushfd + cli ; disable interrupts + + ACQUIRE_SPINLOCK edx, <short Eipe30> + + mov eax, [ecx] ; (eax)-> next entry + or eax, eax ; Is it empty? + je short Eipe20 ; if e, empty list, go Eipe20 +cPublicFpo 0,2 + push edx ; Save SpinLock address + mov edx, [eax] ; (edx)->next entry (after deletion) + mov [ecx], edx ; store address of next in head + pop edx ; Restore SpinLock address +if DBG + mov [eax], 0baddd0ffh +endif + RELEASE_SPINLOCK edx + +cPublicFpo 0,0 + popfd ; restore flags including interrupts + fstRET ExfInterlockedPopEntryList + +Eipe20: RELEASE_SPINLOCK edx + popfd + xor eax,eax + fstRET ExfInterlockedPopEntryList + +Eipe30: popfd + SPIN_ON_SPINLOCK edx, Eipe10 + +endif ; nt_up + +fstENDP ExfInterlockedPopEntryList + + page , 132 + subttl "Interlocked Push Entry List" +;++ +; +; PSINGLE_LIST_ENTRY +; FASTCALL +; 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: +; +; (ecx) ListHead - Supplies a pointer to the head of the singly linked +; list into which an entry is to be inserted. +; +; (edx) ListEntry - Supplies a pointer to the entry to be inserted at the +; head of the list. +; +; (esp+4) Lock - 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. +; +;-- + +cPublicFastCall ExfInterlockedPushEntryList , 3 +ifdef NT_UP +; +; UP Version +; +cPublicFpo 0,1 + pushfd + cli + + mov eax, [ecx] ; (eax)-> next entry (return value also) + mov [edx], eax ; store address of next in new entry + mov [ecx], edx ; set address of next in head + +cPublicFpo 0,0 + popfd ; restore flags including interrupts + fstRET ExfInterlockedPushEntryList + +else +; +; MP Version +; + +cPublicFpo 1,1 + pushfd + push edx + mov edx, [esp+12] ; (edx) = SpinLock + +Eipl10: cli + ACQUIRE_SPINLOCK edx, <short Eipl20> + + pop edx ; (edx)-> Entry to be pushed + mov eax, [ecx] ; (eax)-> next entry (return value also) + mov [edx], eax ; store address of next in new entry + mov [ecx], edx ; set address of next in head + + mov edx, [esp+8] ; (edx) = SpinLock + RELEASE_SPINLOCK edx + +cPublicFpo 0,0 + popfd ; restore flags including interrupts + fstRET ExfInterlockedPushEntryList + +cPublicFpo 1,2 +Eipl20: pop edx + popfd ; Restore interrupt state + + pushfd + push edx + mov edx, [esp+12] + SPIN_ON_SPINLOCK edx, <short Eipl10> +endif + +fstENDP ExfInterlockedPushEntryList + + page , 132 + subttl "Interlocked Pop Entry Sequenced List" +;++ +; +; PSINGLE_LIST_ENTRY +; FASTCALL +; ExInterlockedPopEntrySList ( +; IN PSINGLE_LIST_ENTRY ListHead, +; IN PKSPIN_LOCK Lock +; ) +; +; Routine Description: +; +; This function removes an entry from the front of a sequenced singly +; linked list so that access to the list is synchronized in an MP 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. +; +; N.B. The cmpxchg8b instruction is only supported on some processors. +; If the host processor does not support this instruction, then +; then following code is patched to contain a jump to the normal +; pop entry code which has a compatible calling sequence and data +; structure. +; +; Arguments: +; +; (ecx) = ListHead - Supplies a pointer to the sequenced listhead from +; which an entry is to be removed. +; +; (edx) = Lock - 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. +; +;-- + +cPublicFastCall ExInterlockedPopEntrySList, 2 + +cPublicFpo 0,2 + +; +; Save nonvolatile registers and read the listhead sequence number followed +; by the listhead next link. +; +; N.B. These two dwords MUST be read exactly in this order. +; + + push ebx ; save nonvolatile registers + push ebp ; + mov ebp, ecx ; save listhead address + mov edx,[ebp] + 4 ; get current sequence number + mov eax,[ebp] + 0 ; get current next link + +; +; If the list is empty, then there is nothing that can be removed. +; + +Epop10: or eax, eax ; check if list is empty + jz short Epop20 ; if z set, list is empty + mov ecx, edx ; copy sequence number and depth + add ecx, 0FFFFH ; adjust sequence number and depth + +; +; N.B. It is possible for the following instruction to fault in the rare +; case where the first entry in the list is allocated on another +; processor and free between the time the free pointer is read above +; and the following instruction. When this happens, the access fault +; code continues execution by skipping the following instruction. +; This results in the compare failing and the entire operation is +; retried. +; + + mov ebx, [eax] ; get address of successor entry + +.586 +ifndef NT_UP + + lock cmpxchg8b qword ptr [ebp] ; compare and exchange + +else + + cmpxchg8b qword ptr [ebp] ; compare and exchange + +endif +.386 + + jnz short Epop10 ; if z clear, exchange failed + +if DBG + + or ebx, ebx ; check if list is empty + jz short Epop20 ; if z set, list is empty + mov ecx, [ebx] ; check if next address is valid + +endif + +; +; Restore nonvolatile registers and return result. +; + +cPublicFpo 0,0 + +Epop20: pop ebp ; restore nonvolatile registers + pop ebx ; + + fstRET ExInterlockedPopEntrySList + +fstENDP ExInterlockedPopEntrySList + + page , 132 + subttl "Interlocked Push Entry Sequenced List" +;++ +; +; PSINGLE_LIST_ENTRY +; FASTCALL +; ExInterlockedPushEntrySList ( +; 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 sequenced singly linked +; list so that access to the list is synchronized in an MP system. +; +; N.B. The cmpxchg8b instruction is only supported on some processors. +; If the host processor does not support this instruction, then +; then following code is patched to contain a jump to the normal +; push entry code which has a compatible calling sequence and data +; structure. +; +; Arguments: +; +; (ecx) ListHead - Supplies a pointer to the sequenced listhead into which +; an entry is to be inserted. +; +; (edx) ListEntry - Supplies a pointer to the entry to be inserted at the +; head of the list. +; +; (esp+4) Lock - 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. +; +;-- + +cPublicFastCall ExInterlockedPushEntrySList, 3 + +cPublicFpo 0,2 + +; +; Save nonvolatile registers and read the listhead sequence number followed +; by the listhead next link. +; +; N.B. These two dwords MUST be read exactly in this order. +; + + push ebx ; save nonvolatile registers + push ebp ; + mov ebp, ecx ; save listhead address + mov ebx, edx ; save list entry address + mov edx,[ebp] + 4 ; get current sequence number + mov eax,[ebp] + 0 ; get current next link +Epsh10: mov [ebx], eax ; set next link in new first entry + mov ecx, edx ; copy sequence number + add ecx, 010001H ; increment sequence number and depth + +.586 +ifndef NT_UP + + lock cmpxchg8b qword ptr [ebp] ; compare and exchange + +else + + cmpxchg8b qword ptr[ebp] ; compare and exchange + +endif +.386 + + jnz short Epsh10 ; if z clear, exchange failed + +; +; Restore nonvolatile registers and return result. +; + +cPublicFpo 0,0 + + pop ebp ; restore nonvolatile registers + pop ebx ; + + fstRET ExInterlockedPushEntrySList + +fstENDP ExInterlockedPushEntrySList + + page , 132 + subttl "Interlocked Pop Entry SList - Alternate" +;++ +; +; PSINGLE_LIST_ENTRY +; FASTCALL +; ExfInterlockedPopEntrySList ( +; IN PSINGLE_LIST_ENTRY ListHead, +; IN PKSPIN_LOCK Lock +; ) +; +; Routine Description: +; +; This function removes an entry from the front of a sequenced singly +; linked list so that access to the list is synchronized in an MP 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. +; +; N.B. The cmpxchg8b instruction is only supported on some processors. +; If the host processor does not support this instruction, then +; this function is used inplace of ExInterlockedPopEntrySList. +; +; Arguments: +; +; (ecx) = ListHead - Supplies a pointer to the sequenced listhead from +; which an entry is to be removed. +; +; (edx) = Lock - 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. +; +; +;-- + +cPublicFastCall ExfInterlockedPopEntrySList, 2 + +cPublicFpo 0,1 +Efpo10: pushfd ; save flags + cli ; disable interrupts + +ifndef NT_UP + + ACQUIRE_SPINLOCK edx, <short Efpo30> ; acquire spinlock + +endif + + mov eax, [ecx] ; get current next link + or eax, eax ; check if list is empty + jz short Efpo20 ; if z set, list is empty + push [eax] ; get address of successor list + pop [ecx] ; store address of next in head + dec dword ptr [ecx] + 4 ; decrement list depth + +Efpo20: ; + +ifndef NT_UP + + RELEASE_SPINLOCK edx ; release spinlock + +endif + +cPublicFpo 0,0 + popfd ; restore flags + + fstRET ExfInterlockedPopEntrySList + +ifndef NT_UP + +cPublicFpo 0,0 +Efpo30: popfd ; restore flags + + SPIN_ON_SPINLOCK edx, Efpo10 ; spin until lock is free + +endif + +fstENDP ExfInterlockedPopEntrySList + + page , 132 + subttl "Interlocked Push Entry SList - Alternate" +;++ +; +; PSINGLE_LIST_ENTRY +; FASTCALL +; 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 sequenced singly linked +; list so that access to the list is synchronized in an MP system. +; +; N.B. The cmpxchg8b instruction is only supported on some processors. +; If the host processor does not support this instruction, then +; this function is used inplace of ExInterlockedPushEntrySList. +; +; Arguments: +; +; (ecx) ListHead - Supplies a pointer to the sequenced listhead into which +; an entry is to be inserted. +; +; (edx) ListEntry - Supplies a pointer to the entry to be inserted at the +; head of the list. +; +; (esp+4) Lock - 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. +;-- + +cPublicFastCall ExfInterlockedPushEntrySList, 3 + +cPublicFpo 0,1 +Efph10: pushfd ; save flags + cli ; disable interrupts + +ifndef NT_UP + + mov eax, [esp] + 8 ; get spinlock address + + ACQUIRE_SPINLOCK eax, <short Efph20> ; acquire spinlock + +endif + + push [ecx] ; get current next link + pop [edx] ; store address of next in new entry + mov [ecx], edx ; set address of next in head + inc dword ptr [ecx] + 4 ; increment list depth + +ifndef NT_UP + + RELEASE_SPINLOCK eax ; release spinlock +endif + +cPublicFpo 0,0 + popfd ; restore flags + + fstRET ExfInterlockedPushEntrySList + +ifndef NT_UP + +cPublicFpo 0,0 +Efph20: popfd ; restore flags + + SPIN_ON_SPINLOCK eax, <short Efph10> ; spin until lock is free + +endif + +fstENDP ExfInterlockedPushEntrySList + + page , 132 + subttl "Interlocked i386 Increment Long" +;++ +; +; INTERLOCKED_RESULT +; FASTCALL +; Exfi386InterlockedIncrementLong ( +; IN PLONG Addend +; ) +; +; Routine Description: +; +; This function atomically increments Addend, returning an ennumerated +; type which indicates what interesting transitions in the value of +; Addend occurred due the operation. +; +; See ExInterlockedIncrementLong. This function is the i386 +; architectural specific version of ExInterlockedIncrementLong. +; No source directly calls this function, instead +; ExInterlockedIncrementLong is called and when built on x86 these +; calls are macroed to the i386 optimized version. +; +; Arguments: +; +; (ecx) Addend - Pointer to variable to increment. +; +; Return Value: +; +; An ennumerated type: +; +; ResultNegative if Addend is < 0 after increment. +; ResultZero if Addend is = 0 after increment. +; ResultPositive if Addend is > 0 after increment. +; +;-- + +cPublicFastCall Exfi386InterlockedIncrementLong, 1 +cPublicFpo 0, 0 + +ifdef NT_UP + add dword ptr [ecx],1 +else + lock add dword ptr [ecx],1 +endif + lahf ; (ah) = flags + and eax,EFLAG_SELECT ; clear all but sign and zero flags + fstRET Exfi386InterlockedIncrementLong + +fstENDP Exfi386InterlockedIncrementLong + + + page , 132 + subttl "Interlocked i386 Decrement Long" +;++ +; +; INTERLOCKED_RESULT +; FASTCALL +; Exfi386InterlockedDecrementLong ( +; IN PLONG Addend, +; IN PKSPIN_LOCK Lock +; ) +; +; Routine Description: +; +; This function atomically decrements Addend, returning an ennumerated +; type which indicates what interesting transitions in the value of +; Addend occurred due the operation. +; +; See Exi386InterlockedDecrementLong. This function is the i386 +; architectural specific version of ExInterlockedDecrementLong. +; No source directly calls this function, instead +; ExInterlockedDecrementLong is called and when built on x86 these +; calls are macroed to the i386 optimized version. +; +; Arguments: +; +; Addend (esp+4) - Pointer to variable to decrement. +; +; Lock (esp+8) - Spinlock used to implement atomicity. +; (not actually used on x86) +; +; Return Value: +; +; An ennumerated type: +; +; ResultNegative if Addend is < 0 after decrement. +; ResultZero if Addend is = 0 after decrement. +; ResultPositive if Addend is > 0 after decrement. +; +;-- + +cPublicFastCall Exfi386InterlockedDecrementLong , 1 +cPublicFpo 0, 0 + +ifdef NT_UP + sub dword ptr [ecx], 1 +else + lock sub dword ptr [ecx], 1 +endif + lahf ; (ah) = flags + and eax, EFLAG_SELECT ; clear all but sign and zero flags + fstRET Exfi386InterlockedDecrementLong + +fstENDP Exfi386InterlockedDecrementLong + + page , 132 + subttl "Interlocked i386 Exchange Ulong" +;++ +; +; ULONG +; FASTCALL +; Exfi386InterlockedExchangeUlong ( +; IN PULONG Target, +; IN ULONG Value +; ) +; +; Routine Description: +; +; This function atomically exchanges the Target and Value, returning +; the prior contents of Target +; +; See Exi386InterlockedExchangeUlong. This function is the i386 +; architectural specific version of ExInterlockedDecrementLong. +; No source directly calls this function, instead +; ExInterlockedDecrementLong is called and when built on x86 these +; calls are macroed to the i386 optimized version. +; +; Arguments: +; +; (ecx) = Source - Address of ULONG to exchange +; (edx) = Value - New value of ULONG +; +; Return Value: +; +; The prior value of Source +;-- + +cPublicFastCall Exfi386InterlockedExchangeUlong, 2 +cPublicFpo 0,0 +cPublicFastCall InterlockedExchange, 2 + +.486 +ifndef NT_UP + xchg [ecx], edx ; make the exchange + mov eax, edx +else + mov eax, [ecx] ; get comperand value +Ixchg: cmpxchg [ecx], edx ; compare and swap + jnz Ixchg ; if nz, exchange failed +endif +.386 + + fstRET Exfi386InterlockedExchangeUlong +fstENDP InterlockedExchange +fstENDP Exfi386InterlockedExchangeUlong + +;++ +; +; LONG +; InterlockedIncrement( +; IN PLONG Addend +; ) +; +; Routine Description: +; +; This function performs an interlocked add of one to the addend variable. +; +; No checking is done for overflow. +; +; Arguments: +; +; Addend (ecx) - Supplies a pointer to a variable whose value is to be +; incremented by one. +; +; Return Value: +; +; (eax) - The incremented value. +; +;-- + +cPublicFastCall InterlockedIncrement,1 +cPublicFpo 0,0 + + mov eax, 1 ; set increment value + +.486 +ifndef NT_UP + lock xadd [ecx], eax ; interlocked increment +else + xadd [ecx], eax ; interlocked increment +endif +.386p + inc eax ; adjust return value + + fstRET InterlockedIncrement + +fstENDP InterlockedIncrement + + page , 132 + subttl "InterlockedDecrment" +;++ +; +; LONG +; InterlockedDecrement( +; IN PLONG Addend +; ) +; +; Routine Description: +; +; This function performs an interlocked add of -1 to the addend variable. +; +; No checking is done for overflow +; +; Arguments: +; +; Addend (ecx) - Supplies a pointer to a variable whose value is to be +; decremented by one. +; +; Return Value: +; +; (eax) - The decremented value. +; +;-- + +cPublicFastCall InterlockedDecrement,1 +cPublicFpo 0,0 + + mov eax, -1 ; set decrment value + +.486 +ifndef NT_UP + lock xadd [ecx], eax ; interlocked decrement +else + xadd [ecx], eax ; interlocked decrement +endif +.386 + + dec eax ; adjust return value + + fstRET InterlockedDecrement + +fstENDP InterlockedDecrement + + page , 132 + subttl "Interlocked Compare Exchange" +;++ +; +; PVOID +; FASTCALL +; 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: +; +; (ecx) Destination - Supplies a pointer to destination value. +; +; (edx) Exchange - Supplies the exchange value. +; +; [esp + 4] Comperand - Supplies the comperand value. +; +; Return Value: +; +; The initial destination value is returned as the function value. +; +;-- + +cPublicFastCall InterlockedCompareExchange, 3 +cPublicFpo 0,0 + + mov eax, [esp + 4] ; set comperand value +.486 +ifndef NT_UP + lock cmpxchg [ecx], edx ; compare and exchange +else + cmpxchg [ecx], edx ; compare and exchange +endif +.386 + + fstRET InterlockedCompareExchange + +fstENDP InterlockedCompareExchange + + page , 132 + subttl "Interlocked Compare Exchange 64-bits" +;++ +; +; ULONGLONG +; FASTCALL +; ExInterlockedCompareExchange64 ( +; IN PULONGLONG Destination, +; IN PULONGLONG Exchange, +; IN PULONGLONG Comperand, +; IN PKSPIN_LOCK Lock +; ) +; +; Routine Description: +; +; This function performs a compare and exchange of 64-bits. +; +; N.B. The cmpxchg8b instruction is only supported on some processors. +; If the host processor does not support this instruction, then +; then following code is patched to contain a jump to the normal +; compare exchange 64-bit code which has a compatible calling +; sequence and data structure. +; +; Arguments: +; +; (ecx) Destination - Supplies a pointer to the destination variable. +; +; (edx) Exchange - Supplies a pointer to the exchange value. +; +; (esp+4) Comperand - Supplies a pointer to the comperand value. +; +; (esp+4) Lock - Supplies a pointer to a spin lock to use if the cmpxchg8b +; instruction is not available on the host system. +; +; Return Value: +; +; The current destination value is returned as the function value. +; +;-- + +cPublicFastCall ExInterlockedCompareExchange64, 4 + +cPublicFpo 0,2 + +; +; Save nonvolatile registers and read the exchange and comperand values. +; + + push ebx ; save nonvolatile registers + push ebp ; + mov ebp, ecx ; set destination address + mov ebx, [edx] ; get exchange value + mov ecx, [edx] + 4 ; + mov edx, [esp] + 12 ; get comperand address + mov eax, [edx] ; get comperand value + mov edx, [edx] + 4 ; + +.586 +ifndef NT_UP + + lock cmpxchg8b qword ptr [ebp] ; compare and exchange + +else + + cmpxchg8b qword ptr[ebp] ; compare and exchange + +endif +.386 + +; +; Restore nonvolatile registers and return result in edx:eax. +; + +cPublicFpo 0,0 + + pop ebp ; restore nonvolatile registers + pop ebx ; + + fstRET ExInterlockedCompareExchange64 + +fstENDP ExInterlockedCompareExchange64 + +; +; The following version of the compare exchange 64-bits function is used +; when the host processor does not support the cmpxchg8 instruction. +; + +cPublicFastCall ExpInterlockedCompareExchange64, 4 + +cPublicFpo 0,2 + +; +; Save nonvolatile registers and read the exchange and comperand values. +; + + push ebx ; save nonvolatile registers + push ebp ; + mov ebp, ecx ; set destination address + mov ebx, [edx] ; get exchange value + mov ecx, [edx] + 4 ; + mov edx, [esp] + 12 ; get comperand address + mov eax, [edx] ; get comperand value + mov edx, [edx] + 4 ; + +ifndef NT_UP + +cPublicFpo 0,4 + + push esi ; save register + pushfd ; save flags + mov esi, [esp] + 24 ; get address of lock +Eicx10: cli ; disable interrupts + + ACQUIRE_SPINLOCK esi, <short Eicx40> ; acquire spinlock + +else + +cPublicFpo 0,3 + + pushfd ; save flags + cli ; disable interrupts + +endif + + cmp eax, [ebp] ; compare current with comperand + jne short Eicx30 ; if ne, low part mismatch + cmp edx, [ebp] + 4 ; compare current with comperand + jne short Eicx30 ; if ne, high part mismatch + mov [ebp], ebx ; store exchange value + mov [ebp] + 4, ecx ; + +; +; Restore nonvolatile registers and return result in edx:eax. +; + +cPublicFpo 0,0 + +ifndef NT_UP + +Eicx20: RELEASE_SPINLOCK esi ; release spin lock + + popfd ; restore flags + pop esi ; restore register + +else + +Eicx20: popfd ; restore flags + +endif + + pop ebp ; restore nonvolatile registers + pop ebx ; + + fstRET ExpInterlockedCompareExchange64 + +; +; The current and comperand values mismatch. Return the current destination +; value. +; + +Eicx30: mov eax, [ebp] ; get current destination value + mov edx, [ebp] + 4 ; + jmp short Eicx20 ; + +; +; The spinlock is currently owned. +; + +ifndef NT_UP + +Eicx40: popfd ; restore flags + pushfd ; save flags + + SPIN_ON_SPINLOCK esi, <short Eicx10> ; spin until lock free + +endif + +fstENDP ExpInterlockedCompareExchange64 + + page , 132 + subttl "Interlocked Exchange Add" +;++ +; +; LONG +; FASTCALL +; 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: +; +; (ecx) Addend - Supplies a pointer to a variable whose value is to be +; adjusted by the increment value. +; +; (edx) Increment - Supplies the increment value to be added to the +; addend variable. +; +; Return Value: +; +; The initial value of the addend variable. +; +;-- + +cPublicFastCall InterlockedExchangeAdd, 2 +cPublicFpo 0,0 + +.486 +ifndef NT_UP + lock xadd [ecx], edx ; exchange add +else + xadd [ecx], edx ; exchange add +endif +.386 + + mov eax, edx ; set initial value + + fstRET InterlockedExchangeAdd + +fstENDP InterlockedExchangeAdd + +_TEXT$00 ends + end |