diff options
Diffstat (limited to 'include/asm-i386/paravirt.h')
-rw-r--r-- | include/asm-i386/paravirt.h | 189 |
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__ |
9 | struct thread_struct; | 27 | struct thread_struct; |
10 | struct Xgt_desc_struct; | 28 | struct 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 | ||
150 | static inline unsigned long __raw_local_save_flags(void) | ||
151 | { | ||
152 | return paravirt_ops.save_fl(); | ||
153 | } | ||
154 | |||
155 | static inline void raw_local_irq_restore(unsigned long flags) | ||
156 | { | ||
157 | return paravirt_ops.restore_fl(flags); | ||
158 | } | ||
159 | |||
160 | static inline void raw_local_irq_disable(void) | ||
161 | { | ||
162 | paravirt_ops.irq_disable(); | ||
163 | } | ||
164 | |||
165 | static inline void raw_local_irq_enable(void) | ||
166 | { | ||
167 | paravirt_ops.irq_enable(); | ||
168 | } | ||
169 | |||
170 | static 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 | |||
179 | static inline void raw_safe_halt(void) | 177 | static 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" | 269 | struct 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 | |||
285 | static 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 | |||
298 | static 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 | |||
308 | static 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 | |||
318 | static 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 | |||
328 | static 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 | 363 | 771:; \ |
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 | 365 | 772:; \ |
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 */ |