~ubuntu-branches/ubuntu/quantal/open-vm-tools/quantal-201210021442

« back to all changes in this revision

Viewing changes to lib/include/vm_atomic.h

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn
  • Date: 2011-03-31 14:20:05 UTC
  • mfrom: (1.4.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20110331142005-3n9red91p7ogkweo
Tags: 2011.03.28-387002-0ubuntu1
* Merge latest upstream git tag.  This has the unlocked_ioctl change
  needed to fix dkms build failures (LP: #727342)
* Changes in debian/rules:
  - work around a bug in toolbox/Makefile, where install-exec-hook is
    not happening.  This needs to get fixed the right way.
  - don't install 'vmware-user' which seems to no longer exist
  - move /etc/xdg into open-vm-toolbox (which should be done using .install)
* debian/open-vm-tools.init: add 'modprobe [-r] vmblock'. (LP: #332323)
* debian/rules and debian/open-vm-toolbox.lintian-overrides:
  - Make vmware-user-suid-wrapper suid-root (LP: #332323)

Show diffs side-by-side

added added

removed removed

Lines of Context:
65
65
   volatile uint64 value;
66
66
} Atomic_uint64 ALIGNED(8);
67
67
 
68
 
#ifdef __arm__
69
 
#ifdef __GNUC__
70
 
EXTERN Atomic_uint32 atomicLocked64bit;
71
 
#ifndef FAKE_ATOMIC
72
 
   /*
73
 
    * Definitions for kernel function call which attempts an
74
 
    * atomic exchange, returning 0 only upon success.
75
 
    * The code actually called is put in memory by the kernel,
76
 
    * and is in fact what the kernel uses for this atomic
77
 
    * instruction.  This does not work for Linux versions
78
 
    * before 2.6 or (obviously) for non-Linux implementations.
79
 
    * For other implementations on ARMv6 and up, use
80
 
    * LDREX/SUBS/STREXEQ/LDRNE/ADDS/BNE spin-lock; for pre-ARMv6,
81
 
    * use SWP-based spin-lock.
82
 
    */
83
 
#if !defined(__linux__)
84
 
#define __kernel_cmpxchg(x, y, z) _fn__kernel_cmpxchgNotImplementedOnNonLinuxARM
85
 
#else
86
 
   typedef int (__kernel_cmpxchg_t)(uint32 oldVal,
87
 
                                    uint32 newVal,
88
 
                                    volatile uint32 *mem);
89
 
#define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0)
90
 
#endif
91
 
#endif // FAKE_ATOMIC
92
 
#endif // __GNUC__
93
 
#endif // __arm__
94
68
 
95
69
/*
96
70
 * Prototypes for msft atomics.  These are defined & inlined by the
99
73
 * have to use these.  Unfortunately, we still have to use some inline asm
100
74
 * for the 32 bit code since the and/or/xor implementations didn't show up
101
75
 * untill xp or 2k3.
102
 
 * 
 
76
 *
103
77
 * The declarations for the intrinsic functions were taken from ntddk.h
104
78
 * in the DDK. The declarations must match otherwise the 64-bit c++
105
79
 * compiler will complain about second linkage of the intrinsic functions.
106
 
 * We define the intrinsic using the basic types corresponding to the 
 
80
 * We define the intrinsic using the basic types corresponding to the
107
81
 * Windows typedefs. This avoids having to include windows header files
108
82
 * to get to the windows types.
109
83
 */
147
121
#endif
148
122
#endif /* _MSC_VER */
149
123
 
 
124
#ifdef __arm__
 
125
#   if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) ||  \
 
126
       defined(__ARM_ARCH_7R__)|| defined(__ARM_ARCH_7M__)
 
127
#      define VM_ARM_V7
 
128
#   else
 
129
#     error Only ARMv7 extends the synchronization primitives ldrex/strex.   \
 
130
            For the lower ARM version, please implement the atomic functions \
 
131
            by kernel APIs.
 
132
#   endif
 
133
#endif
 
134
 
 
135
/* Data Memory Barrier */
 
136
#ifdef VM_ARM_V7
 
137
#define dmb() __asm__ __volatile__("dmb" : : : "memory")
 
138
#endif
 
139
 
150
140
 
151
141
/* Convert a volatile uint32 to Atomic_uint32. */
152
142
static INLINE Atomic_uint32 *
178
168
 *
179
169
 *      Atomic_SetFence sets AtomicUseFence to the given value.
180
170
 *
181
 
 *      Atomic_Init computes and sets AtomicUseFence.
 
171
 *      Atomic_Init computes and sets AtomicUseFence for x86.
182
172
 *      It does not take into account the number of processors.
183
173
 *
184
174
 *      The rationale for all this complexity is that Atomic_Init
367
357
Atomic_ReadWrite(Atomic_uint32 *var, // IN
368
358
                 uint32 val)         // IN
369
359
{
370
 
#ifdef FAKE_ATOMIC
371
 
   uint32 retval = var->value;
372
 
   var->value = val;
373
 
   return retval;
374
 
#elif defined(__GNUC__)
375
 
#ifdef __arm__
376
 
   register uint32 retval;
377
 
   register volatile uint32 *mem = &(var->value);
378
 
   /* XXX - ARMv5 only: for ARMv6, use LDREX/STREX/CMP/BEQ spin-lock */
379
 
   __asm__ __volatile__("swp %0, %1, [%2]"
380
 
                        : "=&r,&r" (retval)
381
 
                        : "r,0" (val), "r,r" (mem) : "memory");
382
 
   return retval;
383
 
#else // __arm__ (assume x86*)
 
360
#ifdef __GNUC__
 
361
#ifdef VM_ARM_V7
 
362
   register volatile uint32 retVal;
 
363
   register volatile uint32 res;
 
364
 
 
365
   dmb();
 
366
 
 
367
   __asm__ __volatile__(
 
368
   "1: ldrex %[retVal], [%[var]] \n\t"
 
369
      "strex %[res], %[val], [%[var]] \n\t"
 
370
      "teq %[res], #0 \n\t"
 
371
      "bne 1b"
 
372
      : [retVal] "=&r" (retVal), [res] "=&r" (res)
 
373
      : [var] "r" (&var->value), [val] "r" (val)
 
374
      : "memory", "cc"
 
375
   );
 
376
 
 
377
   dmb();
 
378
 
 
379
   return retVal;
 
380
#else // __VM_ARM_V7 (assume x86*)
384
381
   /* Checked against the Intel manual and GCC --walken */
385
382
   __asm__ __volatile__(
386
383
      "xchgl %0, %1"
387
 
#   if VM_ASM_PLUS
388
384
      : "=r" (val),
389
385
        "+m" (var->value)
390
386
      : "0" (val)
391
 
#   else
392
 
      : "=r" (val),
393
 
        "=m" (var->value)
394
 
      : "0" (val),
395
 
        "1" (var->value)
396
 
#   endif
397
387
   );
398
388
   AtomicEpilogue();
399
389
   return val;
400
 
#endif // __arm__
 
390
#endif // VM_ARM_V7
401
391
#elif defined _MSC_VER
402
392
#if _MSC_VER >= 1310
403
393
   return _InterlockedExchange((long *)&var->value, (long)val);
411
401
      // eax is the return value, this is documented to work - edward
412
402
   }
413
403
#pragma warning(pop)
414
 
#endif
 
404
#endif // _MSC_VER >= 1310
415
405
#else
416
406
#error No compiler defined for Atomic_ReadWrite
417
 
#endif
 
407
#endif // __GNUC__
418
408
}
419
409
#define Atomic_ReadWrite32 Atomic_ReadWrite
420
410
 
440
430
                        uint32 oldVal,      // IN
441
431
                        uint32 newVal)      // IN
442
432
{
443
 
#ifdef FAKE_ATOMIC
444
 
   uint32 readVal = var->value;
445
 
 
446
 
   if (oldVal == readVal) {
447
 
     var->value = newVal;
448
 
   }
449
 
   return oldVal;
450
 
#elif defined(__GNUC__)
451
 
#ifdef __arm__
452
 
   uint32 readVal;
453
 
   register volatile uint32 *mem = &(var->value);
454
 
 
455
 
   // loop until var not oldVal or var successfully replaced when var oldVal
456
 
   do {
457
 
      readVal = Atomic_Read(var);
458
 
      if (oldVal != readVal) {
459
 
         return readVal;
460
 
      }
461
 
   } while (__kernel_cmpxchg(oldVal, newVal, mem) != 0);
462
 
   return oldVal; // success
463
 
#else // __arm__ (assume x86*)
 
433
#ifdef __GNUC__
 
434
#ifdef VM_ARM_V7
 
435
   register uint32 retVal;
 
436
   register uint32 res;
 
437
 
 
438
   dmb();
 
439
 
 
440
   __asm__ __volatile__(
 
441
   "1: ldrex %[retVal], [%[var]] \n\t"
 
442
      "mov %[res], #1 \n\t"
 
443
      "teq %[retVal], %[oldVal] \n\t"
 
444
      "strexeq %[res], %[newVal], [%[var]] \n\t"
 
445
      "teq %[res], #0 \n\t"
 
446
      "bne 1b"
 
447
      : [retVal] "=&r" (retVal), [res] "=&r" (res)
 
448
      : [var] "r" (&var->value), [oldVal] "r" (oldVal), [newVal] "r" (newVal)
 
449
      : "memory", "cc"
 
450
   );
 
451
 
 
452
   dmb();
 
453
 
 
454
   return retVal;
 
455
#else // VM_ARM_V7 (assume x86*)
464
456
   uint32 val;
465
457
 
466
458
   /* Checked against the Intel manual and GCC --walken */
467
459
   __asm__ __volatile__(
468
460
      "lock; cmpxchgl %2, %1"
469
 
#   if VM_ASM_PLUS
470
461
      : "=a" (val),
471
462
        "+m" (var->value)
472
463
      : "r" (newVal),
473
464
        "0" (oldVal)
474
 
#   else
475
 
      : "=a" (val),
476
 
        "=m" (var->value)
477
 
      : "r" (newVal),
478
 
        "0" (oldVal)
479
 
     /*
480
 
      * "1" (var->value): results in inconsistent constraints on gcc 2.7.2.3
481
 
      * when compiling enterprise-2.2.17-14-RH7.0-update.
482
 
      * The constraint has been commented out for now. We may consider doing
483
 
      * this systematically, but we need to be sure it is the right thing to
484
 
      * do. However, it is also possible that the offending use of this asm
485
 
      * function will be removed in the near future in which case we may
486
 
      * decide to reintroduce the constraint instead. hpreg & agesen.
487
 
      */
488
 
#   endif
489
465
      : "cc"
490
466
   );
491
467
   AtomicEpilogue();
492
468
   return val;
493
 
#endif // __arm__
 
469
#endif // VM_ARM_V7
494
470
#elif defined _MSC_VER
495
471
#if _MSC_VER >= 1310
496
472
   return _InterlockedCompareExchange((long *)&var->value,
582
558
Atomic_And(Atomic_uint32 *var, // IN
583
559
           uint32 val)         // IN
584
560
{
585
 
#ifdef FAKE_ATOMIC
586
 
   var->value &= val;
587
 
#elif defined(__GNUC__)
588
 
#ifdef __arm__
589
 
   /* same as Atomic_FetchAndAnd without return value */
590
 
   uint32 res;
591
 
   register volatile uint32 *mem = &(var->value);
592
 
 
593
 
   do {
594
 
     res = Atomic_Read(var);
595
 
   } while (__kernel_cmpxchg(res, res & val, mem) != 0);
596
 
#else // __arm__
 
561
#ifdef __GNUC__
 
562
#ifdef VM_ARM_V7
 
563
   register volatile uint32 res;
 
564
   register volatile uint32 tmp;
 
565
 
 
566
   dmb();
 
567
 
 
568
   __asm__ __volatile__(
 
569
   "1: ldrex %[tmp], [%[var]] \n\t"
 
570
      "and %[tmp], %[val] \n\t"
 
571
      "strex %[res], %[tmp], [%[var]] \n\t"
 
572
      "teq %[res], #0 \n\t"
 
573
      "bne 1b"
 
574
      : [res] "=&r" (res), [tmp] "=&r" (tmp)
 
575
      : [var] "r" (&var->value), [val] "r" (val)
 
576
      : "memory", "cc"
 
577
   );
 
578
 
 
579
   dmb();
 
580
#else /* VM_ARM_V7 */
597
581
   /* Checked against the Intel manual and GCC --walken */
598
582
   __asm__ __volatile__(
599
583
      "lock; andl %1, %0"
600
 
#   if VM_ASM_PLUS
601
584
      : "+m" (var->value)
602
585
      : "ri" (val)
603
 
#   else
604
 
      : "=m" (var->value)
605
 
      : "ri" (val),
606
 
        "0" (var->value)
607
 
#   endif
608
586
      : "cc"
609
587
   );
610
588
   AtomicEpilogue();
611
 
#endif // __arm__
 
589
#endif // VM_ARM_V7
612
590
#elif defined _MSC_VER
613
591
#if defined(__x86_64__)
614
592
   _InterlockedAnd((long *)&var->value, (long)val);
644
622
Atomic_Or(Atomic_uint32 *var, // IN
645
623
          uint32 val)         // IN
646
624
{
647
 
#ifdef FAKE_ATOMIC
648
 
   var->value |= val;
649
 
#elif defined(__GNUC__)
650
 
#ifdef __arm__
651
 
   /* same as Atomic_FetchAndOr without return value */
652
 
   uint32 res;
653
 
   register volatile uint32 *mem = &(var->value);
654
 
 
655
 
   do {
656
 
     res = Atomic_Read(var);
657
 
   } while (__kernel_cmpxchg(res, res | val, mem) != 0);
658
 
#else // __arm__
 
625
#ifdef __GNUC__
 
626
#ifdef VM_ARM_V7
 
627
   register volatile uint32 res;
 
628
   register volatile uint32 tmp;
 
629
 
 
630
   dmb();
 
631
 
 
632
   __asm__ __volatile__(
 
633
   "1: ldrex %[tmp], [%[var]] \n\t"
 
634
      "orr %[tmp], %[val] \n\t"
 
635
      "strex %[res], %[tmp], [%[var]] \n\t"
 
636
      "teq %[res], #0 \n\t"
 
637
      "bne 1b"
 
638
      : [res] "=&r" (res), [tmp] "=&r" (tmp)
 
639
      : [var] "r" (&var->value), [val] "r" (val)
 
640
      : "memory", "cc"
 
641
   );
 
642
 
 
643
   dmb();
 
644
#else // VM_ARM_V7
659
645
   /* Checked against the Intel manual and GCC --walken */
660
646
   __asm__ __volatile__(
661
647
      "lock; orl %1, %0"
662
 
#   if VM_ASM_PLUS
663
648
      : "+m" (var->value)
664
649
      : "ri" (val)
665
 
#   else
666
 
      : "=m" (var->value)
667
 
      : "ri" (val),
668
 
        "0" (var->value)
669
 
#   endif
670
650
      : "cc"
671
651
   );
672
652
   AtomicEpilogue();
673
 
#endif // __arm__
 
653
#endif // VM_ARM_V7
674
654
#elif defined _MSC_VER
675
655
#if defined(__x86_64__)
676
656
   _InterlockedOr((long *)&var->value, (long)val);
706
686
Atomic_Xor(Atomic_uint32 *var, // IN
707
687
           uint32 val)         // IN
708
688
{
709
 
#ifdef FAKE_ATOMIC
710
 
   var->value ^= val;
711
 
#elif defined(__GNUC__)
712
 
#ifdef __arm__
713
 
   uint32 res;
714
 
   register volatile uint32 *mem = &(var->value);
715
 
 
716
 
   do {
717
 
     res = Atomic_Read(var);
718
 
   } while (__kernel_cmpxchg(res, res ^ val, mem) != 0);
719
 
#else // __arm__
 
689
#ifdef __GNUC__
 
690
#ifdef VM_ARM_V7
 
691
   register volatile uint32 res;
 
692
   register volatile uint32 tmp;
 
693
 
 
694
   dmb();
 
695
 
 
696
   __asm__ __volatile__(
 
697
   "1: ldrex %[tmp], [%[var]] \n\t"
 
698
      "eor %[tmp], %[val] \n\t"
 
699
      "strex %[res], %[tmp], [%[var]] \n\t"
 
700
      "teq %[res], #0 \n\t"
 
701
      "bne 1b"
 
702
      : [res] "=&r" (res), [tmp] "=&r" (tmp)
 
703
      : [var] "r" (&var->value), [val] "r" (val)
 
704
      : "memory", "cc"
 
705
   );
 
706
 
 
707
   dmb();
 
708
#else // VM_ARM_V7
720
709
   /* Checked against the Intel manual and GCC --walken */
721
710
   __asm__ __volatile__(
722
711
      "lock; xorl %1, %0"
723
 
#   if VM_ASM_PLUS
724
712
      : "+m" (var->value)
725
713
      : "ri" (val)
726
 
#   else
727
 
      : "=m" (var->value)
728
 
      : "ri" (val),
729
 
        "0" (var->value)
730
 
#   endif
731
714
      : "cc"
732
715
   );
733
716
   AtomicEpilogue();
734
 
#endif // __arm__
 
717
#endif // VM_ARM_V7
735
718
#elif defined _MSC_VER
736
719
#if defined(__x86_64__)
737
720
   _InterlockedXor((long *)&var->value, (long)val);
806
789
Atomic_Add(Atomic_uint32 *var, // IN
807
790
           uint32 val)         // IN
808
791
{
809
 
#ifdef FAKE_ATOMIC
810
 
   var->value += val;
811
 
#elif defined(__GNUC__)
812
 
#ifdef __arm__
813
 
   /* same as Atomic_FetchAndAddUnfenced without return value */
814
 
   uint32 res;
815
 
   register volatile uint32 *mem = &(var->value);
816
 
 
817
 
   do {
818
 
     res = Atomic_Read(var);
819
 
   } while (__kernel_cmpxchg(res, res + val, mem) != 0);
820
 
#else // __arm__
 
792
#ifdef __GNUC__
 
793
#ifdef VM_ARM_V7
 
794
   register volatile uint32 res;
 
795
   register volatile uint32 tmp;
 
796
 
 
797
   dmb();
 
798
 
 
799
   __asm__ __volatile__(
 
800
   "1: ldrex %[tmp], [%[var]] \n\t"
 
801
      "add %[tmp], %[val] \n\t"
 
802
      "strex %[res], %[tmp], [%[var]] \n\t"
 
803
      "teq %[res], #0 \n\t"
 
804
      "bne 1b"
 
805
      : [res] "=&r" (res), [tmp] "=&r" (tmp)
 
806
      : [var] "r" (&var->value), [val] "r" (val)
 
807
      : "memory", "cc"
 
808
   );
 
809
 
 
810
   dmb();
 
811
#else // VM_ARM_V7
821
812
   /* Checked against the Intel manual and GCC --walken */
822
813
   __asm__ __volatile__(
823
814
      "lock; addl %1, %0"
824
 
#   if VM_ASM_PLUS
825
815
      : "+m" (var->value)
826
816
      : "ri" (val)
827
 
#   else
828
 
      : "=m" (var->value)
829
 
      : "ri" (val),
830
 
        "0" (var->value)
831
 
#   endif
832
817
      : "cc"
833
818
   );
834
819
   AtomicEpilogue();
835
 
#endif // __arm__
 
820
#endif // VM_ARM_V7
836
821
#elif defined _MSC_VER
837
822
#if _MSC_VER >= 1310
838
823
   _InterlockedExchangeAdd((long *)&var->value, (long)val);
907
892
Atomic_Sub(Atomic_uint32 *var, // IN
908
893
           uint32 val)         // IN
909
894
{
910
 
#ifdef FAKE_ATOMIC
911
 
   var->value -= val;
912
 
#elif defined(__GNUC__)
913
 
#ifdef __arm__
914
 
   uint32 res;
915
 
   register volatile uint32 *mem = &(var->value);
916
 
 
917
 
   do {
918
 
     res = Atomic_Read(var);
919
 
   } while (__kernel_cmpxchg(res, res - val, mem) != 0);
920
 
#else // __arm__
 
895
#ifdef __GNUC__
 
896
#ifdef VM_ARM_V7
 
897
   register volatile uint32 res;
 
898
   register volatile uint32 tmp;
 
899
 
 
900
   dmb();
 
901
 
 
902
   __asm__ __volatile__(
 
903
      "1: ldrex %[tmp], [%[var]] \n\t"
 
904
      "sub %[tmp], %[val] \n\t"
 
905
      "strex %[res], %[tmp], [%[var]] \n\t"
 
906
      "teq %[res], #0 \n\t"
 
907
      "bne 1b"
 
908
      : [res] "=&r" (res), [tmp] "=&r" (tmp)
 
909
      : [var] "r" (&var->value), [val] "r" (val)
 
910
      : "memory", "cc"
 
911
   );
 
912
 
 
913
   dmb();
 
914
#else // VM_ARM_V7
921
915
   /* Checked against the Intel manual and GCC --walken */
922
916
   __asm__ __volatile__(
923
917
      "lock; subl %1, %0"
924
 
#   if VM_ASM_PLUS
925
918
      : "+m" (var->value)
926
919
      : "ri" (val)
927
 
#   else
928
 
      : "=m" (var->value)
929
 
      : "ri" (val),
930
 
        "0" (var->value)
931
 
#   endif
932
920
      : "cc"
933
921
   );
934
922
   AtomicEpilogue();
935
 
#endif // __arm__
 
923
#endif // VM_ARM_V7
936
924
#elif defined _MSC_VER
937
925
#if _MSC_VER >= 1310
938
926
   _InterlockedExchangeAdd((long *)&var->value, (long)-val);
1007
995
Atomic_Inc(Atomic_uint32 *var) // IN
1008
996
{
1009
997
#ifdef __GNUC__
1010
 
#ifdef __arm__
1011
 
   /* just use Atomic_Add */
 
998
#ifdef VM_ARM_V7
1012
999
   Atomic_Add(var, 1);
1013
 
#else // __arm__
 
1000
#else // VM_ARM_V7
1014
1001
   /* Checked against the Intel manual and GCC --walken */
1015
1002
   __asm__ __volatile__(
1016
1003
      "lock; incl %0"
1017
 
#   if VM_ASM_PLUS
1018
1004
      : "+m" (var->value)
1019
1005
      :
1020
 
#   else
1021
 
      : "=m" (var->value)
1022
 
      : "0" (var->value)
1023
 
#   endif
1024
1006
      : "cc"
1025
1007
   );
1026
1008
   AtomicEpilogue();
1027
 
#endif // __arm__
 
1009
#endif // VM_ARM_V7
1028
1010
#elif defined _MSC_VER
1029
1011
#if _MSC_VER >= 1310
1030
1012
   _InterlockedIncrement((long *)&var->value);
1059
1041
Atomic_Dec(Atomic_uint32 *var) // IN
1060
1042
{
1061
1043
#ifdef __GNUC__
1062
 
#ifdef __arm__
1063
 
   /* just use Atomic_Sub */
 
1044
#ifdef VM_ARM_V7
1064
1045
   Atomic_Sub(var, 1);
1065
 
#else // __arm__
 
1046
#else // VM_ARM_V7
1066
1047
   /* Checked against the Intel manual and GCC --walken */
1067
1048
   __asm__ __volatile__(
1068
1049
      "lock; decl %0"
1069
 
#   if VM_ASM_PLUS
1070
1050
      : "+m" (var->value)
1071
1051
      :
1072
 
#   else
1073
 
      : "=m" (var->value)
1074
 
      : "0" (var->value)
1075
 
#   endif
1076
1052
      : "cc"
1077
1053
   );
1078
1054
   AtomicEpilogue();
1079
 
#endif // __arm__
 
1055
#endif // VM_ARM_V7
1080
1056
#elif defined _MSC_VER
1081
1057
#if _MSC_VER >= 1310
1082
1058
   _InterlockedDecrement((long *)&var->value);
1119
1095
{
1120
1096
   uint32 res;
1121
1097
 
1122
 
#if defined(__arm__) && !defined(FAKE_ATOMIC)
1123
 
   register volatile uint32 *mem = &(var->value);
1124
 
   do {
1125
 
      res = Atomic_Read(var);
1126
 
   } while (__kernel_cmpxchg(res, res | val, mem) != 0);
1127
 
#else
1128
1098
   do {
1129
1099
      res = Atomic_Read(var);
1130
1100
   } while (res != Atomic_ReadIfEqualWrite(var, res, res | val));
1131
 
#endif
 
1101
 
1132
1102
   return res;
1133
1103
}
1134
1104
 
1155
1125
{
1156
1126
   uint32 res;
1157
1127
 
1158
 
#if defined(__arm__) && !defined(FAKE_ATOMIC)
1159
 
   register volatile uint32 *mem = &(var->value);
1160
 
   do {
1161
 
      res = Atomic_Read(var);
1162
 
   } while (__kernel_cmpxchg(res, res & val, mem) != 0);
1163
 
#else
1164
1128
   do {
1165
1129
      res = Atomic_Read(var);
1166
1130
   } while (res != Atomic_ReadIfEqualWrite(var, res, res & val));
1167
 
#endif
 
1131
 
1168
1132
   return res;
1169
1133
}
1170
1134
#define Atomic_ReadOr32 Atomic_FetchAndOr
1199
1163
 
1200
1164
   return res;
1201
1165
}
1202
 
#endif
 
1166
 
 
1167
 
 
1168
/*
 
1169
 *-----------------------------------------------------------------------------
 
1170
 *
 
1171
 * Atomic_ReadAnd64 --
 
1172
 *
 
1173
 *      Atomic read (returned), bitwise AND with a value, write.
 
1174
 *
 
1175
 * Results:
 
1176
 *      The value of the variable before the operation.
 
1177
 *
 
1178
 * Side effects:
 
1179
 *      None
 
1180
 *
 
1181
 *-----------------------------------------------------------------------------
 
1182
 */
 
1183
 
 
1184
static INLINE uint64
 
1185
Atomic_ReadAnd64(Atomic_uint64 *var, // IN
 
1186
                 uint64 val)         // IN
 
1187
{
 
1188
   uint64 res;
 
1189
 
 
1190
   do {
 
1191
      res = var->value;
 
1192
   } while (res != Atomic_ReadIfEqualWrite64(var, res, res & val));
 
1193
 
 
1194
   return res;
 
1195
}
 
1196
#endif // __x86_64__
1203
1197
 
1204
1198
 
1205
1199
/*
1229
1223
Atomic_FetchAndAddUnfenced(Atomic_uint32 *var, // IN
1230
1224
                           uint32 val)         // IN
1231
1225
{
1232
 
#ifdef FAKE_ATOMIC
1233
 
   uint32 res = var->value;
1234
 
   var->value = res + val;
1235
 
   return res;
1236
 
#elif defined(__GNUC__)
1237
 
#ifdef __arm__
1238
 
   uint32 res;
1239
 
 
1240
 
   register volatile uint32 *mem = &(var->value);
1241
 
   do {
1242
 
      res = Atomic_Read(var);
1243
 
   } while (__kernel_cmpxchg(res, res + val, mem) != 0);
1244
 
 
1245
 
   return res;
1246
 
#else // __arm__
 
1226
#ifdef __GNUC__
 
1227
#ifdef VM_ARM_V7
 
1228
   register volatile uint32 res;
 
1229
   register volatile uint32 retVal;
 
1230
 
 
1231
   dmb();
 
1232
 
 
1233
   __asm__ __volatile__(
 
1234
      "1: ldrex %[retVal], [%[var]] \n\t"
 
1235
      "add %[val], %[retVal] \n\t"
 
1236
      "strex %[res], %[val], [%[var]] \n\t"
 
1237
      "teq %[res], #0 \n\t"
 
1238
      "bne 1b"
 
1239
      : [res] "=&r" (res), [retVal] "=&r" (retVal)
 
1240
      : [var] "r" (&var->value), [val] "r" (val)
 
1241
      : "memory", "cc"
 
1242
   );
 
1243
 
 
1244
   dmb();
 
1245
 
 
1246
   return retVal;
 
1247
#else // VM_ARM_V7
1247
1248
   /* Checked against the Intel manual and GCC --walken */
1248
1249
   __asm__ __volatile__(
1249
 
#   if VM_ASM_PLUS
1250
1250
      "lock; xaddl %0, %1"
1251
1251
      : "=r" (val),
1252
1252
        "+m" (var->value)
1253
1253
      : "0" (val)
1254
1254
      : "cc"
1255
 
#   else
1256
 
      "lock; xaddl %0, (%1)"
1257
 
      : "=r" (val)
1258
 
      : "r" (&var->value),
1259
 
        "0" (val)
1260
 
      : "cc", "memory"
1261
 
#   endif
1262
1255
   );
1263
1256
   return val;
1264
 
#endif // __arm__
 
1257
#endif // VM_ARM_V7
1265
1258
#elif defined _MSC_VER
1266
1259
#if _MSC_VER >= 1310
1267
1260
   return _InterlockedExchangeAdd((long *)&var->value, (long)val);
1309
1302
Atomic_FetchAndAdd(Atomic_uint32 *var, // IN
1310
1303
                   uint32 val)         // IN
1311
1304
{
1312
 
#if defined(__GNUC__) && !defined(__arm__)
 
1305
#if defined(__GNUC__) && !defined(VM_ARM_V7)
1313
1306
   val = Atomic_FetchAndAddUnfenced(var, val);
1314
1307
   AtomicEpilogue();
1315
1308
   return val;
1523
1516
 *-----------------------------------------------------------------------------
1524
1517
 */
1525
1518
 
1526
 
#ifdef __arm__
1527
 
#define Atomic_CMPXCHG64(x, y, z) _fnAtomic_CMPXCHG64_NotImplementedOnARM
1528
 
#else // __arm__
1529
1519
#if defined(__GNUC__) && __GNUC__ < 3
1530
1520
static Bool
1531
1521
#else
1535
1525
                 uint64 const *oldVal, // IN
1536
1526
                 uint64 const *newVal) // IN
1537
1527
{
1538
 
#ifdef FAKE_ATOMIC
1539
 
   uint64 readVal = var->value;
1540
 
 
1541
 
   if (*oldVal == readVal) {
1542
 
     var->value = *newVal;
1543
 
   }
1544
 
   return (*oldVal == readVal);
1545
 
#elif defined(__GNUC__)
 
1528
#ifdef __GNUC__
1546
1529
   Bool equal;
1547
1530
 
1548
1531
   /* Checked against the Intel manual and GCC --walken */
1558
1541
        "2" (*oldVal)
1559
1542
      : "cc"
1560
1543
   );
1561
 
#else /* 32-bit version */
 
1544
#elif !defined(VM_ARM_V7) /* 32-bit version for non-ARM */
1562
1545
   int dummy1, dummy2;
1563
1546
#   if defined __PIC__
1564
1547
   /*
1628
1611
   __asm__ __volatile__(
1629
1612
      "lock; cmpxchg8b %0" "\n\t"
1630
1613
      "sete %1"
1631
 
#      if VM_ASM_PLUS
1632
1614
      : "+m" (*var),
1633
 
#      else
1634
 
      : "=m" (*var),
1635
 
#      endif
1636
1615
        "=qm" (equal),
1637
1616
        "=a" (dummy1),
1638
1617
        "=d" (dummy2)
1643
1622
      : "cc"
1644
1623
   );
1645
1624
#   endif
1646
 
#endif /* 32-bit version */
 
1625
#elif defined(VM_ARM_V7)
 
1626
   volatile uint64 tmp;
 
1627
 
 
1628
   dmb();
 
1629
 
 
1630
   __asm__ __volatile__(
 
1631
      "ldrexd %[tmp], %H[tmp], [%[var]] \n\t"
 
1632
      "mov %[equal], #1 \n\t"
 
1633
      "teq %[tmp], %[oldVal] \n\t"
 
1634
      "teqeq %H[tmp], %H[oldVal] \n\t"
 
1635
      "strexdeq  %[equal], %[newVal], %H[newVal], [%[var]]"
 
1636
      : [equal] "=&r" (equal), [tmp] "=&r" (tmp)
 
1637
      : [var] "r" (&var->value), [oldVal] "r" (*oldVal), [newVal] "r" (*newVal)
 
1638
      : "memory", "cc"
 
1639
   );
 
1640
 
 
1641
   dmb();
 
1642
 
 
1643
   return !equal;
 
1644
#endif
 
1645
#ifndef VM_ARM_V7
1647
1646
   AtomicEpilogue();
1648
1647
   return equal;
 
1648
#endif // VM_ARM_V7
1649
1649
#elif defined _MSC_VER
1650
1650
#if defined(__x86_64__)
1651
1651
   return (__int64)*oldVal == _InterlockedCompareExchange64((__int64 *)&var->value,
1671
1671
#endif
1672
1672
#else
1673
1673
#error No compiler defined for Atomic_CMPXCHG64
1674
 
#endif
 
1674
#endif // !GNUC
1675
1675
}
1676
 
#endif // __arm__
1677
1676
 
1678
1677
 
1679
1678
/*
1697
1696
                 uint32 oldVal, // IN
1698
1697
                 uint32 newVal) // IN
1699
1698
{
1700
 
#ifdef FAKE_ATOMIC
1701
 
   uint32 readVal = var->value;
1702
 
 
1703
 
   if (oldVal == readVal) {
1704
 
     var->value = newVal;
1705
 
   }
1706
 
   return (oldVal == readVal);
1707
 
#elif defined(__GNUC__)
1708
 
#ifdef __arm__
1709
 
   register volatile uint32 *mem = &(var->value);
1710
 
 
1711
 
   return !__kernel_cmpxchg(oldVal, newVal, mem);
1712
 
#else // __arm__
 
1699
#ifdef __GNUC__
1713
1700
   Bool equal;
1714
 
 
 
1701
#ifdef VM_ARM_V7
 
1702
   volatile uint64 tmp;
 
1703
 
 
1704
   dmb();
 
1705
 
 
1706
   __asm__ __volatile__(
 
1707
      "ldrex %[tmp], [%[var]] \n\t"
 
1708
      "mov %[equal], #1 \n\t"
 
1709
      "teq %[tmp], %[oldVal] \n\t"
 
1710
      "strexeq  %[equal], %[newVal], [%[var]]"
 
1711
      : [equal] "=&r" (equal), [tmp] "=&r" (tmp)
 
1712
      : [var] "r" (&var->value), [oldVal] "r" (oldVal), [newVal] "r" (newVal)
 
1713
      : "memory", "cc"
 
1714
   );
 
1715
 
 
1716
   dmb();
 
1717
 
 
1718
   return !equal;
 
1719
#else // VM_ARM_V7
1715
1720
   uint32 dummy;
 
1721
 
1716
1722
   __asm__ __volatile__(
1717
1723
      "lock; cmpxchgl %3, %0" "\n\t"
1718
1724
      "sete %1"
1719
 
#   if VM_ASM_PLUS
1720
1725
      : "+m" (*var),
1721
1726
        "=qm" (equal),
1722
1727
        "=a" (dummy)
1723
1728
      : "r" (newVal),
1724
1729
        "2" (oldVal)
1725
 
#   else
1726
 
      : "=m" (*var),
1727
 
        "=qm" (equal),
1728
 
        "=a" (dummy)
1729
 
      : /*"0" (*var), */
1730
 
        "r" (newVal),
1731
 
        "2" (oldVal)
1732
 
#   endif
1733
1730
      : "cc"
1734
1731
   );
1735
1732
   AtomicEpilogue();
1736
1733
   return equal;
1737
 
#endif // __arm__
 
1734
#endif // VM_ARM_V7
1738
1735
#else // defined(__GNUC__)
1739
1736
   return (Atomic_ReadIfEqualWrite(var, oldVal, newVal) == oldVal);
1740
 
#endif // defined(__GNUC__)
 
1737
#endif // !defined(__GNUC__)
1741
1738
}
1742
1739
 
1743
1740
 
1744
 
#ifdef __arm__
1745
 
 
1746
 
#define Atomic_Read64(x)          _fnAtomic_Read64_NotImplementedOnARM
1747
 
#define Atomic_FetchAndAdd64(x,y) _fnAtomic_FetchAndAdd64_NotImplementedOnARM
1748
 
#define Atomic_FetchAndInc64(x)   _fnAtomic_FetchAndInc64_NotImplementedOnARM
1749
 
#define Atomic_FetchAndDec64(x)   _fnAtomic_FetchAndDec64_NotImplementedOnARM
1750
 
#define Atomic_Inc64(x)           _fnAtomic_Inc64_NotImplementedOnARM
1751
 
#define Atomic_Dec64(x)           _fnAtomic_Dec64_NotImplementedOnARM
1752
 
#define Atomic_ReadWrite64(x,y)   _fnAtomic_ReadWrite64_NotImplementedOnARM
1753
 
#define Atomic_Write64(x,y)       _fnAtomic_Write64_NotImplementedOnARM
1754
 
#define Atomic_And64(x)           _fnAtomic_And64_NotImplementedOnARM
1755
 
#define Atomic_Or64(x)            _fnAtomic_Or64_NotImplementedOnARM
1756
 
 
1757
 
#else // __arm__
1758
 
 
1759
1741
/*
1760
1742
 *-----------------------------------------------------------------------------
1761
1743
 *
1775
1757
static INLINE uint64
1776
1758
Atomic_Read64(Atomic_uint64 const *var) // IN
1777
1759
{
1778
 
#if defined(FAKE_ATOMIC)
1779
 
   return var->value;
1780
 
#elif defined(__x86_64__)
1781
 
   return var->value;
1782
 
#elif defined(__GNUC__) && defined(__i386__) /* GCC on x86 */
 
1760
#if defined(__GNUC__) && defined(__x86_64__)
 
1761
   uint64 value;
 
1762
 
 
1763
#ifdef VMM
 
1764
   ASSERT((uintptr_t)var % 8 == 0);
 
1765
#endif
 
1766
   /*
 
1767
    * Use asm to ensure we emit a single load.
 
1768
    */
 
1769
   __asm__ __volatile__(
 
1770
      "movq %1, %0"
 
1771
      : "=r" (value)
 
1772
      : "m" (var->value)
 
1773
   );
 
1774
   return value;
 
1775
#elif defined(__GNUC__) && defined(__i386__)
1783
1776
   uint64 value;
1784
1777
   /*
1785
1778
    * Since cmpxchg8b will replace the contents of EDX:EAX with the
1800
1793
   );
1801
1794
   AtomicEpilogue();
1802
1795
   return value;
1803
 
#elif defined _MSC_VER /* MSC (assume on x86 for now) */
 
1796
#elif defined (_MSC_VER) && defined(__x86_64__)
 
1797
   /*
 
1798
    * Microsoft docs guarantee "Simple reads and writes to properly
 
1799
    * aligned 64-bit variables are atomic on 64-bit Windows."
 
1800
    * http://msdn.microsoft.com/en-us/library/ms684122%28VS.85%29.aspx
 
1801
    *
 
1802
    * XXX Verify that value is properly aligned. Bug 61315.
 
1803
    */
 
1804
   return var->value;
 
1805
#elif defined (_MSC_VER) && defined(__i386__)
1804
1806
#   pragma warning(push)
1805
1807
#   pragma warning(disable : 4035)              // disable no-return warning
1806
1808
   {
1811
1813
      // edx:eax is the return value; this is documented to work. --mann
1812
1814
   }
1813
1815
#   pragma warning(pop)
1814
 
#else
1815
 
#   error No compiler defined for Atomic_Read64
1816
 
#endif
1817
 
}
 
1816
#elif defined(__GNUC__) && defined (VM_ARM_V7)
 
1817
   uint64 value;
 
1818
 
 
1819
   __asm__ __volatile__(
 
1820
      "ldrexd %[value], %H[value], [%[var]] \n\t"
 
1821
      : [value] "=&r" (value)
 
1822
      : [var] "r" (&var->value)
 
1823
   );
 
1824
 
 
1825
   return value;
 
1826
#endif
 
1827
}
 
1828
 
 
1829
 
 
1830
/*
 
1831
 *----------------------------------------------------------------------
 
1832
 *
 
1833
 * Atomic_ReadUnaligned64 --
 
1834
 *
 
1835
 *      Atomically read a 64 bit integer, possibly misaligned.
 
1836
 *      This function can be *very* expensive, costing over 50 kcycles
 
1837
 *      on Nehalem.
 
1838
 * 
 
1839
 *      Note that "var" needs to be writable, even though it will not
 
1840
 *      be modified.
 
1841
 *
 
1842
 * Results:
 
1843
 *      The value of the atomic variable.
 
1844
 *
 
1845
 * Side effects:
 
1846
 *      None
 
1847
 *
 
1848
 *----------------------------------------------------------------------
 
1849
 */
 
1850
#if defined(__x86_64__)
 
1851
static INLINE uint64
 
1852
Atomic_ReadUnaligned64(Atomic_uint64 const *var)
 
1853
{
 
1854
   return Atomic_ReadIfEqualWrite64((Atomic_uint64*)var, 0, 0);
 
1855
}
 
1856
#endif
1818
1857
 
1819
1858
 
1820
1859
/*
2049
2088
{
2050
2089
#if defined(__x86_64__)
2051
2090
#if defined(__GNUC__)
 
2091
 
 
2092
#ifdef VMM
 
2093
   ASSERT((uintptr_t)var % 8 == 0);
 
2094
#endif
2052
2095
   /*
2053
2096
    * There is no move instruction for 64-bit immediate to memory, so unless
2054
2097
    * the immediate value fits in 32-bit (i.e. can be sign-extended), GCC
2066
2109
    * Microsoft docs guarantee "Simple reads and writes to properly aligned 
2067
2110
    * 64-bit variables are atomic on 64-bit Windows."
2068
2111
    * http://msdn.microsoft.com/en-us/library/ms684122%28VS.85%29.aspx
 
2112
    *
 
2113
    * XXX Verify that value is properly aligned. Bug 61315.
2069
2114
    */
2070
2115
 
2071
2116
   var->value = val;
2169
2214
#endif
2170
2215
}
2171
2216
 
2172
 
#endif // __arm__
2173
 
 
2174
2217
 
2175
2218
/*
2176
2219
 * Template code for the Atomic_<name> type and its operators.