aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorBharat Bhushan <Bharat.Bhushan@freescale.com>2013-01-15 17:24:39 -0500
committerAlexander Graf <agraf@suse.de>2013-02-13 06:56:40 -0500
commit1d542d9c2bbca9b99835fef6a938b9ae9dd7ca2a (patch)
treeb5bc9857625feb811cce562f45ec3cf259739395 /arch/powerpc
parentffe129ecd79779221fdb03305049ec8b5a8beb0f (diff)
KVM: PPC: booke: Allow multiple exception types
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>
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/include/asm/kvm_ppc.h2
-rw-r--r--arch/powerpc/kvm/booke.c14
-rw-r--r--arch/powerpc/kvm/booke.h1
-rw-r--r--arch/powerpc/kvm/booke_interrupts.S37
-rw-r--r--arch/powerpc/kvm/e500.c16
5 files changed, 54 insertions, 16 deletions
diff --git a/arch/powerpc/include/asm/kvm_ppc.h b/arch/powerpc/include/asm/kvm_ppc.h
index 493630e209c8..44a657adf416 100644
--- a/arch/powerpc/include/asm/kvm_ppc.h
+++ b/arch/powerpc/include/asm/kvm_ppc.h
@@ -49,8 +49,6 @@ enum emulation_result {
49 49
50extern int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu); 50extern int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
51extern int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu); 51extern int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
52extern char kvmppc_handlers_start[];
53extern unsigned long kvmppc_handler_len;
54extern void kvmppc_handler_highmem(void); 52extern void kvmppc_handler_highmem(void);
55 53
56extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu); 54extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu);
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index 8779cd4c52d9..d2f502d209ff 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -1594,7 +1594,9 @@ int __init kvmppc_booke_init(void)
1594{ 1594{
1595#ifndef CONFIG_KVM_BOOKE_HV 1595#ifndef CONFIG_KVM_BOOKE_HV
1596 unsigned long ivor[16]; 1596 unsigned long ivor[16];
1597 unsigned long *handler = kvmppc_booke_handler_addr;
1597 unsigned long max_ivor = 0; 1598 unsigned long max_ivor = 0;
1599 unsigned long handler_len;
1598 int i; 1600 int i;
1599 1601
1600 /* We install our own exception handlers by hijacking IVPR. IVPR must 1602 /* We install our own exception handlers by hijacking IVPR. IVPR must
@@ -1627,14 +1629,16 @@ int __init kvmppc_booke_init(void)
1627 1629
1628 for (i = 0; i < 16; i++) { 1630 for (i = 0; i < 16; i++) {
1629 if (ivor[i] > max_ivor) 1631 if (ivor[i] > max_ivor)
1630 max_ivor = ivor[i]; 1632 max_ivor = i;
1631 1633
1634 handler_len = handler[i + 1] - handler[i];
1632 memcpy((void *)kvmppc_booke_handlers + ivor[i], 1635 memcpy((void *)kvmppc_booke_handlers + ivor[i],
1633 kvmppc_handlers_start + i * kvmppc_handler_len, 1636 (void *)handler[i], handler_len);
1634 kvmppc_handler_len);
1635 } 1637 }
1636 flush_icache_range(kvmppc_booke_handlers, 1638
1637 kvmppc_booke_handlers + max_ivor + kvmppc_handler_len); 1639 handler_len = handler[max_ivor + 1] - handler[max_ivor];
1640 flush_icache_range(kvmppc_booke_handlers, kvmppc_booke_handlers +
1641 ivor[max_ivor] + handler_len);
1638#endif /* !BOOKE_HV */ 1642#endif /* !BOOKE_HV */
1639 return 0; 1643 return 0;
1640} 1644}
diff --git a/arch/powerpc/kvm/booke.h b/arch/powerpc/kvm/booke.h
index e9b88e433f64..5fd1ba693579 100644
--- a/arch/powerpc/kvm/booke.h
+++ b/arch/powerpc/kvm/booke.h
@@ -65,6 +65,7 @@
65 (1 << BOOKE_IRQPRIO_CRITICAL)) 65 (1 << BOOKE_IRQPRIO_CRITICAL))
66 66
67extern unsigned long kvmppc_booke_handlers; 67extern unsigned long kvmppc_booke_handlers;
68extern unsigned long kvmppc_booke_handler_addr[];
68 69
69void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr); 70void kvmppc_set_msr(struct kvm_vcpu *vcpu, u32 new_msr);
70void kvmppc_mmu_msr_notify(struct kvm_vcpu *vcpu, u32 old_msr); 71void kvmppc_mmu_msr_notify(struct kvm_vcpu *vcpu, u32 old_msr);
diff --git a/arch/powerpc/kvm/booke_interrupts.S b/arch/powerpc/kvm/booke_interrupts.S
index ca16d57f7686..eae848376440 100644
--- a/arch/powerpc/kvm/booke_interrupts.S
+++ b/arch/powerpc/kvm/booke_interrupts.S
@@ -74,6 +74,14 @@ _GLOBAL(kvmppc_handler_\ivor_nr)
74 bctr 74 bctr
75.endm 75.endm
76 76
77.macro KVM_HANDLER_ADDR ivor_nr
78 .long kvmppc_handler_\ivor_nr
79.endm
80
81.macro KVM_HANDLER_END
82 .long kvmppc_handlers_end
83.endm
84
77_GLOBAL(kvmppc_handlers_start) 85_GLOBAL(kvmppc_handlers_start)
78KVM_HANDLER BOOKE_INTERRUPT_CRITICAL SPRN_SPRG_RSCRATCH_CRIT SPRN_CSRR0 86KVM_HANDLER BOOKE_INTERRUPT_CRITICAL SPRN_SPRG_RSCRATCH_CRIT SPRN_CSRR0
79KVM_HANDLER BOOKE_INTERRUPT_MACHINE_CHECK SPRN_SPRG_RSCRATCH_MC SPRN_MCSRR0 87KVM_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
94KVM_HANDLER BOOKE_INTERRUPT_SPE_UNAVAIL SPRN_SPRG_RSCRATCH0 SPRN_SRR0 102KVM_HANDLER BOOKE_INTERRUPT_SPE_UNAVAIL SPRN_SPRG_RSCRATCH0 SPRN_SRR0
95KVM_HANDLER BOOKE_INTERRUPT_SPE_FP_DATA SPRN_SPRG_RSCRATCH0 SPRN_SRR0 103KVM_HANDLER BOOKE_INTERRUPT_SPE_FP_DATA SPRN_SPRG_RSCRATCH0 SPRN_SRR0
96KVM_HANDLER BOOKE_INTERRUPT_SPE_FP_ROUND SPRN_SPRG_RSCRATCH0 SPRN_SRR0 104KVM_HANDLER BOOKE_INTERRUPT_SPE_FP_ROUND SPRN_SPRG_RSCRATCH0 SPRN_SRR0
97 105_GLOBAL(kvmppc_handlers_end)
98_GLOBAL(kvmppc_handler_len)
99 .long kvmppc_handler_1 - kvmppc_handler_0
100 106
101/* Registers: 107/* Registers:
102 * SPRG_SCRATCH0: guest r4 108 * SPRG_SCRATCH0: guest r4
@@ -461,6 +467,31 @@ lightweight_exit:
461 lwz r4, VCPU_GPR(R4)(r4) 467 lwz r4, VCPU_GPR(R4)(r4)
462 rfi 468 rfi
463 469
470 .data
471 .align 4
472 .globl kvmppc_booke_handler_addr
473kvmppc_booke_handler_addr:
474KVM_HANDLER_ADDR BOOKE_INTERRUPT_CRITICAL
475KVM_HANDLER_ADDR BOOKE_INTERRUPT_MACHINE_CHECK
476KVM_HANDLER_ADDR BOOKE_INTERRUPT_DATA_STORAGE
477KVM_HANDLER_ADDR BOOKE_INTERRUPT_INST_STORAGE
478KVM_HANDLER_ADDR BOOKE_INTERRUPT_EXTERNAL
479KVM_HANDLER_ADDR BOOKE_INTERRUPT_ALIGNMENT
480KVM_HANDLER_ADDR BOOKE_INTERRUPT_PROGRAM
481KVM_HANDLER_ADDR BOOKE_INTERRUPT_FP_UNAVAIL
482KVM_HANDLER_ADDR BOOKE_INTERRUPT_SYSCALL
483KVM_HANDLER_ADDR BOOKE_INTERRUPT_AP_UNAVAIL
484KVM_HANDLER_ADDR BOOKE_INTERRUPT_DECREMENTER
485KVM_HANDLER_ADDR BOOKE_INTERRUPT_FIT
486KVM_HANDLER_ADDR BOOKE_INTERRUPT_WATCHDOG
487KVM_HANDLER_ADDR BOOKE_INTERRUPT_DTLB_MISS
488KVM_HANDLER_ADDR BOOKE_INTERRUPT_ITLB_MISS
489KVM_HANDLER_ADDR BOOKE_INTERRUPT_DEBUG
490KVM_HANDLER_ADDR BOOKE_INTERRUPT_SPE_UNAVAIL
491KVM_HANDLER_ADDR BOOKE_INTERRUPT_SPE_FP_DATA
492KVM_HANDLER_ADDR BOOKE_INTERRUPT_SPE_FP_ROUND
493KVM_HANDLER_END /*Always keep this in end*/
494
464#ifdef CONFIG_SPE 495#ifdef CONFIG_SPE
465_GLOBAL(kvmppc_save_guest_spe) 496_GLOBAL(kvmppc_save_guest_spe)
466 cmpi 0,r3,0 497 cmpi 0,r3,0
diff --git a/arch/powerpc/kvm/e500.c b/arch/powerpc/kvm/e500.c
index b479ed77c515..6dd4de7802bf 100644
--- a/arch/powerpc/kvm/e500.c
+++ b/arch/powerpc/kvm/e500.c
@@ -491,6 +491,9 @@ static int __init kvmppc_e500_init(void)
491{ 491{
492 int r, i; 492 int r, i;
493 unsigned long ivor[3]; 493 unsigned long ivor[3];
494 /* Process remaining handlers above the generic first 16 */
495 unsigned long *handler = &kvmppc_booke_handler_addr[16];
496 unsigned long handler_len;
494 unsigned long max_ivor = 0; 497 unsigned long max_ivor = 0;
495 498
496 r = kvmppc_core_check_processor_compat(); 499 r = kvmppc_core_check_processor_compat();
@@ -506,15 +509,16 @@ static int __init kvmppc_e500_init(void)
506 ivor[1] = mfspr(SPRN_IVOR33); 509 ivor[1] = mfspr(SPRN_IVOR33);
507 ivor[2] = mfspr(SPRN_IVOR34); 510 ivor[2] = mfspr(SPRN_IVOR34);
508 for (i = 0; i < 3; i++) { 511 for (i = 0; i < 3; i++) {
509 if (ivor[i] > max_ivor) 512 if (ivor[i] > ivor[max_ivor])
510 max_ivor = ivor[i]; 513 max_ivor = i;
511 514
515 handler_len = handler[i + 1] - handler[i];
512 memcpy((void *)kvmppc_booke_handlers + ivor[i], 516 memcpy((void *)kvmppc_booke_handlers + ivor[i],
513 kvmppc_handlers_start + (i + 16) * kvmppc_handler_len, 517 (void *)handler[i], handler_len);
514 kvmppc_handler_len);
515 } 518 }
516 flush_icache_range(kvmppc_booke_handlers, 519 handler_len = handler[max_ivor + 1] - handler[max_ivor];
517 kvmppc_booke_handlers + max_ivor + kvmppc_handler_len); 520 flush_icache_range(kvmppc_booke_handlers, kvmppc_booke_handlers +
521 ivor[max_ivor] + handler_len);
518 522
519 return kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), 0, THIS_MODULE); 523 return kvm_init(NULL, sizeof(struct kvmppc_vcpu_e500), 0, THIS_MODULE);
520} 524}