path: root/arch/mips/kvm/dyntrans.c
diff options
authorLinus Torvalds <torvalds@linux-foundation.org>2017-02-22 18:22:53 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2017-02-22 18:22:53 -0800
commitfd7e9a88348472521d999434ee02f25735c7dadf (patch)
tree90e6249e58d90ba9d590cfed4481c29ca36a05dc /arch/mips/kvm/dyntrans.c
parent5066e4a34081dd82fb625f2f382bfa29ca421a3f (diff)
parentdd0fd8bca1850ddadf5d33a9ed28f3707cd98ac7 (diff)
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
Pull KVM updates from Paolo Bonzini: "4.11 is going to be a relatively large release for KVM, with a little over 200 commits and noteworthy changes for most architectures. ARM: - GICv3 save/restore - cache flushing fixes - working MSI injection for GICv3 ITS - physical timer emulation MIPS: - various improvements under the hood - support for SMP guests - a large rewrite of MMU emulation. KVM MIPS can now use MMU notifiers to support copy-on-write, KSM, idle page tracking, swapping, ballooning and everything else. KVM_CAP_READONLY_MEM is also supported, so that writes to some memory regions can be treated as MMIO. The new MMU also paves the way for hardware virtualization support. PPC: - support for POWER9 using the radix-tree MMU for host and guest - resizable hashed page table - bugfixes. s390: - expose more features to the guest - more SIMD extensions - instruction execution protection - ESOP2 x86: - improved hashing in the MMU - faster PageLRU tracking for Intel CPUs without EPT A/D bits - some refactoring of nested VMX entry/exit code, preparing for live migration support of nested hypervisors - expose yet another AVX512 CPUID bit - host-to-guest PTP support - refactoring of interrupt injection, with some optimizations thrown in and some duct tape removed. - remove lazy FPU handling - optimizations of user-mode exits - optimizations of vcpu_is_preempted() for KVM guests generic: - alternative signaling mechanism that doesn't pound on tsk->sighand->siglock" * tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm: (195 commits) x86/kvm: Provide optimized version of vcpu_is_preempted() for x86-64 x86/paravirt: Change vcp_is_preempted() arg type to long KVM: VMX: use correct vmcs_read/write for guest segment selector/base x86/kvm/vmx: Defer TR reload after VM exit x86/asm/64: Drop __cacheline_aligned from struct x86_hw_tss x86/kvm/vmx: Simplify segment_base() x86/kvm/vmx: Get rid of segment_base() on 64-bit kernels x86/kvm/vmx: Don't fetch the TSS base from the GDT x86/asm: Define the kernel TSS limit in a macro kvm: fix page struct leak in handle_vmon KVM: PPC: Book3S HV: Disable HPT resizing on POWER9 for now KVM: Return an error code only as a constant in kvm_get_dirty_log() KVM: Return an error code only as a constant in kvm_get_dirty_log_protect() KVM: Return directly after a failed copy_from_user() in kvm_vm_compat_ioctl() KVM: x86: remove code for lazy FPU handling KVM: race-free exit from KVM_RUN without POSIX signals KVM: PPC: Book3S HV: Turn "KVM guest htab" message into a debug message KVM: PPC: Book3S PR: Ratelimit copy data failure error messages KVM: Support vCPU-based gfn->hva cache KVM: use separate generations for each address space ...
Diffstat (limited to 'arch/mips/kvm/dyntrans.c')
1 files changed, 31 insertions, 21 deletions
diff --git a/arch/mips/kvm/dyntrans.c b/arch/mips/kvm/dyntrans.c
index 010cef240688..f8e772564d74 100644
--- a/arch/mips/kvm/dyntrans.c
+++ b/arch/mips/kvm/dyntrans.c
@@ -13,6 +13,7 @@
#include <linux/err.h>
#include <linux/highmem.h>
#include <linux/kvm_host.h>
+#include <linux/uaccess.h>
#include <linux/vmalloc.h>
#include <linux/fs.h>
#include <linux/bootmem.h>
@@ -29,28 +30,37 @@
static int kvm_mips_trans_replace(struct kvm_vcpu *vcpu, u32 *opc,
union mips_instruction replace)
- unsigned long paddr, flags;
- void *vaddr;
- if (KVM_GUEST_KSEGX((unsigned long)opc) == KVM_GUEST_KSEG0) {
- paddr = kvm_mips_translate_guest_kseg0_to_hpa(vcpu,
- (unsigned long)opc);
- vaddr = kmap_atomic(pfn_to_page(PHYS_PFN(paddr)));
- vaddr += paddr & ~PAGE_MASK;
- memcpy(vaddr, (void *)&replace, sizeof(u32));
- local_flush_icache_range((unsigned long)vaddr,
- (unsigned long)vaddr + 32);
- kunmap_atomic(vaddr);
- } else if (KVM_GUEST_KSEGX((unsigned long) opc) == KVM_GUEST_KSEG23) {
- local_irq_save(flags);
- memcpy((void *)opc, (void *)&replace, sizeof(u32));
- __local_flush_icache_user_range((unsigned long)opc,
- (unsigned long)opc + 32);
- local_irq_restore(flags);
- } else {
- kvm_err("%s: Invalid address: %p\n", __func__, opc);
- return -EFAULT;
+ unsigned long vaddr = (unsigned long)opc;
+ int err;
+ /* The GVA page table is still active so use the Linux TLB handlers */
+ kvm_trap_emul_gva_lockless_begin(vcpu);
+ err = put_user(replace.word, opc);
+ kvm_trap_emul_gva_lockless_end(vcpu);
+ if (unlikely(err)) {
+ /*
+ * We write protect clean pages in GVA page table so normal
+ * Linux TLB mod handler doesn't silently dirty the page.
+ * Its also possible we raced with a GVA invalidation.
+ * Try to force the page to become dirty.
+ */
+ err = kvm_trap_emul_gva_fault(vcpu, vaddr, true);
+ if (unlikely(err)) {
+ kvm_info("%s: Address unwriteable: %p\n",
+ __func__, opc);
+ return -EFAULT;
+ }
+ /*
+ * Try again. This will likely trigger a TLB refill, which will
+ * fetch the new dirty entry from the GVA page table, which
+ * should then succeed.
+ */
+ goto retry;
+ __local_flush_icache_user_range(vaddr, vaddr + 4);
return 0;

Privacy Policy