aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2017-01-03 12:43:00 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-01-12 05:39:09 -0500
commit26a401a6a52f7b838ce65b3b48e314c0a4aaa348 (patch)
tree02463c3509ef19a8fdb991ee32ddbec69572afb8 /arch/mips
parentf39969ab0418a9ef7da3f6e571359449b3497d83 (diff)
KVM: MIPS: Don't clobber CP0_Status.UX
commit 4c881451d3017033597ea186cf79ae41a73e1ef8 upstream. On 64-bit kernels, MIPS KVM will clear CP0_Status.UX to prevent the guest (running in user mode) from accessing the 64-bit memory segments. However the previous value of CP0_Status.UX is never restored when exiting from the guest. If the user process uses 64-bit addressing (the n64 ABI) this can result in address error exceptions from the kernel if it needs to deliver a signal before returning to user mode, as the kernel will need to write a sigframe to high user addresses on the user stack which are disallowed by CP0_Status.UX=0. This is fixed by explicitly setting SX and UX again when exiting from the guest, and explicitly clearing those bits when returning to the guest. Having the SX and UX bits set when handling guest exits (rather than only when exiting to userland) will be helpful when we support VZ, since we shouldn't need to directly read or write guest memory, so it will be valid for cache management IPIs to access host user addresses. Signed-off-by: James Hogan <james.hogan@imgtec.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: "Radim Krčmář" <rkrcmar@redhat.com> Cc: Ralf Baechle <ralf@linux-mips.org> Cc: linux-mips@linux-mips.org Cc: kvm@vger.kernel.org Signed-off-by: Radim Krčmář <rkrcmar@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/kvm/entry.c5
1 files changed, 4 insertions, 1 deletions
diff --git a/arch/mips/kvm/entry.c b/arch/mips/kvm/entry.c
index 6a02b3a3fa65..e92fb190e2d6 100644
--- a/arch/mips/kvm/entry.c
+++ b/arch/mips/kvm/entry.c
@@ -521,6 +521,9 @@ void *kvm_mips_build_exit(void *addr)
521 uasm_i_and(&p, V0, V0, AT); 521 uasm_i_and(&p, V0, V0, AT);
522 uasm_i_lui(&p, AT, ST0_CU0 >> 16); 522 uasm_i_lui(&p, AT, ST0_CU0 >> 16);
523 uasm_i_or(&p, V0, V0, AT); 523 uasm_i_or(&p, V0, V0, AT);
524#ifdef CONFIG_64BIT
525 uasm_i_ori(&p, V0, V0, ST0_SX | ST0_UX);
526#endif
524 uasm_i_mtc0(&p, V0, C0_STATUS); 527 uasm_i_mtc0(&p, V0, C0_STATUS);
525 uasm_i_ehb(&p); 528 uasm_i_ehb(&p);
526 529
@@ -643,7 +646,7 @@ static void *kvm_mips_build_ret_to_guest(void *addr)
643 646
644 /* Setup status register for running guest in UM */ 647 /* Setup status register for running guest in UM */
645 uasm_i_ori(&p, V1, V1, ST0_EXL | KSU_USER | ST0_IE); 648 uasm_i_ori(&p, V1, V1, ST0_EXL | KSU_USER | ST0_IE);
646 UASM_i_LA(&p, AT, ~(ST0_CU0 | ST0_MX)); 649 UASM_i_LA(&p, AT, ~(ST0_CU0 | ST0_MX | ST0_SX | ST0_UX));
647 uasm_i_and(&p, V1, V1, AT); 650 uasm_i_and(&p, V1, V1, AT);
648 uasm_i_mtc0(&p, V1, C0_STATUS); 651 uasm_i_mtc0(&p, V1, C0_STATUS);
649 uasm_i_ehb(&p); 652 uasm_i_ehb(&p);