Subversion Repositories Kolibri OS

Rev

Rev 1408 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1408 Rev 1631
Line 24... Line 24...
24
#define __xchg(x, ptr, size)						\
24
#define __xchg(x, ptr, size)						\
25
({									\
25
({									\
26
	__typeof(*(ptr)) __x = (x);					\
26
	__typeof(*(ptr)) __x = (x);					\
27
	switch (size) {							\
27
	switch (size) {							\
28
	case 1:								\
28
	case 1:								\
-
 
29
	{								\
-
 
30
		volatile u8 *__ptr = (volatile u8 *)(ptr);		\
29
		asm volatile("xchgb %b0,%1"				\
31
		asm volatile("xchgb %0,%1"				\
30
			     : "=q" (__x)				\
32
			     : "=q" (__x), "+m" (*__ptr)		\
31
			     : "m" (*__xg(ptr)), "0" (__x)		\
33
			     : "0" (__x)				\
32
			     : "memory");				\
34
			     : "memory");				\
33
		break;							\
35
		break;							\
-
 
36
	}								\
34
	case 2:								\
37
	case 2:								\
-
 
38
	{								\
-
 
39
		volatile u16 *__ptr = (volatile u16 *)(ptr);		\
35
		asm volatile("xchgw %w0,%1"				\
40
		asm volatile("xchgw %0,%1"				\
36
			     : "=r" (__x)				\
41
			     : "=r" (__x), "+m" (*__ptr)		\
37
			     : "m" (*__xg(ptr)), "0" (__x)		\
42
			     : "0" (__x)				\
38
			     : "memory");				\
43
			     : "memory");				\
39
		break;							\
44
		break;							\
-
 
45
	}								\
40
	case 4:								\
46
	case 4:								\
-
 
47
	{								\
-
 
48
		volatile u32 *__ptr = (volatile u32 *)(ptr);		\
41
		asm volatile("xchgl %0,%1"				\
49
		asm volatile("xchgl %0,%1"				\
42
			     : "=r" (__x)				\
50
			     : "=r" (__x), "+m" (*__ptr)		\
43
			     : "m" (*__xg(ptr)), "0" (__x)		\
51
			     : "0" (__x)				\
44
			     : "memory");				\
52
			     : "memory");				\
45
		break;							\
53
		break;							\
-
 
54
	}								\
46
	default:							\
55
	default:							\
47
		__xchg_wrong_size();					\
56
		__xchg_wrong_size();					\
48
	}								\
57
	}								\
49
	__x;								\
58
	__x;								\
50
})
59
})
Line 51... Line 60...
51
 
60
 
52
#define xchg(ptr, v)							\
61
#define xchg(ptr, v)							\
Line 53... Line 62...
53
	__xchg((v), (ptr), sizeof(*ptr))
62
	__xchg((v), (ptr), sizeof(*ptr))
54
 
63
 
55
/*
64
/*
56
 * The semantics of XCHGCMP8B are a bit strange, this is why
65
 * CMPXCHG8B only writes to the target if we had the previous
57
 * there is a loop and the loading of %%eax and %%edx has to
66
 * value in registers, otherwise it acts as a read and gives us the
58
 * be inside. This inlines well in most cases, the cached
-
 
59
 * cost is around ~38 cycles. (in the future we might want
-
 
60
 * to do an SIMD/3DNOW!/MMX/FPU 64-bit store here, but that
67
 * "new previous" value.  That is why there is a loop.  Preloading
61
 * might have an implicit FPU-save as a cost, so it's not
68
 * EDX:EAX is a performance optimization: in the common case it means
-
 
69
 * we need only one locked operation.
-
 
70
 *
-
 
71
 * A SIMD/3DNOW!/MMX/FPU 64-bit store here would require at the very
62
 * clear which path to go.)
72
 * least an FPU save and/or %cr0.ts manipulation.
63
 *
73
 *
64
 * cmpxchg8b must be used with the lock prefix here to allow
-
 
65
 * the instruction to be executed atomically, see page 3-102
74
 * cmpxchg8b must be used with the lock prefix here to allow the
66
 * of the instruction set reference 24319102.pdf. We need
75
 * instruction to be executed atomically.  We need to have the reader
67
 * the reader side to see the coherent 64bit value.
76
 * side to see the coherent 64bit value.
68
 */
-
 
69
static inline void __set_64bit(unsigned long long *ptr,
77
 */
-
 
78
static inline void set_64bit(volatile u64 *ptr, u64 value)
-
 
79
{
-
 
80
	u32 low  = value;
-
 
81
	u32 high = value >> 32;
70
			       unsigned int low, unsigned int high)
82
	u64 prev = *ptr;
71
{
-
 
72
	asm volatile("\n1:\t"
-
 
73
		     "movl (%0), %%eax\n\t"
83
 
74
		     "movl 4(%0), %%edx\n\t"
84
	asm volatile("\n1:\t"
75
		     LOCK_PREFIX "cmpxchg8b (%0)\n\t"
-
 
76
		     "jnz 1b"
85
		     LOCK_PREFIX "cmpxchg8b %0\n\t"
77
		     : /* no outputs */
-
 
78
		     : "D"(ptr),
86
		     "jnz 1b"
79
		       "b"(low),
87
		     : "=m" (*ptr), "+A" (prev)
80
		       "c"(high)
-
 
81
		     : "ax", "dx", "memory");
-
 
82
}
-
 
83
 
-
 
84
static inline void __set_64bit_constant(unsigned long long *ptr,
-
 
85
					unsigned long long value)
-
 
86
{
-
 
87
	__set_64bit(ptr, (unsigned int)value, (unsigned int)(value >> 32));
-
 
88
}
-
 
89
 
-
 
90
#define ll_low(x)	*(((unsigned int *)&(x)) + 0)
-
 
91
#define ll_high(x)	*(((unsigned int *)&(x)) + 1)
-
 
92
 
-
 
93
static inline void __set_64bit_var(unsigned long long *ptr,
-
 
94
				   unsigned long long value)
-
 
95
{
88
		     : "b" (low), "c" (high)
Line 96... Line -...
96
	__set_64bit(ptr, ll_low(value), ll_high(value));
-
 
97
}
-
 
98
 
-
 
99
#define set_64bit(ptr, value)			\
-
 
100
	(__builtin_constant_p((value))		\
-
 
101
	 ? __set_64bit_constant((ptr), (value))	\
-
 
102
	 : __set_64bit_var((ptr), (value)))
-
 
103
 
-
 
104
#define _set_64bit(ptr, value)						\
-
 
105
	(__builtin_constant_p(value)					\
-
 
106
	 ? __set_64bit(ptr, (unsigned int)(value),			\
-
 
107
		       (unsigned int)((value) >> 32))			\
89
		     : "memory");
Line 108... Line 90...
108
	 : __set_64bit(ptr, ll_low((value)), ll_high((value))))
90
}
109
 
91
 
110
extern void __cmpxchg_wrong_size(void);
92
extern void __cmpxchg_wrong_size(void);
Line 119... Line 101...
119
	__typeof__(*(ptr)) __ret;					\
101
	__typeof__(*(ptr)) __ret;					\
120
	__typeof__(*(ptr)) __old = (old);				\
102
	__typeof__(*(ptr)) __old = (old);				\
121
	__typeof__(*(ptr)) __new = (new);				\
103
	__typeof__(*(ptr)) __new = (new);				\
122
	switch (size) {							\
104
	switch (size) {							\
123
	case 1:								\
105
	case 1:								\
-
 
106
	{								\
-
 
107
		volatile u8 *__ptr = (volatile u8 *)(ptr);		\
124
		asm volatile(lock "cmpxchgb %b1,%2"			\
108
		asm volatile(lock "cmpxchgb %2,%1"			\
125
			     : "=a"(__ret)				\
109
			     : "=a" (__ret), "+m" (*__ptr)		\
126
			     : "q"(__new), "m"(*__xg(ptr)), "0"(__old)	\
110
			     : "q" (__new), "0" (__old)			\
127
			     : "memory");				\
111
			     : "memory");				\
128
		break;							\
112
		break;							\
-
 
113
	}								\
129
	case 2:								\
114
	case 2:								\
-
 
115
	{								\
-
 
116
		volatile u16 *__ptr = (volatile u16 *)(ptr);		\
130
		asm volatile(lock "cmpxchgw %w1,%2"			\
117
		asm volatile(lock "cmpxchgw %2,%1"			\
131
			     : "=a"(__ret)				\
118
			     : "=a" (__ret), "+m" (*__ptr)		\
132
			     : "r"(__new), "m"(*__xg(ptr)), "0"(__old)	\
119
			     : "r" (__new), "0" (__old)			\
133
			     : "memory");				\
120
			     : "memory");				\
134
		break;							\
121
		break;							\
-
 
122
	}								\
135
	case 4:								\
123
	case 4:								\
-
 
124
	{								\
-
 
125
		volatile u32 *__ptr = (volatile u32 *)(ptr);		\
136
		asm volatile(lock "cmpxchgl %1,%2"			\
126
		asm volatile(lock "cmpxchgl %2,%1"			\
137
			     : "=a"(__ret)				\
127
			     : "=a" (__ret), "+m" (*__ptr)		\
138
			     : "r"(__new), "m"(*__xg(ptr)), "0"(__old)	\
128
			     : "r" (__new), "0" (__old)			\
139
			     : "memory");				\
129
			     : "memory");				\
140
		break;							\
130
		break;							\
-
 
131
	}								\
141
	default:							\
132
	default:							\
142
		__cmpxchg_wrong_size();					\
133
		__cmpxchg_wrong_size();					\
143
	}								\
134
	}								\
144
	__ret;								\
135
	__ret;								\
145
})
136
})
Line 173... Line 164...
173
#define cmpxchg64_local(ptr, o, n)					\
164
#define cmpxchg64_local(ptr, o, n)					\
174
	((__typeof__(*(ptr)))__cmpxchg64_local((ptr), (unsigned long long)(o), \
165
	((__typeof__(*(ptr)))__cmpxchg64_local((ptr), (unsigned long long)(o), \
175
					       (unsigned long long)(n)))
166
					       (unsigned long long)(n)))
176
#endif
167
#endif
Line 177... Line 168...
177
 
168
 
178
static inline unsigned long long __cmpxchg64(volatile void *ptr,
-
 
179
					     unsigned long long old,
-
 
180
					     unsigned long long new)
169
static inline u64 __cmpxchg64(volatile u64 *ptr, u64 old, u64 new)
181
{
170
{
182
	unsigned long long prev;
171
	u64 prev;
183
	asm volatile(LOCK_PREFIX "cmpxchg8b %3"
172
	asm volatile(LOCK_PREFIX "cmpxchg8b %1"
184
		     : "=A"(prev)
173
		     : "=A" (prev),
185
		     : "b"((unsigned long)new),
174
		       "+m" (*ptr)
186
		       "c"((unsigned long)(new >> 32)),
175
		     : "b" ((u32)new),
187
		       "m"(*__xg(ptr)),
176
		       "c" ((u32)(new >> 32)),
188
		       "0"(old)
177
		       "0" (old)
189
		     : "memory");
178
		     : "memory");
190
	return prev;
179
	return prev;
Line 191... Line 180...
191
}
180
}
192
 
-
 
193
static inline unsigned long long __cmpxchg64_local(volatile void *ptr,
-
 
194
						   unsigned long long old,
181
 
195
						   unsigned long long new)
182
static inline u64 __cmpxchg64_local(volatile u64 *ptr, u64 old, u64 new)
196
{
183
{
197
	unsigned long long prev;
184
	u64 prev;
198
	asm volatile("cmpxchg8b %3"
185
	asm volatile("cmpxchg8b %1"
199
		     : "=A"(prev)
186
		     : "=A" (prev),
200
		     : "b"((unsigned long)new),
187
		       "+m" (*ptr)
201
		       "c"((unsigned long)(new >> 32)),
188
		     : "b" ((u32)new),
202
		       "m"(*__xg(ptr)),
189
		       "c" ((u32)(new >> 32)),
203
		       "0"(old)
190
		       "0" (old)
204
		     : "memory");
191
		     : "memory");
Line 210... Line 197...
210
 * Building a kernel capable running on 80386. It may be necessary to
197
 * Building a kernel capable running on 80386. It may be necessary to
211
 * simulate the cmpxchg on the 80386 CPU. For that purpose we define
198
 * simulate the cmpxchg on the 80386 CPU. For that purpose we define
212
 * a function for each of the sizes we support.
199
 * a function for each of the sizes we support.
213
 */
200
 */
Line -... Line 201...
-
 
201
 
-
 
202
extern unsigned long cmpxchg_386_u8(volatile void *, u8, u8);
-
 
203
extern unsigned long cmpxchg_386_u16(volatile void *, u16, u16);
-
 
204
extern unsigned long cmpxchg_386_u32(volatile void *, u32, u32);
-
 
205
 
-
 
206
static inline unsigned long cmpxchg_386(volatile void *ptr, unsigned long old,
-
 
207
					unsigned long new, int size)
-
 
208
{
-
 
209
	switch (size) {
-
 
210
	case 1:
-
 
211
		return cmpxchg_386_u8(ptr, old, new);
-
 
212
	case 2:
-
 
213
		return cmpxchg_386_u16(ptr, old, new);
-
 
214
	case 4:
-
 
215
		return cmpxchg_386_u32(ptr, old, new);
-
 
216
	}
-
 
217
	return old;
-
 
218
}
214
 
219
 
215
#define cmpxchg(ptr, o, n)						\
220
#define cmpxchg(ptr, o, n)						\
216
({									\
221
({									\
217
	__typeof__(*(ptr)) __ret;					\
222
	__typeof__(*(ptr)) __ret;					\
218
    __ret = (__typeof__(*(ptr)))__cmpxchg((ptr),        \
223
		__ret = (__typeof__(*(ptr)))__cmpxchg((ptr),		\
Line 234... Line 239...
234
/*
239
/*
235
 * Building a kernel capable running on 80386 and 80486. It may be necessary
240
 * Building a kernel capable running on 80386 and 80486. It may be necessary
236
 * to simulate the cmpxchg8b on the 80386 and 80486 CPU.
241
 * to simulate the cmpxchg8b on the 80386 and 80486 CPU.
237
 */
242
 */
Line 238... Line -...
238
 
-
 
239
extern unsigned long long cmpxchg_486_u64(volatile void *, u64, u64);
-
 
240
 
243
 
241
#define cmpxchg64(ptr, o, n)					\
244
#define cmpxchg64(ptr, o, n)					\
242
({								\
245
({								\
243
	__typeof__(*(ptr)) __ret;				\
246
	__typeof__(*(ptr)) __ret;				\
244
	__typeof__(*(ptr)) __old = (o);				\
247
	__typeof__(*(ptr)) __old = (o);				\
-
 
248
	__typeof__(*(ptr)) __new = (n);				\
245
	__typeof__(*(ptr)) __new = (n);				\
249
	alternative_io(LOCK_PREFIX_HERE				\
246
	alternative_io("call cmpxchg8b_emu",			\
250
			"call cmpxchg8b_emu",			\
247
			"lock; cmpxchg8b (%%esi)" ,		\
251
			"lock; cmpxchg8b (%%esi)" ,		\
248
		       X86_FEATURE_CX8,				\
252
		       X86_FEATURE_CX8,				\
249
		       "=A" (__ret),				\
253
		       "=A" (__ret),				\
250
		       "S" ((ptr)), "0" (__old),		\
254
		       "S" ((ptr)), "0" (__old),		\
251
		       "b" ((unsigned int)__new),		\
255
		       "b" ((unsigned int)__new),		\
252
		       "c" ((unsigned int)(__new>>32))		\
256
		       "c" ((unsigned int)(__new>>32))		\
253
		       : "memory");				\
257
		       : "memory");				\
Line 254... Line -...
254
	__ret; })
-
 
255
 
258
	__ret; })
256
 
259
 
257
 
260
 
258
#define cmpxchg64_local(ptr, o, n)					\
261
#define cmpxchg64_local(ptr, o, n)				\
259
({									\
262
({								\
-
 
263
	__typeof__(*(ptr)) __ret;				\
260
	__typeof__(*(ptr)) __ret;					\
264
	__typeof__(*(ptr)) __old = (o);				\
261
	if (likely(boot_cpu_data.x86 > 4))				\
265
	__typeof__(*(ptr)) __new = (n);				\
262
		__ret = (__typeof__(*(ptr)))__cmpxchg64_local((ptr),	\
266
	alternative_io("call cmpxchg8b_emu",			\
263
				(unsigned long long)(o),		\
267
		       "cmpxchg8b (%%esi)" ,			\
264
				(unsigned long long)(n));		\
268
		       X86_FEATURE_CX8,				\
265
	else								\
269
		       "=A" (__ret),				\
266
		__ret = (__typeof__(*(ptr)))cmpxchg_486_u64((ptr),	\
270
		       "S" ((ptr)), "0" (__old),		\
267
				(unsigned long long)(o),		\
271
		       "b" ((unsigned int)__new),		\
Line 268... Line 272...
268
				(unsigned long long)(n));		\
272
		       "c" ((unsigned int)(__new>>32))		\
Line 269... Line 273...
269
	__ret;								\
273
		       : "memory");				\