diff options
-rw-r--r-- | arch/i386/kernel/paravirt.c | 14 | ||||
-rw-r--r-- | arch/i386/kernel/vmi.c | 39 | ||||
-rw-r--r-- | include/asm-i386/paravirt.h | 177 |
3 files changed, 104 insertions, 126 deletions
diff --git a/arch/i386/kernel/paravirt.c b/arch/i386/kernel/paravirt.c index 54cc14d99740..f2982832d3b9 100644 --- a/arch/i386/kernel/paravirt.c +++ b/arch/i386/kernel/paravirt.c | |||
@@ -58,7 +58,6 @@ DEF_NATIVE(cli, "cli"); | |||
58 | DEF_NATIVE(sti, "sti"); | 58 | DEF_NATIVE(sti, "sti"); |
59 | DEF_NATIVE(popf, "push %eax; popf"); | 59 | DEF_NATIVE(popf, "push %eax; popf"); |
60 | DEF_NATIVE(pushf, "pushf; pop %eax"); | 60 | DEF_NATIVE(pushf, "pushf; pop %eax"); |
61 | DEF_NATIVE(pushf_cli, "pushf; pop %eax; cli"); | ||
62 | DEF_NATIVE(iret, "iret"); | 61 | DEF_NATIVE(iret, "iret"); |
63 | DEF_NATIVE(sti_sysexit, "sti; sysexit"); | 62 | DEF_NATIVE(sti_sysexit, "sti; sysexit"); |
64 | 63 | ||
@@ -66,13 +65,12 @@ static const struct native_insns | |||
66 | { | 65 | { |
67 | const char *start, *end; | 66 | const char *start, *end; |
68 | } native_insns[] = { | 67 | } native_insns[] = { |
69 | [PARAVIRT_IRQ_DISABLE] = { start_cli, end_cli }, | 68 | [PARAVIRT_PATCH(irq_disable)] = { start_cli, end_cli }, |
70 | [PARAVIRT_IRQ_ENABLE] = { start_sti, end_sti }, | 69 | [PARAVIRT_PATCH(irq_enable)] = { start_sti, end_sti }, |
71 | [PARAVIRT_RESTORE_FLAGS] = { start_popf, end_popf }, | 70 | [PARAVIRT_PATCH(restore_fl)] = { start_popf, end_popf }, |
72 | [PARAVIRT_SAVE_FLAGS] = { start_pushf, end_pushf }, | 71 | [PARAVIRT_PATCH(save_fl)] = { start_pushf, end_pushf }, |
73 | [PARAVIRT_SAVE_FLAGS_IRQ_DISABLE] = { start_pushf_cli, end_pushf_cli }, | 72 | [PARAVIRT_PATCH(iret)] = { start_iret, end_iret }, |
74 | [PARAVIRT_INTERRUPT_RETURN] = { start_iret, end_iret }, | 73 | [PARAVIRT_PATCH(irq_enable_sysexit)] = { start_sti_sysexit, end_sti_sysexit }, |
75 | [PARAVIRT_STI_SYSEXIT] = { start_sti_sysexit, end_sti_sysexit }, | ||
76 | }; | 74 | }; |
77 | 75 | ||
78 | static unsigned native_patch(u8 type, u16 clobbers, void *insns, unsigned len) | 76 | static unsigned native_patch(u8 type, u16 clobbers, void *insns, unsigned len) |
diff --git a/arch/i386/kernel/vmi.c b/arch/i386/kernel/vmi.c index ea77d93f59dd..b8d01c3cbff4 100644 --- a/arch/i386/kernel/vmi.c +++ b/arch/i386/kernel/vmi.c | |||
@@ -83,11 +83,6 @@ extern struct paravirt_patch __start_parainstructions[], | |||
83 | #define MNEM_JMP 0xe9 | 83 | #define MNEM_JMP 0xe9 |
84 | #define MNEM_RET 0xc3 | 84 | #define MNEM_RET 0xc3 |
85 | 85 | ||
86 | static char irq_save_disable_callout[] = { | ||
87 | MNEM_CALL, 0, 0, 0, 0, | ||
88 | MNEM_CALL, 0, 0, 0, 0, | ||
89 | MNEM_RET | ||
90 | }; | ||
91 | #define IRQ_PATCH_INT_MASK 0 | 86 | #define IRQ_PATCH_INT_MASK 0 |
92 | #define IRQ_PATCH_DISABLE 5 | 87 | #define IRQ_PATCH_DISABLE 5 |
93 | 88 | ||
@@ -135,33 +130,17 @@ static unsigned patch_internal(int call, unsigned len, void *insns) | |||
135 | static unsigned vmi_patch(u8 type, u16 clobbers, void *insns, unsigned len) | 130 | static unsigned vmi_patch(u8 type, u16 clobbers, void *insns, unsigned len) |
136 | { | 131 | { |
137 | switch (type) { | 132 | switch (type) { |
138 | case PARAVIRT_IRQ_DISABLE: | 133 | case PARAVIRT_PATCH(irq_disable): |
139 | return patch_internal(VMI_CALL_DisableInterrupts, len, insns); | 134 | return patch_internal(VMI_CALL_DisableInterrupts, len, insns); |
140 | case PARAVIRT_IRQ_ENABLE: | 135 | case PARAVIRT_PATCH(irq_enable): |
141 | return patch_internal(VMI_CALL_EnableInterrupts, len, insns); | 136 | return patch_internal(VMI_CALL_EnableInterrupts, len, insns); |
142 | case PARAVIRT_RESTORE_FLAGS: | 137 | case PARAVIRT_PATCH(restore_fl): |
143 | return patch_internal(VMI_CALL_SetInterruptMask, len, insns); | 138 | return patch_internal(VMI_CALL_SetInterruptMask, len, insns); |
144 | case PARAVIRT_SAVE_FLAGS: | 139 | case PARAVIRT_PATCH(save_fl): |
145 | return patch_internal(VMI_CALL_GetInterruptMask, len, insns); | 140 | return patch_internal(VMI_CALL_GetInterruptMask, len, insns); |
146 | case PARAVIRT_SAVE_FLAGS_IRQ_DISABLE: | 141 | case PARAVIRT_PATCH(iret): |
147 | if (len >= 10) { | ||
148 | patch_internal(VMI_CALL_GetInterruptMask, len, insns); | ||
149 | patch_internal(VMI_CALL_DisableInterrupts, len-5, insns+5); | ||
150 | return 10; | ||
151 | } else { | ||
152 | /* | ||
153 | * You bastards didn't leave enough room to | ||
154 | * patch save_flags_irq_disable inline. Patch | ||
155 | * to a helper | ||
156 | */ | ||
157 | BUG_ON(len < 5); | ||
158 | *(char *)insns = MNEM_CALL; | ||
159 | patch_offset(insns, irq_save_disable_callout); | ||
160 | return 5; | ||
161 | } | ||
162 | case PARAVIRT_INTERRUPT_RETURN: | ||
163 | return patch_internal(VMI_CALL_IRET, len, insns); | 142 | return patch_internal(VMI_CALL_IRET, len, insns); |
164 | case PARAVIRT_STI_SYSEXIT: | 143 | case PARAVIRT_PATCH(irq_enable_sysexit): |
165 | return patch_internal(VMI_CALL_SYSEXIT, len, insns); | 144 | return patch_internal(VMI_CALL_SYSEXIT, len, insns); |
166 | default: | 145 | default: |
167 | break; | 146 | break; |
@@ -796,12 +775,6 @@ static inline int __init activate_vmi(void) | |||
796 | para_fill(irq_disable, DisableInterrupts); | 775 | para_fill(irq_disable, DisableInterrupts); |
797 | para_fill(irq_enable, EnableInterrupts); | 776 | para_fill(irq_enable, EnableInterrupts); |
798 | 777 | ||
799 | /* irq_save_disable !!! sheer pain */ | ||
800 | patch_offset(&irq_save_disable_callout[IRQ_PATCH_INT_MASK], | ||
801 | (char *)paravirt_ops.save_fl); | ||
802 | patch_offset(&irq_save_disable_callout[IRQ_PATCH_DISABLE], | ||
803 | (char *)paravirt_ops.irq_disable); | ||
804 | |||
805 | para_fill(wbinvd, WBINVD); | 778 | para_fill(wbinvd, WBINVD); |
806 | para_fill(read_tsc, RDTSC); | 779 | para_fill(read_tsc, RDTSC); |
807 | 780 | ||
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 |