File: /usr/src/linux/include/asm-i386/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     
114     #define read_cr4() ({ \
115     	unsigned int __dummy; \
116     	__asm__( \
117     		"movl %%cr4,%0\n\t" \
118     		:"=r" (__dummy)); \
119     	__dummy; \
120     })
121     #define write_cr4(x) \
122     	__asm__("movl %0,%%cr4": :"r" (x));
123     #define stts() write_cr0(8 | read_cr0())
124     
125     #endif	/* __KERNEL__ */
126     
127     #define wbinvd() \
128     	__asm__ __volatile__ ("wbinvd": : :"memory");
129     
130     static inline unsigned long get_limit(unsigned long segment)
131     {
132     	unsigned long __limit;
133     	__asm__("lsll %1,%0"
134     		:"=r" (__limit):"r" (segment));
135     	return __limit+1;
136     }
137     
138     #define nop() __asm__ __volatile__ ("nop")
139     
140     #define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
141     
142     #define tas(ptr) (xchg((ptr),1))
143     
144     struct __xchg_dummy { unsigned long a[100]; };
145     #define __xg(x) ((struct __xchg_dummy *)(x))
146     
147     
148     /*
149      * The semantics of XCHGCMP8B are a bit strange, this is why
150      * there is a loop and the loading of %%eax and %%edx has to
151      * be inside. This inlines well in most cases, the cached
152      * cost is around ~38 cycles. (in the future we might want
153      * to do an SIMD/3DNOW!/MMX/FPU 64-bit store here, but that
154      * might have an implicit FPU-save as a cost, so it's not
155      * clear which path to go.)
156      */
157     static inline void __set_64bit (unsigned long long * ptr,
158     		unsigned int low, unsigned int high)
159     {
160     	__asm__ __volatile__ (
161     		"\n1:\t"
162     		"movl (%0), %%eax\n\t"
163     		"movl 4(%0), %%edx\n\t"
164     		"cmpxchg8b (%0)\n\t"
165     		"jnz 1b"
166     		: /* no outputs */
167     		:	"D"(ptr),
168     			"b"(low),
169     			"c"(high)
170     		:	"ax","dx","memory");
171     }
172     
173     static inline void __set_64bit_constant (unsigned long long *ptr,
174     						 unsigned long long value)
175     {
176     	__set_64bit(ptr,(unsigned int)(value), (unsigned int)((value)>>32ULL));
177     }
178     #define ll_low(x)	*(((unsigned int*)&(x))+0)
179     #define ll_high(x)	*(((unsigned int*)&(x))+1)
180     
181     static inline void __set_64bit_var (unsigned long long *ptr,
182     			 unsigned long long value)
183     {
184     	__set_64bit(ptr,ll_low(value), ll_high(value));
185     }
186     
187     #define set_64bit(ptr,value) \
188     (__builtin_constant_p(value) ? \
189      __set_64bit_constant(ptr, value) : \
190      __set_64bit_var(ptr, value) )
191     
192     #define _set_64bit(ptr,value) \
193     (__builtin_constant_p(value) ? \
194      __set_64bit(ptr, (unsigned int)(value), (unsigned int)((value)>>32ULL) ) : \
195      __set_64bit(ptr, ll_low(value), ll_high(value)) )
196     
197     /*
198      * Note: no "lock" prefix even on SMP: xchg always implies lock anyway
199      * Note 2: xchg has side effect, so that attribute volatile is necessary,
200      *	  but generally the primitive is invalid, *ptr is output argument. --ANK
201      */
202     static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
203     {
204     	switch (size) {
205     		case 1:
206     			__asm__ __volatile__("xchgb %b0,%1"
207     				:"=q" (x)
208     				:"m" (*__xg(ptr)), "0" (x)
209     				:"memory");
210     			break;
211     		case 2:
212     			__asm__ __volatile__("xchgw %w0,%1"
213     				:"=r" (x)
214     				:"m" (*__xg(ptr)), "0" (x)
215     				:"memory");
216     			break;
217     		case 4:
218     			__asm__ __volatile__("xchgl %0,%1"
219     				:"=r" (x)
220     				:"m" (*__xg(ptr)), "0" (x)
221     				:"memory");
222     			break;
223     	}
224     	return x;
225     }
226     
227     /*
228      * Atomic compare and exchange.  Compare OLD with MEM, if identical,
229      * store NEW in MEM.  Return the initial value in MEM.  Success is
230      * indicated by comparing RETURN with OLD.
231      */
232     
233     #ifdef CONFIG_X86_CMPXCHG
234     #define __HAVE_ARCH_CMPXCHG 1
235     
236     static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
237     				      unsigned long new, int size)
238     {
239     	unsigned long prev;
240     	switch (size) {
241     	case 1:
242     		__asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
243     				     : "=a"(prev)
244     				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
245     				     : "memory");
246     		return prev;
247     	case 2:
248     		__asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
249     				     : "=a"(prev)
250     				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
251     				     : "memory");
252     		return prev;
253     	case 4:
254     		__asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2"
255     				     : "=a"(prev)
256     				     : "q"(new), "m"(*__xg(ptr)), "0"(old)
257     				     : "memory");
258     		return prev;
259     	}
260     	return old;
261     }
262     
263     #define cmpxchg(ptr,o,n)\
264     	((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
265     					(unsigned long)(n),sizeof(*(ptr))))
266         
267     #else
268     /* Compiling for a 386 proper.	Is it worth implementing via cli/sti?  */
269     #endif
270     
271     /*
272      * Force strict CPU ordering.
273      * And yes, this is required on UP too when we're talking
274      * to devices.
275      *
276      * For now, "wmb()" doesn't actually do anything, as all
277      * Intel CPU's follow what Intel calls a *Processor Order*,
278      * in which all writes are seen in the program order even
279      * outside the CPU.
280      *
281      * I expect future Intel CPU's to have a weaker ordering,
282      * but I'd also expect them to finally get their act together
283      * and add some real memory barriers if so.
284      */
285     #define mb() 	__asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
286     #define rmb()	mb()
287     #define wmb()	__asm__ __volatile__ ("": : :"memory")
288     
289     #ifdef CONFIG_SMP
290     #define smp_mb()	mb()
291     #define smp_rmb()	rmb()
292     #define smp_wmb()	wmb()
293     #else
294     #define smp_mb()	barrier()
295     #define smp_rmb()	barrier()
296     #define smp_wmb()	barrier()
297     #endif
298     
299     #define set_mb(var, value) do { xchg(&var, value); } while (0)
300     #define set_wmb(var, value) do { var = value; wmb(); } while (0)
301     
302     /* interrupt control.. */
303     #define __save_flags(x)		__asm__ __volatile__("pushfl ; popl %0":"=g" (x): /* no input */)
304     #define __restore_flags(x) 	__asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory", "cc")
305     #define __cli() 		__asm__ __volatile__("cli": : :"memory")
306     #define __sti()			__asm__ __volatile__("sti": : :"memory")
307     /* used in the idle loop; sti takes one instruction cycle to complete */
308     #define safe_halt()		__asm__ __volatile__("sti; hlt": : :"memory")
309     
310     /* For spinlocks etc */
311     #define local_irq_save(x)	__asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
312     #define local_irq_restore(x)	__restore_flags(x)
313     #define local_irq_disable()	__cli()
314     #define local_irq_enable()	__sti()
315     
316     #ifdef CONFIG_SMP
317     
318     extern void __global_cli(void);
319     extern void __global_sti(void);
320     extern unsigned long __global_save_flags(void);
321     extern void __global_restore_flags(unsigned long);
322     #define cli() __global_cli()
323     #define sti() __global_sti()
324     #define save_flags(x) ((x)=__global_save_flags())
325     #define restore_flags(x) __global_restore_flags(x)
326     
327     #else
328     
329     #define cli() __cli()
330     #define sti() __sti()
331     #define save_flags(x) __save_flags(x)
332     #define restore_flags(x) __restore_flags(x)
333     
334     #endif
335     
336     /*
337      * disable hlt during certain critical i/o operations
338      */
339     #define HAVE_DISABLE_HLT
340     void disable_hlt(void);
341     void enable_hlt(void);
342     
343     #endif
344