1 |
1275 |
phoenix |
#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 |
|
|
|
8 |
|
|
#ifdef __KERNEL__
|
9 |
|
|
|
10 |
|
|
#ifdef CONFIG_SMP
|
11 |
|
|
#define LOCK_PREFIX "lock ; "
|
12 |
|
|
#else
|
13 |
|
|
#define LOCK_PREFIX ""
|
14 |
|
|
#endif
|
15 |
|
|
|
16 |
|
|
#define prepare_to_switch() do {} while(0)
|
17 |
|
|
|
18 |
|
|
#define __STR(x) #x
|
19 |
|
|
#define STR(x) __STR(x)
|
20 |
|
|
|
21 |
|
|
#define __PUSH(x) "pushq %%" __STR(x) "\n\t"
|
22 |
|
|
#define __POP(x) "popq %%" __STR(x) "\n\t"
|
23 |
|
|
|
24 |
|
|
struct save_context_frame {
|
25 |
|
|
unsigned long rbp;
|
26 |
|
|
unsigned long rbx;
|
27 |
|
|
unsigned long r11;
|
28 |
|
|
unsigned long r10;
|
29 |
|
|
unsigned long r9;
|
30 |
|
|
unsigned long r8;
|
31 |
|
|
unsigned long rcx;
|
32 |
|
|
unsigned long rdx;
|
33 |
|
|
unsigned long r15;
|
34 |
|
|
unsigned long r14;
|
35 |
|
|
unsigned long r13;
|
36 |
|
|
unsigned long r12;
|
37 |
|
|
unsigned long rdi;
|
38 |
|
|
unsigned long rsi;
|
39 |
|
|
};
|
40 |
|
|
|
41 |
|
|
/* frame pointer must be last for get_wchan */
|
42 |
|
|
#define SAVE_CONTEXT \
|
43 |
|
|
__PUSH(rsi) __PUSH(rdi) \
|
44 |
|
|
__PUSH(r12) __PUSH(r13) __PUSH(r14) __PUSH(r15) \
|
45 |
|
|
__PUSH(rdx) __PUSH(rcx) __PUSH(r8) __PUSH(r9) __PUSH(r10) __PUSH(r11) \
|
46 |
|
|
__PUSH(rbx) __PUSH(rbp)
|
47 |
|
|
#define RESTORE_CONTEXT \
|
48 |
|
|
__POP(rbp) __POP(rbx) \
|
49 |
|
|
__POP(r11) __POP(r10) __POP(r9) __POP(r8) __POP(rcx) __POP(rdx) \
|
50 |
|
|
__POP(r15) __POP(r14) __POP(r13) __POP(r12) \
|
51 |
|
|
__POP(rdi) __POP(rsi)
|
52 |
|
|
|
53 |
|
|
#define switch_to(prev,next,last) do { void *l; \
|
54 |
|
|
asm volatile(SAVE_CONTEXT \
|
55 |
|
|
"movq %%rsp,%0\n\t" /* save RSP */ \
|
56 |
|
|
"movq %3,%%rsp\n\t" /* restore RSP */ \
|
57 |
|
|
"leaq thread_return(%%rip),%%rax\n\t" \
|
58 |
|
|
"movq %%rax,%1\n\t" /* save RIP */ \
|
59 |
|
|
"pushq %4\n\t" /* setup new RIP */ \
|
60 |
|
|
"jmp __switch_to\n\t" \
|
61 |
|
|
".globl thread_return\n" \
|
62 |
|
|
"thread_return:\n\t" \
|
63 |
|
|
RESTORE_CONTEXT \
|
64 |
|
|
:"=m" (prev->thread.rsp),"=m" (prev->thread.rip), "=a" (l) \
|
65 |
|
|
:"m" (next->thread.rsp),"m" (next->thread.rip), \
|
66 |
|
|
"S" (next), "D" (prev) \
|
67 |
|
|
:"memory","cc"); \
|
68 |
|
|
last = l; \
|
69 |
|
|
} while(0)
|
70 |
|
|
|
71 |
|
|
extern void load_gs_index(unsigned);
|
72 |
|
|
|
73 |
|
|
/*
|
74 |
|
|
* Load a segment. Fall back on loading the zero
|
75 |
|
|
* segment if something goes wrong..
|
76 |
|
|
*/
|
77 |
|
|
#define loadsegment(seg,value) \
|
78 |
|
|
asm volatile("\n" \
|
79 |
|
|
"1:\t" \
|
80 |
|
|
"movl %0,%%" #seg "\n" \
|
81 |
|
|
"2:\n" \
|
82 |
|
|
".section .fixup,\"ax\"\n" \
|
83 |
|
|
"3:\t" \
|
84 |
|
|
"movl %1,%%" #seg "\n\t" \
|
85 |
|
|
"jmp 2b\n" \
|
86 |
|
|
".previous\n" \
|
87 |
|
|
".section __ex_table,\"a\"\n\t" \
|
88 |
|
|
".align 4\n\t" \
|
89 |
|
|
".quad 1b,3b\n" \
|
90 |
|
|
".previous" \
|
91 |
|
|
: :"r" ((int)(value)), "r" (0))
|
92 |
|
|
|
93 |
|
|
#define set_debug(value,register) \
|
94 |
|
|
__asm__("movq %0,%%db" #register \
|
95 |
|
|
: /* no output */ \
|
96 |
|
|
:"r" ((unsigned long) value))
|
97 |
|
|
|
98 |
|
|
|
99 |
|
|
/*
|
100 |
|
|
* Clear and set 'TS' bit respectively
|
101 |
|
|
*/
|
102 |
|
|
#define clts() __asm__ __volatile__ ("clts")
|
103 |
|
|
#define read_cr0() ({ \
|
104 |
|
|
unsigned long __dummy; \
|
105 |
|
|
__asm__( \
|
106 |
|
|
"movq %%cr0,%0\n\t" \
|
107 |
|
|
:"=r" (__dummy)); \
|
108 |
|
|
__dummy; \
|
109 |
|
|
})
|
110 |
|
|
#define write_cr0(x) \
|
111 |
|
|
__asm__("movq %0,%%cr0": :"r" (x));
|
112 |
|
|
|
113 |
|
|
#define read_cr4() ({ \
|
114 |
|
|
unsigned long __dummy; \
|
115 |
|
|
__asm__( \
|
116 |
|
|
"movq %%cr4,%0\n\t" \
|
117 |
|
|
:"=r" (__dummy)); \
|
118 |
|
|
__dummy; \
|
119 |
|
|
})
|
120 |
|
|
#define write_cr4(x) \
|
121 |
|
|
__asm__("movq %0,%%cr4": :"r" (x));
|
122 |
|
|
#define stts() write_cr0(8 | read_cr0())
|
123 |
|
|
|
124 |
|
|
#define wbinvd() \
|
125 |
|
|
__asm__ __volatile__ ("wbinvd": : :"memory");
|
126 |
|
|
|
127 |
|
|
#endif /* __KERNEL__ */
|
128 |
|
|
|
129 |
|
|
#define nop() __asm__ __volatile__ ("nop")
|
130 |
|
|
|
131 |
|
|
#define xchg(ptr,v) ((__typeof__(*(ptr)))__xchg((unsigned long)(v),(ptr),sizeof(*(ptr))))
|
132 |
|
|
|
133 |
|
|
#define tas(ptr) (xchg((ptr),1))
|
134 |
|
|
|
135 |
|
|
#define __xg(x) ((volatile long *)(x))
|
136 |
|
|
|
137 |
|
|
extern inline void set_64bit(volatile unsigned long *ptr, unsigned long val)
|
138 |
|
|
{
|
139 |
|
|
*ptr = val;
|
140 |
|
|
}
|
141 |
|
|
|
142 |
|
|
#define _set_64bit set_64bit
|
143 |
|
|
|
144 |
|
|
/*
|
145 |
|
|
* Note: no "lock" prefix even on SMP: xchg always implies lock anyway
|
146 |
|
|
* Note 2: xchg has side effect, so that attribute volatile is necessary,
|
147 |
|
|
* but generally the primitive is invalid, *ptr is output argument. --ANK
|
148 |
|
|
*/
|
149 |
|
|
static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
|
150 |
|
|
{
|
151 |
|
|
switch (size) {
|
152 |
|
|
case 1:
|
153 |
|
|
__asm__ __volatile__("xchgb %b0,%1"
|
154 |
|
|
:"=q" (x)
|
155 |
|
|
:"m" (*__xg(ptr)), "0" (x)
|
156 |
|
|
:"memory");
|
157 |
|
|
break;
|
158 |
|
|
case 2:
|
159 |
|
|
__asm__ __volatile__("xchgw %w0,%1"
|
160 |
|
|
:"=r" (x)
|
161 |
|
|
:"m" (*__xg(ptr)), "0" (x)
|
162 |
|
|
:"memory");
|
163 |
|
|
break;
|
164 |
|
|
case 4:
|
165 |
|
|
__asm__ __volatile__("xchgl %k0,%1"
|
166 |
|
|
:"=r" (x)
|
167 |
|
|
:"m" (*__xg(ptr)), "0" (x)
|
168 |
|
|
:"memory");
|
169 |
|
|
break;
|
170 |
|
|
case 8:
|
171 |
|
|
__asm__ __volatile__("xchgq %0,%1"
|
172 |
|
|
:"=r" (x)
|
173 |
|
|
:"m" (*__xg(ptr)), "0" (x)
|
174 |
|
|
:"memory");
|
175 |
|
|
break;
|
176 |
|
|
}
|
177 |
|
|
return x;
|
178 |
|
|
}
|
179 |
|
|
|
180 |
|
|
/*
|
181 |
|
|
* Atomic compare and exchange. Compare OLD with MEM, if identical,
|
182 |
|
|
* store NEW in MEM. Return the initial value in MEM. Success is
|
183 |
|
|
* indicated by comparing RETURN with OLD.
|
184 |
|
|
*/
|
185 |
|
|
|
186 |
|
|
#define __HAVE_ARCH_CMPXCHG 1
|
187 |
|
|
|
188 |
|
|
static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
|
189 |
|
|
unsigned long new, int size)
|
190 |
|
|
{
|
191 |
|
|
unsigned long prev;
|
192 |
|
|
switch (size) {
|
193 |
|
|
case 1:
|
194 |
|
|
__asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2"
|
195 |
|
|
: "=a"(prev)
|
196 |
|
|
: "q"(new), "m"(*__xg(ptr)), "0"(old)
|
197 |
|
|
: "memory");
|
198 |
|
|
return prev;
|
199 |
|
|
case 2:
|
200 |
|
|
__asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2"
|
201 |
|
|
: "=a"(prev)
|
202 |
|
|
: "q"(new), "m"(*__xg(ptr)), "0"(old)
|
203 |
|
|
: "memory");
|
204 |
|
|
return prev;
|
205 |
|
|
case 4:
|
206 |
|
|
__asm__ __volatile__(LOCK_PREFIX "cmpxchgl %k1,%2"
|
207 |
|
|
: "=a"(prev)
|
208 |
|
|
: "q"(new), "m"(*__xg(ptr)), "0"(old)
|
209 |
|
|
: "memory");
|
210 |
|
|
return prev;
|
211 |
|
|
case 8:
|
212 |
|
|
__asm__ __volatile__(LOCK_PREFIX "cmpxchgq %1,%2"
|
213 |
|
|
: "=a"(prev)
|
214 |
|
|
: "q"(new), "m"(*__xg(ptr)), "0"(old)
|
215 |
|
|
: "memory");
|
216 |
|
|
return prev;
|
217 |
|
|
}
|
218 |
|
|
return old;
|
219 |
|
|
}
|
220 |
|
|
|
221 |
|
|
#define cmpxchg(ptr,o,n)\
|
222 |
|
|
((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\
|
223 |
|
|
(unsigned long)(n),sizeof(*(ptr))))
|
224 |
|
|
|
225 |
|
|
|
226 |
|
|
#ifdef CONFIG_SMP
|
227 |
|
|
#define smp_mb() mb()
|
228 |
|
|
#define smp_rmb() rmb()
|
229 |
|
|
#define smp_wmb() wmb()
|
230 |
|
|
#else
|
231 |
|
|
#define smp_mb() barrier()
|
232 |
|
|
#define smp_rmb() barrier()
|
233 |
|
|
#define smp_wmb() barrier()
|
234 |
|
|
#endif
|
235 |
|
|
|
236 |
|
|
|
237 |
|
|
/*
|
238 |
|
|
* Force strict CPU ordering.
|
239 |
|
|
* And yes, this is required on UP too when we're talking
|
240 |
|
|
* to devices.
|
241 |
|
|
*
|
242 |
|
|
* For now, "wmb()" doesn't actually do anything, as all
|
243 |
|
|
* Intel CPU's follow what Intel calls a *Processor Order*,
|
244 |
|
|
* in which all writes are seen in the program order even
|
245 |
|
|
* outside the CPU.
|
246 |
|
|
*
|
247 |
|
|
* I expect future Intel CPU's to have a weaker ordering,
|
248 |
|
|
* but I'd also expect them to finally get their act together
|
249 |
|
|
* and add some real memory barriers if so.
|
250 |
|
|
*/
|
251 |
|
|
#define mb() asm volatile("mfence":::"memory")
|
252 |
|
|
#define rmb() asm volatile("lfence":::"memory")
|
253 |
|
|
#define wmb() asm volatile("sfence":::"memory")
|
254 |
|
|
#define set_mb(var, value) do { xchg(&var, value); } while (0)
|
255 |
|
|
#define set_wmb(var, value) do { var = value; wmb(); } while (0)
|
256 |
|
|
|
257 |
|
|
#define warn_if_not_ulong(x) do { unsigned long foo; (void) (&(x) == &foo); } while (0)
|
258 |
|
|
|
259 |
|
|
/* interrupt control.. */
|
260 |
|
|
#define __save_flags(x) do { warn_if_not_ulong(x); __asm__ __volatile__("# save_flags \n\t pushfq ; popq %q0":"=g" (x): /* no input */ :"memory"); } while (0)
|
261 |
|
|
#define __restore_flags(x) __asm__ __volatile__("# restore_flags \n\t pushq %0 ; popfq": /* no output */ :"g" (x):"memory", "cc")
|
262 |
|
|
#define __cli() __asm__ __volatile__("cli": : :"memory")
|
263 |
|
|
#define __sti() __asm__ __volatile__("sti": : :"memory")
|
264 |
|
|
/* used in the idle loop; sti takes one instruction cycle to complete */
|
265 |
|
|
#define safe_halt() __asm__ __volatile__("sti; hlt": : :"memory")
|
266 |
|
|
|
267 |
|
|
#define __save_and_cli(x) do { __save_flags(x); __cli(); } while(0)
|
268 |
|
|
#define __save_and_sti(x) do { __save_flags(x); __sti(); } while(0)
|
269 |
|
|
|
270 |
|
|
/* For spinlocks etc */
|
271 |
|
|
#define local_irq_save(x) do { warn_if_not_ulong(x); __asm__ __volatile__("# local_irq_save \n\t pushfq ; popq %0 ; cli":"=g" (x): /* no input */ :"memory"); } while (0)
|
272 |
|
|
#define local_irq_set(x) do { warn_if_not_ulong(x); __asm__ __volatile__("# local_irq_set \n\t pushfq ; popq %0 ; sti":"=g" (x): /* no input */ :"memory"); } while (0)
|
273 |
|
|
#define local_irq_restore(x) __asm__ __volatile__("# local_irq_restore \n\t pushq %0 ; popfq": /* no output */ :"g" (x):"memory")
|
274 |
|
|
#define local_irq_disable() __cli()
|
275 |
|
|
#define local_irq_enable() __sti()
|
276 |
|
|
|
277 |
|
|
#ifdef CONFIG_SMP
|
278 |
|
|
|
279 |
|
|
extern void __global_cli(void);
|
280 |
|
|
extern void __global_sti(void);
|
281 |
|
|
extern unsigned long __global_save_flags(void);
|
282 |
|
|
extern void __global_restore_flags(unsigned long);
|
283 |
|
|
#define cli() __global_cli()
|
284 |
|
|
#define sti() __global_sti()
|
285 |
|
|
#define save_flags(x) ((x)=__global_save_flags())
|
286 |
|
|
#define restore_flags(x) __global_restore_flags(x)
|
287 |
|
|
#define save_and_cli(x) do { save_flags(x); cli(); } while(0)
|
288 |
|
|
#define save_and_sti(x) do { save_flags(x); sti(); } while(0)
|
289 |
|
|
|
290 |
|
|
#else
|
291 |
|
|
|
292 |
|
|
#define cli() __cli()
|
293 |
|
|
#define sti() __sti()
|
294 |
|
|
#define save_flags(x) __save_flags(x)
|
295 |
|
|
#define restore_flags(x) __restore_flags(x)
|
296 |
|
|
#define save_and_cli(x) __save_and_cli(x)
|
297 |
|
|
#define save_and_sti(x) __save_and_sti(x)
|
298 |
|
|
|
299 |
|
|
#endif
|
300 |
|
|
|
301 |
|
|
/* Default simics "magic" breakpoint */
|
302 |
|
|
#define icebp() asm volatile("xchg %%bx,%%bx" ::: "ebx")
|
303 |
|
|
|
304 |
|
|
/*
|
305 |
|
|
* disable hlt during certain critical i/o operations
|
306 |
|
|
*/
|
307 |
|
|
#define HAVE_DISABLE_HLT
|
308 |
|
|
void disable_hlt(void);
|
309 |
|
|
void enable_hlt(void);
|
310 |
|
|
|
311 |
|
|
#endif
|