/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ex/i386/fastinterlck_asm.S * PURPOSE: FASTCALL Interlocked Functions * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) */ /* INCLUDES ******************************************************************/ #include #include .intel_syntax noprefix /* FUNCTIONS ****************************************************************/ /* * NOTE: These functions must obey the following rules: * - Acquire locks only on MP systems. * - Be safe at HIGH_LEVEL (no paged access). * - Preserve flags. * - Disable interrups. */ /*VOID *FASTCALL *ExInterlockedAddLargeStatistic(IN PLARGE_INTEGER Addend, * IN ULONG Increment) */ .global @ExInterlockedAddLargeStatistic@8 @ExInterlockedAddLargeStatistic@8: #ifdef CONFIG_SMP /* Do the addition */ lock add [ecx], edx /* Check for carry bit and return */ jb 1f ret 1: /* Add carry */ lock adc dword ptr [ecx+4], 0 #else /* Do the addition and add the carry */ add dword ptr [ecx], edx adc dword ptr [ecx+4], 0 #endif /* Return */ ret /*ULONG *FASTCALL *ExfInterlockedAddUlong(IN PULONG Addend, * IN ULONG Increment, * IN PKSPIN_LOCK Lock) */ .global @ExfInterlockedAddUlong@12 @ExfInterlockedAddUlong@12: /* Save flags */ pushfd #ifdef CONFIG_SMP /* Get lock address */ mov eax, [esp+8] .start1: #endif /* Disable interrupts */ cli /* Acquire lock */ ACQUIRE_SPINLOCK(eax, .spin1) /* Do the add */ mov eax, [ecx] add [ecx], edx #ifdef CONFIG_SMP /* Get spinlock address and release it */ mov edx, [esp+8] RELEASE_SPINLOCK(edx) #endif /* Restore flags and return */ popfd ret 4 #ifdef CONFIG_SMP .spin1: /* Restore flags and spin */ popfd pushfd SPIN_ON_LOCK(eax, .start1) #endif /*PLIST_ENTRY *FASTCALL *ExfInterlockedInsertHeadList(IN PLIST_ENTRY ListHead, * IN PLIST_ENTRY ListEntry, * IN PKSPIN_LOCK Lock) */ .global @ExfInterlockedInsertHeadList@12 @ExfInterlockedInsertHeadList@12: #ifdef CONFIG_SMP /* Save lock address */ push esi mov esi, [esp+8] #endif /* Save flags and disable interrupts */ pushfd .start2: cli /* Acquire lock */ ACQUIRE_SPINLOCK(esi, .spin2) /* Get list pointer */ mov eax, [ecx] /* Do the insert */ mov [edx], eax mov [edx+4], ecx mov [ecx], edx mov [eax+4], edx /* Release lock and restore flags */ RELEASE_SPINLOCK(esi) popfd #ifdef CONFIG_SMP pop esi #endif /* Check if list was empty */ xor eax, ecx jz 2f /* Return list pointer */ xor eax, ecx 2: ret 4 #ifdef CONFIG_SMP .spin2: popfd pushfd SPIN_ON_LOCK(esi, .start2) #endif /*PLIST_ENTRY *NTAPI *ExfInterlockedInsertTailList(IN PLIST_ENTRY ListHead, * IN PLIST_ENTRY ListEntry, * IN PKSPIN_LOCK Lock) */ .global @ExfInterlockedInsertTailList@12 @ExfInterlockedInsertTailList@12: #ifdef CONFIG_SMP /* Save lock address */ push esi mov esi, [esp+8] #endif /* Save flags and disable interrupts */ pushfd .start3: cli /* Acquire lock */ ACQUIRE_SPINLOCK(esi, .spin3) /* Get list pointer */ mov eax, [ecx+4] /* Do the insert */ mov [edx], ecx mov [edx+4], eax mov [ecx+4], edx mov [eax], edx /* Release lock and restore flags */ RELEASE_SPINLOCK(esi) popfd #ifdef CONFIG_SMP pop esi #endif /* Check if list was empty */ xor eax, ecx jz 2f /* Return list pointer */ xor eax, ecx 2: ret 4 #ifdef CONFIG_SMP .spin3: popfd pushfd SPIN_ON_LOCK(esi, .start3) #endif /*PLIST_ENTRY *FASTCALL *ExfInterlockedRemoveHeadList(IN PLIST_ENTRY ListHead, * IN PKSPIN_LOCK Lock) */ .global @ExfInterlockedRemoveHeadList@8 @ExfInterlockedRemoveHeadList@8: /* Save flags and disable interrupts */ .start4: pushfd cli ACQUIRE_SPINLOCK(edx, .spin4) /* Get list pointer */ mov eax, [ecx] /* Check if it's empty */ cmp eax, ecx je 2f /* Get the next entry and do the deletion*/ #ifdef CONFIG_SMP push ebx mov ebx, [eax] mov [ecx], ebx mov [ebx+4], ecx #else mov edx, [eax] mov [ecx], edx mov [edx+4], ecx #endif /* Release lock */ #ifdef CONFIG_SMP RELEASE_SPINLOCK(edx) pop ebx #endif /* Restore flags */ popfd /* Return */ ret 2: /* Release lock */ RELEASE_SPINLOCK(edx) /* Restore flags */ popfd /* Return empty list */ xor eax, eax ret #ifdef CONFIG_SMP .spin4: popfd SPIN_ON_LOCK(edx, .start4) #endif /*PSINGLE_LIST_ENTRY *FASTCALL *ExfInterlockedPopEntryList(IN PSINGLE_LIST_ENTRY ListHead, * IN PKSPIN_LOCK Lock) */ .global @ExfInterlockedPopEntryList@8 @ExfInterlockedPopEntryList@8: /* Save flags and disable interrupts */ .start5: pushfd cli ACQUIRE_SPINLOCK(edx, .spin5) /* Get list pointer */ mov eax, [ecx] /* Check if it's empty */ or eax, eax je 3f /* Get next entry and do deletion */ #ifdef CONFIG_SMP push edx #endif mov edx, [eax] mov [ecx], edx #ifdef CONFIG_SMP pop edx #endif 2: /* Release lock */ RELEASE_SPINLOCK(edx) /* Restore flags */ popfd /* Return */ ret 3: /* Return empty list */ xor eax, eax jmp 2b #ifdef CONFIG_SMP .spin5: popfd SPIN_ON_LOCK(edx, .start5) #endif /*PSINGLE_LIST_ENTRY *NTAPI *ExfInterlockedPushEntryList(IN PSINGLE_LIST_ENTRY ListHead, * IN PSINGLE_LIST_ENTRY ListEntry, * IN PKSPIN_LOCK Lock) */ .global @ExfInterlockedPushEntryList@12 @ExfInterlockedPushEntryList@12: /* Save flags */ pushfd /* Save lock pointer */ #ifdef CONFIG_SMP push edx mov edx, [esp+12] #endif /* Disable interrupts */ .start6: cli #ifdef CONFIG_SMP ACQUIRE_SPINLOCK(edx, .spin6) pop edx #endif /* Get list pointer */ mov eax, [ecx] /* Do push */ mov [edx], eax mov [ecx], edx /* Release lock */ #ifdef CONFIG_SMP mov edx, [esp+8] RELEASE_SPINLOCK(edx) #endif /* Restore flags */ popfd /* Return */ ret 4 #ifdef CONFIG_SMP .spin6: pop edx popfd pushfd push edx mov edx, [esp+12] SPIN_ON_LOCK(edx, .start6) #endif /*PSINGLE_LIST_ENTRY *NTAPI *ExInterlockedPopEntrySList(IN PSINGLE_LIST_ENTRY ListHead, * IN PKSPIN_LOCK Lock) */ .global @ExInterlockedPopEntrySList@8 .global @InterlockedPopEntrySList@4 @ExInterlockedPopEntrySList@8: @InterlockedPopEntrySList@4: /* Save registers */ push ebx push ebp /* Pointer to list */ mov ebp, ecx /* Get sequence number and link pointer */ mov edx, [ebp+4] mov eax, [ebp] 1: /* Check if the list is empty */ or eax, eax jz 2f /* Copy sequence number and adjust it */ lea ecx, [edx-1] /* Get next pointer and do the exchange */ mov ebx, [eax] LOCK cmpxchg8b [ebp] jnz 1b /* Restore registers and return */ 2: pop ebp pop ebx ret /*PSINGLE_LIST_ENTRY *NTAPI *ExInterlockedPushEntrySList(IN PSINGLE_LIST_ENTRY ListHead, * IN PSINGLE_LIST_ENTRY ListEntry, * IN PKSPIN_LOCK Lock) */ .global @ExInterlockedPushEntrySList@12 @ExInterlockedPushEntrySList@12: /* So we can fall through below */ pop [esp] .global @InterlockedPushEntrySList@8 @InterlockedPushEntrySList@8: /* Save registers */ push ebx push ebp /* Pointer to list */ mov ebp, ecx mov ebx, edx /* Get sequence number and link pointer */ mov edx, [ebp+4] mov eax, [ebp] 1: /* Set link pointer */ mov [ebx], eax /* Copy sequence number and adjust it */ lea ecx, [edx+0x10001] /* Do the exchange */ LOCK cmpxchg8b [ebp] jnz 1b /* Restore registers and return */ 2: pop ebp pop ebx ret /*PSINGLE_LIST_ENTRY *NTAPI *ExInterlockedFlushSList(IN PSINGLE_LIST_ENTRY ListHead) */ .global @ExInterlockedFlushSList@4 @ExInterlockedFlushSList@4: /* Save registers */ push ebx push ebp /* Clear ebx */ xor ebx, ebx /* Pointer to list */ mov ebp, ecx /* Get sequence number and link pointer */ mov edx, [ebp+4] mov eax, [ebp] 1: /* Check if the list is empty */ or eax, eax jz 2f /* Clear sequence and pointer */ mov ecx, edx mov cx, bx /* Do the exchange */ LOCK cmpxchg8b [ebp] jnz 1b /* Restore registers and return */ 2: pop ebp pop ebx ret /*INTERLOCKED_RESULT *FASTCALL *Exfi386InterlockedIncrementLong(IN PLONG Addend) */ .global @Exfi386InterlockedIncrementLong@4 @Exfi386InterlockedIncrementLong@4: /* Do the op */ LOCK add dword ptr [ecx], 1 /* Return */ lahf and eax, EFLAG_SELECT ret /*INTERLOCKED_RESULT *FASTCALL *Exfi386InterlockedDecrementLong(IN PLONG Addend) */ .global @Exfi386InterlockedDecrementLong@4 @Exfi386InterlockedDecrementLong@4: /* Do the op */ LOCK sub dword ptr [ecx], 1 /* Return */ lahf and eax, EFLAG_SELECT ret /*ULONG *FASTCALL *Exfi386InterlockedExchangeUlong(IN PULONG Taget, * IN ULONG Value) */ .global @Exfi386InterlockedExchangeUlong@8 .global @InterlockedExchange@8 @InterlockedExchange@8: @Exfi386InterlockedExchangeUlong@8: #ifdef CONFIG_SMP /* On MP, do the exchange */ xchg [ecx], edx mov eax, edx #else /* On UP, use cmpxchg */ mov eax, [ecx] 1: cmpxchg [ecx], edx jnz 1b #endif /* Return */ ret /*ULONG *FASTCALL *InterlockedIncrement(IN PLONG Addend) */ .global @InterlockedIncrement@4 @InterlockedIncrement@4: /* Do the op */ mov eax, 1 LOCK xadd dword ptr [ecx], eax /* Return */ inc eax ret /*ULONG *FASTCALL *InterlockedDecrement(IN PLONG Addend) */ .global @InterlockedDecrement@4 @InterlockedDecrement@4: /* Do the op */ mov eax, -1 LOCK xadd dword ptr [ecx], eax /* Return */ dec eax ret /*PVOID *FASTCALL *InterlockedCompareExchange(IN OUT PVOID *Destination, * IN PVOID Exchange, * IN PVOID Comperand) */ .global @InterlockedCompareExchange@12 @InterlockedCompareExchange@12: /* Get comperand */ mov eax, [esp+4] /* Do the op */ LOCK cmpxchg dword ptr [ecx], edx /* Return */ ret /*PVOID *FASTCALL *ExfInterlockedCompareExchange64(IN PLONGLONG Destination, * IN PLONGLONG Exchange, * IN PLONGLONG Comperand) */ .global @ExfInterlockedCompareExchange64@12 @ExfInterlockedCompareExchange64@12: /* Save registers */ push ebx push ebp /* Get desination pointer, exchange value and comperand value/address */ mov ebp, ecx mov ebx, [edx] mov ecx, [edx+4] mov edx, [esp+12] mov eax, [edx] mov edx, [edx+4] /* Do the op */ LOCK cmpxchg8b [ebp] /* Restore volatiles */ pop ebp pop ebx /* Return */ ret 4 /*PVOID *FASTCALL *ExfInterlockedCompareExchange64(IN PLONGLONG Destination, * IN PLONGLONG Exchange, * IN PLONGLONG Comperand, * IN PKSPIN_LOCK Lock) */ .global @ExInterlockedCompareExchange64@16 @ExInterlockedCompareExchange64@16: /* Save registers */ push ebp push ebp /* Get desination pointer, exchange value and comperand value/address */ mov ebp, ecx mov ebx, [edx] mov ecx, [edx+4] mov edx, [esp+12] mov eax, [edx] mov edx, [edx+4] /* Do the op */ LOCK cmpxchg8b [ebp] /* Restore volatiles */ pop ebp pop ebx /* Return */ ret 8 /*PVOID *FASTCALL *InterlockedExchangeAdd(IN OUT PLONG Addend, * IN LONG Increment) */ .global @InterlockedExchangeAdd@8 @InterlockedExchangeAdd@8: /* Do the op */ LOCK xadd dword ptr [ecx], edx /* Return */ mov eax, edx ret /* EOF */