File: /usr/include/asm/system.h

1     #ifndef __ASM_SYSTEM_H
2     #define __ASM_SYSTEM_H
3     
4     #include <linux/config.h>
5     #include <linux/kernel.h>
6     #include <asm/segment.h>
7     #include <linux/bitops.h> /* for LOCK_PREFIX */
8     
9     #ifdef __KERNEL__
10     
11     struct task_struct;	/* one of the stranger aspects of C forward declarations.. */
12     extern void FASTCALL(__switch_to(struct task_struct *prev, struct task_struct *next));
13     
14     #define prepare_to_switch()	do { } while(0)
15     #define switch_to(prev,next,last) do {					\
16     	asm volatile("pushl %%esi\n\t"					\
17     		     "pushl %%edi\n\t"					\
18     		     "pushl %%ebp\n\t"					\
19     		     "movl %%esp,%0\n\t"	/* save ESP */		\
20     		     "movl %3,%%esp\n\t"	/* restore ESP */	\
21     		     "movl $1f,%1\n\t"		/* save EIP */		\
22     		     "pushl %4\n\t"		/* restore EIP */	\
23     		     "jmp __switch_to\n"				\
24     		     "1:\t"						\
25     		     "popl %%ebp\n\t"					\
26     		     "popl %%edi\n\t"					\
27     		     "popl %%esi\n\t"					\
28     		     :"=m" (prev->thread.esp),"=m" (prev->thread.eip),	\
29     		      "=b" (last)					\
30     		     :"m" (next->thread.esp),"m" (next->thread.eip),	\
31     		      "a" (prev), "d" (next),				\
32     		      "b" (prev));					\
33     } while (0)
34     
35     #define _set_base(addr,base) do { unsigned long __pr; \
36     __asm__ __volatile__ ("movw %%dx,%1\n\t" \
37     	"rorl $16,%%edx\n\t" \
38     	"movb %%dl,%2\n\t" \
39     	"movb %%dh,%3" \
40     	:"=&d" (__pr) \
41     	:"m" (*((addr)+2)), \
42     	 "m" (*((addr)+4)), \
43     	 "m" (*((addr)+7)), \
44              "0" (base) \
45             ); } while(0)
46     
47     #define _set_limit(addr,limit) do { unsigned long __lr; \
48     __asm__ __volatile__ ("movw %%dx,%1\n\t" \
49     	"rorl $16,%%edx\n\t" \
50     	"movb %2,%%dh\n\t" \
51     	"andb $0xf0,%%dh\n\t" \
52     	"orb %%dh,%%dl\n\t" \
53     	"movb %%dl,%2" \
54     	:"=&d" (__lr) \
55     	:"m" (*(addr)), \
56     	 "m" (*((addr)+6)), \
57     	 "0" (limit) \
58             ); } while(0)
59     
60     #define set_base(ldt,base) _set_base( ((char *)&(ldt)) , (base) )
61     #define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , ((limit)-1)>>12 )
62     
63     static inline unsigned long _get_base(char * addr)
64     {
65     	unsigned long __base;
66     	__asm__("movb %3,%%dh\n\t"
67     		"movb %2,%%dl\n\t"
68     		"shll $16,%%edx\n\t"
69     		"movw %1,%%dx"
70     		:"=&d" (__base)
71     		:"m" (*((addr)+2)),
72     		 "m" (*((addr)+4)),
73     		 "m" (*((addr)+7)));
74     	return __base;
75     }
76     
77     #define get_base(ldt) _get_base( ((char *)&(ldt)) )
78     
79     /*
80      * Load a segment. Fall back on loading the zero
81      * segment if something goes wrong..
82      */
83     #define loadsegment(seg,value)			\
84     	asm volatile("\n"			\
85     		"1:\t"				\
86     		"movl %0,%%" #seg "\n"		\
87     		"2:\n"				\
88     		".section .fixup,\"ax\"\n"	\
89     		"3:\t"				\
90     		"pushl $0\n\t"			\
91     		"popl %%" #seg "\n\t"		\
92     		"jmp 2b\n"			\
93     		".previous\n"			\
94     		".section __ex_table,\"a\"\n\t"	\
95     		".align 4\n\t"			\
96     		".long 1b,3b\n"			\
97     		".previous"			\
98     		: :"m" (*(unsigned int *)&(value)))
99     
100     /*
101      * Clear and set 'TS' bit respectively
102      */
103     #define clts() __asm__ __volatile__ ("clts")
104     #define read_cr0() ({ \
105     	unsigned int __dummy; \
106     	__asm__( \
107     		"movl %%cr0,%0\n\t" \
108     		:"=r" (__dummy)); \
109     	__dummy; \
110     })
111     #define write_cr0(x) \
112     	__asm__("movl %0,%%cr0": :"r" (x));
113     #define stts() write_cr0(8 | read_cr0())
114     
115     #endif	/* __KERNEL__ */
116     
117     static inline unsigned long get_limit(unsigned long segment)
118     {
119     	unsigned long __limit;
120     	__asm__("lsll %1,%0"
121     		:"=r" (__limit):"r" (segment));
122     	return __limit+1;
123     }
124     
125     #define nop() __asm__ __volatile__ ("nop")
126     
127     #define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
128     
129     #define tas(ptr) (xchg((ptr),1))
130     
131     struct __xchg_dummy { unsigned long a[100]; };
132     #define __xg(x) ((struct __xchg_dummy *)(x))
133     
134     
135     /*
136      * The semantics of XCHGCMP8B are a bit strange, this is why
137      * there is a loop and the loading of %%eax and %%edx has to
138      * be inside. This inlines well in most cases, the cached
139      * cost is around ~38 cycles. (in the future we might want
140      * to do an SIMD/3DNOW!/MMX/FPU 64-bit store here, but that
141      * might have an implicit FPU-save as a cost, so it's not
142      * clear which path to go.)
143      */
144     extern inline void __set_64bit (unsigned long long * ptr,
145     		unsigned int low, unsigned int high)
146     {
147     __asm__ __volatile__ (
148     	"1:	movl (%0), %%eax;
149     		movl 4(%0), %%edx;
150     		cmpxchg8b (%0);
151     		jnz 1b"
152     	::		"D"(ptr),
153     			"b"(low),
154     			"c"(high)
155     	:
156     			"ax","dx","memory");
157     }
158     
159     extern inline void __set_64bit_constant (unsigned long long *ptr,
160     						 unsigned long long value)
161     {
162     	__set_64bit(ptr,(unsigned int)(value), (unsigned int)((value)>>32ULL));
163     }
164     #define ll_low(x)	*(((unsigned int*)&(x))+0)
165     #define ll_high(x)	*(((unsigned int*)&(x))+1)
166     
167     extern inline void __set_64bit_var (unsigned long long *ptr,
168     			 unsigned long long value)
169     {
170     	__set_64bit(ptr,ll_low(value), ll_high(value));
171     }
172     
173     #define set_64bit(ptr,value) \
174     (__builtin_constant_p(value) ? \
175      __set_64bit_constant(ptr, value) : \
176      __set_64bit_var(ptr, value) )
177     
178     #define _set_64bit(ptr,value) \
179     (__builtin_constant_p(value) ? \
180      __set_64bit(ptr, (unsigned int)(value), (unsigned int)((value)>>32ULL) ) : \
181      __set_64bit(ptr, ll_low(value), ll_high(value)) )
182     
183     /*
184      * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
185      * Note 2: xchg has side effect, so that attribute volatile is necessary,
186      *	  but generally the primitive is invalid, *ptr is output argument. --ANK
187      */
188     static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
189     {
190     	switch (size) {
191     		case 1:
192     			__asm__ __volatile__("xchgb %b0,%1"
193     				:"=q" (x)
194     				:"m" (*__xg(ptr)), "0" (x)
195     				:"memory");
196     			break;
197     		case 2:
198     			__asm__ __volatile__("xchgw %w0,%1"
199     				:"=r" (x)
200     				:"m" (*__xg(ptr)), "0" (x)
201     				:"memory");
202     			break;
203     		case 4:
204     			__asm__ __volatile__("xchgl %0,%1"
205     				:"=r" (x)
206     				:"m" (*__xg(ptr)), "0" (x)
207     				:"memory");
208     			break;
209     	}
210     	return x;
211     }
212     
213     /*
214      * Atomic compare and exchange.  Compare OLD with MEM, if identical,
215      * store NEW in MEM.  Return the initial value in MEM.  Success is
216      * indicated by comparing RETURN with OLD.
217      */
218     
219     #ifdef CONFIG_X86_CMPXCHG
220     #define __HAVE_ARCH_CMPXCHG 1
221     
222     static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
223     				      unsigned long new, int size)
224     {
225     	unsigned long prev;
226     	switch (size) {
227     	case 1:
228     		__asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
229     				     : "=a"(prev)
230     				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
231     				     : "memory");
232     		return prev;
233     	case 2:
234     		__asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
235     				     : "=a"(prev)
236     				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
237     				     : "memory");
238     		return prev;
239     	case 4:
240     		__asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
241     				     : "=a"(prev)
242     				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
243     				     : "memory");
244     		return prev;
245     	}
246     	return old;
247     }
248     
249     #define cmpxchg(ptr,o,n)\
250     	((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
251     					(unsigned long)(n),sizeof(*(ptr))))
252         
253     #else
254     /* Compiling for a 386 proper.	Is it worth implementing via cli/sti?  */
255     #endif
256     
257     /*
258      * Force strict CPU ordering.
259      * And yes, this is required on UP too when we're talking
260      * to devices.
261      *
262      * For now, "wmb()" doesn't actually do anything, as all
263      * Intel CPU's follow what Intel calls a *Processor Order*,
264      * in which all writes are seen in the program order even
265      * outside the CPU.
266      *
267      * I expect future Intel CPU's to have a weaker ordering,
268      * but I'd also expect them to finally get their act together
269      * and add some real memory barriers if so.
270      */
271     #define mb() 	__asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
272     #define rmb()	mb()
273     #define wmb()	__asm__ __volatile__ ("": : :"memory")
274     
275     #ifdef CONFIG_SMP
276     #define smp_mb()	mb()
277     #define smp_rmb()	rmb()
278     #define smp_wmb()	wmb()
279     #else
280     #define smp_mb()	barrier()
281     #define smp_rmb()	barrier()
282     #define smp_wmb()	barrier()
283     #endif
284     
285     #define set_mb(var, value) do { xchg(&var, value); } while (0)
286     #define set_wmb(var, value) do { var = value; wmb(); } while (0)
287     
288     /* interrupt control.. */
289     #define __save_flags(x)		__asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */)
290     #define __restore_flags(x) 	__asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory")
291     #define __cli() 		__asm__ __volatile__("cli": : :"memory")
292     #define __sti()			__asm__ __volatile__("sti": : :"memory")
293     /* used in the idle loop; sti takes one instruction cycle to complete */
294     #define safe_halt()		__asm__ __volatile__("sti; hlt": : :"memory")
295     
296     /* For spinlocks etc */
297     #define local_irq_save(x)	__asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
298     #define local_irq_restore(x)	__restore_flags(x)
299     #define local_irq_disable()	__cli()
300     #define local_irq_enable()	__sti()
301     
302     #ifdef CONFIG_SMP
303     
304     extern void __global_cli(void);
305     extern void __global_sti(void);
306     extern unsigned long __global_save_flags(void);
307     extern void __global_restore_flags(unsigned long);
308     #define cli() __global_cli()
309     #define sti() __global_sti()
310     #define save_flags(x) ((x)=__global_save_flags())
311     #define restore_flags(x) __global_restore_flags(x)
312     
313     #else
314     
315     #define cli() __cli()
316     #define sti() __sti()
317     #define save_flags(x) __save_flags(x)
318     #define restore_flags(x) __restore_flags(x)
319     
320     #endif
321     
322     /*
323      * disable hlt during certain critical i/o operations
324      */
325     #define HAVE_DISABLE_HLT
326     void disable_hlt(void);
327     void enable_hlt(void);
328     
329     #ifndef abs
330     #define abs(x) ((x)<0 ? -x : x)
331     #endif
332     
333     #endif
334