xref: /kvm-unit-tests/lib/x86/atomic.h (revision dca3f4c041143c8e8dc70c6890a19a5730310230)
1 #ifndef _X86_ATOMIC_H_
2 #define _X86_ATOMIC_H_
3 
4 #include "asm-generic/atomic.h"
5 
6 #include "libcflat.h"
7 
8 typedef struct {
9 	volatile int counter;
10 } atomic_t;
11 
12 #ifdef __i386__
13 
14 /**
15  * atomic_read - read atomic variable
16  * @v: pointer of type atomic_t
17  *
18  * Atomically reads the value of @v.
19  */
atomic_read(const atomic_t * v)20 static inline int atomic_read(const atomic_t *v)
21 {
22 	return v->counter;
23 }
24 
25 /**
26  * atomic_set - set atomic variable
27  * @v: pointer of type atomic_t
28  * @i: required value
29  *
30  * Atomically sets the value of @v to @i.
31  */
atomic_set(atomic_t * v,int i)32 static inline void atomic_set(atomic_t *v, int i)
33 {
34 	v->counter = i;
35 }
36 
37 /**
38  * atomic_inc - increment atomic variable
39  * @v: pointer of type atomic_t
40  *
41  * Atomically increments @v by 1.
42  */
atomic_inc(atomic_t * v)43 static inline void atomic_inc(atomic_t *v)
44 {
45 	asm volatile("lock incl %0"
46 		     : "+m" (v->counter));
47 }
48 
49 /**
50  * atomic_dec - decrement atomic variable
51  * @v: pointer of type atomic_t
52  *
53  * Atomically decrements @v by 1.
54  */
atomic_dec(atomic_t * v)55 static inline void atomic_dec(atomic_t *v)
56 {
57 	asm volatile("lock decl %0"
58 		     : "+m" (v->counter));
59 }
60 
61 typedef struct {
62 	u64 __attribute__((aligned(8))) counter;
63 } atomic64_t;
64 
65 #define ATOMIC64_INIT(val)	{ (val) }
66 
67 /**
68  * atomic64_read - read atomic64 variable
69  * @ptr:      pointer to type atomic64_t
70  *
71  * Atomically reads the value of @ptr and returns it.
72  */
atomic64_read(atomic64_t * ptr)73 static inline u64 atomic64_read(atomic64_t *ptr)
74 {
75 	u64 res;
76 
77 	/*
78 	 * Note, we inline this atomic64_t primitive because
79 	 * it only clobbers EAX/EDX and leaves the others
80 	 * untouched. We also (somewhat subtly) rely on the
81 	 * fact that cmpxchg8b returns the current 64-bit value
82 	 * of the memory location we are touching:
83 	 */
84 	asm volatile("mov %%ebx, %%eax\n\t"
85                      "mov %%ecx, %%edx\n\t"
86                      "lock cmpxchg8b %1\n"
87                      : "=&A" (res)
88                      : "m" (*ptr)
89                      );
90 	return res;
91 }
92 
93 u64 atomic64_cmpxchg(atomic64_t *v, u64 old, u64 new);
94 
95 #elif defined(__x86_64__)
96 
97 /**
98  * atomic_read - read atomic variable
99  * @v: pointer of type atomic_t
100  *
101  * Atomically reads the value of @v.
102  */
atomic_read(const atomic_t * v)103 static inline int atomic_read(const atomic_t *v)
104 {
105 	return v->counter;
106 }
107 
108 /**
109  * atomic_set - set atomic variable
110  * @v: pointer of type atomic_t
111  * @i: required value
112  *
113  * Atomically sets the value of @v to @i.
114  */
atomic_set(atomic_t * v,int i)115 static inline void atomic_set(atomic_t *v, int i)
116 {
117 	v->counter = i;
118 }
119 
120 /**
121  * atomic_inc - increment atomic variable
122  * @v: pointer of type atomic_t
123  *
124  * Atomically increments @v by 1.
125  */
atomic_inc(atomic_t * v)126 static inline void atomic_inc(atomic_t *v)
127 {
128 	asm volatile("lock incl %0"
129 		     : "=m" (v->counter)
130 		     : "m" (v->counter));
131 }
132 
133 /**
134  * atomic_dec - decrement atomic variable
135  * @v: pointer of type atomic_t
136  *
137  * Atomically decrements @v by 1.
138  */
atomic_dec(atomic_t * v)139 static inline void atomic_dec(atomic_t *v)
140 {
141 	asm volatile("lock decl %0"
142 		     : "=m" (v->counter)
143 		     : "m" (v->counter));
144 }
145 
146 typedef struct {
147 	long long counter;
148 } atomic64_t;
149 
150 #define ATOMIC64_INIT(i)	{ (i) }
151 
152 /**
153  * atomic64_read - read atomic64 variable
154  * @v: pointer of type atomic64_t
155  *
156  * Atomically reads the value of @v.
157  * Doesn't imply a read memory barrier.
158  */
atomic64_read(const atomic64_t * v)159 static inline long atomic64_read(const atomic64_t *v)
160 {
161 	return v->counter;
162 }
163 
164 u64 atomic64_cmpxchg(atomic64_t *v, u64 old, u64 new);
165 
166 #endif
167 
168 #endif
169