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 <internal/i386/asmmacro.S>
12 .intel_syntax noprefix
14 /* FUNCTIONS ****************************************************************/
17 * NOTE: These functions must obey the following rules:
18 * - Acquire locks only on MP systems.
19 * - Be safe at HIGH_LEVEL (no paged access).
21 * - Disable interrups.
26 *ExInterlockedAddLargeStatistic(IN PLARGE_INTEGER Addend,
29 .global @ExInterlockedAddLargeStatistic@8
30 @ExInterlockedAddLargeStatistic@8:
36 /* Check for carry bit and return */
42 lock adc dword ptr [ecx+4], 0
44 /* Do the addition and add the carry */
45 add dword ptr [ecx], edx
46 adc dword ptr [ecx+4], 0
53 *ExfInterlockedAddUlong(IN PULONG Addend,
55 * IN PKSPIN_LOCK Lock)
57 .global @ExfInterlockedAddUlong@12
58 @ExfInterlockedAddUlong@12:
64 /* Get lock address */
68 /* Disable interrupts */
72 ACQUIRE_SPINLOCK(eax, .spin1)
79 /* Get spinlock address and release it */
84 /* Restore flags and return */
90 /* Restore flags and spin */
93 SPIN_ON_LOCK(eax, .start1)
98 *ExfInterlockedInsertHeadList(IN PLIST_ENTRY ListHead,
99 * IN PLIST_ENTRY ListEntry,
100 * IN PKSPIN_LOCK Lock)
102 .global @ExfInterlockedInsertHeadList@12
103 @ExfInterlockedInsertHeadList@12:
106 /* Save lock address */
111 /* Save flags and disable interrupts */
117 ACQUIRE_SPINLOCK(esi, .spin2)
119 /* Get list pointer */
128 /* Release lock and restore flags */
129 RELEASE_SPINLOCK(esi)
136 /* Check if list was empty */
140 /* Return list pointer */
149 SPIN_ON_LOCK(esi, .start2)
154 *ExfInterlockedInsertTailList(IN PLIST_ENTRY ListHead,
155 * IN PLIST_ENTRY ListEntry,
156 * IN PKSPIN_LOCK Lock)
158 .global @ExfInterlockedInsertTailList@12
159 @ExfInterlockedInsertTailList@12:
162 /* Save lock address */
167 /* Save flags and disable interrupts */
173 ACQUIRE_SPINLOCK(esi, .spin3)
175 /* Get list pointer */
184 /* Release lock and restore flags */
185 RELEASE_SPINLOCK(esi)
192 /* Check if list was empty */
196 /* Return list pointer */
205 SPIN_ON_LOCK(esi, .start3)
210 *ExfInterlockedRemoveHeadList(IN PLIST_ENTRY ListHead,
211 * IN PKSPIN_LOCK Lock)
213 .global @ExfInterlockedRemoveHeadList@8
214 @ExfInterlockedRemoveHeadList@8:
216 /* Save flags and disable interrupts */
220 ACQUIRE_SPINLOCK(edx, .spin4)
222 /* Get list pointer */
225 /* Check if it's empty */
229 /* Get the next entry and do the deletion */
243 RELEASE_SPINLOCK(edx)
255 RELEASE_SPINLOCK(edx)
260 /* Return empty list */
267 SPIN_ON_LOCK(edx, .start4)
272 *ExfInterlockedPopEntryList(IN PSINGLE_LIST_ENTRY ListHead,
273 * IN PKSPIN_LOCK Lock)
275 .global @ExfInterlockedPopEntryList@8
276 @ExfInterlockedPopEntryList@8:
278 /* Save flags and disable interrupts */
282 ACQUIRE_SPINLOCK(edx, .spin5)
284 /* Get list pointer */
287 /* Check if it's empty */
291 /* Get next entry and do deletion */
303 RELEASE_SPINLOCK(edx)
312 /* Return empty list */
319 SPIN_ON_LOCK(edx, .start5)
324 *ExfInterlockedPushEntryList(IN PSINGLE_LIST_ENTRY ListHead,
325 * IN PSINGLE_LIST_ENTRY ListEntry,
326 * IN PKSPIN_LOCK Lock)
328 .global @ExfInterlockedPushEntryList@12
329 @ExfInterlockedPushEntryList@12:
334 /* Save lock pointer */
340 /* Disable interrupts */
344 ACQUIRE_SPINLOCK(edx, .spin6)
348 /* Get list pointer */
358 RELEASE_SPINLOCK(edx)
374 SPIN_ON_LOCK(edx, .start6)
379 *ExInterlockedPopEntrySList(IN PSINGLE_LIST_ENTRY ListHead,
380 * IN PKSPIN_LOCK Lock)
382 .global @ExInterlockedPopEntrySList@8
383 .global @InterlockedPopEntrySList@4
384 .global _ExpInterlockedPopEntrySListResume@0
385 .global _ExpInterlockedPopEntrySListFault@0
386 .global _ExpInterlockedPopEntrySListEnd@0
387 @ExInterlockedPopEntrySList@8:
388 @InterlockedPopEntrySList@4:
394 /* Pointer to list */
397 /* Get sequence number and link pointer */
398 _ExpInterlockedPopEntrySListResume@0:
402 /* Check if the list is empty */
406 /* Copy sequence number and adjust it */
409 /* Get next pointer and do the exchange */
410 _ExpInterlockedPopEntrySListFault@0:
412 _ExpInterlockedPopEntrySListEnd@0:
414 jnz _ExpInterlockedPopEntrySListResume@0
416 /* Restore registers and return */
424 *ExInterlockedPushEntrySList(IN PSINGLE_LIST_ENTRY ListHead,
425 * IN PSINGLE_LIST_ENTRY ListEntry,
426 * IN PKSPIN_LOCK Lock)
428 .global @ExInterlockedPushEntrySList@12
429 @ExInterlockedPushEntrySList@12:
431 /* So we can fall through below */
434 .global @InterlockedPushEntrySList@8
435 @InterlockedPushEntrySList@8:
441 /* Pointer to list */
445 /* Get sequence number and link pointer */
450 /* Set link pointer */
453 /* Copy sequence number and adjust it */
454 lea ecx, [edx+0x10001]
456 /* Do the exchange */
460 /* Restore registers and return */
468 *ExInterlockedFlushSList(IN PSINGLE_LIST_ENTRY ListHead)
470 .global @ExInterlockedFlushSList@4
471 @ExInterlockedFlushSList@4:
480 /* Pointer to list */
483 /* Get sequence number and link pointer */
488 /* Check if the list is empty */
492 /* Clear sequence and pointer */
496 /* Do the exchange */
500 /* Restore registers and return */
508 *Exfi386InterlockedIncrementLong(IN PLONG Addend)
510 .global @Exfi386InterlockedIncrementLong@4
511 @Exfi386InterlockedIncrementLong@4:
514 LOCK add dword ptr [ecx], 1
518 and eax, EFLAG_SELECT
523 *Exfi386InterlockedDecrementLong(IN PLONG Addend)
525 .global @Exfi386InterlockedDecrementLong@4
526 @Exfi386InterlockedDecrementLong@4:
529 LOCK sub dword ptr [ecx], 1
533 and eax, EFLAG_SELECT
538 *Exfi386InterlockedExchangeUlong(IN PULONG Taget,
541 .global @Exfi386InterlockedExchangeUlong@8
542 @Exfi386InterlockedExchangeUlong@8:
545 /* On MP, do the exchange */
549 /* On UP, use cmpxchg */
561 *ExfInterlockedCompareExchange64(IN PLONGLONG Destination,
562 * IN PLONGLONG Exchange,
563 * IN PLONGLONG Comperand)
565 .global @ExfInterlockedCompareExchange64@12
566 @ExfInterlockedCompareExchange64@12:
572 /* Get destination pointer, exchange value and comperand value/address */
583 /* Restore volatiles */
592 *ExfInterlockedCompareExchange64(IN PLONGLONG Destination,
593 * IN PLONGLONG Exchange,
594 * IN PLONGLONG Comperand,
595 * IN PKSPIN_LOCK Lock)
597 .global @ExInterlockedCompareExchange64@16
598 @ExInterlockedCompareExchange64@16:
604 /* Get destination pointer, exchange value and comperand value/address */
615 /* Restore volatiles */
622 /*** Non-586 functions ***/
626 *ExfInterlockedPopEntrySList(IN PSINGLE_LIST_ENTRY ListHead,
627 * IN PKSPIN_LOCK Lock)
629 .global @ExfInterlockedPopEntrySList@8
630 @ExfInterlockedPopEntrySList@8:
636 /* Disable interrupts */
640 ACQUIRE_SPINLOCK(edx, .spina)
642 /* Get the next link and check if it's empty */
647 /* Get address of the next link and store it */
651 /* Decrement list depth */
652 dec dword ptr [ecx+4]
656 /* Release spinlock */
657 RELEASE_SPINLOCK(edx)
660 /* Restore flags and return */
666 /* Restore flags and spin */
668 SPIN_ON_LOCK(edx, .starta)
673 *ExfInterlockedPushEntrySList(IN PSINGLE_LIST_ENTRY ListHead,
674 * IN PSINGLE_LIST_ENTRY ListEntry,
675 * IN PKSPIN_LOCK Lock)
677 .global @ExfInterlockedPushEntrySList@12
678 @ExfInterlockedPushEntrySList@12:
684 /* Disable interrupts */
690 ACQUIRE_SPINLOCK(eax, .spinb)
693 /* Get the next link and check if it's empty */
696 /* Get address of the next link and store it */
700 /* Increment list depth */
701 inc dword ptr [ecx+4]
704 /* Release spinlock */
705 RELEASE_SPINLOCK(eax)
708 /* Restore flags and return */
714 /* Restore flags and spin */
716 SPIN_ON_LOCK(eax, .startb)
721 *ExpInterlockedCompareExchange64(IN PLONGLONG Destination,
722 * IN PLONGLONG Exchange,
723 * IN PLONGLONG Comperand,
724 * IN PKSPIN_LOCK Lock)
726 .global @ExpInterlockedCompareExchange64@16
727 @ExpInterlockedCompareExchange64@16:
733 /* Get destination pointer, exchange value and comperand value/address */
742 /* Save ESI so we can store KSPINLOCK in it */
745 /* Save flags and lock, and disable interrupts */
751 /* Acquire the spinlock */
752 ACQUIRE_SPINLOCK(esi, .spinc)
754 /* Save flags and disable interrupts */
773 /* Release lock, restore volatiles and flags */
774 RELEASE_SPINLOCK(esi)
781 /* Restore the other volatiles and return */
789 /* Return the current value */
796 /* Restore flags and spin */
799 SPIN_ON_LOCK(esi, .startc)