2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ex/i386/fastinterlck_asm.S
5 * PURPOSE: FASTCALL Interlocked Functions
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
9 /* INCLUDES ******************************************************************/
13 #include <internal/i386/asmmacro.S>
15 /* FUNCTIONS ****************************************************************/
20 * NOTE: These functions must obey the following rules:
21 * - Acquire locks only on MP systems.
22 * - Be safe at HIGH_LEVEL (no paged access).
24 * - Disable interrups.
29 *ExInterlockedAddLargeStatistic(IN PLARGE_INTEGER Addend,
32 PUBLIC @ExInterlockedAddLargeStatistic@8
33 @ExInterlockedAddLargeStatistic@8:
39 /* Check for carry bit and return */
45 lock adc dword ptr [ecx+4], 0
47 /* Do the addition and add the carry */
48 add dword ptr [ecx], edx
49 adc dword ptr [ecx+4], 0
56 *ExfInterlockedAddUlong(IN PULONG Addend,
58 * IN PKSPIN_LOCK Lock)
60 PUBLIC @ExfInterlockedAddUlong@12
61 @ExfInterlockedAddUlong@12:
67 /* Get lock address */
71 /* Disable interrupts */
75 ACQUIRE_SPINLOCK(eax, .spin1)
82 /* Get spinlock address and release it */
87 /* Restore flags and return */
93 /* Restore flags and spin */
96 SPIN_ON_LOCK(eax, .start1)
101 *ExfInterlockedInsertHeadList(IN PLIST_ENTRY ListHead,
102 * IN PLIST_ENTRY ListEntry,
103 * IN PKSPIN_LOCK Lock)
105 PUBLIC @ExfInterlockedInsertHeadList@12
106 @ExfInterlockedInsertHeadList@12:
109 /* Save lock address */
114 /* Save flags and disable interrupts */
120 ACQUIRE_SPINLOCK(esi, .spin2)
122 /* Get list pointer */
131 /* Release lock and restore flags */
132 RELEASE_SPINLOCK(esi)
139 /* Check if list was empty */
143 /* Return list pointer */
152 SPIN_ON_LOCK(esi, .start2)
157 *ExfInterlockedInsertTailList(IN PLIST_ENTRY ListHead,
158 * IN PLIST_ENTRY ListEntry,
159 * IN PKSPIN_LOCK Lock)
161 PUBLIC @ExfInterlockedInsertTailList@12
162 @ExfInterlockedInsertTailList@12:
165 /* Save lock address */
170 /* Save flags and disable interrupts */
176 ACQUIRE_SPINLOCK(esi, .spin3)
178 /* Get list pointer */
187 /* Release lock and restore flags */
188 RELEASE_SPINLOCK(esi)
195 /* Check if list was empty */
199 /* Return list pointer */
208 SPIN_ON_LOCK(esi, .start3)
213 *ExfInterlockedRemoveHeadList(IN PLIST_ENTRY ListHead,
214 * IN PKSPIN_LOCK Lock)
216 PUBLIC @ExfInterlockedRemoveHeadList@8
217 @ExfInterlockedRemoveHeadList@8:
219 /* Save flags and disable interrupts */
223 ACQUIRE_SPINLOCK(edx, .spin4)
225 /* Get list pointer */
228 /* Check if it's empty */
232 /* Get the next entry and do the deletion */
246 RELEASE_SPINLOCK(edx)
258 RELEASE_SPINLOCK(edx)
263 /* Return empty list */
270 SPIN_ON_LOCK(edx, .start4)
275 *ExfInterlockedPopEntryList(IN PSINGLE_LIST_ENTRY ListHead,
276 * IN PKSPIN_LOCK Lock)
278 PUBLIC @ExfInterlockedPopEntryList@8
279 @ExfInterlockedPopEntryList@8:
281 /* Save flags and disable interrupts */
285 ACQUIRE_SPINLOCK(edx, .spin5)
287 /* Get list pointer */
290 /* Check if it's empty */
294 /* Get next entry and do deletion */
306 RELEASE_SPINLOCK(edx)
315 /* Return empty list */
322 SPIN_ON_LOCK(edx, .start5)
327 *ExfInterlockedPushEntryList(IN PSINGLE_LIST_ENTRY ListHead,
328 * IN PSINGLE_LIST_ENTRY ListEntry,
329 * IN PKSPIN_LOCK Lock)
331 PUBLIC @ExfInterlockedPushEntryList@12
332 @ExfInterlockedPushEntryList@12:
337 /* Save lock pointer */
343 /* Disable interrupts */
347 ACQUIRE_SPINLOCK(edx, .spin6)
351 /* Get list pointer */
361 RELEASE_SPINLOCK(edx)
377 SPIN_ON_LOCK(edx, .start6)
382 *ExInterlockedPopEntrySList(IN PSINGLE_LIST_ENTRY ListHead,
383 * IN PKSPIN_LOCK Lock)
385 PUBLIC @ExInterlockedPopEntrySList@8
386 PUBLIC @InterlockedPopEntrySList@4
387 PUBLIC _ExpInterlockedPopEntrySListResume@0
388 PUBLIC _ExpInterlockedPopEntrySListFault@0
389 PUBLIC _ExpInterlockedPopEntrySListEnd@0
390 @ExInterlockedPopEntrySList@8:
391 @InterlockedPopEntrySList@4:
397 /* Pointer to list */
400 /* Get sequence number and link pointer */
401 _ExpInterlockedPopEntrySListResume@0:
405 /* Check if the list is empty */
409 /* Copy sequence number and adjust it */
412 /* Get next pointer and do the exchange */
413 _ExpInterlockedPopEntrySListFault@0:
415 _ExpInterlockedPopEntrySListEnd@0:
416 LOCK cmpxchg8b qword ptr [ebp]
417 jnz _ExpInterlockedPopEntrySListResume@0
419 /* Restore registers and return */
427 *ExInterlockedPushEntrySList(IN PSINGLE_LIST_ENTRY ListHead,
428 * IN PSINGLE_LIST_ENTRY ListEntry,
429 * IN PKSPIN_LOCK Lock)
431 PUBLIC @ExInterlockedPushEntrySList@12
432 @ExInterlockedPushEntrySList@12:
434 /* So we can fall through below */
437 PUBLIC @InterlockedPushEntrySList@8
438 @InterlockedPushEntrySList@8:
444 /* Pointer to list */
448 /* Get sequence number and link pointer */
453 /* Set link pointer */
456 /* Copy sequence number and adjust it */
457 lea ecx, [edx + HEX(10001)]
459 /* Do the exchange */
460 LOCK cmpxchg8b qword ptr [ebp]
463 /* Restore registers and return */
470 *ExInterlockedFlushSList(IN PSINGLE_LIST_ENTRY ListHead)
472 PUBLIC @ExInterlockedFlushSList@4
473 @ExInterlockedFlushSList@4:
482 /* Pointer to list */
485 /* Get sequence number and link pointer */
490 /* Check if the list is empty */
494 /* Clear sequence and pointer */
498 /* Do the exchange */
499 LOCK cmpxchg8b qword ptr [ebp]
502 /* Restore registers and return */
510 *Exfi386InterlockedIncrementLong(IN PLONG Addend)
512 PUBLIC @Exfi386InterlockedIncrementLong@4
513 @Exfi386InterlockedIncrementLong@4:
516 LOCK add dword ptr [ecx], 1
520 and eax, EFLAG_SELECT
525 *Exfi386InterlockedDecrementLong(IN PLONG Addend)
527 PUBLIC @Exfi386InterlockedDecrementLong@4
528 @Exfi386InterlockedDecrementLong@4:
531 LOCK sub dword ptr [ecx], 1
535 and eax, EFLAG_SELECT
540 *Exfi386InterlockedExchangeUlong(IN PULONG Taget,
543 PUBLIC @Exfi386InterlockedExchangeUlong@8
544 @Exfi386InterlockedExchangeUlong@8:
547 /* On MP, do the exchange */
551 /* On UP, use cmpxchg */
563 *ExfInterlockedCompareExchange64(IN PLONGLONG Destination,
564 * IN PLONGLONG Exchange,
565 * IN PLONGLONG Comperand)
567 PUBLIC @ExfInterlockedCompareExchange64@12
568 @ExfInterlockedCompareExchange64@12:
574 /* Get destination pointer, exchange value and comperand value/address */
583 LOCK cmpxchg8b qword ptr [ebp]
585 /* Restore volatiles */
594 *ExfInterlockedCompareExchange64(IN PLONGLONG Destination,
595 * IN PLONGLONG Exchange,
596 * IN PLONGLONG Comperand,
597 * IN PKSPIN_LOCK Lock)
599 PUBLIC @ExInterlockedCompareExchange64@16
600 @ExInterlockedCompareExchange64@16:
606 /* Get destination pointer, exchange value and comperand value/address */
615 LOCK cmpxchg8b qword ptr [ebp]
617 /* Restore volatiles */
624 /*** Non-586 functions ***/
628 *ExfInterlockedPopEntrySList(IN PSINGLE_LIST_ENTRY ListHead,
629 * IN PKSPIN_LOCK Lock)
631 PUBLIC @ExfInterlockedPopEntrySList@8
632 @ExfInterlockedPopEntrySList@8:
638 /* Disable interrupts */
642 ACQUIRE_SPINLOCK(edx, .spina)
644 /* Get the next link and check if it's empty */
649 /* Get address of the next link and store it */
653 /* Decrement list depth */
654 dec dword ptr [ecx+4]
658 /* Release spinlock */
659 RELEASE_SPINLOCK(edx)
662 /* Restore flags and return */
668 /* Restore flags and spin */
670 SPIN_ON_LOCK(edx, .starta)
675 *ExfInterlockedPushEntrySList(IN PSINGLE_LIST_ENTRY ListHead,
676 * IN PSINGLE_LIST_ENTRY ListEntry,
677 * IN PKSPIN_LOCK Lock)
679 PUBLIC @ExfInterlockedPushEntrySList@12
680 @ExfInterlockedPushEntrySList@12:
686 /* Disable interrupts */
692 ACQUIRE_SPINLOCK(eax, .spinb)
695 /* Get the next link and check if it's empty */
698 /* Get address of the next link and store it */
702 /* Increment list depth */
703 inc dword ptr [ecx+4]
706 /* Release spinlock */
707 RELEASE_SPINLOCK(eax)
710 /* Restore flags and return */
716 /* Restore flags and spin */
718 SPIN_ON_LOCK(eax, .startb)
723 *ExpInterlockedCompareExchange64(IN PLONGLONG Destination,
724 * IN PLONGLONG Exchange,
725 * IN PLONGLONG Comperand,
726 * IN PKSPIN_LOCK Lock)
728 PUBLIC @ExpInterlockedCompareExchange64@16
729 @ExpInterlockedCompareExchange64@16:
735 /* Get destination pointer, exchange value and comperand value/address */
744 /* Save ESI so we can store KSPINLOCK in it */
747 /* Save flags and lock, and disable interrupts */
753 /* Acquire the spinlock */
754 ACQUIRE_SPINLOCK(esi, .spinc)
756 /* Save flags and disable interrupts */
775 /* Release lock, restore volatiles and flags */
776 RELEASE_SPINLOCK(esi)
783 /* Restore the other volatiles and return */
791 /* Return the current value */
798 /* Restore flags and spin */
801 SPIN_ON_LOCK(esi, .startc)