aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2014-05-29 05:16:25 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2014-05-30 06:59:54 -0400
commitfacaaec1a72db90127b71d22e788596cf1991ae1 (patch)
treead02ed426464fafa7b56eadd7514eb3f9c9d7d4b /arch/mips
parent90f91356c7d67ddd98d817838df69335cb831eaa (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.h1
-rw-r--r--arch/mips/kvm/kvm_locore.S32
-rw-r--r--arch/mips/kvm/kvm_mips.c3
-rw-r--r--arch/mips/kvm/kvm_mips_dyntrans.c15
-rw-r--r--arch/mips/kvm/kvm_mips_emul.c2
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 */
649extern void mips32_SyncICache(unsigned long addr, unsigned long size);
650extern int kvm_mips_dump_stats(struct kvm_vcpu *vcpu); 649extern int kvm_mips_dump_stats(struct kvm_vcpu *vcpu);
651extern unsigned long kvm_mips_get_ramsize(struct kvm *kvm); 650extern 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
625LEAF(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
63410:
635 synci 0(a0)
636 REG_ADDU a0, a0, v0
637 sltu v1, a0, a1
638 bne v1, zero, 10b
639 nop
640 sync
64120:
642 jr.hb ra
643 nop
644 .set pop
645END(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