aboutsummaryrefslogtreecommitdiffstats
path: root/include/asm-i386/paravirt.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/asm-i386/paravirt.h')
-rw-r--r--include/asm-i386/paravirt.h189
1 files changed, 153 insertions, 36 deletions
diff --git a/include/asm-i386/paravirt.h b/include/asm-i386/paravirt.h
index a7551a44686f..081194751ade 100644
--- a/include/asm-i386/paravirt.h
+++ b/include/asm-i386/paravirt.h
@@ -3,8 +3,26 @@
3/* Various instructions on x86 need to be replaced for 3/* Various instructions on x86 need to be replaced for
4 * para-virtualization: those hooks are defined here. */ 4 * para-virtualization: those hooks are defined here. */
5#include <linux/linkage.h> 5#include <linux/linkage.h>
6#include <linux/stringify.h>
6 7
7#ifdef CONFIG_PARAVIRT 8#ifdef CONFIG_PARAVIRT
9/* These are the most performance critical ops, so we want to be able to patch
10 * callers */
11#define PARAVIRT_IRQ_DISABLE 0
12#define PARAVIRT_IRQ_ENABLE 1
13#define PARAVIRT_RESTORE_FLAGS 2
14#define PARAVIRT_SAVE_FLAGS 3
15#define PARAVIRT_SAVE_FLAGS_IRQ_DISABLE 4
16#define PARAVIRT_INTERRUPT_RETURN 5
17#define PARAVIRT_STI_SYSEXIT 6
18
19/* Bitmask of what can be clobbered: usually at least eax. */
20#define CLBR_NONE 0x0
21#define CLBR_EAX 0x1
22#define CLBR_ECX 0x2
23#define CLBR_EDX 0x4
24#define CLBR_ANY 0x7
25
8#ifndef __ASSEMBLY__ 26#ifndef __ASSEMBLY__
9struct thread_struct; 27struct thread_struct;
10struct Xgt_desc_struct; 28struct Xgt_desc_struct;
@@ -15,6 +33,15 @@ struct paravirt_ops
15 int paravirt_enabled; 33 int paravirt_enabled;
16 const char *name; 34 const char *name;
17 35
36 /*
37 * Patch may replace one of the defined code sequences with arbitrary
38 * code, subject to the same register constraints. This generally
39 * means the code is not free to clobber any registers other than EAX.
40 * The patch function should return the number of bytes of code
41 * generated, as we nop pad the rest in generic code.
42 */
43 unsigned (*patch)(u8 type, u16 clobber, void *firstinsn, unsigned len);
44
18 void (*arch_setup)(void); 45 void (*arch_setup)(void);
19 char *(*memory_setup)(void); 46 char *(*memory_setup)(void);
20 void (*init_IRQ)(void); 47 void (*init_IRQ)(void);
@@ -147,35 +174,6 @@ static inline void __cpuid(unsigned int *eax, unsigned int *ebx,
147#define read_cr4_safe(x) paravirt_ops.read_cr4_safe() 174#define read_cr4_safe(x) paravirt_ops.read_cr4_safe()
148#define write_cr4(x) paravirt_ops.write_cr4(x) 175#define write_cr4(x) paravirt_ops.write_cr4(x)
149 176
150static inline unsigned long __raw_local_save_flags(void)
151{
152 return paravirt_ops.save_fl();
153}
154
155static inline void raw_local_irq_restore(unsigned long flags)
156{
157 return paravirt_ops.restore_fl(flags);
158}
159
160static inline void raw_local_irq_disable(void)
161{
162 paravirt_ops.irq_disable();
163}
164
165static inline void raw_local_irq_enable(void)
166{
167 paravirt_ops.irq_enable();
168}
169
170static inline unsigned long __raw_local_irq_save(void)
171{
172 unsigned long flags = paravirt_ops.save_fl();
173
174 paravirt_ops.irq_disable();
175
176 return flags;
177}
178
179static inline void raw_safe_halt(void) 177static inline void raw_safe_halt(void)
180{ 178{
181 paravirt_ops.safe_halt(); 179 paravirt_ops.safe_halt();
@@ -267,15 +265,134 @@ static inline void slow_down_io(void) {
267#endif 265#endif
268} 266}
269 267
270#define CLI_STRING "pushl %eax; pushl %ecx; pushl %edx; call *paravirt_ops+PARAVIRT_irq_disable; popl %edx; popl %ecx; popl %eax" 268/* These all sit in the .parainstructions section to tell us what to patch. */
271#define STI_STRING "pushl %eax; pushl %ecx; pushl %edx; call *paravirt_ops+PARAVIRT_irq_enable; popl %edx; popl %ecx; popl %eax" 269struct paravirt_patch {
270 u8 *instr; /* original instructions */
271 u8 instrtype; /* type of this instruction */
272 u8 len; /* length of original instruction */
273 u16 clobbers; /* what registers you may clobber */
274};
275
276#define paravirt_alt(insn_string, typenum, clobber) \
277 "771:\n\t" insn_string "\n" "772:\n" \
278 ".pushsection .parainstructions,\"a\"\n" \
279 " .long 771b\n" \
280 " .byte " __stringify(typenum) "\n" \
281 " .byte 772b-771b\n" \
282 " .short " __stringify(clobber) "\n" \
283 ".popsection"
284
285static inline unsigned long __raw_local_save_flags(void)
286{
287 unsigned long f;
288
289 __asm__ __volatile__(paravirt_alt( "pushl %%ecx; pushl %%edx;"
290 "call *%1;"
291 "popl %%edx; popl %%ecx",
292 PARAVIRT_SAVE_FLAGS, CLBR_NONE)
293 : "=a"(f): "m"(paravirt_ops.save_fl)
294 : "memory", "cc");
295 return f;
296}
297
298static inline void raw_local_irq_restore(unsigned long f)
299{
300 __asm__ __volatile__(paravirt_alt( "pushl %%ecx; pushl %%edx;"
301 "call *%1;"
302 "popl %%edx; popl %%ecx",
303 PARAVIRT_RESTORE_FLAGS, CLBR_EAX)
304 : "=a"(f) : "m" (paravirt_ops.restore_fl), "0"(f)
305 : "memory", "cc");
306}
307
308static inline void raw_local_irq_disable(void)
309{
310 __asm__ __volatile__(paravirt_alt( "pushl %%ecx; pushl %%edx;"
311 "call *%0;"
312 "popl %%edx; popl %%ecx",
313 PARAVIRT_IRQ_DISABLE, CLBR_EAX)
314 : : "m" (paravirt_ops.irq_disable)
315 : "memory", "eax", "cc");
316}
317
318static inline void raw_local_irq_enable(void)
319{
320 __asm__ __volatile__(paravirt_alt( "pushl %%ecx; pushl %%edx;"
321 "call *%0;"
322 "popl %%edx; popl %%ecx",
323 PARAVIRT_IRQ_ENABLE, CLBR_EAX)
324 : : "m" (paravirt_ops.irq_enable)
325 : "memory", "eax", "cc");
326}
327
328static inline unsigned long __raw_local_irq_save(void)
329{
330 unsigned long f;
331
332 __asm__ __volatile__(paravirt_alt( "pushl %%ecx; pushl %%edx;"
333 "call *%1; pushl %%eax;"
334 "call *%2; popl %%eax;"
335 "popl %%edx; popl %%ecx",
336 PARAVIRT_SAVE_FLAGS_IRQ_DISABLE,
337 CLBR_NONE)
338 : "=a"(f)
339 : "m" (paravirt_ops.save_fl),
340 "m" (paravirt_ops.irq_disable)
341 : "memory", "cc");
342 return f;
343}
344
345#define CLI_STRING paravirt_alt("pushl %%ecx; pushl %%edx;" \
346 "call *paravirt_ops+%c[irq_disable];" \
347 "popl %%edx; popl %%ecx", \
348 PARAVIRT_IRQ_DISABLE, CLBR_EAX)
349
350#define STI_STRING paravirt_alt("pushl %%ecx; pushl %%edx;" \
351 "call *paravirt_ops+%c[irq_enable];" \
352 "popl %%edx; popl %%ecx", \
353 PARAVIRT_IRQ_ENABLE, CLBR_EAX)
354#define CLI_STI_CLOBBERS , "%eax"
355#define CLI_STI_INPUT_ARGS \
356 , \
357 [irq_disable] "i" (offsetof(struct paravirt_ops, irq_disable)), \
358 [irq_enable] "i" (offsetof(struct paravirt_ops, irq_enable))
359
272#else /* __ASSEMBLY__ */ 360#else /* __ASSEMBLY__ */
273 361
274#define INTERRUPT_RETURN jmp *%cs:paravirt_ops+PARAVIRT_iret 362#define PARA_PATCH(ptype, clobbers, ops) \
275#define DISABLE_INTERRUPTS pushl %eax; pushl %ecx; pushl %edx; call *paravirt_ops+PARAVIRT_irq_disable; popl %edx; popl %ecx; popl %eax 363771:; \
276#define ENABLE_INTERRUPTS pushl %eax; pushl %ecx; pushl %edx; call *%cs:paravirt_ops+PARAVIRT_irq_enable; popl %edx; popl %ecx; popl %eax 364 ops; \
277#define ENABLE_INTERRUPTS_SYSEXIT jmp *%cs:paravirt_ops+PARAVIRT_irq_enable_sysexit 365772:; \
278#define GET_CR0_INTO_EAX call *paravirt_ops+PARAVIRT_read_cr0 366 .pushsection .parainstructions,"a"; \
367 .long 771b; \
368 .byte ptype; \
369 .byte 772b-771b; \
370 .short clobbers; \
371 .popsection
372
373#define INTERRUPT_RETURN \
374 PARA_PATCH(PARAVIRT_INTERRUPT_RETURN, CLBR_ANY, \
375 jmp *%cs:paravirt_ops+PARAVIRT_iret)
376
377#define DISABLE_INTERRUPTS(clobbers) \
378 PARA_PATCH(PARAVIRT_IRQ_DISABLE, clobbers, \
379 pushl %ecx; pushl %edx; \
380 call *paravirt_ops+PARAVIRT_irq_disable; \
381 popl %edx; popl %ecx) \
382
383#define ENABLE_INTERRUPTS(clobbers) \
384 PARA_PATCH(PARAVIRT_IRQ_ENABLE, clobbers, \
385 pushl %ecx; pushl %edx; \
386 call *%cs:paravirt_ops+PARAVIRT_irq_enable; \
387 popl %edx; popl %ecx)
388
389#define ENABLE_INTERRUPTS_SYSEXIT \
390 PARA_PATCH(PARAVIRT_STI_SYSEXIT, CLBR_ANY, \
391 jmp *%cs:paravirt_ops+PARAVIRT_irq_enable_sysexit)
392
393#define GET_CR0_INTO_EAX \
394 call *paravirt_ops+PARAVIRT_read_cr0
395
279#endif /* __ASSEMBLY__ */ 396#endif /* __ASSEMBLY__ */
280#endif /* CONFIG_PARAVIRT */ 397#endif /* CONFIG_PARAVIRT */
281#endif /* __ASM_PARAVIRT_H */ 398#endif /* __ASM_PARAVIRT_H */