diff options
author | Jeremy Fitzhardinge <jeremy@goop.org> | 2007-05-02 13:27:14 -0400 |
---|---|---|
committer | Andi Kleen <andi@basil.nowhere.org> | 2007-05-02 13:27:14 -0400 |
commit | d582203578a1f3d408e27bb9042e8635954cd320 (patch) | |
tree | 385952bdda8f9c2b6b4c9c659a0eba872749e948 /include/asm-i386/paravirt.h | |
parent | 98de032b681d8a7532d44dfc66aa5c0c1c755a9d (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/asm-i386/paravirt.h')
-rw-r--r-- | include/asm-i386/paravirt.h | 177 |
1 files changed, 92 insertions, 85 deletions
diff --git a/include/asm-i386/paravirt.h b/include/asm-i386/paravirt.h index b4cc2fc4031e..1dbc01f4ed4d 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 | ||
192 | extern struct paravirt_ops paravirt_ops; | 181 | extern 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 | ||
196 | static inline void load_esp0(struct tss_struct *tss, | 207 | static inline void load_esp0(struct tss_struct *tss, |
@@ -515,93 +526,89 @@ struct paravirt_patch_site { | |||
515 | extern struct paravirt_patch_site __parainstructions[], | 526 | extern 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 | |||
527 | static inline unsigned long __raw_local_save_flags(void) | 529 | static 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 | ||
540 | static inline void raw_local_irq_restore(unsigned long f) | 543 | static 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 | ||
550 | static inline void raw_local_irq_disable(void) | 555 | static 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 | ||
560 | static inline void raw_local_irq_enable(void) | 566 | static 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 | ||
570 | static inline unsigned long __raw_local_irq_save(void) | 577 | static 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) \ | ||
605 | 771:; \ | 612 | 771:; \ |
606 | ops; \ | 613 | ops; \ |
607 | 772:; \ | 614 | 772:; \ |
@@ -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 |