aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorAlexander Graf <agraf@suse.de>2012-02-20 17:57:26 -0500
committerAvi Kivity <avi@redhat.com>2012-04-08 05:55:26 -0400
commit4e642ccbd6a3f1410155c7700f54b56b6c7df9a2 (patch)
tree7c1362f967a0ed2c3563cc945f0498e491cc92cc /arch
parent95f2e921446dbc2e9a785734049ee349a67434bd (diff)
KVM: PPC: booke: expose good state on irq reinject
When reinjecting an interrupt into the host interrupt handler after we're back in host kernel land, we need to tell the kernel where the interrupt happened. We can't tell it that we were in guest state, because that might lead to random code walking host addresses. So instead, we tell it that we came from the interrupt reinject code. This helps getting reasonable numbers out of perf. Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/kvm/booke.c56
1 files changed, 41 insertions, 15 deletions
diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c
index ee39c8a80c6..488936bece6 100644
--- a/arch/powerpc/kvm/booke.c
+++ b/arch/powerpc/kvm/booke.c
@@ -595,37 +595,63 @@ static int emulation_exit(struct kvm_run *run, struct kvm_vcpu *vcpu)
595 } 595 }
596} 596}
597 597
598/** 598static void kvmppc_fill_pt_regs(struct pt_regs *regs)
599 * kvmppc_handle_exit
600 *
601 * Return value is in the form (errcode<<2 | RESUME_FLAG_HOST | RESUME_FLAG_NV)
602 */
603int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
604 unsigned int exit_nr)
605{ 599{
606 int r = RESUME_HOST; 600 ulong r1, ip, msr, lr;
601
602 asm("mr %0, 1" : "=r"(r1));
603 asm("mflr %0" : "=r"(lr));
604 asm("mfmsr %0" : "=r"(msr));
605 asm("bl 1f; 1: mflr %0" : "=r"(ip));
606
607 memset(regs, 0, sizeof(*regs));
608 regs->gpr[1] = r1;
609 regs->nip = ip;
610 regs->msr = msr;
611 regs->link = lr;
612}
607 613
608 /* update before a new last_exit_type is rewritten */ 614static void kvmppc_restart_interrupt(struct kvm_vcpu *vcpu,
609 kvmppc_update_timing_stats(vcpu); 615 unsigned int exit_nr)
616{
617 struct pt_regs regs;
610 618
611 switch (exit_nr) { 619 switch (exit_nr) {
612 case BOOKE_INTERRUPT_EXTERNAL: 620 case BOOKE_INTERRUPT_EXTERNAL:
613 do_IRQ(current->thread.regs); 621 kvmppc_fill_pt_regs(&regs);
622 do_IRQ(&regs);
614 break; 623 break;
615
616 case BOOKE_INTERRUPT_DECREMENTER: 624 case BOOKE_INTERRUPT_DECREMENTER:
617 timer_interrupt(current->thread.regs); 625 kvmppc_fill_pt_regs(&regs);
626 timer_interrupt(&regs);
618 break; 627 break;
619
620#if defined(CONFIG_PPC_FSL_BOOK3E) || defined(CONFIG_PPC_BOOK3E_64) 628#if defined(CONFIG_PPC_FSL_BOOK3E) || defined(CONFIG_PPC_BOOK3E_64)
621 case BOOKE_INTERRUPT_DOORBELL: 629 case BOOKE_INTERRUPT_DOORBELL:
622 doorbell_exception(current->thread.regs); 630 kvmppc_fill_pt_regs(&regs);
631 doorbell_exception(&regs);
623 break; 632 break;
624#endif 633#endif
625 case BOOKE_INTERRUPT_MACHINE_CHECK: 634 case BOOKE_INTERRUPT_MACHINE_CHECK:
626 /* FIXME */ 635 /* FIXME */
627 break; 636 break;
628 } 637 }
638}
639
640/**
641 * kvmppc_handle_exit
642 *
643 * Return value is in the form (errcode<<2 | RESUME_FLAG_HOST | RESUME_FLAG_NV)
644 */
645int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
646 unsigned int exit_nr)
647{
648 int r = RESUME_HOST;
649
650 /* update before a new last_exit_type is rewritten */
651 kvmppc_update_timing_stats(vcpu);
652
653 /* restart interrupts if they were meant for the host */
654 kvmppc_restart_interrupt(vcpu, exit_nr);
629 655
630 local_irq_enable(); 656 local_irq_enable();
631 657