aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorJeremy Fitzhardinge <jeremy@goop.org>2007-05-02 13:27:14 -0400
committerAndi Kleen <andi@basil.nowhere.org>2007-05-02 13:27:14 -0400
commitd582203578a1f3d408e27bb9042e8635954cd320 (patch)
tree385952bdda8f9c2b6b4c9c659a0eba872749e948 /include
parent98de032b681d8a7532d44dfc66aa5c0c1c755a9d (diff)
[PATCH] i386: PARAVIRT: Use patch site IDs computed from offset in paravirt_ops structure
Use patch type identifiers derived from the offset of the operation in the paravirt_ops structure. This avoids having to maintain a separate enum for patch site types. Also, since the identifier is derived from the offset into paravirt_ops, the offset can be derived from the identifier. This is used to remove replicated information in the various callsite macros, which has been a source of bugs in the past. This patch also drops the fused save_fl+cli operation, which doesn't really add much and makes things more complex - specifically because it breaks the 1:1 relationship between identifiers and offsets. If this operation turns out to be particularly beneficial, then the right answer is to define a new entrypoint for it. Signed-off-by: Jeremy Fitzhardinge <jeremy@xensource.com> Signed-off-by: Andi Kleen <ak@suse.de> Cc: Rusty Russell <rusty@rustcorp.com.au> Cc: Zachary Amsden <zach@vmware.com>
Diffstat (limited to 'include')
-rw-r--r--include/asm-i386/paravirt.h177
1 files changed, 92 insertions, 85 deletions
diff --git a/include/asm-i386/paravirt.h b/include/asm-i386/paravirt.h
index b4cc2fc4031..1dbc01f4ed4 100644
--- a/include/asm-i386/paravirt.h
+++ b/include/asm-i386/paravirt.h
@@ -4,19 +4,8 @@
4 * para-virtualization: those hooks are defined here. */ 4 * para-virtualization: those hooks are defined here. */
5 5
6#ifdef CONFIG_PARAVIRT 6#ifdef CONFIG_PARAVIRT
7#include <linux/stringify.h>
8#include <asm/page.h> 7#include <asm/page.h>
9 8
10/* These are the most performance critical ops, so we want to be able to patch
11 * callers */
12#define PARAVIRT_IRQ_DISABLE 0
13#define PARAVIRT_IRQ_ENABLE 1
14#define PARAVIRT_RESTORE_FLAGS 2
15#define PARAVIRT_SAVE_FLAGS 3
16#define PARAVIRT_SAVE_FLAGS_IRQ_DISABLE 4
17#define PARAVIRT_INTERRUPT_RETURN 5
18#define PARAVIRT_STI_SYSEXIT 6
19
20/* Bitmask of what can be clobbered: usually at least eax. */ 9/* Bitmask of what can be clobbered: usually at least eax. */
21#define CLBR_NONE 0x0 10#define CLBR_NONE 0x0
22#define CLBR_EAX 0x1 11#define CLBR_EAX 0x1
@@ -191,6 +180,28 @@ struct paravirt_ops
191 180
192extern struct paravirt_ops paravirt_ops; 181extern struct paravirt_ops paravirt_ops;
193 182
183#define PARAVIRT_PATCH(x) \
184 (offsetof(struct paravirt_ops, x) / sizeof(void *))
185
186#define paravirt_type(type) \
187 [paravirt_typenum] "i" (PARAVIRT_PATCH(type))
188#define paravirt_clobber(clobber) \
189 [paravirt_clobber] "i" (clobber)
190
191#define PARAVIRT_CALL "call *paravirt_ops+%c[paravirt_typenum]*4;"
192
193#define _paravirt_alt(insn_string, type, clobber) \
194 "771:\n\t" insn_string "\n" "772:\n" \
195 ".pushsection .parainstructions,\"a\"\n" \
196 " .long 771b\n" \
197 " .byte " type "\n" \
198 " .byte 772b-771b\n" \
199 " .short " clobber "\n" \
200 ".popsection\n"
201
202#define paravirt_alt(insn_string) \
203 _paravirt_alt(insn_string, "%c[paravirt_typenum]", "%c[paravirt_clobber]")
204
194#define paravirt_enabled() (paravirt_ops.paravirt_enabled) 205#define paravirt_enabled() (paravirt_ops.paravirt_enabled)
195 206
196static inline void load_esp0(struct tss_struct *tss, 207static inline void load_esp0(struct tss_struct *tss,
@@ -515,93 +526,89 @@ struct paravirt_patch_site {
515extern struct paravirt_patch_site __parainstructions[], 526extern struct paravirt_patch_site __parainstructions[],
516 __parainstructions_end[]; 527 __parainstructions_end[];
517 528
518#define paravirt_alt(insn_string, typenum, clobber) \
519 "771:\n\t" insn_string "\n" "772:\n" \
520 ".pushsection .parainstructions,\"a\"\n" \
521 " .long 771b\n" \
522 " .byte " __stringify(typenum) "\n" \
523 " .byte 772b-771b\n" \
524 " .short " __stringify(clobber) "\n" \
525 ".popsection"
526
527static inline unsigned long __raw_local_save_flags(void) 529static inline unsigned long __raw_local_save_flags(void)
528{ 530{
529 unsigned long f; 531 unsigned long f;
530 532
531 __asm__ __volatile__(paravirt_alt( "pushl %%ecx; pushl %%edx;" 533 asm volatile(paravirt_alt("pushl %%ecx; pushl %%edx;"
532 "call *%1;" 534 PARAVIRT_CALL
533 "popl %%edx; popl %%ecx", 535 "popl %%edx; popl %%ecx")
534 PARAVIRT_SAVE_FLAGS, CLBR_NONE) 536 : "=a"(f)
535 : "=a"(f): "m"(paravirt_ops.save_fl) 537 : paravirt_type(save_fl),
536 : "memory", "cc"); 538 paravirt_clobber(CLBR_NONE)
539 : "memory", "cc");
537 return f; 540 return f;
538} 541}
539 542
540static inline void raw_local_irq_restore(unsigned long f) 543static inline void raw_local_irq_restore(unsigned long f)
541{ 544{
542 __asm__ __volatile__(paravirt_alt( "pushl %%ecx; pushl %%edx;" 545 asm volatile(paravirt_alt("pushl %%ecx; pushl %%edx;"
543 "call *%1;" 546 PARAVIRT_CALL
544 "popl %%edx; popl %%ecx", 547 "popl %%edx; popl %%ecx")
545 PARAVIRT_RESTORE_FLAGS, CLBR_EAX) 548 : "=a"(f)
546 : "=a"(f) : "m" (paravirt_ops.restore_fl), "0"(f) 549 : "0"(f),
547 : "memory", "cc"); 550 paravirt_type(restore_fl),
551 paravirt_clobber(CLBR_EAX)
552 : "memory", "cc");
548} 553}
549 554
550static inline void raw_local_irq_disable(void) 555static inline void raw_local_irq_disable(void)
551{ 556{
552 __asm__ __volatile__(paravirt_alt( "pushl %%ecx; pushl %%edx;" 557 asm volatile(paravirt_alt("pushl %%ecx; pushl %%edx;"
553 "call *%0;" 558 PARAVIRT_CALL
554 "popl %%edx; popl %%ecx", 559 "popl %%edx; popl %%ecx")
555 PARAVIRT_IRQ_DISABLE, CLBR_EAX) 560 :
556 : : "m" (paravirt_ops.irq_disable) 561 : paravirt_type(irq_disable),
557 : "memory", "eax", "cc"); 562 paravirt_clobber(CLBR_EAX)
563 : "memory", "eax", "cc");
558} 564}
559 565
560static inline void raw_local_irq_enable(void) 566static inline void raw_local_irq_enable(void)
561{ 567{
562 __asm__ __volatile__(paravirt_alt( "pushl %%ecx; pushl %%edx;" 568 asm volatile(paravirt_alt("pushl %%ecx; pushl %%edx;"
563 "call *%0;" 569 PARAVIRT_CALL
564 "popl %%edx; popl %%ecx", 570 "popl %%edx; popl %%ecx")
565 PARAVIRT_IRQ_ENABLE, CLBR_EAX) 571 :
566 : : "m" (paravirt_ops.irq_enable) 572 : paravirt_type(irq_enable),
567 : "memory", "eax", "cc"); 573 paravirt_clobber(CLBR_EAX)
574 : "memory", "eax", "cc");
568} 575}
569 576
570static inline unsigned long __raw_local_irq_save(void) 577static inline unsigned long __raw_local_irq_save(void)
571{ 578{
572 unsigned long f; 579 unsigned long f;
573 580
574 __asm__ __volatile__(paravirt_alt( "pushl %%ecx; pushl %%edx;" 581 f = __raw_local_save_flags();
575 "call *%1; pushl %%eax;" 582 raw_local_irq_disable();
576 "call *%2; popl %%eax;"
577 "popl %%edx; popl %%ecx",
578 PARAVIRT_SAVE_FLAGS_IRQ_DISABLE,
579 CLBR_NONE)
580 : "=a"(f)
581 : "m" (paravirt_ops.save_fl),
582 "m" (paravirt_ops.irq_disable)
583 : "memory", "cc");
584 return f; 583 return f;
585} 584}
586 585
587#define CLI_STRING paravirt_alt("pushl %%ecx; pushl %%edx;" \ 586#define CLI_STRING \
588 "call *paravirt_ops+%c[irq_disable];" \ 587 _paravirt_alt("pushl %%ecx; pushl %%edx;" \
589 "popl %%edx; popl %%ecx", \ 588 "call *paravirt_ops+%c[paravirt_cli_type]*4;" \
590 PARAVIRT_IRQ_DISABLE, CLBR_EAX) 589 "popl %%edx; popl %%ecx", \
590 "%c[paravirt_cli_type]", "%c[paravirt_clobber]")
591
592#define STI_STRING \
593 _paravirt_alt("pushl %%ecx; pushl %%edx;" \
594 "call *paravirt_ops+%c[paravirt_sti_type]*4;" \
595 "popl %%edx; popl %%ecx", \
596 "%c[paravirt_sti_type]", "%c[paravirt_clobber]")
591 597
592#define STI_STRING paravirt_alt("pushl %%ecx; pushl %%edx;" \
593 "call *paravirt_ops+%c[irq_enable];" \
594 "popl %%edx; popl %%ecx", \
595 PARAVIRT_IRQ_ENABLE, CLBR_EAX)
596#define CLI_STI_CLOBBERS , "%eax" 598#define CLI_STI_CLOBBERS , "%eax"
597#define CLI_STI_INPUT_ARGS \ 599#define CLI_STI_INPUT_ARGS \
598 , \ 600 , \
599 [irq_disable] "i" (offsetof(struct paravirt_ops, irq_disable)), \ 601 [paravirt_cli_type] "i" (PARAVIRT_PATCH(irq_disable)), \
600 [irq_enable] "i" (offsetof(struct paravirt_ops, irq_enable)) 602 [paravirt_sti_type] "i" (PARAVIRT_PATCH(irq_enable)), \
603 paravirt_clobber(CLBR_EAX)
604
605#undef PARAVIRT_CALL
601 606
602#else /* __ASSEMBLY__ */ 607#else /* __ASSEMBLY__ */
603 608
604#define PARA_PATCH(ptype, clobbers, ops) \ 609#define PARA_PATCH(off) ((off) / 4)
610
611#define PARA_SITE(ptype, clobbers, ops) \
605771:; \ 612771:; \
606 ops; \ 613 ops; \
607772:; \ 614772:; \
@@ -612,25 +619,25 @@ static inline unsigned long __raw_local_irq_save(void)
612 .short clobbers; \ 619 .short clobbers; \
613 .popsection 620 .popsection
614 621
615#define INTERRUPT_RETURN \ 622#define INTERRUPT_RETURN \
616 PARA_PATCH(PARAVIRT_INTERRUPT_RETURN, CLBR_ANY, \ 623 PARA_SITE(PARA_PATCH(PARAVIRT_iret), CLBR_ANY, \
617 jmp *%cs:paravirt_ops+PARAVIRT_iret) 624 jmp *%cs:paravirt_ops+PARAVIRT_iret)
618 625
619#define DISABLE_INTERRUPTS(clobbers) \ 626#define DISABLE_INTERRUPTS(clobbers) \
620 PARA_PATCH(PARAVIRT_IRQ_DISABLE, clobbers, \ 627 PARA_SITE(PARA_PATCH(PARAVIRT_irq_disable), clobbers, \
621 pushl %ecx; pushl %edx; \ 628 pushl %ecx; pushl %edx; \
622 call *paravirt_ops+PARAVIRT_irq_disable; \ 629 call *%cs:paravirt_ops+PARAVIRT_irq_disable; \
623 popl %edx; popl %ecx) \ 630 popl %edx; popl %ecx) \
624 631
625#define ENABLE_INTERRUPTS(clobbers) \ 632#define ENABLE_INTERRUPTS(clobbers) \
626 PARA_PATCH(PARAVIRT_IRQ_ENABLE, clobbers, \ 633 PARA_SITE(PARA_PATCH(PARAVIRT_irq_enable), clobbers, \
627 pushl %ecx; pushl %edx; \ 634 pushl %ecx; pushl %edx; \
628 call *%cs:paravirt_ops+PARAVIRT_irq_enable; \ 635 call *%cs:paravirt_ops+PARAVIRT_irq_enable; \
629 popl %edx; popl %ecx) 636 popl %edx; popl %ecx)
630 637
631#define ENABLE_INTERRUPTS_SYSEXIT \ 638#define ENABLE_INTERRUPTS_SYSEXIT \
632 PARA_PATCH(PARAVIRT_STI_SYSEXIT, CLBR_ANY, \ 639 PARA_SITE(PARA_PATCH(PARAVIRT_irq_enable_sysexit), CLBR_ANY, \
633 jmp *%cs:paravirt_ops+PARAVIRT_irq_enable_sysexit) 640 jmp *%cs:paravirt_ops+PARAVIRT_irq_enable_sysexit)
634 641
635#define GET_CR0_INTO_EAX \ 642#define GET_CR0_INTO_EAX \
636 call *paravirt_ops+PARAVIRT_read_cr0 643 call *paravirt_ops+PARAVIRT_read_cr0