162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2015 - ARM Ltd
462306a36Sopenharmony_ci * Author: Marc Zyngier <marc.zyngier@arm.com>
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/irqflags.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <asm/kvm_hyp.h>
1062306a36Sopenharmony_ci#include <asm/kvm_mmu.h>
1162306a36Sopenharmony_ci#include <asm/tlbflush.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistruct tlb_inv_context {
1462306a36Sopenharmony_ci	unsigned long	flags;
1562306a36Sopenharmony_ci	u64		tcr;
1662306a36Sopenharmony_ci	u64		sctlr;
1762306a36Sopenharmony_ci};
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic void __tlb_switch_to_guest(struct kvm_s2_mmu *mmu,
2062306a36Sopenharmony_ci				  struct tlb_inv_context *cxt)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	u64 val;
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	local_irq_save(cxt->flags);
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci	if (cpus_have_final_cap(ARM64_WORKAROUND_SPECULATIVE_AT)) {
2762306a36Sopenharmony_ci		/*
2862306a36Sopenharmony_ci		 * For CPUs that are affected by ARM errata 1165522 or 1530923,
2962306a36Sopenharmony_ci		 * we cannot trust stage-1 to be in a correct state at that
3062306a36Sopenharmony_ci		 * point. Since we do not want to force a full load of the
3162306a36Sopenharmony_ci		 * vcpu state, we prevent the EL1 page-table walker to
3262306a36Sopenharmony_ci		 * allocate new TLBs. This is done by setting the EPD bits
3362306a36Sopenharmony_ci		 * in the TCR_EL1 register. We also need to prevent it to
3462306a36Sopenharmony_ci		 * allocate IPA->PA walks, so we enable the S1 MMU...
3562306a36Sopenharmony_ci		 */
3662306a36Sopenharmony_ci		val = cxt->tcr = read_sysreg_el1(SYS_TCR);
3762306a36Sopenharmony_ci		val |= TCR_EPD1_MASK | TCR_EPD0_MASK;
3862306a36Sopenharmony_ci		write_sysreg_el1(val, SYS_TCR);
3962306a36Sopenharmony_ci		val = cxt->sctlr = read_sysreg_el1(SYS_SCTLR);
4062306a36Sopenharmony_ci		val |= SCTLR_ELx_M;
4162306a36Sopenharmony_ci		write_sysreg_el1(val, SYS_SCTLR);
4262306a36Sopenharmony_ci	}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	/*
4562306a36Sopenharmony_ci	 * With VHE enabled, we have HCR_EL2.{E2H,TGE} = {1,1}, and
4662306a36Sopenharmony_ci	 * most TLB operations target EL2/EL0. In order to affect the
4762306a36Sopenharmony_ci	 * guest TLBs (EL1/EL0), we need to change one of these two
4862306a36Sopenharmony_ci	 * bits. Changing E2H is impossible (goodbye TTBR1_EL2), so
4962306a36Sopenharmony_ci	 * let's flip TGE before executing the TLB operation.
5062306a36Sopenharmony_ci	 *
5162306a36Sopenharmony_ci	 * ARM erratum 1165522 requires some special handling (again),
5262306a36Sopenharmony_ci	 * as we need to make sure both stages of translation are in
5362306a36Sopenharmony_ci	 * place before clearing TGE. __load_stage2() already
5462306a36Sopenharmony_ci	 * has an ISB in order to deal with this.
5562306a36Sopenharmony_ci	 */
5662306a36Sopenharmony_ci	__load_stage2(mmu, mmu->arch);
5762306a36Sopenharmony_ci	val = read_sysreg(hcr_el2);
5862306a36Sopenharmony_ci	val &= ~HCR_TGE;
5962306a36Sopenharmony_ci	write_sysreg(val, hcr_el2);
6062306a36Sopenharmony_ci	isb();
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic void __tlb_switch_to_host(struct tlb_inv_context *cxt)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	/*
6662306a36Sopenharmony_ci	 * We're done with the TLB operation, let's restore the host's
6762306a36Sopenharmony_ci	 * view of HCR_EL2.
6862306a36Sopenharmony_ci	 */
6962306a36Sopenharmony_ci	write_sysreg(0, vttbr_el2);
7062306a36Sopenharmony_ci	write_sysreg(HCR_HOST_VHE_FLAGS, hcr_el2);
7162306a36Sopenharmony_ci	isb();
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	if (cpus_have_final_cap(ARM64_WORKAROUND_SPECULATIVE_AT)) {
7462306a36Sopenharmony_ci		/* Restore the registers to what they were */
7562306a36Sopenharmony_ci		write_sysreg_el1(cxt->tcr, SYS_TCR);
7662306a36Sopenharmony_ci		write_sysreg_el1(cxt->sctlr, SYS_SCTLR);
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	local_irq_restore(cxt->flags);
8062306a36Sopenharmony_ci}
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_civoid __kvm_tlb_flush_vmid_ipa(struct kvm_s2_mmu *mmu,
8362306a36Sopenharmony_ci			      phys_addr_t ipa, int level)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	struct tlb_inv_context cxt;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	dsb(ishst);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	/* Switch to requested VMID */
9062306a36Sopenharmony_ci	__tlb_switch_to_guest(mmu, &cxt);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	/*
9362306a36Sopenharmony_ci	 * We could do so much better if we had the VA as well.
9462306a36Sopenharmony_ci	 * Instead, we invalidate Stage-2 for this IPA, and the
9562306a36Sopenharmony_ci	 * whole of Stage-1. Weep...
9662306a36Sopenharmony_ci	 */
9762306a36Sopenharmony_ci	ipa >>= 12;
9862306a36Sopenharmony_ci	__tlbi_level(ipas2e1is, ipa, level);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	/*
10162306a36Sopenharmony_ci	 * We have to ensure completion of the invalidation at Stage-2,
10262306a36Sopenharmony_ci	 * since a table walk on another CPU could refill a TLB with a
10362306a36Sopenharmony_ci	 * complete (S1 + S2) walk based on the old Stage-2 mapping if
10462306a36Sopenharmony_ci	 * the Stage-1 invalidation happened first.
10562306a36Sopenharmony_ci	 */
10662306a36Sopenharmony_ci	dsb(ish);
10762306a36Sopenharmony_ci	__tlbi(vmalle1is);
10862306a36Sopenharmony_ci	dsb(ish);
10962306a36Sopenharmony_ci	isb();
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	__tlb_switch_to_host(&cxt);
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_civoid __kvm_tlb_flush_vmid_ipa_nsh(struct kvm_s2_mmu *mmu,
11562306a36Sopenharmony_ci				  phys_addr_t ipa, int level)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	struct tlb_inv_context cxt;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	dsb(nshst);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	/* Switch to requested VMID */
12262306a36Sopenharmony_ci	__tlb_switch_to_guest(mmu, &cxt);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	/*
12562306a36Sopenharmony_ci	 * We could do so much better if we had the VA as well.
12662306a36Sopenharmony_ci	 * Instead, we invalidate Stage-2 for this IPA, and the
12762306a36Sopenharmony_ci	 * whole of Stage-1. Weep...
12862306a36Sopenharmony_ci	 */
12962306a36Sopenharmony_ci	ipa >>= 12;
13062306a36Sopenharmony_ci	__tlbi_level(ipas2e1, ipa, level);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	/*
13362306a36Sopenharmony_ci	 * We have to ensure completion of the invalidation at Stage-2,
13462306a36Sopenharmony_ci	 * since a table walk on another CPU could refill a TLB with a
13562306a36Sopenharmony_ci	 * complete (S1 + S2) walk based on the old Stage-2 mapping if
13662306a36Sopenharmony_ci	 * the Stage-1 invalidation happened first.
13762306a36Sopenharmony_ci	 */
13862306a36Sopenharmony_ci	dsb(nsh);
13962306a36Sopenharmony_ci	__tlbi(vmalle1);
14062306a36Sopenharmony_ci	dsb(nsh);
14162306a36Sopenharmony_ci	isb();
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	__tlb_switch_to_host(&cxt);
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_civoid __kvm_tlb_flush_vmid_range(struct kvm_s2_mmu *mmu,
14762306a36Sopenharmony_ci				phys_addr_t start, unsigned long pages)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	struct tlb_inv_context cxt;
15062306a36Sopenharmony_ci	unsigned long stride;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	/*
15362306a36Sopenharmony_ci	 * Since the range of addresses may not be mapped at
15462306a36Sopenharmony_ci	 * the same level, assume the worst case as PAGE_SIZE
15562306a36Sopenharmony_ci	 */
15662306a36Sopenharmony_ci	stride = PAGE_SIZE;
15762306a36Sopenharmony_ci	start = round_down(start, stride);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	dsb(ishst);
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	/* Switch to requested VMID */
16262306a36Sopenharmony_ci	__tlb_switch_to_guest(mmu, &cxt);
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	__flush_s2_tlb_range_op(ipas2e1is, start, pages, stride, 0);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	dsb(ish);
16762306a36Sopenharmony_ci	__tlbi(vmalle1is);
16862306a36Sopenharmony_ci	dsb(ish);
16962306a36Sopenharmony_ci	isb();
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	__tlb_switch_to_host(&cxt);
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_civoid __kvm_tlb_flush_vmid(struct kvm_s2_mmu *mmu)
17562306a36Sopenharmony_ci{
17662306a36Sopenharmony_ci	struct tlb_inv_context cxt;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	dsb(ishst);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	/* Switch to requested VMID */
18162306a36Sopenharmony_ci	__tlb_switch_to_guest(mmu, &cxt);
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	__tlbi(vmalls12e1is);
18462306a36Sopenharmony_ci	dsb(ish);
18562306a36Sopenharmony_ci	isb();
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	__tlb_switch_to_host(&cxt);
18862306a36Sopenharmony_ci}
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_civoid __kvm_flush_cpu_context(struct kvm_s2_mmu *mmu)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	struct tlb_inv_context cxt;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	/* Switch to requested VMID */
19562306a36Sopenharmony_ci	__tlb_switch_to_guest(mmu, &cxt);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	__tlbi(vmalle1);
19862306a36Sopenharmony_ci	asm volatile("ic iallu");
19962306a36Sopenharmony_ci	dsb(nsh);
20062306a36Sopenharmony_ci	isb();
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	__tlb_switch_to_host(&cxt);
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_civoid __kvm_flush_vm_context(void)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	dsb(ishst);
20862306a36Sopenharmony_ci	__tlbi(alle1is);
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	/*
21162306a36Sopenharmony_ci	 * VIPT and PIPT caches are not affected by VMID, so no maintenance
21262306a36Sopenharmony_ci	 * is necessary across a VMID rollover.
21362306a36Sopenharmony_ci	 *
21462306a36Sopenharmony_ci	 * VPIPT caches constrain lookup and maintenance to the active VMID,
21562306a36Sopenharmony_ci	 * so we need to invalidate lines with a stale VMID to avoid an ABA
21662306a36Sopenharmony_ci	 * race after multiple rollovers.
21762306a36Sopenharmony_ci	 *
21862306a36Sopenharmony_ci	 */
21962306a36Sopenharmony_ci	if (icache_is_vpipt())
22062306a36Sopenharmony_ci		asm volatile("ic ialluis");
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	dsb(ish);
22362306a36Sopenharmony_ci}
224