MIPS: KVM: Use local_flush_icache_range to fix RI on XBurst
authorJames Hogan <james.hogan@imgtec.com>
Thu, 29 May 2014 09:16:25 +0000 (10:16 +0100)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 30 May 2014 10:59:54 +0000 (12:59 +0200)
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>
arch/mips/include/asm/kvm_host.h
arch/mips/kvm/kvm_locore.S
arch/mips/kvm/kvm_mips.c
arch/mips/kvm/kvm_mips_dyntrans.c
arch/mips/kvm/kvm_mips_emul.c

index 060aaa6348d7e8cd39fa2acda69e30bf9be6e7fa..f0e25c6d10b20e1b48329f5d57e38eb2744f85e7 100644 (file)
@@ -646,7 +646,6 @@ extern int kvm_mips_trans_mtc0(uint32_t inst, uint32_t *opc,
                               struct kvm_vcpu *vcpu);
 
 /* Misc */
-extern void mips32_SyncICache(unsigned long addr, unsigned long size);
 extern int kvm_mips_dump_stats(struct kvm_vcpu *vcpu);
 extern unsigned long kvm_mips_get_ramsize(struct kvm *kvm);
 
index bbace092ad0addef5277391a14944d5590b97be4..033ac343e72c81ca7a3a09cf1626359760a529a4 100644 (file)
@@ -611,35 +611,3 @@ MIPSX(exceptions):
        .word _C_LABEL(MIPSX(GuestException))   # 29
        .word _C_LABEL(MIPSX(GuestException))   # 30
        .word _C_LABEL(MIPSX(GuestException))   # 31
-
-
-/* This routine makes changes to the instruction stream effective to the hardware.
- * It should be called after the instruction stream is written.
- * On return, the new instructions are effective.
- * Inputs:
- * a0 = Start address of new instruction stream
- * a1 = Size, in bytes, of new instruction stream
- */
-
-#define HW_SYNCI_Step       $1
-LEAF(MIPSX(SyncICache))
-       .set    push
-       .set    mips32r2
-       beq     a1, zero, 20f
-        nop
-       REG_ADDU a1, a0, a1
-       rdhwr   v0, HW_SYNCI_Step
-       beq     v0, zero, 20f
-        nop
-10:
-       synci   0(a0)
-       REG_ADDU a0, a0, v0
-       sltu    v1, a0, a1
-       bne     v1, zero, 10b
-        nop
-       sync
-20:
-       jr.hb   ra
-        nop
-       .set    pop
-END(MIPSX(SyncICache))
index 1e12762ae7ea35deb6f69cdc988f70d278c88491..2a80a906ccc7c78b03dfaf44791014b9c905945f 100644 (file)
@@ -345,7 +345,8 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm, unsigned int id)
               mips32_GuestExceptionEnd - mips32_GuestException);
 
        /* Invalidate the icache for these ranges */
-       mips32_SyncICache((unsigned long) gebase, ALIGN(size, PAGE_SIZE));
+       local_flush_icache_range((unsigned long)gebase,
+                               (unsigned long)gebase + ALIGN(size, PAGE_SIZE));
 
        /* Allocate comm page for guest kernel, a TLB will be reserved for mapping GVA @ 0xFFFF8000 to this page */
        vcpu->arch.kseg0_commpage = kzalloc(PAGE_SIZE << 1, GFP_KERNEL);
index 96528e2d1ea678dd335232eed86556f00963882d..b80e41d858fd7150423285968908ed7c4f3677fc 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/vmalloc.h>
 #include <linux/fs.h>
 #include <linux/bootmem.h>
+#include <asm/cacheflush.h>
 
 #include "kvm_mips_comm.h"
 
@@ -40,7 +41,7 @@ kvm_mips_trans_cache_index(uint32_t inst, uint32_t *opc,
            CKSEG0ADDR(kvm_mips_translate_guest_kseg0_to_hpa
                       (vcpu, (unsigned long) opc));
        memcpy((void *)kseg0_opc, (void *)&synci_inst, sizeof(uint32_t));
-       mips32_SyncICache(kseg0_opc, 32);
+       local_flush_icache_range(kseg0_opc, kseg0_opc + 32);
 
        return result;
 }
@@ -66,7 +67,7 @@ kvm_mips_trans_cache_va(uint32_t inst, uint32_t *opc,
            CKSEG0ADDR(kvm_mips_translate_guest_kseg0_to_hpa
                       (vcpu, (unsigned long) opc));
        memcpy((void *)kseg0_opc, (void *)&synci_inst, sizeof(uint32_t));
-       mips32_SyncICache(kseg0_opc, 32);
+       local_flush_icache_range(kseg0_opc, kseg0_opc + 32);
 
        return result;
 }
@@ -99,11 +100,12 @@ kvm_mips_trans_mfc0(uint32_t inst, uint32_t *opc, struct kvm_vcpu *vcpu)
                    CKSEG0ADDR(kvm_mips_translate_guest_kseg0_to_hpa
                               (vcpu, (unsigned long) opc));
                memcpy((void *)kseg0_opc, (void *)&mfc0_inst, sizeof(uint32_t));
-               mips32_SyncICache(kseg0_opc, 32);
+               local_flush_icache_range(kseg0_opc, kseg0_opc + 32);
        } else if (KVM_GUEST_KSEGX((unsigned long) opc) == KVM_GUEST_KSEG23) {
                local_irq_save(flags);
                memcpy((void *)opc, (void *)&mfc0_inst, sizeof(uint32_t));
-               mips32_SyncICache((unsigned long) opc, 32);
+               local_flush_icache_range((unsigned long)opc,
+                                        (unsigned long)opc + 32);
                local_irq_restore(flags);
        } else {
                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)
                    CKSEG0ADDR(kvm_mips_translate_guest_kseg0_to_hpa
                               (vcpu, (unsigned long) opc));
                memcpy((void *)kseg0_opc, (void *)&mtc0_inst, sizeof(uint32_t));
-               mips32_SyncICache(kseg0_opc, 32);
+               local_flush_icache_range(kseg0_opc, kseg0_opc + 32);
        } else if (KVM_GUEST_KSEGX((unsigned long) opc) == KVM_GUEST_KSEG23) {
                local_irq_save(flags);
                memcpy((void *)opc, (void *)&mtc0_inst, sizeof(uint32_t));
-               mips32_SyncICache((unsigned long) opc, 32);
+               local_flush_icache_range((unsigned long)opc,
+                                        (unsigned long)opc + 32);
                local_irq_restore(flags);
        } else {
                kvm_err("%s: Invalid address: %p\n", __func__, opc);
index e3fec99941a7de2caaae5eb6bd28563f48c9aac3..bad31c6235d43bd1f4ffa3a7b1d8b16b56a3209e 100644 (file)
@@ -887,7 +887,7 @@ int kvm_mips_sync_icache(unsigned long va, struct kvm_vcpu *vcpu)
 
        printk("%s: va: %#lx, unmapped: %#x\n", __func__, va, CKSEG0ADDR(pa));
 
-       mips32_SyncICache(CKSEG0ADDR(pa), 32);
+       local_flush_icache_range(CKSEG0ADDR(pa), 32);
        return 0;
 }