]> rtime.felk.cvut.cz Git - linux-imx.git/commitdiff
KVM: PPC: booke: Allow multiple exception types
authorBharat Bhushan <Bharat.Bhushan@freescale.com>
Tue, 15 Jan 2013 22:24:39 +0000 (22:24 +0000)
committerAlexander Graf <agraf@suse.de>
Wed, 13 Feb 2013 11:56:40 +0000 (12:56 +0100)
Current kvmppc_booke_handlers uses the same macro (KVM_HANDLER) and
all handlers are considered to be the same size. This will not be
the case if we want to use different macros for different handlers.

This patch improves the kvmppc_booke_handler so that it can
support different macros for different handlers.

Signed-off-by: Liu Yu <yu.liu@freescale.com>
[bharat.bhushan@freescale.com: Substantial changes]
Signed-off-by: Bharat Bhushan <bharat.bhushan@freescale.com>
Signed-off-by: Alexander Graf <agraf@suse.de>
arch/powerpc/include/asm/kvm_ppc.h
arch/powerpc/kvm/booke.c
arch/powerpc/kvm/booke.h
arch/powerpc/kvm/booke_interrupts.S
arch/powerpc/kvm/e500.c

index 493630e209c8f394d81c5aa23e0380d3a4f820fc..44a657adf41606c3219a0577ac78952ee6b9c64a 100644 (file)
@@ -49,8 +49,6 @@ enum emulation_result {
 
 extern int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
 extern int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
-extern char kvmppc_handlers_start[];
-extern unsigned long kvmppc_handler_len;
 extern void kvmppc_handler_highmem(void);
 
 extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu);
index 8779cd4c52d9c67e69916304a5319c1b2b39d00c..d2f502d209ff03a1b4a2126b4252304d1016c037 100644 (file)
@@ -1594,7 +1594,9 @@ int __init kvmppc_booke_init(void)
 {
 #ifndef CONFIG_KVM_BOOKE_HV
        unsigned long ivor[16];
+       unsigned long *handler = kvmppc_booke_handler_addr;
        unsigned long max_ivor = 0;
+       unsigned long handler_len;
        int i;
 
        /* We install our own exception handlers by hijacking IVPR. IVPR must
@@ -1627,14 +1629,16 @@ int __init kvmppc_booke_init(void)
 
        for (i = 0; i < 16; i++) {
                if (ivor[i] > max_ivor)
-                       max_ivor = ivor[i];
+                       max_ivor = i;
 
+               handler_len = handler[i + 1] - handler[i];
                memcpy((void *)kvmppc_booke_handlers + ivor[i],
-                      kvmppc_handlers_start + i * kvmppc_handler_len,
-                      kvmppc_handler_len);
+                      (void *)handler[i], handler_len);
        }
-       flush_icache_range(kvmppc_booke_handlers,
-                          kvmppc_booke_handlers + max_ivor + kvmppc_handler_len);
+
+       handler_len = handler[max_ivor + 1] - handler[max_ivor];
+       flush_icache_range(kvmppc_booke_handlers, kvmppc_booke_handlers +
+                          ivor[max_ivor] + handler_len);
 #endif /* !BOOKE_HV */
        return 0;
 }
index e9b88e433f64a3d835d8b8970ab6ff6a6d0ebf56..5fd1ba69357997381e8003b01d91fd13d81754d5 100644 (file)
@@ -65,6 +65,7 @@
                          (1 << BOOKE_IRQPRIO_CRITICAL))
 
 extern unsigned long kvmppc_booke_handlers;
+extern unsigned long kvmppc_booke_handler_addr[];
 
 void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr);
 void kvmppc_mmu_msr_notify(struct kvm_vcpu *vcpu, u32 old_msr);
index ca16d57f7686da06bd23971aaff8cf59e5293bc0..eae8483764408d752d0917f5607da139896d7c28 100644 (file)
@@ -74,6 +74,14 @@ _GLOBAL(kvmppc_handler_\ivor_nr)
        bctr
 .endm
 
+.macro KVM_HANDLER_ADDR ivor_nr
+       .long   kvmppc_handler_\ivor_nr
+.endm
+
+.macro KVM_HANDLER_END
+       .long   kvmppc_handlers_end
+.endm
+
 _GLOBAL(kvmppc_handlers_start)
 KVM_HANDLER BOOKE_INTERRUPT_CRITICAL SPRN_SPRG_RSCRATCH_CRIT SPRN_CSRR0
 KVM_HANDLER BOOKE_INTERRUPT_MACHINE_CHECK  SPRN_SPRG_RSCRATCH_MC SPRN_MCSRR0
@@ -94,9 +102,7 @@ KVM_HANDLER BOOKE_INTERRUPT_DEBUG SPRN_SPRG_RSCRATCH_CRIT SPRN_CSRR0
 KVM_HANDLER BOOKE_INTERRUPT_SPE_UNAVAIL SPRN_SPRG_RSCRATCH0 SPRN_SRR0
 KVM_HANDLER BOOKE_INTERRUPT_SPE_FP_DATA SPRN_SPRG_RSCRATCH0 SPRN_SRR0
 KVM_HANDLER BOOKE_INTERRUPT_SPE_FP_ROUND SPRN_SPRG_RSCRATCH0 SPRN_SRR0
-
-_GLOBAL(kvmppc_handler_len)
-       .long kvmppc_handler_1 - kvmppc_handler_0
+_GLOBAL(kvmppc_handlers_end)
 
 /* Registers:
  *  SPRG_SCRATCH0: guest r4
@@ -461,6 +467,31 @@ lightweight_exit:
        lwz     r4, VCPU_GPR(R4)(r4)
        rfi
 
+       .data
+       .align  4
+       .globl  kvmppc_booke_handler_addr
+kvmppc_booke_handler_addr:
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_CRITICAL
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_MACHINE_CHECK
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_DATA_STORAGE
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_INST_STORAGE
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_EXTERNAL
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_ALIGNMENT
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_PROGRAM
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_FP_UNAVAIL
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_SYSCALL
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_AP_UNAVAIL
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_DECREMENTER
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_FIT
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_WATCHDOG
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_DTLB_MISS
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_ITLB_MISS
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_DEBUG
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_SPE_UNAVAIL
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_SPE_FP_DATA
+KVM_HANDLER_ADDR BOOKE_INTERRUPT_SPE_FP_ROUND
+KVM_HANDLER_END /*Always keep this in end*/
+
 #ifdef CONFIG_SPE
 _GLOBAL(kvmppc_save_guest_spe)
        cmpi    0,r3,0
index b479ed77c515331315703d18a214d849f7209b2e..6dd4de7802bfea4e591070968ba0169116682137 100644 (file)
@@ -491,6 +491,9 @@ static int __init kvmppc_e500_init(void)
 {
        int r, i;
        unsigned long ivor[3];
+       /* Process remaining handlers above the generic first 16 */
+       unsigned long *handler = &kvmppc_booke_handler_addr[16];
+       unsigned long handler_len;
        unsigned long max_ivor = 0;
 
        r = kvmppc_core_check_processor_compat();
@@ -506,15 +509,16 @@ static int __init kvmppc_e500_init(void)
        ivor[1] = mfspr(SPRN_IVOR33);
        ivor[2] = mfspr(SPRN_IVOR34);
        for (i = 0; i < 3; i++) {
-               if (ivor[i] > max_ivor)
-                       max_ivor = ivor[i];
+               if (ivor[i] > ivor[max_ivor])
+                       max_ivor = i;
 
+               handler_len = handler[i + 1] - handler[i];
                memcpy((void *)kvmppc_booke_handlers + ivor[i],
-                      kvmppc_handlers_start + (i + 16) * kvmppc_handler_len,
-                      kvmppc_handler_len);
+                      (void *)handler[i], handler_len);
        }
-       flush_icache_range(kvmppc_booke_handlers,
-                       kvmppc_booke_handlers + max_ivor + kvmppc_handler_len);
+       handler_len = handler[max_ivor + 1] - handler[max_ivor];
+       flush_icache_range(kvmppc_booke_handlers, kvmppc_booke_handlers +
+                          ivor[max_ivor] + handler_len);
 
        return kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), 0, THIS_MODULE);
 }