diff options
author | James Hogan <james.hogan@imgtec.com> | 2014-05-29 05:16:25 -0400 |
---|---|---|
committer | Paolo Bonzini <pbonzini@redhat.com> | 2014-05-30 06:59:54 -0400 |
commit | facaaec1a72db90127b71d22e788596cf1991ae1 (patch) | |
tree | ad02ed426464fafa7b56eadd7514eb3f9c9d7d4b /arch/mips | |
parent | 90f91356c7d67ddd98d817838df69335cb831eaa (diff) |
MIPS: KVM: Use local_flush_icache_range to fix RI on XBurst
MIPS KVM uses mips32_SyncICache to synchronise the icache with the
dcache after dynamically modifying guest instructions or writing guest
exception vector. However this uses rdhwr to get the SYNCI step, which
causes a reserved instruction exception on Ingenic XBurst cores.
It would seem to make more sense to use local_flush_icache_range()
instead which does the same thing but is more portable.
Signed-off-by: James Hogan <james.hogan@imgtec.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Gleb Natapov <gleb@kernel.org>
Cc: kvm@vger.kernel.org
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: linux-mips@linux-mips.org
Cc: Sanjay Lal <sanjayl@kymasys.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'arch/mips')
-rw-r--r-- | arch/mips/include/asm/kvm_host.h | 1 | ||||
-rw-r--r-- | arch/mips/kvm/kvm_locore.S | 32 | ||||
-rw-r--r-- | arch/mips/kvm/kvm_mips.c | 3 | ||||
-rw-r--r-- | arch/mips/kvm/kvm_mips_dyntrans.c | 15 | ||||
-rw-r--r-- | arch/mips/kvm/kvm_mips_emul.c | 2 |
5 files changed, 12 insertions, 41 deletions
diff --git a/arch/mips/include/asm/kvm_host.h b/arch/mips/include/asm/kvm_host.h index 060aaa6348d7..f0e25c6d10b2 100644 --- a/arch/mips/include/asm/kvm_host.h +++ b/arch/mips/include/asm/kvm_host.h | |||
@@ -646,7 +646,6 @@ extern int kvm_mips_trans_mtc0(uint32_t inst, uint32_t *opc, | |||
646 | struct kvm_vcpu *vcpu); | 646 | struct kvm_vcpu *vcpu); |
647 | 647 | ||
648 | /* Misc */ | 648 | /* Misc */ |
649 | extern void mips32_SyncICache(unsigned long addr, unsigned long size); | ||
650 | extern int kvm_mips_dump_stats(struct kvm_vcpu *vcpu); | 649 | extern int kvm_mips_dump_stats(struct kvm_vcpu *vcpu); |
651 | extern unsigned long kvm_mips_get_ramsize(struct kvm *kvm); | 650 | extern unsigned long kvm_mips_get_ramsize(struct kvm *kvm); |
652 | 651 | ||
diff --git a/arch/mips/kvm/kvm_locore.S b/arch/mips/kvm/kvm_locore.S index bbace092ad0a..033ac343e72c 100644 --- a/arch/mips/kvm/kvm_locore.S +++ b/arch/mips/kvm/kvm_locore.S | |||
@@ -611,35 +611,3 @@ MIPSX(exceptions): | |||
611 | .word _C_LABEL(MIPSX(GuestException)) # 29 | 611 | .word _C_LABEL(MIPSX(GuestException)) # 29 |
612 | .word _C_LABEL(MIPSX(GuestException)) # 30 | 612 | .word _C_LABEL(MIPSX(GuestException)) # 30 |
613 | .word _C_LABEL(MIPSX(GuestException)) # 31 | 613 | .word _C_LABEL(MIPSX(GuestException)) # 31 |
614 | |||
615 | |||
616 | /* This routine makes changes to the instruction stream effective to the hardware. | ||
617 | * It should be called after the instruction stream is written. | ||
618 | * On return, the new instructions are effective. | ||
619 | * Inputs: | ||
620 | * a0 = Start address of new instruction stream | ||
621 | * a1 = Size, in bytes, of new instruction stream | ||
622 | */ | ||
623 | |||
624 | #define HW_SYNCI_Step $1 | ||
625 | LEAF(MIPSX(SyncICache)) | ||
626 | .set push | ||
627 | .set mips32r2 | ||
628 | beq a1, zero, 20f | ||
629 | nop | ||
630 | REG_ADDU a1, a0, a1 | ||
631 | rdhwr v0, HW_SYNCI_Step | ||
632 | beq v0, zero, 20f | ||
633 | nop | ||
634 | 10: | ||
635 | synci 0(a0) | ||
636 | REG_ADDU a0, a0, v0 | ||
637 | sltu v1, a0, a1 | ||
638 | bne v1, zero, 10b | ||
639 | nop | ||
640 | sync | ||
641 | 20: | ||
642 | jr.hb ra | ||
643 | nop | ||
644 | .set pop | ||
645 | END(MIPSX(SyncICache)) | ||
diff --git a/arch/mips/kvm/kvm_mips.c b/arch/mips/kvm/kvm_mips.c index 1e12762ae7ea..2a80a906ccc7 100644 --- a/arch/mips/kvm/kvm_mips.c +++ b/arch/mips/kvm/kvm_mips.c | |||
@@ -345,7 +345,8 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id) | |||
345 | mips32_GuestExceptionEnd - mips32_GuestException); | 345 | mips32_GuestExceptionEnd - mips32_GuestException); |
346 | 346 | ||
347 | /* Invalidate the icache for these ranges */ | 347 | /* Invalidate the icache for these ranges */ |
348 | mips32_SyncICache((unsigned long) gebase, ALIGN(size, PAGE_SIZE)); | 348 | local_flush_icache_range((unsigned long)gebase, |
349 | (unsigned long)gebase + ALIGN(size, PAGE_SIZE)); | ||
349 | 350 | ||
350 | /* Allocate comm page for guest kernel, a TLB will be reserved for mapping GVA @ 0xFFFF8000 to this page */ | 351 | /* Allocate comm page for guest kernel, a TLB will be reserved for mapping GVA @ 0xFFFF8000 to this page */ |
351 | vcpu->arch.kseg0_commpage = kzalloc(PAGE_SIZE << 1, GFP_KERNEL); | 352 | vcpu->arch.kseg0_commpage = kzalloc(PAGE_SIZE << 1, GFP_KERNEL); |
diff --git a/arch/mips/kvm/kvm_mips_dyntrans.c b/arch/mips/kvm/kvm_mips_dyntrans.c index 96528e2d1ea6..b80e41d858fd 100644 --- a/arch/mips/kvm/kvm_mips_dyntrans.c +++ b/arch/mips/kvm/kvm_mips_dyntrans.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/vmalloc.h> | 16 | #include <linux/vmalloc.h> |
17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
18 | #include <linux/bootmem.h> | 18 | #include <linux/bootmem.h> |
19 | #include <asm/cacheflush.h> | ||
19 | 20 | ||
20 | #include "kvm_mips_comm.h" | 21 | #include "kvm_mips_comm.h" |
21 | 22 | ||
@@ -40,7 +41,7 @@ kvm_mips_trans_cache_index(uint32_t inst, uint32_t *opc, | |||
40 | CKSEG0ADDR(kvm_mips_translate_guest_kseg0_to_hpa | 41 | CKSEG0ADDR(kvm_mips_translate_guest_kseg0_to_hpa |
41 | (vcpu, (unsigned long) opc)); | 42 | (vcpu, (unsigned long) opc)); |
42 | memcpy((void *)kseg0_opc, (void *)&synci_inst, sizeof(uint32_t)); | 43 | memcpy((void *)kseg0_opc, (void *)&synci_inst, sizeof(uint32_t)); |
43 | mips32_SyncICache(kseg0_opc, 32); | 44 | local_flush_icache_range(kseg0_opc, kseg0_opc + 32); |
44 | 45 | ||
45 | return result; | 46 | return result; |
46 | } | 47 | } |
@@ -66,7 +67,7 @@ kvm_mips_trans_cache_va(uint32_t inst, uint32_t *opc, | |||
66 | CKSEG0ADDR(kvm_mips_translate_guest_kseg0_to_hpa | 67 | CKSEG0ADDR(kvm_mips_translate_guest_kseg0_to_hpa |
67 | (vcpu, (unsigned long) opc)); | 68 | (vcpu, (unsigned long) opc)); |
68 | memcpy((void *)kseg0_opc, (void *)&synci_inst, sizeof(uint32_t)); | 69 | memcpy((void *)kseg0_opc, (void *)&synci_inst, sizeof(uint32_t)); |
69 | mips32_SyncICache(kseg0_opc, 32); | 70 | local_flush_icache_range(kseg0_opc, kseg0_opc + 32); |
70 | 71 | ||
71 | return result; | 72 | return result; |
72 | } | 73 | } |
@@ -99,11 +100,12 @@ kvm_mips_trans_mfc0(uint32_t inst, uint32_t *opc, struct kvm_vcpu *vcpu) | |||
99 | CKSEG0ADDR(kvm_mips_translate_guest_kseg0_to_hpa | 100 | CKSEG0ADDR(kvm_mips_translate_guest_kseg0_to_hpa |
100 | (vcpu, (unsigned long) opc)); | 101 | (vcpu, (unsigned long) opc)); |
101 | memcpy((void *)kseg0_opc, (void *)&mfc0_inst, sizeof(uint32_t)); | 102 | memcpy((void *)kseg0_opc, (void *)&mfc0_inst, sizeof(uint32_t)); |
102 | mips32_SyncICache(kseg0_opc, 32); | 103 | local_flush_icache_range(kseg0_opc, kseg0_opc + 32); |
103 | } else if (KVM_GUEST_KSEGX((unsigned long) opc) == KVM_GUEST_KSEG23) { | 104 | } else if (KVM_GUEST_KSEGX((unsigned long) opc) == KVM_GUEST_KSEG23) { |
104 | local_irq_save(flags); | 105 | local_irq_save(flags); |
105 | memcpy((void *)opc, (void *)&mfc0_inst, sizeof(uint32_t)); | 106 | memcpy((void *)opc, (void *)&mfc0_inst, sizeof(uint32_t)); |
106 | mips32_SyncICache((unsigned long) opc, 32); | 107 | local_flush_icache_range((unsigned long)opc, |
108 | (unsigned long)opc + 32); | ||
107 | local_irq_restore(flags); | 109 | local_irq_restore(flags); |
108 | } else { | 110 | } else { |
109 | kvm_err("%s: Invalid address: %p\n", __func__, opc); | 111 | kvm_err("%s: Invalid address: %p\n", __func__, opc); |
@@ -134,11 +136,12 @@ kvm_mips_trans_mtc0(uint32_t inst, uint32_t *opc, struct kvm_vcpu *vcpu) | |||
134 | CKSEG0ADDR(kvm_mips_translate_guest_kseg0_to_hpa | 136 | CKSEG0ADDR(kvm_mips_translate_guest_kseg0_to_hpa |
135 | (vcpu, (unsigned long) opc)); | 137 | (vcpu, (unsigned long) opc)); |
136 | memcpy((void *)kseg0_opc, (void *)&mtc0_inst, sizeof(uint32_t)); | 138 | memcpy((void *)kseg0_opc, (void *)&mtc0_inst, sizeof(uint32_t)); |
137 | mips32_SyncICache(kseg0_opc, 32); | 139 | local_flush_icache_range(kseg0_opc, kseg0_opc + 32); |
138 | } else if (KVM_GUEST_KSEGX((unsigned long) opc) == KVM_GUEST_KSEG23) { | 140 | } else if (KVM_GUEST_KSEGX((unsigned long) opc) == KVM_GUEST_KSEG23) { |
139 | local_irq_save(flags); | 141 | local_irq_save(flags); |
140 | memcpy((void *)opc, (void *)&mtc0_inst, sizeof(uint32_t)); | 142 | memcpy((void *)opc, (void *)&mtc0_inst, sizeof(uint32_t)); |
141 | mips32_SyncICache((unsigned long) opc, 32); | 143 | local_flush_icache_range((unsigned long)opc, |
144 | (unsigned long)opc + 32); | ||
142 | local_irq_restore(flags); | 145 | local_irq_restore(flags); |
143 | } else { | 146 | } else { |
144 | kvm_err("%s: Invalid address: %p\n", __func__, opc); | 147 | kvm_err("%s: Invalid address: %p\n", __func__, opc); |
diff --git a/arch/mips/kvm/kvm_mips_emul.c b/arch/mips/kvm/kvm_mips_emul.c index e3fec99941a7..bad31c6235d4 100644 --- a/arch/mips/kvm/kvm_mips_emul.c +++ b/arch/mips/kvm/kvm_mips_emul.c | |||
@@ -887,7 +887,7 @@ int kvm_mips_sync_icache(unsigned long va, struct kvm_vcpu *vcpu) | |||
887 | 887 | ||
888 | printk("%s: va: %#lx, unmapped: %#x\n", __func__, va, CKSEG0ADDR(pa)); | 888 | printk("%s: va: %#lx, unmapped: %#x\n", __func__, va, CKSEG0ADDR(pa)); |
889 | 889 | ||
890 | mips32_SyncICache(CKSEG0ADDR(pa), 32); | 890 | local_flush_icache_range(CKSEG0ADDR(pa), 32); |
891 | return 0; | 891 | return 0; |
892 | } | 892 | } |
893 | 893 | ||