aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kvm
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kvm')
-rw-r--r--arch/powerpc/kvm/book3s.c193
1 files changed, 188 insertions, 5 deletions
diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c
index 02861fda73da..2cb181396f82 100644
--- a/arch/powerpc/kvm/book3s.c
+++ b/arch/powerpc/kvm/book3s.c
@@ -33,6 +33,9 @@
33 33
34/* #define EXIT_DEBUG */ 34/* #define EXIT_DEBUG */
35/* #define EXIT_DEBUG_SIMPLE */ 35/* #define EXIT_DEBUG_SIMPLE */
36/* #define DEBUG_EXT */
37
38static void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr);
36 39
37struct kvm_stats_debugfs_item debugfs_entries[] = { 40struct kvm_stats_debugfs_item debugfs_entries[] = {
38 { "exits", VCPU_STAT(sum_exits) }, 41 { "exits", VCPU_STAT(sum_exits) },
@@ -77,6 +80,10 @@ void kvmppc_core_vcpu_put(struct kvm_vcpu *vcpu)
77 memcpy(&to_book3s(vcpu)->shadow_vcpu, &get_paca()->shadow_vcpu, 80 memcpy(&to_book3s(vcpu)->shadow_vcpu, &get_paca()->shadow_vcpu,
78 sizeof(get_paca()->shadow_vcpu)); 81 sizeof(get_paca()->shadow_vcpu));
79 to_book3s(vcpu)->slb_shadow_max = get_paca()->kvm_slb_max; 82 to_book3s(vcpu)->slb_shadow_max = get_paca()->kvm_slb_max;
83
84 kvmppc_giveup_ext(vcpu, MSR_FP);
85 kvmppc_giveup_ext(vcpu, MSR_VEC);
86 kvmppc_giveup_ext(vcpu, MSR_VSX);
80} 87}
81 88
82#if defined(EXIT_DEBUG) 89#if defined(EXIT_DEBUG)
@@ -97,9 +104,9 @@ void kvmppc_set_msr(struct kvm_vcpu *vcpu, u64 msr)
97 msr &= to_book3s(vcpu)->msr_mask; 104 msr &= to_book3s(vcpu)->msr_mask;
98 vcpu->arch.msr = msr; 105 vcpu->arch.msr = msr;
99 vcpu->arch.shadow_msr = msr | MSR_USER32; 106 vcpu->arch.shadow_msr = msr | MSR_USER32;
100 vcpu->arch.shadow_msr &= ( MSR_VEC | MSR_VSX | MSR_FP | MSR_FE0 | 107 vcpu->arch.shadow_msr &= (MSR_FE0 | MSR_USER64 | MSR_SE | MSR_BE |
101 MSR_USER64 | MSR_SE | MSR_BE | MSR_DE | 108 MSR_DE | MSR_FE1);
102 MSR_FE1); 109 vcpu->arch.shadow_msr |= (msr & vcpu->arch.guest_owned_ext);
103 110
104 if (msr & (MSR_WE|MSR_POW)) { 111 if (msr & (MSR_WE|MSR_POW)) {
105 if (!vcpu->arch.pending_exceptions) { 112 if (!vcpu->arch.pending_exceptions) {
@@ -551,6 +558,117 @@ int kvmppc_handle_pagefault(struct kvm_run *run, struct kvm_vcpu *vcpu,
551 return r; 558 return r;
552} 559}
553 560
561static inline int get_fpr_index(int i)
562{
563#ifdef CONFIG_VSX
564 i *= 2;
565#endif
566 return i;
567}
568
569/* Give up external provider (FPU, Altivec, VSX) */
570static void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr)
571{
572 struct thread_struct *t = &current->thread;
573 u64 *vcpu_fpr = vcpu->arch.fpr;
574 u64 *vcpu_vsx = vcpu->arch.vsr;
575 u64 *thread_fpr = (u64*)t->fpr;
576 int i;
577
578 if (!(vcpu->arch.guest_owned_ext & msr))
579 return;
580
581#ifdef DEBUG_EXT
582 printk(KERN_INFO "Giving up ext 0x%lx\n", msr);
583#endif
584
585 switch (msr) {
586 case MSR_FP:
587 giveup_fpu(current);
588 for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++)
589 vcpu_fpr[i] = thread_fpr[get_fpr_index(i)];
590
591 vcpu->arch.fpscr = t->fpscr.val;
592 break;
593 case MSR_VEC:
594#ifdef CONFIG_ALTIVEC
595 giveup_altivec(current);
596 memcpy(vcpu->arch.vr, t->vr, sizeof(vcpu->arch.vr));
597 vcpu->arch.vscr = t->vscr;
598#endif
599 break;
600 case MSR_VSX:
601#ifdef CONFIG_VSX
602 __giveup_vsx(current);
603 for (i = 0; i < ARRAY_SIZE(vcpu->arch.vsr); i++)
604 vcpu_vsx[i] = thread_fpr[get_fpr_index(i) + 1];
605#endif
606 break;
607 default:
608 BUG();
609 }
610
611 vcpu->arch.guest_owned_ext &= ~msr;
612 current->thread.regs->msr &= ~msr;
613 kvmppc_set_msr(vcpu, vcpu->arch.msr);
614}
615
616/* Handle external providers (FPU, Altivec, VSX) */
617static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
618 ulong msr)
619{
620 struct thread_struct *t = &current->thread;
621 u64 *vcpu_fpr = vcpu->arch.fpr;
622 u64 *vcpu_vsx = vcpu->arch.vsr;
623 u64 *thread_fpr = (u64*)t->fpr;
624 int i;
625
626 if (!(vcpu->arch.msr & msr)) {
627 kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
628 return RESUME_GUEST;
629 }
630
631#ifdef DEBUG_EXT
632 printk(KERN_INFO "Loading up ext 0x%lx\n", msr);
633#endif
634
635 current->thread.regs->msr |= msr;
636
637 switch (msr) {
638 case MSR_FP:
639 for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++)
640 thread_fpr[get_fpr_index(i)] = vcpu_fpr[i];
641
642 t->fpscr.val = vcpu->arch.fpscr;
643 t->fpexc_mode = 0;
644 kvmppc_load_up_fpu();
645 break;
646 case MSR_VEC:
647#ifdef CONFIG_ALTIVEC
648 memcpy(t->vr, vcpu->arch.vr, sizeof(vcpu->arch.vr));
649 t->vscr = vcpu->arch.vscr;
650 t->vrsave = -1;
651 kvmppc_load_up_altivec();
652#endif
653 break;
654 case MSR_VSX:
655#ifdef CONFIG_VSX
656 for (i = 0; i < ARRAY_SIZE(vcpu->arch.vsr); i++)
657 thread_fpr[get_fpr_index(i) + 1] = vcpu_vsx[i];
658 kvmppc_load_up_vsx();
659#endif
660 break;
661 default:
662 BUG();
663 }
664
665 vcpu->arch.guest_owned_ext |= msr;
666
667 kvmppc_set_msr(vcpu, vcpu->arch.msr);
668
669 return RESUME_GUEST;
670}
671
554int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, 672int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
555 unsigned int exit_nr) 673 unsigned int exit_nr)
556{ 674{
@@ -674,11 +792,17 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
674 kvmppc_book3s_queue_irqprio(vcpu, exit_nr); 792 kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
675 r = RESUME_GUEST; 793 r = RESUME_GUEST;
676 break; 794 break;
677 case BOOK3S_INTERRUPT_MACHINE_CHECK:
678 case BOOK3S_INTERRUPT_FP_UNAVAIL: 795 case BOOK3S_INTERRUPT_FP_UNAVAIL:
679 case BOOK3S_INTERRUPT_TRACE: 796 r = kvmppc_handle_ext(vcpu, exit_nr, MSR_FP);
797 break;
680 case BOOK3S_INTERRUPT_ALTIVEC: 798 case BOOK3S_INTERRUPT_ALTIVEC:
799 r = kvmppc_handle_ext(vcpu, exit_nr, MSR_VEC);
800 break;
681 case BOOK3S_INTERRUPT_VSX: 801 case BOOK3S_INTERRUPT_VSX:
802 r = kvmppc_handle_ext(vcpu, exit_nr, MSR_VSX);
803 break;
804 case BOOK3S_INTERRUPT_MACHINE_CHECK:
805 case BOOK3S_INTERRUPT_TRACE:
682 kvmppc_book3s_queue_irqprio(vcpu, exit_nr); 806 kvmppc_book3s_queue_irqprio(vcpu, exit_nr);
683 r = RESUME_GUEST; 807 r = RESUME_GUEST;
684 break; 808 break;
@@ -959,6 +1083,10 @@ extern int __kvmppc_vcpu_entry(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
959int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu) 1083int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
960{ 1084{
961 int ret; 1085 int ret;
1086 struct thread_struct ext_bkp;
1087 bool save_vec = current->thread.used_vr;
1088 bool save_vsx = current->thread.used_vsr;
1089 ulong ext_msr;
962 1090
963 /* No need to go into the guest when all we do is going out */ 1091 /* No need to go into the guest when all we do is going out */
964 if (signal_pending(current)) { 1092 if (signal_pending(current)) {
@@ -966,6 +1094,35 @@ int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
966 return -EINTR; 1094 return -EINTR;
967 } 1095 }
968 1096
1097 /* Save FPU state in stack */
1098 if (current->thread.regs->msr & MSR_FP)
1099 giveup_fpu(current);
1100 memcpy(ext_bkp.fpr, current->thread.fpr, sizeof(current->thread.fpr));
1101 ext_bkp.fpscr = current->thread.fpscr;
1102 ext_bkp.fpexc_mode = current->thread.fpexc_mode;
1103
1104#ifdef CONFIG_ALTIVEC
1105 /* Save Altivec state in stack */
1106 if (save_vec) {
1107 if (current->thread.regs->msr & MSR_VEC)
1108 giveup_altivec(current);
1109 memcpy(ext_bkp.vr, current->thread.vr, sizeof(ext_bkp.vr));
1110 ext_bkp.vscr = current->thread.vscr;
1111 ext_bkp.vrsave = current->thread.vrsave;
1112 }
1113 ext_bkp.used_vr = current->thread.used_vr;
1114#endif
1115
1116#ifdef CONFIG_VSX
1117 /* Save VSX state in stack */
1118 if (save_vsx && (current->thread.regs->msr & MSR_VSX))
1119 __giveup_vsx(current);
1120 ext_bkp.used_vsr = current->thread.used_vsr;
1121#endif
1122
1123 /* Remember the MSR with disabled extensions */
1124 ext_msr = current->thread.regs->msr;
1125
969 /* XXX we get called with irq disabled - change that! */ 1126 /* XXX we get called with irq disabled - change that! */
970 local_irq_enable(); 1127 local_irq_enable();
971 1128
@@ -973,6 +1130,32 @@ int __kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
973 1130
974 local_irq_disable(); 1131 local_irq_disable();
975 1132
1133 current->thread.regs->msr = ext_msr;
1134
1135 /* Make sure we save the guest FPU/Altivec/VSX state */
1136 kvmppc_giveup_ext(vcpu, MSR_FP);
1137 kvmppc_giveup_ext(vcpu, MSR_VEC);
1138 kvmppc_giveup_ext(vcpu, MSR_VSX);
1139
1140 /* Restore FPU state from stack */
1141 memcpy(current->thread.fpr, ext_bkp.fpr, sizeof(ext_bkp.fpr));
1142 current->thread.fpscr = ext_bkp.fpscr;
1143 current->thread.fpexc_mode = ext_bkp.fpexc_mode;
1144
1145#ifdef CONFIG_ALTIVEC
1146 /* Restore Altivec state from stack */
1147 if (save_vec && current->thread.used_vr) {
1148 memcpy(current->thread.vr, ext_bkp.vr, sizeof(ext_bkp.vr));
1149 current->thread.vscr = ext_bkp.vscr;
1150 current->thread.vrsave= ext_bkp.vrsave;
1151 }
1152 current->thread.used_vr = ext_bkp.used_vr;
1153#endif
1154
1155#ifdef CONFIG_VSX
1156 current->thread.used_vsr = ext_bkp.used_vsr;
1157#endif
1158
976 return ret; 1159 return ret;
977} 1160}
978 1161