| From c4c6f2cad9e1d4cc076bc183c3689cc9e7019c75 Mon Sep 17 00:00:00 2001 |
| From: James Hogan <james.hogan@imgtec.com> |
| Date: Wed, 4 Feb 2015 10:52:03 +0000 |
| Subject: KVM: MIPS: Disable HTW while in guest |
| |
| From: James Hogan <james.hogan@imgtec.com> |
| |
| commit c4c6f2cad9e1d4cc076bc183c3689cc9e7019c75 upstream. |
| |
| Ensure any hardware page table walker (HTW) is disabled while in KVM |
| guest mode, as KVM doesn't yet set up hardware page table walking for |
| guest mappings so the wrong mappings would get loaded, resulting in the |
| guest hanging or crashing once it reaches userland. |
| |
| The HTW is disabled and re-enabled around the call to |
| __kvm_mips_vcpu_run() which does the initial switch into guest mode and |
| the final switch out of guest context. Additionally it is enabled for |
| the duration of guest exits (i.e. kvm_mips_handle_exit()), getting |
| disabled again before returning back to guest or host. |
| |
| In all cases the HTW is only disabled in normal kernel mode while |
| interrupts are disabled, so that the HTW doesn't get left disabled if |
| the process is preempted. |
| |
| Signed-off-by: James Hogan <james.hogan@imgtec.com> |
| Cc: Paolo Bonzini <pbonzini@redhat.com> |
| Cc: Ralf Baechle <ralf@linux-mips.org> |
| Cc: Markos Chandras <markos.chandras@imgtec.com> |
| Cc: Gleb Natapov <gleb@kernel.org> |
| Cc: kvm@vger.kernel.org |
| Cc: linux-mips@linux-mips.org |
| Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/mips/kvm/mips.c | 13 +++++++++++++ |
| 1 file changed, 13 insertions(+) |
| |
| --- a/arch/mips/kvm/mips.c |
| +++ b/arch/mips/kvm/mips.c |
| @@ -18,6 +18,7 @@ |
| #include <asm/page.h> |
| #include <asm/cacheflush.h> |
| #include <asm/mmu_context.h> |
| +#include <asm/pgtable.h> |
| |
| #include <linux/kvm_host.h> |
| |
| @@ -385,8 +386,14 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_v |
| |
| kvm_guest_enter(); |
| |
| + /* Disable hardware page table walking while in guest */ |
| + htw_stop(); |
| + |
| r = __kvm_mips_vcpu_run(run, vcpu); |
| |
| + /* Re-enable HTW before enabling interrupts */ |
| + htw_start(); |
| + |
| kvm_guest_exit(); |
| local_irq_enable(); |
| |
| @@ -1002,6 +1009,9 @@ int kvm_mips_handle_exit(struct kvm_run |
| enum emulation_result er = EMULATE_DONE; |
| int ret = RESUME_GUEST; |
| |
| + /* re-enable HTW before enabling interrupts */ |
| + htw_start(); |
| + |
| /* Set a default exit reason */ |
| run->exit_reason = KVM_EXIT_UNKNOWN; |
| run->ready_for_interrupt_injection = 1; |
| @@ -1136,6 +1146,9 @@ skip_emul: |
| } |
| } |
| |
| + /* Disable HTW before returning to guest or host */ |
| + htw_stop(); |
| + |
| return ret; |
| } |
| |