diff options
Diffstat (limited to 'private/ntos/ex/i386')
-rw-r--r-- | private/ntos/ex/i386/evpair.asm | 152 | ||||
-rw-r--r-- | private/ntos/ex/i386/fmutex.asm | 186 | ||||
-rw-r--r-- | private/ntos/ex/i386/intrlfst.asm | 1531 | ||||
-rw-r--r-- | private/ntos/ex/i386/intrlock.asm | 1054 | ||||
-rw-r--r-- | private/ntos/ex/i386/probe.c | 120 | ||||
-rw-r--r-- | private/ntos/ex/i386/raisests.asm | 316 | ||||
-rw-r--r-- | private/ntos/ex/i386/resoura.asm | 110 | ||||
-rw-r--r-- | private/ntos/ex/i386/sources | 8 | ||||
-rw-r--r-- | private/ntos/ex/i386/splocks.asm | 208 |
9 files changed, 3685 insertions, 0 deletions
diff --git a/private/ntos/ex/i386/evpair.asm b/private/ntos/ex/i386/evpair.asm new file mode 100644 index 000000000..e06ab6f87 --- /dev/null +++ b/private/ntos/ex/i386/evpair.asm @@ -0,0 +1,152 @@ + title "Event Pair Support" +;++ +; +; Copyright (c) 1989 Microsoft Corporation +; +; Module Name: +; +; evpair.asm +; +; Abstract: +; +; +; This module contains the implementation for the fast event pair +; system services that are used for client/server synchronization. +; sethiwaitlo, setlowaithi. +; +; +; Author: +; +; Mark Lucovsky (markl) 03-Feb-1992 +; +; Environment: +; +; Kernel mode. +; +; Revision History: +; +; +;-- +.386p +; .xlist +include ks386.inc +include callconv.inc ; calling convention macros +; .list + +EXTRNP _KiSetServerWaitClientEvent,3 +extrn _KeTickCount:DWORD +extrn _ExpTickCountMultiplier:DWORD + +_TEXT SEGMENT DWORD PUBLIC 'CODE' + ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING + + page ,132 + subttl "NtSetLowWaitHighThread" + +;++ +; Routine Description: +; +; This function uses the prereferenced client/server event pair pointer +; and sets the low event of the event pair and waits on the high event +; of the event pair object. +; +; N.B. This service assumes that it has been called from user mode. +; +; Arguments: +; +; None. +; +; Return Value: +; +; TBS +; +;-- + +cPublicProc _NtSetLowWaitHighThread, 0 +cPublicFpo 0, 0 + + mov eax,fs:PcPrcbData+PbCurrentThread + mov eax,dword ptr [eax+EtEventPair] + or eax,eax + jz $BAIL + mov ecx,eax ; compute address of events + add eax,EpEventLow ; server event + add ecx,EpEventHigh ; client event + stdCall _KiSetServerWaitClientEvent, <eax, ecx, 1> + xor eax,eax + stdRET _NtSetLowWaitHighThread +$BAIL: + mov eax,STATUS_NO_EVENT_PAIR + stdRET _NtSetLowWaitHighThread +stdENDP _NtSetLowWaitHighThread + + page ,132 + subttl "NtSetHighWaitLowThread" + +;++ +; Routine Description: +; +; This function uses the prereferenced client/server event pair pointer +; and sets the low event of the event pair and waits on the high event +; of the event pair object. +; +; N.B. This service assumes that it has been called from user mode. +; +; Arguments: +; +; None. +; +; Return Value: +; +; TBS +; +;-- +;PUBLIC _NtSetHighWaitLowThread, 0 +cPublicProc _NtSetHighWaitLowThread, 0 +cPublicFpo 0, 0 + + mov eax,fs:PcPrcbData+PbCurrentThread + mov eax,dword ptr [eax+EtEventPair] + or eax,eax + jz $BAIL1 + mov ecx,eax ; compute address of events + add eax,EpEventHigh ; server event + add ecx,EpEventLow ; client event + stdCall _KiSetServerWaitClientEvent, <eax, ecx, 1> + xor eax,eax + stdRET _NtSetHighWaitLowThread +$BAIL1: + mov eax,STATUS_NO_EVENT_PAIR + stdRET _NtSetHighWaitLowThread +stdENDP _NtSetHighWaitLowThread + +;++ +; +; Routine Description: +; +; This function returns number of milliseconds since the system +; booted. This function is designed to support the Win32 GetTicKCount +; API. +; +; Arguments: +; +; NONE +; +; Return Value: +; +; Returns the number of milliseconds that have transpired since boot +; +;-- + +cPublicProc _NtGetTickCount, 0 +cPublicFpo 0, 0 + + mov eax,dword ptr [_KeTickCount] + mul dword ptr [_ExpTickCountMultiplier] + shrd eax,edx,24 ; compute resultant tick count + + stdRET _NtGetTickCount +stdENDP _NtGetTickCount + +_TEXT ends + end diff --git a/private/ntos/ex/i386/fmutex.asm b/private/ntos/ex/i386/fmutex.asm new file mode 100644 index 000000000..6f419d35a --- /dev/null +++ b/private/ntos/ex/i386/fmutex.asm @@ -0,0 +1,186 @@ + TITLE "Fast Mutex Support" +;++ +; +; Copyright (c) 1994 Microsoft Corporation +; +; Module Name: +; +; spinlock.asm +; +; Abstract: +; +; This module implements teh code necessary to acquire and release fast +; mutexs without raising or lowering IRQL. +; +; Author: +; +; David N. Cutler (davec) 26-May-1994 +; +; Environment: +; +; Kernel mode only. +; +; Revision History: +; +;-- + +.386p + .xlist +include ks386.inc +include callconv.inc ; calling convention macros +include mac386.inc + .list + + EXTRNP _KeSetEventBoostPriority, 2 + EXTRNP _KeWaitForSingleObject, 5 + +ifdef NT_UP + LOCK_ADD equ add + LOCK_DEC equ dec +else + LOCK_ADD equ lock add + LOCK_DEC equ lock dec +endif + +_TEXT$00 SEGMENT DWORD PUBLIC 'CODE' + ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING + +;++ +; +; VOID +; FASTCALL +; ExAcquireFastMutexUnsafe ( +; IN PFAST_MUTEX FastMutex +; ) +; +; Routine description: +; +; This function acquires ownership of a fast mutex, but does not raise +; IRQL to APC level. +; +; Arguments: +; +; (ecx) = FastMutex - Supplies a pointer to a fast mutex. +; +; Return Value: +; +; None. +; +;-- + +cPublicFastCall ExAcquireFastMutexUnsafe,1 +cPublicFpo 0,0 + + LOCK_DEC dword ptr [ecx].FmCount ; decrement lock count + jnz short afm10 ; if nz, ownership not obtained + fstRet ExAcquireFastMutexUnsafe ; return + +afm10: inc dword ptr [ecx].FmContention ; increment contention count + add ecx, FmEvent ; wait for ownership event + stdCall _KeWaitForSingleObject,<ecx,WrExecutive,0,0,0> ; + fstRet ExAcquireFastMutexUnsafe ; return + +fstENDP ExAcquireFastMutexUnsafe + +;++ +; +; VOID +; FASTCALL +; ExReleaseFastMutexUnsafe ( +; IN PFAST_MUTEX FastMutex +; ) +; +; Routine description: +; +; This function releases ownership of a fast mutex, and does nt +; restore IRQL to its previous value. +; +; Arguments: +; +; (ecx) = FastMutex - Supplies a pointer to a fast mutex. +; +; Return Value: +; +; None. +; +;-- + +cPublicFastCall ExReleaseFastMutexUnsafe,1 +cPublicFpo 0,0 + + LOCK_ADD dword ptr [ecx].FmCount, 1 ; increment ownership count + jng short rfm10 ; if ng, waiter present + fstRet ExReleaseFastMutexUnsafe ; return + +rfm10: add ecx, FmEvent ; compute event address + stdCall _KeSetEventBoostPriority,<ecx, 0> ; set ownerhsip event + fstRet ExReleaseFastMutexUnsafe ; return + +fstENDP ExReleaseFastMutexUnsafe + + +;++ +; +; BOOLEAN +; FASTCALL +; ExTryToAcquireFastMutexUnsafe ( +; IN PFAST_MUTEX FastMutex +; ) +; +; Routine description: +; +; This function attempts to acquire ownership of a fast mutex, and if +; successful, does not raise IRQL to APC level. +; +; Arguments: +; +; (ecx) = FastMutex - Supplies a pointer to a fast mutex. +; +; Return Value: +; +; Returns TRUE if the FAST_MUTEX was acquired; otherwise false +; +;-- + +if 0 + +cPublicFastCall ExTryToAcquireFastMutexUnsafe,1 +cPublicFpo 0,0 + +ifdef NT_UP + + cli ; disable interrupts + +endif + + cmp dword ptr [ecx].FmCount, 1 ; check if mutex already owned + jne short tam10 ; if ne, mutex already owned + +ifndef NT_UP + + mov eax, 1 ; set value to compare against + mov edx, 0 ; set value to set + lock cmpxchg dword ptr [ecx].FmCount, edx ; attempt to acquire fast mutex + jne short tam10 ; if ne, mutex already owned + +else + + mov dword ptr [ecx].FmCount, 0 ; set mutex owned + sti ; enable interrupts + +endif + + mov eax, 1 ; set return value + fstRet ExTryToAcquireFastMutexUnsafe ; return + +tam10: xor eax, eax ; set return value + fstRet ExTryToAcquireFastMutexUnsafe ; return + +fstENDP ExTryToAcquireFastMutexUnsafe + +endif + + +_TEXT$00 ends + + end 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 diff --git a/private/ntos/ex/i386/intrlock.asm b/private/ntos/ex/i386/intrlock.asm new file mode 100644 index 000000000..4891af4e8 --- /dev/null +++ b/private/ntos/ex/i386/intrlock.asm @@ -0,0 +1,1054 @@ + title "Interlocked Support" +;++ +; +; Copyright (c) 1989 Microsoft Corporation +; +; Module Name: +; +; intrlock.asm +; +; Abstract: +; +; This module implements functions to support interlocked operations. +; Interlocked operations can only operate on nonpaged data. +; +; Author: +; +; Shie-Lin Tzong (shielint) 12-Feb-1990 +; +; Environment: +; +; Any mode. +; +; Revision History: +; +; bryanwi 1-aug-90 Clean up and fix stuff. +; bryanwi 3-aug-90 Add ExInterlockedIncrementLlong,... +; +;-- +.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 "ExInterlockedAddLargeInteger" +;++ +; +; 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 unsigned large integer. The initial value of +; the addend variable is returned as the function value. +; +; Arguments: +; +; (TOS+4) = Addend - a pointer to the addend value +; (TOS+8) = Increment - the increment value +; (TOS+16) = Lock - a pointer to a pointer to a spin lock +; +; Return Value: +; +; The initial value of the addend variable is stored in eax:edx +; +;-- + +EiulAddend equ [ebp + 8] +EiulIncrement equ [ebp + 12] +EiulLock equ [ebp + 20] +EiulRetval equ [ebp - 8] + +cPublicProc _ExInterlockedAddLargeInteger, 4 + + push ebp + mov ebp,esp + sub esp, 8 + +ifndef NT_UP + mov eax,EiulLock ; (eax) -> KSPIN_LOCK +endif + +eiul10: pushfd + cli ; disable interrupts + ACQUIRE_SPINLOCK eax,<short eiul20> + + mov eax,EiulAddend ; (eax)-> addend variable + mov ecx,[eax] ; (ecx)= low part of addend value + mov edx,[eax]+4 ; (edx)= high part of addend value + mov EiulRetVal,ecx ; set low part of return value + mov EiulRetVal+4,edx ; set high part of return value + add ecx,EiulIncrement ; add low parts of large integer + adc edx,EiulIncrement+4 ; add high parts of large integer and carry + mov eax,EiulAddend ; RELOAD (eax)-> addend variable + mov [eax],ecx ; store low part of result + mov [eax]+4,edx ; store high part of result + +ifndef NT_UP + mov eax,EiulLock + RELEASE_SPINLOCK eax ; NOTHING if NT_UP = 1 +endif + popfd ; restore flags including interrupts + mov eax, EiulRetval ; calling convention + mov edx, EiulRetval+4 ; calling convention + mov esp, ebp + pop ebp + stdRET _ExInterlockedAddLargeInteger + +ifndef NT_UP +eiul20: popfd + SPIN_ON_SPINLOCK eax, eiul10 +endif + +stdENDP _ExInterlockedAddLargeInteger + + page ,132 + subttl "ExInterlocked Exchange Add Large Integer" +;++ +; +; LARGE_INTEGER +; ExInterlockedExchangeAddLargeInteger ( +; 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 unsigned large integer. The initial value of +; the addend variable 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 +; add large integer code which has a compatible calling sequence +; and data structure. +; +; Arguments: +; +; (TOS + 4) = Addend - Supplies a pointer to the addend variable. +; +; (TOS + 8) = Increment - Supplies the increment value. +; +; (TOS + 16) = Lock - Supplies a pointer a spin lock. +; +; N.B. This routine does not use the spin lock. +; +; Return Value: +; +; The initial value of the addend variable is stored in eax:edx. +; +;-- + +XaAddend equ [esp + 12] +XaIncrement equ [esp + 16] +XaLock equ [esp + 24] + +cPublicProc _ExInterlockedExchangeAddLargeInteger, 4 + +cPublicFpo 0,2 + +; +; Save nonvolatile registers and get the addend value. +; + + push ebx ; save nonvolatile registers + push ebp ; + mov ebp, XaAddend ; get the addend variable address + mov eax,[ebp] + 0 ; get low part of addend value + mov edx,[ebp] + 4 ; get high part of addend value + +; +; Add the increment value to the addend value. +; + +Xa10: mov ebx, eax ; copy low part of addend value + mov ecx, edx ; copy high part of addend value + add ebx, XaIncrement ; add low part of increment value + adc ecx, XaIncrement + 4 ; add high part of increment value + +; +; Exchange the updated addend value with the previous addend value. +; + +.586 +ifndef NT_UP + + lock cmpxchg8b qword ptr [ebp] ; compare and exchange + +else + + cmpxchg8b qword ptr [ebp] ; compare and exchange + +endif +.386 + + jnz short Xa10 ; if z clear, exchange failed + +; +; Restore nonvolatile registers and return result. +; + +cPublicFpo 0,0 + + pop ebp ; + pop ebx ; + + stdRET _ExInterlockedExchangeAddLargeInteger + +stdENDP _ExInterlockedExchangeAddLargeInteger + + page , 132 + subttl "Interlocked Add Unsigned Long" +;++ +; +; 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 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. +; +; 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. +; +;-- + +EialAddend equ [esp + 8] +EialIncrement equ [esp + 12] +EialLock equ [esp + 16] + +; end of arguments + +cPublicProc _ExInterlockedAddUlong , 3 +cPublicFpo 3, 1 + +ifdef NT_UP +; +; UP version of ExInterlockedAddUlong +; + + pushfd + cli ; disable interrupts + + mov ecx, EialAddend ; (ecx)->initial addend value + mov edx, [ecx] ; (edx)= initial addend value + mov eax, edx ; (eax)= initial addend value + add edx, EialIncrement ; (edx)=adjusted value + mov [ecx], edx ; [ecx]=adjusted value + + popfd ; restore flags including ints + stdRET _ExInterlockedAddUlong ; cRetURN + +else + +; +; MP version of ExInterlockedAddUlong +; + pushfd + mov edx,EialLock ; (edx)-> KSPIN_LOCK +Eial10: cli ; disable interrupts + ACQUIRE_SPINLOCK edx, <short Eial20> + + mov ecx, EialAddend ; (ecx)->initial addend value + mov eax, [ecx] ; (eax)=initial addend value + add eax, EialIncrement ; (eax)=adjusted value + mov [ecx], eax ; [ecx]=adjusted value + sub eax, EialIncrement ; (eax)=initial addend value + + RELEASE_SPINLOCK edx + popfd + stdRET _ExInterlockedAddUlong ; cRetURN + +Eial20: popfd + pushfd + SPIN_ON_SPINLOCK edx, <short Eial10> +endif + +stdENDP _ExInterlockedAddUlong + + + page , 132 + subttl "Interlocked Insert Head List" +;++ +; +; 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. +; +; N.B. The pages of data which this routine operates on MUST be +; present. No page fault is allowed in this routine. +; +; Arguments: +; +; ListHead - Supplies a pointer to the head of the doubly linked +; list into which an entry is to be inserted. +; +; ListEntry - Supplies a pointer to the entry to be inserted at the +; head of the list. +; +; 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. +; +;-- + +EiihListHead equ [esp + 8] +EiihListEntry equ [esp + 12] +EiihLock equ [esp + 16] + +; end arguments + +cPublicProc _ExInterlockedInsertHeadList , 3 +cPublicFpo 3, 1 + +ifndef NT_UP + mov edx, EiihLock - 4 ; (edx)->KSPIN_LOCK +endif +Eiih10: pushfd + cli + ACQUIRE_SPINLOCK edx,<short Eiih20> + + mov eax, EiihListHead ; (eax)->head of linked list + mov ecx, EiihListEntry ; (ecx)->entry to be inserted + mov edx, LsFlink[eax] ; (edx)->next entry in the list + mov [ecx]+LsFlink, edx ; store next link in entry + mov [ecx]+LsBlink, eax ; store previous link in entry + mov [eax]+LsFlink, ecx ; store next link in head + mov [edx]+LsBlink, ecx ; store previous link in next + +ifndef NT_UP + mov ecx, EiihLock ; (ecx)->KSPIN_LOCK + RELEASE_SPINLOCK ecx +endif +cPublicFpo 3, 0 + popfd ; restore flags including interrupts + + xor eax,edx ; return null if list was empty + jz short Eiih15 + mov eax,edx ; otherwise return prev. entry at head +Eiih15: + stdRET _ExInterlockedInsertHeadList + +ifndef NT_UP +align 4 +Eiih20: popfd + SPIN_ON_SPINLOCK edx, <short Eiih10> +endif + +stdENDP _ExInterlockedInsertHeadList + + + page , 132 + subttl "Interlocked Insert Tail List" +;++ +; +; 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. +; +; N.B. The pages of data which this routine operates on MUST be +; present. No page fault is allowed in this routine. +; +; Arguments: +; +; ListHead - Supplies a pointer to the head of the doubly linked +; list into which an entry is to be inserted. +; +; ListEntry - Supplies a pointer to the entry to be inserted at the +; tail of the list. +; +; 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. +; +;-- + +EiitListHead equ [esp + 8] +EiitListEntry equ [esp + 12] +EiitLock equ [esp + 16] + +; end arguments + +cPublicProc _ExInterlockedInsertTailList , 3 +cPublicFpo 3, 1 + + +ifndef NT_UP + mov edx,EiitLock - 4 ; (edx)->KSPIN_LOCK +endif + +Eiit10: pushfd + cli ; disable interrupts + ACQUIRE_SPINLOCK edx, <short Eiit20> + + mov eax, EiihListHead ; (eax)->head of linked list + mov ecx, EiihListEntry ; (ecx)->entry to be inserted + mov edx, LsBlink[eax] ; (edx)->previous entry in the list + mov [ecx]+LsFlink, eax ; store next link in entry + mov [ecx]+LsBlink, edx ; store previous link in entry + mov [eax]+LsBlink, ecx ; store previous link in head + mov [edx]+LsFlink, ecx ; store next link in next + +ifndef NT_UP + mov ecx,EiitLock ; (ecx)->KSPIN_LOCK + RELEASE_SPINLOCK ecx +endif +cPublicFpo 3,0 + popfd ; restore flags including interrupts + + xor eax,edx ; return null if list was empty + jz short Eiit15 + mov eax,edx ; otherwise return prev. entry at tail +Eiit15: + stdRET _ExInterlockedInsertTailList + +ifndef NT_UP +align 4 +Eiit20: popfd + SPIN_ON_SPINLOCK edx, <short Eiit10> +endif + +stdENDP _ExInterlockedInsertTailList + + page , 132 + subttl "Interlocked Remove Head List" +;++ +; +; 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. +; +; N.B. The pages of data which this routine operates on MUST be +; present. No page fault is allowed in this routine. +; +; Arguments: +; +; ListHead - Supplies a pointer to the head of the doubly linked +; list from which an entry is to be removed. +; +; 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. +; +;-- + +EirhListHead equ [esp + 8] +EirhLock equ [esp + 12] + +; end of arguments + +cPublicProc _ExInterlockedRemoveHeadList , 2 +cPublicFpo 2, 1 + +ifndef NT_UP + mov edx, EirhLock - 4 ; (edx)-> KSPIN_LOCK +endif + +Eirh10: pushfd + cli + + ACQUIRE_SPINLOCK edx, <Eirh30> + + mov edx, EirhListHead ; (edx)-> head of list + mov eax, [edx]+LsFlink ; (eax)-> next entry + cmp eax, edx ; Is list empty? + je short Eirh20 ; if e, list is empty, go Eirh20 + mov ecx, [eax]+LsFlink ; (ecx)-> next entry(after deletion) + mov [edx]+LsFlink, ecx ; store address of next in head + mov [ecx]+LsBlink, edx ; store address of previous in next +if DBG + mov [eax]+LsFlink, 0baddd0ffh + mov [eax]+LsBlink, 0baddd0ffh +endif +ifndef NT_UP + mov edx, EirhLock ; (edx)-> KSPIN_LOCK + RELEASE_SPINLOCK edx +endif +cPublicFpo 2, 0 + popfd ; restore flags including interrupts + stdRET _ExInterlockedRemoveHeadList ; cReturn entry + +align 4 +Eirh20: +ifndef NT_UP + mov edx, EirhLock ; (edx)-> KSPIN_LOCK + RELEASE_SPINLOCK edx +endif + popfd + xor eax,eax ; (eax) = null for empty list + stdRET _ExInterlockedRemoveHeadList ; cReturn NULL + +ifndef NT_UP +align 4 +Eirh30: popfd + SPIN_ON_SPINLOCK edx, Eirh10 +endif + +stdENDP _ExInterlockedRemoveHeadList + + page , 132 + subttl "Interlocked Pop Entry List" +;++ +; +; PSINGLE_LIST_ENTRY +; ExInterlockedPopEntryList ( +; 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: +; +; ListHead - Supplies a pointer to the head of the singly linked +; list from which an entry is to be removed. +; +; 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. +; +;-- + +; end of arguments + +cPublicProc _ExInterlockedPopEntryList , 2 +cPublicFpo 2,1 + +ifndef NT_UP + mov edx, [esp+8] ; (edx)-> KSPIN_LOCK +endif + +Eipe10: pushfd + cli ; disable interrupts + + ACQUIRE_SPINLOCK edx, <short Eipe30> + + mov ecx, [esp+8] ; (ecx)-> head of list + mov eax, [ecx] ; (eax)-> next entry + or eax, eax ; Is it empty? + je short Eipe20 ; if e, empty list, go Eipe20 + mov edx, [eax] ; (edx)->next entry (after deletion) + mov [ecx], edx ; store address of next in head +if DBG + mov [eax], 0baddd0ffh +endif +ifndef NT_UP + mov edx, [esp+12] ; (edx)-> KSPIN_LOCK + RELEASE_SPINLOCK edx +endif +cPublicFpo 2,0 + popfd ; restore flags including interrupts + stdRET _ExInterlockedPopEntryList ; cReturn (eax)->removed entry + +align 4 +Eipe20: RELEASE_SPINLOCK edx + popfd + xor eax,eax + stdRET _ExInterlockedPopEntryList ; cReturn (eax)=NULL + +ifndef NT_UP +align 4 +Eipe30: popfd + SPIN_ON_SPINLOCK edx, Eipe10 +endif + +stdENDP _ExInterlockedPopEntryList + + page , 132 + subttl "Interlocked Push Entry List" +;++ +; +; 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 - Supplies a pointer to the head of the singly linked +; list into which an entry is to be inserted. +; +; ListEntry - Supplies a pointer to the entry to be inserted at the +; head of the list. +; +; 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. +; +;-- + +; end of arguments + +cPublicProc _ExInterlockedPushEntryList , 3 +cPublicFpo 3,1 + +ifndef NT_UP + mov edx, [esp+12] ; (edx)->KSPIN_LOCK +endif + +Eipl10: pushfd + cli + + ACQUIRE_SPINLOCK edx, <short Eipl20> + + mov edx, [esp+8] ; (edx)-> Head of list + mov eax, [edx] ; (eax)-> next entry (return value also) + mov ecx, [esp+12] ; (ecx)-> Entry to be pushed + mov [ecx], eax ; store address of next in new entry + mov [edx], ecx ; set address of next in head + +ifndef NT_UP + mov edx, [esp+16] ; (edx)->KSPIN_LOCK + RELEASE_SPINLOCK edx +endif +cPublicFpo 3,0 + popfd ; restore flags including interrupts + stdRET _ExInterlockedPushEntryList + +ifndef NT_UP +align 4 +Eipl20: popfd + SPIN_ON_SPINLOCK edx, <short Eipl10> +endif + +stdENDP _ExInterlockedPushEntryList + + page , 132 + subttl "Interlocked Increment Long" +;++ +; +; INTERLOCKED_RESULT +; ExInterlockedIncrementLong ( +; IN PLONG Addend, +; IN PKSPIN_LOCK Lock +; ) +; +; 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. +; +; It is NOT possible to mix ExInterlockedDecrementLong and +; ExInterlockedIncrementong with ExInterlockedAddUlong. +; +; +; Arguments: +; +; Addend (esp+4) - Pointer to variable to increment. +; +; Lock (esp+8) - Spinlock used to implement atomicity. +; (not actually used on x86) +; +; 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. +; +;-- + +cPublicProc _ExInterlockedIncrementLong , 2 +cPublicFpo 2, 0 + + mov eax, [esp+4] ; (eax) -> addend +ifdef NT_UP + add dword ptr [eax],1 +else + lock add dword ptr [eax],1 +endif + lahf ; (ah) = flags + and eax,EFLAG_SELECT ; clear all but sign and zero flags + stdRET _ExInterlockedIncrementLong + +stdENDP _ExInterlockedIncrementLong + + + page , 132 + subttl "Interlocked Decrement Long" +;++ +; +; INTERLOCKED_RESULT +; ExInterlockedDecrementLong ( +; 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. +; +; It is NOT possible to mix ExInterlockedDecrementLong and +; ExInterlockedIncrementong with ExInterlockedAddUlong. +; +; 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. +; +;-- + +cPublicProc _ExInterlockedDecrementLong , 2 +cPublicFpo 2, 0 + + mov eax, [esp+4] ; (eax) -> addend +ifdef NT_UP + sub dword ptr [eax], 1 +else + lock sub dword ptr [eax], 1 +endif + lahf ; (ah) = flags + and eax, EFLAG_SELECT ; clear all but sign and zero flags + stdRET _ExInterlockedDecrementLong + +stdENDP _ExInterlockedDecrementLong + + page , 132 + subttl "Interlocked Exchange Ulong" +;++ +; +; ULONG +; ExInterlockedExchangeUlong ( +; IN PULONG Target, +; IN ULONG Value, +; IN PKSPIN_LOCK Lock +; ) +; +; Routine Description: +; +; This function atomically exchanges the Target and Value, returning +; the prior contents of Target +; +; This function does not necessarily synchronize with the Lock. +; +; Arguments: +; +; Target - Address of ULONG to exchange +; Value - New value of ULONG +; Lock - SpinLock used to implement atomicity. +; +; Return Value: +; +; The prior value of Source +;-- + +cPublicProc _ExInterlockedExchangeUlong, 3 +cPublicFpo 3,0 + +ifndef NT_UP + mov edx, [esp+4] ; (edx) = Target + mov eax, [esp+8] ; (eax) = Value + + xchg [edx], eax ; make the exchange +else + mov edx, [esp+4] ; (edx) = Target + mov ecx, [esp+8] ; (eax) = Value + + pushfd + cli + mov eax, [edx] ; get current value + mov [edx], ecx ; store new value + popfd +endif + + stdRET _ExInterlockedExchangeUlong + +stdENDP _ExInterlockedExchangeUlong + + page , 132 + subttl "Interlocked i386 Increment Long" +;++ +; +; INTERLOCKED_RESULT +; Exi386InterlockedIncrementLong ( +; 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: +; +; Addend (esp+4) - Pointer to variable to increment. +; +; Lock (esp+8) - Spinlock used to implement atomicity. +; (not actually used on x86) +; +; 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. +; +;-- + +cPublicProc _Exi386InterlockedIncrementLong , 1 +cPublicFpo 1, 0 + + mov eax, [esp+4] ; (eax) -> addend +ifdef NT_UP + add dword ptr [eax],1 +else + lock add dword ptr [eax],1 +endif + lahf ; (ah) = flags + and eax,EFLAG_SELECT ; clear all but sign and zero flags + stdRET _Exi386InterlockedIncrementLong + +stdENDP _Exi386InterlockedIncrementLong + + + page , 132 + subttl "Interlocked i386 Decrement Long" +;++ +; +; INTERLOCKED_RESULT +; ExInterlockedDecrementLong ( +; 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. +; +;-- + +cPublicProc _Exi386InterlockedDecrementLong , 1 +cPublicFpo 1, 0 + + mov eax, [esp+4] ; (eax) -> addend +ifdef NT_UP + sub dword ptr [eax], 1 +else + lock sub dword ptr [eax], 1 +endif + lahf ; (ah) = flags + and eax, EFLAG_SELECT ; clear all but sign and zero flags + stdRET _Exi386InterlockedDecrementLong + +stdENDP _Exi386InterlockedDecrementLong + + page , 132 + subttl "Interlocked i386 Exchange Ulong" + +;++ +; +; ULONG +; Exi386InterlockedExchangeUlong ( +; IN PULONG Target, +; IN ULONG Value, +; IN PKSPIN_LOCK Lock +; ) +; +; 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: +; +; Source - Address of ULONG to exchange +; Value - New value of ULONG +; Lock - SpinLock used to implement atomicity. +; +; Return Value: +; +; The prior value of Source +;-- + +cPublicProc _Exi386InterlockedExchangeUlong, 2 +cPublicFpo 2,0 + +ifndef NT_UP + mov edx, [esp+4] ; (edx) = Target + mov eax, [esp+8] ; (eax) = Value + + xchg [edx], eax ; make the exchange +else + mov edx, [esp+4] ; (edx) = Target + mov ecx, [esp+8] ; (eax) = Value + + pushfd + cli + mov eax, [edx] ; get current value + mov [edx], ecx ; store new value + popfd +endif + + stdRET _Exi386InterlockedExchangeUlong + +stdENDP _Exi386InterlockedExchangeUlong + +_TEXT$00 ends + end diff --git a/private/ntos/ex/i386/probe.c b/private/ntos/ex/i386/probe.c new file mode 100644 index 000000000..e65bd0d9a --- /dev/null +++ b/private/ntos/ex/i386/probe.c @@ -0,0 +1,120 @@ +/*++ + +Copyright (c) 1989-1993 Microsoft Corporation + +Module Name: + + probe.c + +Abstract: + + This module contains implements the probe for write function. + +Author: + + David N. Cutler (davec) 5-May-1989 + +Environment: + + Any mode. + +Revision History: + +--*/ + +#include "exp.h" + +#if defined(ALLOC_PRAGMA) +#pragma alloc_text(PAGE, ProbeForWrite) +#endif + + +VOID +ProbeForWrite ( + IN PVOID Address, + IN ULONG Length, + IN ULONG Alignment + ) + +/*++ + +Routine Description: + + This function probes a structure for write accessibility and ensures + correct alignment of the structure. If the structure is not accessible + or has incorrect alignment, then an exception is raised. + +Arguments: + + Address - Supplies a pointer to the structure to be probed. + + Length - Supplies the length of the structure. + + Alignment - Supplies the required alignment of the structure expressed + as the number of bytes in the primitive datatype (e.g., 1 for char, + 2 for short, 4 for long, and 8 for quad). + +Return Value: + + None. + +--*/ + +{ + + ULONG StartAddress; + ULONG EndAddress; + + // + // If the structure has zero length, then do not probe the structure for + // write accessibility or alignment. + // + + if (Length != 0) { + + // + // If the structure is not properly aligned, then raise a data + // misalignment exception. + // + + ASSERT((Alignment == 1) || (Alignment == 2) || + (Alignment == 4) || (Alignment == 8)); + + StartAddress = (ULONG)Address; + if ((StartAddress & (Alignment - 1)) == 0) { + + // + // Compute the ending address of the structure and probe for + // write accessibility. + // + + EndAddress = StartAddress + Length - 1; + if ((StartAddress <= EndAddress) & + (EndAddress < MM_USER_PROBE_ADDRESS)) { + + // + // N.B. Only the contents of the buffer may be probed. + // Therefore the starting byte is probed for the + // first page, and then the first byte in the page + // for each succeeding page. + // + + EndAddress = (EndAddress & ~(PAGE_SIZE - 1)) + PAGE_SIZE; + do { + *(volatile CHAR *)StartAddress = *(volatile CHAR *)StartAddress; + StartAddress = (StartAddress & ~(PAGE_SIZE - 1)) + PAGE_SIZE; + } while (StartAddress != EndAddress); + + return; + + } else { + ExRaiseStatus(STATUS_ACCESS_VIOLATION); + } + + } else { + ExRaiseStatus(STATUS_DATATYPE_MISALIGNMENT); + } + } + + return; +} diff --git a/private/ntos/ex/i386/raisests.asm b/private/ntos/ex/i386/raisests.asm new file mode 100644 index 000000000..9a9688b1b --- /dev/null +++ b/private/ntos/ex/i386/raisests.asm @@ -0,0 +1,316 @@ + title "Raise Exception" +;++ +; +; Copyright (c) 1990 Microsoft Corporation +; +; Module Name: +; +; raisests.asm +; +; Abstract: +; +; This module implements the function to raise a software exception. +; +; Author: +; +; Bryan Willman 11 Nov 90 +; +; Environment: +; +; Any mode. +; +; Revision History: +; +;-- +.386p + .xlist +include ks386.inc +include callconv.inc ; calling convention macros + .list + + EXTRNP _RtlDispatchException,2 + EXTRNP _ZwContinue,2 + EXTRNP _ZwRaiseException,3 + +_TEXT$01 SEGMENT DWORD PUBLIC 'CODE' + ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING + +; +; Context flags definition. +; + +CONTEXT_SETTING EQU CONTEXT_INTEGER OR CONTEXT_CONTROL OR CONTEXT_SEGMENTS + +; +; Exception record length definition. +; + +EXCEPTION_RECORD_LENGTH EQU (ErExceptionInformation + 16) AND 0fffffff0H + + page + subttl "Raise Software Exception" +;++ +; +; VOID +; ExRaiseException ( +; IN PEXCEPTION_RECORD ExceptionRecord +; ) +; +; Routine Description: +; +; This function raises a software exception by building a context record, +; establishing the stack limits of the current processor mode, and calling +; the exception dispatcher. If the exception dispatcher finds a handler +; to process the exception, then control is returned to the caller using +; the NtContinue system service. Otherwise the NtLastChance system service +; is called to provide default handing. +; +; N.B. On the 386, floating point state is not defined for non-fp +; exceptions. Therefore, this routine does not attempt to +; capture it. +; +; This means this routine cannot be used to report fp exceptions. +; +; Arguments: +; +; ExceptionRecord (ebp+8) - Supplies a pointer to an exception record. +; +; Return Value: +; +; None. +; +;-- + +cPublicProc _ExRaiseException , 1 + + push ebp + mov ebp,esp + pushfd ; save flags before sub + sub esp,ContextFrameLength ; Allocate a context record + +; +; Save regs we use in context record +; + + mov [(ebp-ContextFrameLength-4)+CsEax],eax + mov [(ebp-ContextFrameLength-4)+CsEcx],ecx + +; +; Get pointer to exception report record, and set the exceptionaddress +; field to be our return address +; + + mov eax,[ebp+8] ; (eax) -> ExceptionReportRecord + + mov ecx,[ebp+4] + mov [eax.ErExceptionAddress],ecx + +; +; Copy machine context into the context record +; + + lea eax,[ebp-ContextFrameLength-4] ; (eax) -> Context record + + mov [eax.CsEip],ecx + + mov [eax.CsEbx],ebx + mov [eax.CsEdx],edx + + mov [eax.CsEsi],esi + mov [eax.CsEdi],edi + + lea ecx,[ebp+8] + mov [eax.CsEsp],ecx + + mov ecx,[ebp] + mov [eax.CsEbp],ecx + + mov ecx,[ebp-4] + mov [eax.CsEflags],ecx + + mov dword ptr [eax.CsSegCs],cs + mov dword ptr [eax.CsSegDs],ds + mov dword ptr [eax.CsSegEs],es + mov dword ptr [eax.CsSegFs],fs + mov dword ptr [eax.CsSegGs],gs + mov dword ptr [eax.CsSegSs],ss + +; +; Set Context flags, note that FLOATING_POINT is NOT set. +; + + mov dword ptr [eax.CsContextFlags],CONTEXT_SETTING + +; +; _RtlDispatchException(ExceptionRecord, ContextRecord) +; + stdCall _RtlDispatchException, <[ebp+8],eax> +; +; If the exception is successfully dispatched, then continue execution. +; Otherwise, give the kernel debugger a chance to handle the exception. +; + lea ecx,[ebp-ContextFrameLength-4] ; (eax) -> Context record + + or eax, eax + jz short ere10 + + stdCall _ZwContinue, <ecx,0> + jmp short ere20 + +ere10: + stdCall _ZwRaiseException, <[ebp+8],ecx,0> + +ere20: +; +; Either the attempt to continue execution or the attempt to give +; the kernel debugger a chance to handle the exception failed. Raise +; a noncontinuable exception. +; + stdCall _ExRaiseStatus, <eax> + + +stdENDP _ExRaiseException + + page + subttl "Raise Software Exception" +;++ +; +; VOID +; ExRaiseStatus ( +; IN NTSTATUS Status +; ) +; +; Routine Description: +; +; This function raises a software exception with the specified status value +; by building a context record, establishing the stack limits of the current +; processor mode, and calling the exception dispatcher. If the exception +; dispatcher finds a handler to process the exception, then control is +; returned to the caller using the NtContinue system service. Otherwise +; the NtLastChance system service is called to provide default handing. +; +; N.B. On the 386, floating point state is not defined for non-fp +; exceptions. Therefore, this routine does not attempt to +; capture it. +; +; This means this routine cannot be used to report fp exceptions. +; +; Arguments: +; +; Status - Supplies the status value to be used as the exception code +; for the exception that is to be raised. +; +; Return Value: +; +; None. + +; Arguments: +; +;-- + +cPublicProc _ExRaiseStatus,1 + + push ebp + mov ebp,esp + pushfd ; save flags before sub + sub esp,ContextFrameLength+ExceptionRecordLength + +; +; Save regs we use in context record +; + + mov [(ebp-ContextFrameLength-4)+CsEax],eax + mov [(ebp-ContextFrameLength-4)+CsEcx],ecx + +; +; Copy machine context into the context record +; + + + lea eax,[ebp-ContextFrameLength-4] ; (eax) -> Context record + + mov ecx,[ebp+4] ; [ecx] = returned address + mov [eax.CsEip],ecx + + mov [eax.CsEbx],ebx + mov [eax.CsEdx],edx + + mov [eax.CsEsi],esi + mov [eax.CsEdi],edi + + lea ecx,[ebp+8] + mov [eax.CsEsp],ecx + + mov ecx,[ebp] + mov [eax.CsEbp],ecx + + mov ecx,[ebp-4] + mov [eax.CsEflags],ecx + + mov dword ptr [eax.CsSegCs],cs + mov dword ptr [eax.CsSegDs],ds + mov dword ptr [eax.CsSegEs],es + mov dword ptr [eax.CsSegFs],fs + mov dword ptr [eax.CsSegGs],gs + mov dword ptr [eax.CsSegSs],ss + +; +; Set Context flags, note that FLOATING_POINT is NOT set. +; + + mov dword ptr [eax.CsContextFlags],CONTEXT_SETTING + +; +; Get pointer to exception report record, and set the exceptionaddress +; field to be our return address +; + + lea eax,[ebp-ContextFrameLength-ExceptionRecordLength-4] + ; (eax) -> ExceptionRecord + mov ecx,[ebp+4] + mov dword ptr [eax.ErExceptionAddress],ecx + mov ecx,[ebp+8] + mov dword ptr [eax.ErExceptionCode],ecx + mov dword ptr [eax.ErNumberParameters], 0 + mov dword ptr [eax.ErExceptionRecord], 0 + mov dword ptr [eax.ErExceptionFlags], EXCEPTION_NONCONTINUABLE + +; +; _RtlDispatchException(ExceptionRecord, ContextRecord) +; + + lea ecx,[ebp-ContextFrameLength-4] ; (eax) -> Context record + +; ecx - Context record +; eax - Exception record + stdCall _RtlDispatchException, <eax, ecx> + +; +; An unwind was not initiated during the dispatching of a noncontinuable +; exception. Give the kernel debugger a chance to handle the exception. +; + +; +; _ZwRaiseException(ExceptionRecord, ContextRecord, FirstChance=TRUE) +; + + lea ecx,[ebp-ContextFrameLength-4] ; (eax) -> Context record + lea eax,[ebp-ContextFrameLength-ExceptionRecordLength-4] +; 1 - TRUE +; ecx - Context Record +; eax - Exception Report Record + stdCall _ZwRaiseException, <eax, ecx, 1> + +; +; We came back, suggesting some sort of error in the call. Raise +; a status exception to report this, return from ZwRaiseException is type. +; + + stdCall _ExRaiseStatus, <eax> + + +stdENDP _ExRaiseStatus + +_TEXT$01 ends + end + diff --git a/private/ntos/ex/i386/resoura.asm b/private/ntos/ex/i386/resoura.asm new file mode 100644 index 000000000..d4e3ef0f7 --- /dev/null +++ b/private/ntos/ex/i386/resoura.asm @@ -0,0 +1,110 @@ + title "Resource package x86 optimzations" +;++ +; +;Copyright (c) 1991 Microsoft Corporation +; +;Module Name: +; +; resoura.asm +; +;Abstract: +; +; Optimized preambles for some HOT resource code paths. +; +; Takes first crack at satisfying the ExResource API, if it +; can't it passes it onto the full blown API. +; +; Optimized for UP free builds only! +; +;Author: +; +; Ken Reneris (kenr) 13-Jan-1992 +; +;Revision History: +; +;-- +.386p +include ks386.inc +include callconv.inc ; calling convention macros +include mac386.inc + + + EXTRNP _ExpReleaseResourceForThread,2 + +ExculsiveWaiter equ 1 ; From ddkresrc.c +SharedWaiter equ 2 ; From ddkresrc.c +AnyWaiter equ (ExculsiveWaiter+SharedWaiter) + +_TEXT$00 SEGMENT PARA PUBLIC 'CODE' + ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING + +ifdef NT_UP +ife DBG +;++ +; +; VOID +; ExReleaseResourceForThread( +; IN PNTDDK_ERESOURCE Resource, +; IN ERESOURCE_THREAD OurThread +; ) +; +; +; Routine Description: +; +; This routine release the input resource the indcated thread. The +; resource can have been acquired for either shared or exclusive access. +; +; Arguments: +; +; Resource - Supplies the resource to release +; +; Thread - Supplies the thread that originally acquired the resource +; +; Return Value: +; +; None. +; +;-- + +cPublicProc _ExReleaseResourceForThread,2 +cPublicFpo 2,0 + mov ecx, [esp+4] ; resource + mov eax, [esp+8] ; our thread + + cli + + test byte ptr [ecx].RsFlag, AnyWaiter ; any waiter? + jnz short rrt_longway_ddk ; yes, go long + + test byte ptr [ecx].RsFlag, RsOwnedExclusive ; exclusive? + jz short rrt_longway_ddk ; bad release, go abort + + mov edx, [ecx].RsOwnerThreads ; (edx) = ownerthread table + cmp [edx], eax ; our thread at table[0]? + jne short rrt_longway_ddk ; bad release, go abort + + mov eax, [ecx].RsOwnerCounts + dec byte ptr [eax] ; thread count -= 1 + jnz short rrt_exit_ddk ; if not zero, all done + + mov dword ptr [edx], 0 ; clear thread table[0] + dec word ptr [ecx].RsActiveCount ; resource count -= 1 + and byte ptr [ecx].RsFlag, not RsOwnedExclusive + +rrt_exit_ddk: + sti + stdRET _ExReleaseResourceForThread + +rrt_longway_ddk: + sti + jmp _ExpReleaseResourceForThread@8 + + +stdENDP _ExReleaseResourceForThread + +endif +endif + +_TEXT$00 ends + +end diff --git a/private/ntos/ex/i386/sources b/private/ntos/ex/i386/sources new file mode 100644 index 000000000..51968b081 --- /dev/null +++ b/private/ntos/ex/i386/sources @@ -0,0 +1,8 @@ +i386_SOURCES=..\i386\evpair.asm \ + ..\i386\fmutex.asm \ + ..\i386\intrlock.asm \ + ..\i386\intrlfst.asm \ + ..\i386\raisests.asm \ + ..\i386\probe.c \ + ..\i386\splocks.asm \ + ..\i386\resoura.asm diff --git a/private/ntos/ex/i386/splocks.asm b/private/ntos/ex/i386/splocks.asm new file mode 100644 index 000000000..154cfb26f --- /dev/null +++ b/private/ntos/ex/i386/splocks.asm @@ -0,0 +1,208 @@ + title "Global SpinLock declerations" +;++ +; +;Copyright (c) 1991 Microsoft Corporation +; +;Module Name: +; +; splocks.asm +; +;Abstract: +; +; All global spinlocks in the kernel image are declared in this +; module. This is done so that each spinlock can be spaced out +; sufficiently to guaarantee that the L2 cache does not thrash +; by having a spinlock and another high use varible in the same +; cache line. +; +;Author: +; +; Ken Reneris (kenr) 13-Jan-1992 +; +;Revision History: +; +;-- +.386p + .xlist + +PADLOCKS equ 64 + + +SPINLOCK macro SpinLockName + public SpinLockName +SpinLockName dd 0 + +ifndef NT_UP + db PADLOCKS-4 dup (0) +endif +endm + +ULONG macro VaribleName + public VaribleName +VaribleName dd 0 + +ifndef NT_UP + db PADLOCKS-4 dup (0) +endif +endm + +_DATA SEGMENT PARA PUBLIC 'DATA' + +; +; Static SpinLocks from ntos\cc\cachedat.c +; + +;;align PADLOCKS + db PADLOCKS dup (0) + +SPINLOCK _CcMasterSpinLock +SPINLOCK _CcWorkQueueSpinlock +SPINLOCK _CcVacbSpinLock +SPINLOCK _CcDeferredWriteSpinLock +SPINLOCK _CcDebugTraceLock +SPINLOCK _CcBcbSpinLock + + +; +; Static SpinLocks from ntos\ex +; + +SPINLOCK _ExpLuidLock ; luid.c +SPINLOCK _NonPagedPoolLock ; pool.c +SPINLOCK _PoolTraceLock ; pool.c +SPINLOCK _ExpResourceSpinLock ; resource.c + + +; +; Static SpinLocks from ntos\io\iodata.c +; + +SPINLOCK _IopCompletionLock +SPINLOCK _IopCancelSpinLock +SPINLOCK _IopVpbSpinLock +SPINLOCK _IopDatabaseLock +SPINLOCK _IopErrorLogLock +SPINLOCK _IopErrorLogAllocationLock +SPINLOCK _IopTimerLock +SPINLOCK _IoStatisticsLock +SPINLOCK _IopFastLockSpinLock + + +; +; Static SpinLocks from ntos\kd\kdlock.c +; + +SPINLOCK _KdpDebuggerLock + + +; +; Static SpinLocks from ntos\ke\kernldat.c +; + +SPINLOCK _KiContextSwapLock +SPINLOCK _KiDispatcherLock +SPINLOCK _KiFreezeExecutionLock +SPINLOCK _KiFreezeLockBackup +ULONG _KiHardwareTrigger +SPINLOCK _KiProfileLock + +; +; Static SpinLocks from ntos\mm\miglobal.c +; + +SPINLOCK _MmPfnLock +SPINLOCK _MmSystemSpaceLock +SPINLOCK _MmChargeCommitmentLock +SPINLOCK _MmAllowWSExpansionLock + +; +; Static SpinLocks from ntos\ps\psinit.c +; + +SPINLOCK _PspEventPairLock +SPINLOCK _PsLoadedModuleSpinLock + +; +; Static SpinLocks from ntos\fsrtl\fsrtlp.c +; + +SPINLOCK _FsRtlStrucSupSpinLock ; fsrtlp.c + + db PADLOCKS dup (0) + +; +; KeTickCount - This is the number of clock ticks that have occurred since +; the system was booted. This count is used to compute a millisecond +; tick counter. +; + + public _KeTickCount +_KeTickCount dd 0, 0, 0 + +; +; KeMaximumIncrement - This is the maximum time between clock interrupts +; in 100ns units that is supported by the host HAL. +; + + public _KeMaximumIncrement +_KeMaximumIncrement dd 0 + +; +; KeTimeAdjustment - This is the actual number of 100ns units that are to +; be added to the system time at each interval timer interupt. This +; value is copied from KeTimeIncrement at system start up and can be +; later modified via the set system information service. +; timer table entries. +; + + public _KeTimeAdjustment +_KeTimeAdjustment dd 0 + +; +; KiTickOffset - This is the number of 100ns units remaining before a tick +; is added to the tick count and the system time is updated. +; + + public _KiTickOffset +_KiTickOffset dd 0 + +; +; KiMaximumDpcQueueDepth - This is used to control how many DPCs can be +; queued before a DPC of medium importance will trigger a dispatch +; interrupt. +; + + public _KiMaximumDpcQueueDepth +_KiMaximumDpcQueueDepth dd 4 + +; +; KiMinimumDpcRate - This is the rate of DPC requests per clock tick that +; must be exceeded before DPC batching of medium importance DPCs +; will occur. +; + + public _KiMinimumDpcRate +_KiMinimumDpcRate dd 3 + +; +; KiAdjustDpcThreshold - This is the threshold used by the clock interrupt +; routine to control the rate at which the processor's DPC queue depth +; is dynamically adjusted. +; + + public _KiAdjustDpcThreshold +_KiAdjustDpcThreshold dd 20 + +; +; KiIdealDpcRate - This is used to control the aggressiveness of the DPC +; rate adjusting algorithm when decrementing the queue depth. As long +; as the DPC rate for the last tick is greater than this rate, the +; DPC queue depth will not be decremented. +; + + public _KiIdealDpcRate +_KiIdealDpcRate dd 20 + +_DATA ends + +end |