diff options
author | Paul Mackerras <paulus@samba.org> | 2013-10-04 07:45:04 -0400 |
---|---|---|
committer | Alexander Graf <agraf@suse.de> | 2013-10-17 08:49:37 -0400 |
commit | 44a3add86311bb9d060d795bcdcdc9b8c7a35bd0 (patch) | |
tree | 453d0aa59c4b4cdbd0c855e4a51dafae9eb5a7a6 /arch/powerpc/kvm | |
parent | f1378b1c0bdce349e21f271dec0612a6cfac5d14 (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>
Diffstat (limited to 'arch/powerpc/kvm')
-rw-r--r-- | arch/powerpc/kvm/book3s_hv_rmhandlers.S | 31 |
1 files changed, 25 insertions, 6 deletions
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 | |||
390 | BEGIN_FTR_SECTION | 393 | BEGIN_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 |
1199 | END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206) | 1206 | END_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 */ |
1202 | BEGIN_FTR_SECTION | 1213 | BEGIN_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 | */ | ||
1969 | kvmppc_bad_host_intr: | ||
1970 | b . | ||