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 ******************************************************************/
11 #include <reactos/asm.h>
13 #include <internal/i386/asmmacro.S>
15 /* FUNCTIONS ****************************************************************/
21 * NOTE: These functions must obey the following rules:
22 * - Acquire locks only on MP systems.
23 * - Be safe at HIGH_LEVEL (no paged access).
25 * - Disable interrups.
30 *ExInterlockedAddLargeStatistic(IN PLARGE_INTEGER Addend,
33 .global @ExInterlockedAddLargeStatistic@8
34 @ExInterlockedAddLargeStatistic@8:
40 /* Check for carry bit and return */
46 lock adc dword ptr [ecx+4], 0
48 /* Do the addition and add the carry */
49 add dword ptr [ecx], edx
50 adc dword ptr [ecx+4], 0
57 *ExfInterlockedAddUlong(IN PULONG Addend,
59 * IN PKSPIN_LOCK Lock)
61 .global @ExfInterlockedAddUlong@12
62 @ExfInterlockedAddUlong@12:
68 /* Get lock address */
72 /* Disable interrupts */
76 ACQUIRE_SPINLOCK(eax, .spin1)
83 /* Get spinlock address and release it */
88 /* Restore flags and return */
94 /* Restore flags and spin */
97 SPIN_ON_LOCK(eax, .start1)
102 *ExfInterlockedInsertHeadList(IN PLIST_ENTRY ListHead,
103 * IN PLIST_ENTRY ListEntry,
104 * IN PKSPIN_LOCK Lock)
106 .global @ExfInterlockedInsertHeadList@12
107 @ExfInterlockedInsertHeadList@12:
110 /* Save lock address */
115 /* Save flags and disable interrupts */
121 ACQUIRE_SPINLOCK(esi, .spin2)
123 /* Get list pointer */
132 /* Release lock and restore flags */
133 RELEASE_SPINLOCK(esi)
140 /* Check if list was empty */
144 /* Return list pointer */
153 SPIN_ON_LOCK(esi, .start2)
158 *ExfInterlockedInsertTailList(IN PLIST_ENTRY ListHead,
159 * IN PLIST_ENTRY ListEntry,
160 * IN PKSPIN_LOCK Lock)
162 .global @ExfInterlockedInsertTailList@12
163 @ExfInterlockedInsertTailList@12:
166 /* Save lock address */
171 /* Save flags and disable interrupts */
177 ACQUIRE_SPINLOCK(esi, .spin3)
179 /* Get list pointer */
188 /* Release lock and restore flags */
189 RELEASE_SPINLOCK(esi)
196 /* Check if list was empty */
200 /* Return list pointer */
209 SPIN_ON_LOCK(esi, .start3)
214 *ExfInterlockedRemoveHeadList(IN PLIST_ENTRY ListHead,
215 * IN PKSPIN_LOCK Lock)
217 .global @ExfInterlockedRemoveHeadList@8
218 @ExfInterlockedRemoveHeadList@8:
220 /* Save flags and disable interrupts */
224 ACQUIRE_SPINLOCK(edx, .spin4)
226 /* Get list pointer */
229 /* Check if it's empty */
233 /* Get the next entry and do the deletion */
247 RELEASE_SPINLOCK(edx)
259 RELEASE_SPINLOCK(edx)
264 /* Return empty list */
271 SPIN_ON_LOCK(edx, .start4)
276 *ExfInterlockedPopEntryList(IN PSINGLE_LIST_ENTRY ListHead,
277 * IN PKSPIN_LOCK Lock)
279 .global @ExfInterlockedPopEntryList@8
280 @ExfInterlockedPopEntryList@8:
282 /* Save flags and disable interrupts */
286 ACQUIRE_SPINLOCK(edx, .spin5)
288 /* Get list pointer */
291 /* Check if it's empty */
295 /* Get next entry and do deletion */
307 RELEASE_SPINLOCK(edx)
316 /* Return empty list */
323 SPIN_ON_LOCK(edx, .start5)
328 *ExfInterlockedPushEntryList(IN PSINGLE_LIST_ENTRY ListHead,
329 * IN PSINGLE_LIST_ENTRY ListEntry,
330 * IN PKSPIN_LOCK Lock)
332 .global @ExfInterlockedPushEntryList@12
333 @ExfInterlockedPushEntryList@12:
338 /* Save lock pointer */
344 /* Disable interrupts */
348 ACQUIRE_SPINLOCK(edx, .spin6)
352 /* Get list pointer */
362 RELEASE_SPINLOCK(edx)
378 SPIN_ON_LOCK(edx, .start6)
383 *ExInterlockedPopEntrySList(IN PSINGLE_LIST_ENTRY ListHead,
384 * IN PKSPIN_LOCK Lock)
386 .global @ExInterlockedPopEntrySList@8
387 .global @InterlockedPopEntrySList@4
388 .global _ExpInterlockedPopEntrySListResume@0
389 .global _ExpInterlockedPopEntrySListFault@0
390 .global _ExpInterlockedPopEntrySListEnd@0
391 @ExInterlockedPopEntrySList@8:
392 @InterlockedPopEntrySList@4:
398 /* Pointer to list */
401 /* Get sequence number and link pointer */
402 _ExpInterlockedPopEntrySListResume@0:
406 /* Check if the list is empty */
410 /* Copy sequence number and adjust it */
413 /* Get next pointer and do the exchange */
414 _ExpInterlockedPopEntrySListFault@0:
416 _ExpInterlockedPopEntrySListEnd@0:
417 LOCK cmpxchg8b qword ptr [ebp]
418 jnz _ExpInterlockedPopEntrySListResume@0
420 /* Restore registers and return */
428 *ExInterlockedPushEntrySList(IN PSINGLE_LIST_ENTRY ListHead,
429 * IN PSINGLE_LIST_ENTRY ListEntry,
430 * IN PKSPIN_LOCK Lock)
432 .global @ExInterlockedPushEntrySList@12
433 @ExInterlockedPushEntrySList@12:
435 /* So we can fall through below */
438 .global @InterlockedPushEntrySList@8
439 @InterlockedPushEntrySList@8:
445 /* Pointer to list */
449 /* Get sequence number and link pointer */
454 /* Set link pointer */
457 /* Copy sequence number and adjust it */
458 lea ecx, [edx+0x10001]
460 /* Do the exchange */
461 LOCK cmpxchg8b qword ptr [ebp]
464 /* Restore registers and return */
472 *ExInterlockedFlushSList(IN PSINGLE_LIST_ENTRY ListHead)
474 .global @ExInterlockedFlushSList@4
475 @ExInterlockedFlushSList@4:
484 /* Pointer to list */
487 /* Get sequence number and link pointer */
492 /* Check if the list is empty */
496 /* Clear sequence and pointer */
500 /* Do the exchange */
501 LOCK cmpxchg8b qword ptr [ebp]
504 /* Restore registers and return */
512 *Exfi386InterlockedIncrementLong(IN PLONG Addend)
514 .global @Exfi386InterlockedIncrementLong@4
515 @Exfi386InterlockedIncrementLong@4:
518 LOCK add dword ptr [ecx], 1
522 and eax, EFLAG_SELECT
527 *Exfi386InterlockedDecrementLong(IN PLONG Addend)
529 .global @Exfi386InterlockedDecrementLong@4
530 @Exfi386InterlockedDecrementLong@4:
533 LOCK sub dword ptr [ecx], 1
537 and eax, EFLAG_SELECT
542 *Exfi386InterlockedExchangeUlong(IN PULONG Taget,
545 .global @Exfi386InterlockedExchangeUlong@8
546 @Exfi386InterlockedExchangeUlong@8:
549 /* On MP, do the exchange */
553 /* On UP, use cmpxchg */
565 *ExfInterlockedCompareExchange64(IN PLONGLONG Destination,
566 * IN PLONGLONG Exchange,
567 * IN PLONGLONG Comperand)
569 .global @ExfInterlockedCompareExchange64@12
570 @ExfInterlockedCompareExchange64@12:
576 /* Get destination pointer, exchange value and comperand value/address */
585 LOCK cmpxchg8b qword ptr [ebp]
587 /* Restore volatiles */
596 *ExfInterlockedCompareExchange64(IN PLONGLONG Destination,
597 * IN PLONGLONG Exchange,
598 * IN PLONGLONG Comperand,
599 * IN PKSPIN_LOCK Lock)
601 .global @ExInterlockedCompareExchange64@16
602 @ExInterlockedCompareExchange64@16:
608 /* Get destination pointer, exchange value and comperand value/address */
617 LOCK cmpxchg8b qword ptr [ebp]
619 /* Restore volatiles */
626 /*** Non-586 functions ***/
630 *ExfInterlockedPopEntrySList(IN PSINGLE_LIST_ENTRY ListHead,
631 * IN PKSPIN_LOCK Lock)
633 .global @ExfInterlockedPopEntrySList@8
634 @ExfInterlockedPopEntrySList@8:
640 /* Disable interrupts */
644 ACQUIRE_SPINLOCK(edx, .spina)
646 /* Get the next link and check if it's empty */
651 /* Get address of the next link and store it */
655 /* Decrement list depth */
656 dec dword ptr [ecx+4]
660 /* Release spinlock */
661 RELEASE_SPINLOCK(edx)
664 /* Restore flags and return */
670 /* Restore flags and spin */
672 SPIN_ON_LOCK(edx, .starta)
677 *ExfInterlockedPushEntrySList(IN PSINGLE_LIST_ENTRY ListHead,
678 * IN PSINGLE_LIST_ENTRY ListEntry,
679 * IN PKSPIN_LOCK Lock)
681 .global @ExfInterlockedPushEntrySList@12
682 @ExfInterlockedPushEntrySList@12:
688 /* Disable interrupts */
694 ACQUIRE_SPINLOCK(eax, .spinb)
697 /* Get the next link and check if it's empty */
700 /* Get address of the next link and store it */
704 /* Increment list depth */
705 inc dword ptr [ecx+4]
708 /* Release spinlock */
709 RELEASE_SPINLOCK(eax)
712 /* Restore flags and return */
718 /* Restore flags and spin */
720 SPIN_ON_LOCK(eax, .startb)
725 *ExpInterlockedCompareExchange64(IN PLONGLONG Destination,
726 * IN PLONGLONG Exchange,
727 * IN PLONGLONG Comperand,
728 * IN PKSPIN_LOCK Lock)
730 .global @ExpInterlockedCompareExchange64@16
731 @ExpInterlockedCompareExchange64@16:
737 /* Get destination pointer, exchange value and comperand value/address */
746 /* Save ESI so we can store KSPINLOCK in it */
749 /* Save flags and lock, and disable interrupts */
755 /* Acquire the spinlock */
756 ACQUIRE_SPINLOCK(esi, .spinc)
758 /* Save flags and disable interrupts */
777 /* Release lock, restore volatiles and flags */
778 RELEASE_SPINLOCK(esi)
785 /* Restore the other volatiles and return */
793 /* Return the current value */
800 /* Restore flags and spin */
803 SPIN_ON_LOCK(esi, .startc)