aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2013-10-04 07:45:04 -0400
committerAlexander Graf <agraf@suse.de>2013-10-17 08:49:37 -0400
commit44a3add86311bb9d060d795bcdcdc9b8c7a35bd0 (patch)
tree453d0aa59c4b4cdbd0c855e4a51dafae9eb5a7a6
parentf1378b1c0bdce349e21f271dec0612a6cfac5d14 (diff)
KVM: PPC: Book3S HV: Better handling of exceptions that happen in real mode
When an interrupt or exception happens in the guest that comes to the host, the CPU goes to hypervisor real mode (MMU off) to handle the exception but doesn't change the MMU context. After saving a few registers, we then clear the "in guest" flag. If, for any reason, we get an exception in the real-mode code, that then gets handled by the normal kernel exception handlers, which turn the MMU on. This is disastrous if the MMU is still set to the guest context, since we end up executing instructions from random places in the guest kernel with hypervisor privilege. In order to catch this situation, we define a new value for the "in guest" flag, KVM_GUEST_MODE_HOST_HV, to indicate that we are in hypervisor real mode with guest MMU context. If the "in guest" flag is set to this value, we branch off to an emergency handler. For the moment, this just does a branch to self to stop the CPU from doing anything further. While we're here, we define another new flag value to indicate that we are in a HV guest, as distinct from a PR guest. This will be useful when we have a kernel that can support both PR and HV guests concurrently. Signed-off-by: Paul Mackerras <paulus@samba.org> Signed-off-by: Alexander Graf <agraf@suse.de>
-rw-r--r--arch/powerpc/include/asm/kvm_asm.h2
-rw-r--r--arch/powerpc/kvm/book3s_hv_rmhandlers.S31
2 files changed, 27 insertions, 6 deletions
diff --git a/arch/powerpc/include/asm/kvm_asm.h b/arch/powerpc/include/asm/kvm_asm.h
index e2d4d467ee93..1bd92fd43cfb 100644
--- a/arch/powerpc/include/asm/kvm_asm.h
+++ b/arch/powerpc/include/asm/kvm_asm.h
@@ -138,6 +138,8 @@
138#define KVM_GUEST_MODE_NONE 0 138#define KVM_GUEST_MODE_NONE 0
139#define KVM_GUEST_MODE_GUEST 1 139#define KVM_GUEST_MODE_GUEST 1
140#define KVM_GUEST_MODE_SKIP 2 140#define KVM_GUEST_MODE_SKIP 2
141#define KVM_GUEST_MODE_GUEST_HV 3
142#define KVM_GUEST_MODE_HOST_HV 4
141 143
142#define KVM_INST_FETCH_FAILED -1 144#define KVM_INST_FETCH_FAILED -1
143 145
diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
index 6e3370f42a63..84105eb18a0e 100644
--- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S
+++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S
@@ -387,6 +387,9 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
387 mtspr SPRN_DAR, r5 387 mtspr SPRN_DAR, r5
388 mtspr SPRN_DSISR, r6 388 mtspr SPRN_DSISR, r6
389 389
390 li r6, KVM_GUEST_MODE_HOST_HV
391 stb r6, HSTATE_IN_GUEST(r13)
392
390BEGIN_FTR_SECTION 393BEGIN_FTR_SECTION
391 /* Restore AMR and UAMOR, set AMOR to all 1s */ 394 /* Restore AMR and UAMOR, set AMOR to all 1s */
392 ld r5,VCPU_AMR(r4) 395 ld r5,VCPU_AMR(r4)
@@ -690,7 +693,7 @@ fast_guest_return:
690 mtspr SPRN_HSRR1,r11 693 mtspr SPRN_HSRR1,r11
691 694
692 /* Activate guest mode, so faults get handled by KVM */ 695 /* Activate guest mode, so faults get handled by KVM */
693 li r9, KVM_GUEST_MODE_GUEST 696 li r9, KVM_GUEST_MODE_GUEST_HV
694 stb r9, HSTATE_IN_GUEST(r13) 697 stb r9, HSTATE_IN_GUEST(r13)
695 698
696 /* Enter guest */ 699 /* Enter guest */
@@ -750,6 +753,14 @@ kvmppc_interrupt:
750 */ 753 */
751 /* abuse host_r2 as third scratch area; we get r2 from PACATOC(r13) */ 754 /* abuse host_r2 as third scratch area; we get r2 from PACATOC(r13) */
752 std r9, HSTATE_HOST_R2(r13) 755 std r9, HSTATE_HOST_R2(r13)
756
757 lbz r9, HSTATE_IN_GUEST(r13)
758 cmpwi r9, KVM_GUEST_MODE_HOST_HV
759 beq kvmppc_bad_host_intr
760 /* We're now back in the host but in guest MMU context */
761 li r9, KVM_GUEST_MODE_HOST_HV
762 stb r9, HSTATE_IN_GUEST(r13)
763
753 ld r9, HSTATE_KVM_VCPU(r13) 764 ld r9, HSTATE_KVM_VCPU(r13)
754 765
755 /* Save registers */ 766 /* Save registers */
@@ -801,10 +812,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR)
801 std r3, VCPU_GPR(R13)(r9) 812 std r3, VCPU_GPR(R13)(r9)
802 std r4, VCPU_LR(r9) 813 std r4, VCPU_LR(r9)
803 814
804 /* Unset guest mode */
805 li r0, KVM_GUEST_MODE_NONE
806 stb r0, HSTATE_IN_GUEST(r13)
807
808 stw r12,VCPU_TRAP(r9) 815 stw r12,VCPU_TRAP(r9)
809 816
810 /* Save HEIR (HV emulation assist reg) in last_inst 817 /* Save HEIR (HV emulation assist reg) in last_inst
@@ -1198,6 +1205,10 @@ BEGIN_FTR_SECTION
1198 mtspr SPRN_AMR,r6 1205 mtspr SPRN_AMR,r6
1199END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) 1206END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
1200 1207
1208 /* Unset guest mode */
1209 li r0, KVM_GUEST_MODE_NONE
1210 stb r0, HSTATE_IN_GUEST(r13)
1211
1201 /* Switch DSCR back to host value */ 1212 /* Switch DSCR back to host value */
1202BEGIN_FTR_SECTION 1213BEGIN_FTR_SECTION
1203 mfspr r8, SPRN_DSCR 1214 mfspr r8, SPRN_DSCR
@@ -1400,7 +1411,7 @@ fast_interrupt_c_return:
1400 stw r8, VCPU_LAST_INST(r9) 1411 stw r8, VCPU_LAST_INST(r9)
1401 1412
1402 /* Unset guest mode. */ 1413 /* Unset guest mode. */
1403 li r0, KVM_GUEST_MODE_NONE 1414 li r0, KVM_GUEST_MODE_HOST_HV
1404 stb r0, HSTATE_IN_GUEST(r13) 1415 stb r0, HSTATE_IN_GUEST(r13)
1405 b guest_exit_cont 1416 b guest_exit_cont
1406 1417
@@ -1949,3 +1960,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
1949 lwz r7,VCPU_VRSAVE(r4) 1960 lwz r7,VCPU_VRSAVE(r4)
1950 mtspr SPRN_VRSAVE,r7 1961 mtspr SPRN_VRSAVE,r7
1951 blr 1962 blr
1963
1964/*
1965 * We come here if we get any exception or interrupt while we are
1966 * executing host real mode code while in guest MMU context.
1967 * For now just spin, but we should do something better.
1968 */
1969kvmppc_bad_host_intr:
1970 b .