Commit 62d228b8 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'fixes' of git://git.kernel.org/pub/scm/virt/kvm/kvm

Pull KVM fixes from Gleb Natapov.

* 'fixes' of git://git.kernel.org/pub/scm/virt/kvm/kvm:
  KVM: VMX: set "blocked by NMI" flag if EPT violation happens during IRET from NMI
  kvm: free resources after canceling async_pf
  KVM: nEPT: reset PDPTR register cache on nested vmentry emulation
  KVM: mmu: allow page tables to be in read-only slots
  KVM: x86 emulator: emulate RETF imm
parents 84fca9f3 0be9c7a8
...@@ -2025,6 +2025,17 @@ static int em_ret_far(struct x86_emulate_ctxt *ctxt) ...@@ -2025,6 +2025,17 @@ static int em_ret_far(struct x86_emulate_ctxt *ctxt)
return rc; return rc;
} }
static int em_ret_far_imm(struct x86_emulate_ctxt *ctxt)
{
int rc;
rc = em_ret_far(ctxt);
if (rc != X86EMUL_CONTINUE)
return rc;
rsp_increment(ctxt, ctxt->src.val);
return X86EMUL_CONTINUE;
}
static int em_cmpxchg(struct x86_emulate_ctxt *ctxt) static int em_cmpxchg(struct x86_emulate_ctxt *ctxt)
{ {
/* Save real source value, then compare EAX against destination. */ /* Save real source value, then compare EAX against destination. */
...@@ -3763,7 +3774,8 @@ static const struct opcode opcode_table[256] = { ...@@ -3763,7 +3774,8 @@ static const struct opcode opcode_table[256] = {
G(ByteOp, group11), G(0, group11), G(ByteOp, group11), G(0, group11),
/* 0xC8 - 0xCF */ /* 0xC8 - 0xCF */
I(Stack | SrcImmU16 | Src2ImmByte, em_enter), I(Stack, em_leave), I(Stack | SrcImmU16 | Src2ImmByte, em_enter), I(Stack, em_leave),
N, I(ImplicitOps | Stack, em_ret_far), I(ImplicitOps | Stack | SrcImmU16, em_ret_far_imm),
I(ImplicitOps | Stack, em_ret_far),
D(ImplicitOps), DI(SrcImmByte, intn), D(ImplicitOps), DI(SrcImmByte, intn),
D(ImplicitOps | No64), II(ImplicitOps, em_iret, iret), D(ImplicitOps | No64), II(ImplicitOps, em_iret, iret),
/* 0xD0 - 0xD7 */ /* 0xD0 - 0xD7 */
......
...@@ -99,6 +99,7 @@ struct guest_walker { ...@@ -99,6 +99,7 @@ struct guest_walker {
pt_element_t prefetch_ptes[PTE_PREFETCH_NUM]; pt_element_t prefetch_ptes[PTE_PREFETCH_NUM];
gpa_t pte_gpa[PT_MAX_FULL_LEVELS]; gpa_t pte_gpa[PT_MAX_FULL_LEVELS];
pt_element_t __user *ptep_user[PT_MAX_FULL_LEVELS]; pt_element_t __user *ptep_user[PT_MAX_FULL_LEVELS];
bool pte_writable[PT_MAX_FULL_LEVELS];
unsigned pt_access; unsigned pt_access;
unsigned pte_access; unsigned pte_access;
gfn_t gfn; gfn_t gfn;
...@@ -235,6 +236,22 @@ static int FNAME(update_accessed_dirty_bits)(struct kvm_vcpu *vcpu, ...@@ -235,6 +236,22 @@ static int FNAME(update_accessed_dirty_bits)(struct kvm_vcpu *vcpu,
if (pte == orig_pte) if (pte == orig_pte)
continue; continue;
/*
* If the slot is read-only, simply do not process the accessed
* and dirty bits. This is the correct thing to do if the slot
* is ROM, and page tables in read-as-ROM/write-as-MMIO slots
* are only supported if the accessed and dirty bits are already
* set in the ROM (so that MMIO writes are never needed).
*
* Note that NPT does not allow this at all and faults, since
* it always wants nested page table entries for the guest
* page tables to be writable. And EPT works but will simply
* overwrite the read-only memory to set the accessed and dirty
* bits.
*/
if (unlikely(!walker->pte_writable[level - 1]))
continue;
ret = FNAME(cmpxchg_gpte)(vcpu, mmu, ptep_user, index, orig_pte, pte); ret = FNAME(cmpxchg_gpte)(vcpu, mmu, ptep_user, index, orig_pte, pte);
if (ret) if (ret)
return ret; return ret;
...@@ -309,7 +326,8 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker, ...@@ -309,7 +326,8 @@ static int FNAME(walk_addr_generic)(struct guest_walker *walker,
goto error; goto error;
real_gfn = gpa_to_gfn(real_gfn); real_gfn = gpa_to_gfn(real_gfn);
host_addr = gfn_to_hva(vcpu->kvm, real_gfn); host_addr = gfn_to_hva_prot(vcpu->kvm, real_gfn,
&walker->pte_writable[walker->level - 1]);
if (unlikely(kvm_is_error_hva(host_addr))) if (unlikely(kvm_is_error_hva(host_addr)))
goto error; goto error;
......
...@@ -5339,6 +5339,15 @@ static int handle_ept_violation(struct kvm_vcpu *vcpu) ...@@ -5339,6 +5339,15 @@ static int handle_ept_violation(struct kvm_vcpu *vcpu)
return 0; return 0;
} }
/*
* EPT violation happened while executing iret from NMI,
* "blocked by NMI" bit has to be set before next VM entry.
* There are errata that may cause this bit to not be set:
* AAK134, BY25.
*/
if (exit_qualification & INTR_INFO_UNBLOCK_NMI)
vmcs_set_bits(GUEST_INTERRUPTIBILITY_INFO, GUEST_INTR_STATE_NMI);
gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS); gpa = vmcs_read64(GUEST_PHYSICAL_ADDRESS);
trace_kvm_page_fault(gpa, exit_qualification); trace_kvm_page_fault(gpa, exit_qualification);
...@@ -7766,6 +7775,10 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12) ...@@ -7766,6 +7775,10 @@ static void prepare_vmcs02(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
vmcs_write64(GUEST_PDPTR1, vmcs12->guest_pdptr1); vmcs_write64(GUEST_PDPTR1, vmcs12->guest_pdptr1);
vmcs_write64(GUEST_PDPTR2, vmcs12->guest_pdptr2); vmcs_write64(GUEST_PDPTR2, vmcs12->guest_pdptr2);
vmcs_write64(GUEST_PDPTR3, vmcs12->guest_pdptr3); vmcs_write64(GUEST_PDPTR3, vmcs12->guest_pdptr3);
__clear_bit(VCPU_EXREG_PDPTR,
(unsigned long *)&vcpu->arch.regs_avail);
__clear_bit(VCPU_EXREG_PDPTR,
(unsigned long *)&vcpu->arch.regs_dirty);
} }
kvm_register_write(vcpu, VCPU_REGS_RSP, vmcs12->guest_rsp); kvm_register_write(vcpu, VCPU_REGS_RSP, vmcs12->guest_rsp);
......
...@@ -533,6 +533,7 @@ int gfn_to_page_many_atomic(struct kvm *kvm, gfn_t gfn, struct page **pages, ...@@ -533,6 +533,7 @@ int gfn_to_page_many_atomic(struct kvm *kvm, gfn_t gfn, struct page **pages,
struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn); struct page *gfn_to_page(struct kvm *kvm, gfn_t gfn);
unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn); unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn);
unsigned long gfn_to_hva_prot(struct kvm *kvm, gfn_t gfn, bool *writable);
unsigned long gfn_to_hva_memslot(struct kvm_memory_slot *slot, gfn_t gfn); unsigned long gfn_to_hva_memslot(struct kvm_memory_slot *slot, gfn_t gfn);
void kvm_release_page_clean(struct page *page); void kvm_release_page_clean(struct page *page);
void kvm_release_page_dirty(struct page *page); void kvm_release_page_dirty(struct page *page);
......
...@@ -101,8 +101,11 @@ void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu) ...@@ -101,8 +101,11 @@ void kvm_clear_async_pf_completion_queue(struct kvm_vcpu *vcpu)
typeof(*work), queue); typeof(*work), queue);
cancel_work_sync(&work->work); cancel_work_sync(&work->work);
list_del(&work->queue); list_del(&work->queue);
if (!work->done) /* work was canceled */ if (!work->done) { /* work was canceled */
mmdrop(work->mm);
kvm_put_kvm(vcpu->kvm); /* == work->vcpu->kvm */
kmem_cache_free(async_pf_cache, work); kmem_cache_free(async_pf_cache, work);
}
} }
spin_lock(&vcpu->async_pf.lock); spin_lock(&vcpu->async_pf.lock);
......
...@@ -1058,11 +1058,15 @@ unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn) ...@@ -1058,11 +1058,15 @@ unsigned long gfn_to_hva(struct kvm *kvm, gfn_t gfn)
EXPORT_SYMBOL_GPL(gfn_to_hva); EXPORT_SYMBOL_GPL(gfn_to_hva);
/* /*
* The hva returned by this function is only allowed to be read. * If writable is set to false, the hva returned by this function is only
* It should pair with kvm_read_hva() or kvm_read_hva_atomic(). * allowed to be read.
*/ */
static unsigned long gfn_to_hva_read(struct kvm *kvm, gfn_t gfn) unsigned long gfn_to_hva_prot(struct kvm *kvm, gfn_t gfn, bool *writable)
{ {
struct kvm_memory_slot *slot = gfn_to_memslot(kvm, gfn);
if (writable)
*writable = !memslot_is_readonly(slot);
return __gfn_to_hva_many(gfn_to_memslot(kvm, gfn), gfn, NULL, false); return __gfn_to_hva_many(gfn_to_memslot(kvm, gfn), gfn, NULL, false);
} }
...@@ -1430,7 +1434,7 @@ int kvm_read_guest_page(struct kvm *kvm, gfn_t gfn, void *data, int offset, ...@@ -1430,7 +1434,7 @@ int kvm_read_guest_page(struct kvm *kvm, gfn_t gfn, void *data, int offset,
int r; int r;
unsigned long addr; unsigned long addr;
addr = gfn_to_hva_read(kvm, gfn); addr = gfn_to_hva_prot(kvm, gfn, NULL);
if (kvm_is_error_hva(addr)) if (kvm_is_error_hva(addr))
return -EFAULT; return -EFAULT;
r = kvm_read_hva(data, (void __user *)addr + offset, len); r = kvm_read_hva(data, (void __user *)addr + offset, len);
...@@ -1468,7 +1472,7 @@ int kvm_read_guest_atomic(struct kvm *kvm, gpa_t gpa, void *data, ...@@ -1468,7 +1472,7 @@ int kvm_read_guest_atomic(struct kvm *kvm, gpa_t gpa, void *data,
gfn_t gfn = gpa >> PAGE_SHIFT; gfn_t gfn = gpa >> PAGE_SHIFT;
int offset = offset_in_page(gpa); int offset = offset_in_page(gpa);
addr = gfn_to_hva_read(kvm, gfn); addr = gfn_to_hva_prot(kvm, gfn, NULL);
if (kvm_is_error_hva(addr)) if (kvm_is_error_hva(addr))
return -EFAULT; return -EFAULT;
pagefault_disable(); pagefault_disable();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment