mirror of
https://github.com/torvalds/linux.git
synced 2024-11-27 06:31:52 +00:00
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: Oliver Upton <oliver.upton@linux.dev>
This commit is contained in:
commit
054056bf98
@ -224,16 +224,41 @@ 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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -1228,7 +1228,7 @@ static s64 kvm_arm64_ftr_safe_value(u32 id, const struct arm64_ftr_bits *ftrp,
|
||||
return arm64_ftr_safe_value(&kvm_ftr, new, cur);
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* arm64_check_features() - Check if a feature register value constitutes
|
||||
* a subset of features indicated by the idreg's KVM sanitised limit.
|
||||
*
|
||||
|
@ -136,6 +136,31 @@ TRACE_EVENT(kvm_mmio_emulate,
|
||||
__entry->vcpu_pc, __entry->instr, __entry->cpsr)
|
||||
);
|
||||
|
||||
TRACE_EVENT(kvm_mmio_nisv,
|
||||
TP_PROTO(unsigned long vcpu_pc, unsigned long esr,
|
||||
unsigned long far, unsigned long ipa),
|
||||
TP_ARGS(vcpu_pc, esr, far, ipa),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__field( unsigned long, vcpu_pc )
|
||||
__field( unsigned long, esr )
|
||||
__field( unsigned long, far )
|
||||
__field( unsigned long, ipa )
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__entry->vcpu_pc = vcpu_pc;
|
||||
__entry->esr = esr;
|
||||
__entry->far = far;
|
||||
__entry->ipa = ipa;
|
||||
),
|
||||
|
||||
TP_printk("ipa %#016lx, esr %#016lx, far %#016lx, pc %#016lx",
|
||||
__entry->ipa, __entry->esr,
|
||||
__entry->far, __entry->vcpu_pc)
|
||||
);
|
||||
|
||||
|
||||
TRACE_EVENT(kvm_set_way_flush,
|
||||
TP_PROTO(unsigned long vcpu_pc, bool cache),
|
||||
TP_ARGS(vcpu_pc, cache),
|
||||
|
@ -135,8 +135,8 @@ static void guest_at(void)
|
||||
uint64_t par;
|
||||
|
||||
asm volatile("at s1e1r, %0" :: "r" (guest_test_memory));
|
||||
par = read_sysreg(par_el1);
|
||||
isb();
|
||||
par = read_sysreg(par_el1);
|
||||
|
||||
/* Bit 1 indicates whether the AT was successful */
|
||||
GUEST_ASSERT_EQ(par & 1, 0);
|
||||
@ -842,6 +842,7 @@ static void help(char *name)
|
||||
.name = SCAT2(ro_memslot_no_syndrome, _access), \
|
||||
.data_memslot_flags = KVM_MEM_READONLY, \
|
||||
.pt_memslot_flags = KVM_MEM_READONLY, \
|
||||
.guest_prepare = { _PREPARE(_access) }, \
|
||||
.guest_test = _access, \
|
||||
.fail_vcpu_run_handler = fail_vcpu_run_mmio_no_syndrome_handler, \
|
||||
.expected_events = { .fail_vcpu_runs = 1 }, \
|
||||
@ -865,6 +866,7 @@ static void help(char *name)
|
||||
.name = SCAT2(ro_memslot_no_syn_and_dlog, _access), \
|
||||
.data_memslot_flags = KVM_MEM_READONLY | KVM_MEM_LOG_DIRTY_PAGES, \
|
||||
.pt_memslot_flags = KVM_MEM_READONLY | KVM_MEM_LOG_DIRTY_PAGES, \
|
||||
.guest_prepare = { _PREPARE(_access) }, \
|
||||
.guest_test = _access, \
|
||||
.guest_test_check = { _test_check }, \
|
||||
.fail_vcpu_run_handler = fail_vcpu_run_mmio_no_syndrome_handler, \
|
||||
@ -894,6 +896,7 @@ static void help(char *name)
|
||||
.data_memslot_flags = KVM_MEM_READONLY, \
|
||||
.pt_memslot_flags = KVM_MEM_READONLY, \
|
||||
.mem_mark_cmd = CMD_HOLE_DATA | CMD_HOLE_PT, \
|
||||
.guest_prepare = { _PREPARE(_access) }, \
|
||||
.guest_test = _access, \
|
||||
.uffd_data_handler = _uffd_data_handler, \
|
||||
.uffd_pt_handler = uffd_pt_handler, \
|
||||
|
Loading…
Reference in New Issue
Block a user