Commit 054056bf authored by Oliver Upton's avatar Oliver Upton
Browse files

Merge branch kvm-arm64/misc into kvmarm/next



* kvm-arm64/misc:
  : Miscellaneous updates
  :
  :  - Put an upper bound on the number of I-cache invalidations by
  :    cacheline to avoid soft lockups
  :
  :  - Get rid of bogus refererence count transfer for THP mappings
  :
  :  - Do a local TLB invalidation on permission fault race
  :
  :  - Fixes for page_fault_test KVM selftest
  :
  :  - Add a tracepoint for detecting MMIO instructions unsupported by KVM
  KVM: arm64: Add tracepoint for MMIO accesses where ISV==0
  KVM: arm64: selftest: Perform ISB before reading PAR_EL1
  KVM: arm64: selftest: Add the missing .guest_prepare()
  KVM: arm64: Always invalidate TLB for stage-2 permission faults
  KVM: arm64: Do not transfer page refcount for THP adjustment
  KVM: arm64: Avoid soft lockups due to I-cache maintenance
  arm64: tlbflush: Rename MAX_TLBI_OPS
  KVM: arm64: Don't use kerneldoc comment for arm64_check_features()

Signed-off-by: default avatarOliver Upton <oliver.upton@linux.dev>
parents 6465e260 d11974dc
Loading
Loading
Loading
Loading
+31 −6
Original line number Diff line number Diff line
@@ -224,17 +224,42 @@ static inline void __clean_dcache_guest_page(void *va, size_t size)
	kvm_flush_dcache_to_poc(va, size);
}

static inline size_t __invalidate_icache_max_range(void)
{
	u8 iminline;
	u64 ctr;

	asm volatile(ALTERNATIVE_CB("movz %0, #0\n"
				    "movk %0, #0, lsl #16\n"
				    "movk %0, #0, lsl #32\n"
				    "movk %0, #0, lsl #48\n",
				    ARM64_ALWAYS_SYSTEM,
				    kvm_compute_final_ctr_el0)
		     : "=r" (ctr));

	iminline = SYS_FIELD_GET(CTR_EL0, IminLine, ctr) + 2;
	return MAX_DVM_OPS << iminline;
}

static inline void __invalidate_icache_guest_page(void *va, size_t size)
{
	if (icache_is_aliasing()) {
		/* any kind of VIPT cache */
	/*
	 * VPIPT I-cache maintenance must be done from EL2. See comment in the
	 * nVHE flavor of __kvm_tlb_flush_vmid_ipa().
	 */
	if (icache_is_vpipt() && read_sysreg(CurrentEL) != CurrentEL_EL2)
		return;

	/*
	 * Blow the whole I-cache if it is aliasing (i.e. VIPT) or the
	 * invalidation range exceeds our arbitrary limit on invadations by
	 * cache line.
	 */
	if (icache_is_aliasing() || size > __invalidate_icache_max_range())
		icache_inval_all_pou();
	} else if (read_sysreg(CurrentEL) != CurrentEL_EL1 ||
		   !icache_is_vpipt()) {
		/* PIPT or VPIPT at EL2 (see comment in __kvm_tlb_flush_vmid_ipa) */
	else
		icache_inval_pou((unsigned long)va, (unsigned long)va + size);
}
}

void kvm_set_way_flush(struct kvm_vcpu *vcpu);
void kvm_toggle_cache(struct kvm_vcpu *vcpu, bool was_enabled);
+4 −4
Original line number Diff line number Diff line
@@ -333,7 +333,7 @@ static inline void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch)
 * This is meant to avoid soft lock-ups on large TLB flushing ranges and not
 * necessarily a performance improvement.
 */
#define MAX_TLBI_OPS	PTRS_PER_PTE
#define MAX_DVM_OPS	PTRS_PER_PTE

/*
 * __flush_tlb_range_op - Perform TLBI operation upon a range
@@ -413,12 +413,12 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma,

	/*
	 * When not uses TLB range ops, we can handle up to
	 * (MAX_TLBI_OPS - 1) pages;
	 * (MAX_DVM_OPS - 1) pages;
	 * When uses TLB range ops, we can handle up to
	 * (MAX_TLBI_RANGE_PAGES - 1) pages.
	 */
	if ((!system_supports_tlb_range() &&
	     (end - start) >= (MAX_TLBI_OPS * stride)) ||
	     (end - start) >= (MAX_DVM_OPS * stride)) ||
	    pages >= MAX_TLBI_RANGE_PAGES) {
		flush_tlb_mm(vma->vm_mm);
		return;
@@ -451,7 +451,7 @@ static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end
{
	unsigned long addr;

	if ((end - start) > (MAX_TLBI_OPS * PAGE_SIZE)) {
	if ((end - start) > (MAX_DVM_OPS * PAGE_SIZE)) {
		flush_tlb_all();
		return;
	}
+1 −1
Original line number Diff line number Diff line
@@ -1314,7 +1314,7 @@ int kvm_pgtable_stage2_relax_perms(struct kvm_pgtable *pgt, u64 addr,
	ret = stage2_update_leaf_attrs(pgt, addr, 1, set, clr, NULL, &level,
				       KVM_PGTABLE_WALK_HANDLE_FAULT |
				       KVM_PGTABLE_WALK_SHARED);
	if (!ret)
	if (!ret || ret == -EAGAIN)
		kvm_call_hyp(__kvm_tlb_flush_vmid_ipa_nsh, pgt->mmu, addr, level);
	return ret;
}
+3 −1
Original line number Diff line number Diff line
@@ -135,6 +135,9 @@ int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
	 * volunteered to do so, and bail out otherwise.
	 */
	if (!kvm_vcpu_dabt_isvalid(vcpu)) {
		trace_kvm_mmio_nisv(*vcpu_pc(vcpu), kvm_vcpu_get_esr(vcpu),
				    kvm_vcpu_get_hfar(vcpu), fault_ipa);

		if (test_bit(KVM_ARCH_FLAG_RETURN_NISV_IO_ABORT_TO_USER,
			     &vcpu->kvm->arch.flags)) {
			run->exit_reason = KVM_EXIT_ARM_NISV;
@@ -143,7 +146,6 @@ int io_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
			return 0;
		}

		kvm_pr_unimpl("Data abort outside memslots with no valid syndrome info\n");
		return -ENOSYS;
	}

+0 −20
Original line number Diff line number Diff line
@@ -1298,28 +1298,8 @@ transparent_hugepage_adjust(struct kvm *kvm, struct kvm_memory_slot *memslot,
		if (sz < PMD_SIZE)
			return PAGE_SIZE;

		/*
		 * The address we faulted on is backed by a transparent huge
		 * page.  However, because we map the compound huge page and
		 * not the individual tail page, we need to transfer the
		 * refcount to the head page.  We have to be careful that the
		 * THP doesn't start to split while we are adjusting the
		 * refcounts.
		 *
		 * We are sure this doesn't happen, because mmu_invalidate_retry
		 * was successful and we are holding the mmu_lock, so if this
		 * THP is trying to split, it will be blocked in the mmu
		 * notifier before touching any of the pages, specifically
		 * before being able to call __split_huge_page_refcount().
		 *
		 * We can therefore safely transfer the refcount from PG_tail
		 * to PG_head and switch the pfn from a tail page to the head
		 * page accordingly.
		 */
		*ipap &= PMD_MASK;
		kvm_release_pfn_clean(pfn);
		pfn &= ~(PTRS_PER_PMD - 1);
		get_page(pfn_to_page(pfn));
		*pfnp = pfn;

		return PMD_SIZE;
Loading