Commit 26e013b3 authored by Marc Zyngier's avatar Marc Zyngier
Browse files

Merge branch kvm-arm64/fwb-for-all into kvmarm-master/next



* kvm-arm64/fwb-for-all:
  : .
  : Allow pKVM's host stage-2 mappings to use the Force Write Back version
  : of the memory attributes by using the "pass-through' encoding.
  :
  : This avoids having two separate encodings for S2 on a given platform.
  : .
  KVM: arm64: Simplify PAGE_S2_MEMATTR
  KVM: arm64: Kill KVM_PGTABLE_S2_NOFWB
  KVM: arm64: Switch pKVM host S2 over to KVM_PGTABLE_S2_AS_S1
  KVM: arm64: Add KVM_PGTABLE_S2_AS_S1 flag
  arm64: Add MT_S2{,_FWB}_AS_S1 encodings

Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
parents 183ac2b2 65d00e37
Loading
Loading
Loading
Loading
+3 −4
Original line number Diff line number Diff line
@@ -231,13 +231,12 @@ struct kvm_pgtable_mm_ops {

/**
 * enum kvm_pgtable_stage2_flags - Stage-2 page-table flags.
 * @KVM_PGTABLE_S2_NOFWB:	Don't enforce Normal-WB even if the CPUs have
 *				ARM64_HAS_STAGE2_FWB.
 * @KVM_PGTABLE_S2_IDMAP:	Only use identity mappings.
 * @KVM_PGTABLE_S2_AS_S1:	Final memory attributes are that of Stage-1.
 */
enum kvm_pgtable_stage2_flags {
	KVM_PGTABLE_S2_NOFWB			= BIT(0),
	KVM_PGTABLE_S2_IDMAP			= BIT(1),
	KVM_PGTABLE_S2_IDMAP			= BIT(0),
	KVM_PGTABLE_S2_AS_S1			= BIT(1),
};

/**
+8 −3
Original line number Diff line number Diff line
@@ -175,19 +175,24 @@
#define MT_DEVICE_nGnRE		4

/*
 * Memory types for Stage-2 translation
 * Memory types for Stage-2 translation when HCR_EL2.FWB=0. See R_HMNDG,
 * R_TNHFM, R_GQFSF and I_MCQKW for the details on how these attributes get
 * combined with Stage-1.
 */
#define MT_S2_NORMAL		0xf
#define MT_S2_NORMAL_NC		0x5
#define MT_S2_DEVICE_nGnRE	0x1
#define MT_S2_AS_S1		MT_S2_NORMAL

/*
 * Memory types for Stage-2 translation when ID_AA64MMFR2_EL1.FWB is 0001
 * Stage-2 enforces Normal-WB and Device-nGnRE
 * Memory types for Stage-2 translation when HCR_EL2.FWB=1. Stage-2 enforces
 * Normal-WB and Device-nGnRE, unless we actively say that S1 wins. See
 * R_VRJSW and R_RHWZM for details.
 */
#define MT_S2_FWB_NORMAL	6
#define MT_S2_FWB_NORMAL_NC	5
#define MT_S2_FWB_DEVICE_nGnRE	1
#define MT_S2_FWB_AS_S1		7

#ifdef CONFIG_ARM64_4K_PAGES
#define IOREMAP_MAX_ORDER	(PUD_SHIFT)
+2 −2
Original line number Diff line number Diff line
@@ -109,10 +109,10 @@ static inline bool __pure lpa2_is_enabled(void)
#define PAGE_KERNEL_EXEC	__pgprot(_PAGE_KERNEL_EXEC)
#define PAGE_KERNEL_EXEC_CONT	__pgprot(_PAGE_KERNEL_EXEC_CONT)

#define PAGE_S2_MEMATTR(attr, has_fwb)					\
#define PAGE_S2_MEMATTR(attr)						\
	({								\
		u64 __val;						\
		if (has_fwb)						\
		if (cpus_have_final_cap(ARM64_HAS_STAGE2_FWB))		\
			__val = PTE_S2_MEMATTR(MT_S2_FWB_ ## attr);	\
		else							\
			__val = PTE_S2_MEMATTR(MT_S2_ ## attr);		\
+3 −1
Original line number Diff line number Diff line
@@ -19,7 +19,7 @@
#include <nvhe/mem_protect.h>
#include <nvhe/mm.h>

#define KVM_HOST_S2_FLAGS (KVM_PGTABLE_S2_NOFWB | KVM_PGTABLE_S2_IDMAP)
#define KVM_HOST_S2_FLAGS (KVM_PGTABLE_S2_AS_S1 | KVM_PGTABLE_S2_IDMAP)

struct host_mmu host_mmu;

@@ -324,6 +324,8 @@ int __pkvm_prot_finalize(void)
	params->vttbr = kvm_get_vttbr(mmu);
	params->vtcr = mmu->vtcr;
	params->hcr_el2 |= HCR_VM;
	if (cpus_have_final_cap(ARM64_HAS_STAGE2_FWB))
		params->hcr_el2 |= HCR_FWB;

	/*
	 * The CMO below not only cleans the updated params to the
+14 −12
Original line number Diff line number Diff line
@@ -647,14 +647,6 @@ u64 kvm_get_vtcr(u64 mmfr0, u64 mmfr1, u32 phys_shift)
	return vtcr;
}

static bool stage2_has_fwb(struct kvm_pgtable *pgt)
{
	if (!cpus_have_final_cap(ARM64_HAS_STAGE2_FWB))
		return false;

	return !(pgt->flags & KVM_PGTABLE_S2_NOFWB);
}

void kvm_tlb_flush_vmid_range(struct kvm_s2_mmu *mmu,
				phys_addr_t addr, size_t size)
{
@@ -675,7 +667,17 @@ void kvm_tlb_flush_vmid_range(struct kvm_s2_mmu *mmu,
	}
}

#define KVM_S2_MEMATTR(pgt, attr) PAGE_S2_MEMATTR(attr, stage2_has_fwb(pgt))
#define KVM_S2_MEMATTR(pgt, attr)					\
	({								\
		kvm_pte_t __attr;					\
									\
		if ((pgt)->flags & KVM_PGTABLE_S2_AS_S1)		\
			__attr = PAGE_S2_MEMATTR(AS_S1);		\
		else							\
			__attr = PAGE_S2_MEMATTR(attr);			\
									\
		__attr;							\
	})

static int stage2_set_xn_attr(enum kvm_pgtable_prot prot, kvm_pte_t *attr)
{
@@ -884,7 +886,7 @@ static bool stage2_unmap_defer_tlb_flush(struct kvm_pgtable *pgt)
	 * system supporting FWB as the optimization is entirely
	 * pointless when the unmap walker needs to perform CMOs.
	 */
	return system_supports_tlb_range() && stage2_has_fwb(pgt);
	return system_supports_tlb_range() && cpus_have_final_cap(ARM64_HAS_STAGE2_FWB);
}

static void stage2_unmap_put_pte(const struct kvm_pgtable_visit_ctx *ctx,
@@ -1164,7 +1166,7 @@ static int stage2_unmap_walker(const struct kvm_pgtable_visit_ctx *ctx,
		if (mm_ops->page_count(childp) != 1)
			return 0;
	} else if (stage2_pte_cacheable(pgt, ctx->old)) {
		need_flush = !stage2_has_fwb(pgt);
		need_flush = !cpus_have_final_cap(ARM64_HAS_STAGE2_FWB);
	}

	/*
@@ -1395,7 +1397,7 @@ int kvm_pgtable_stage2_flush(struct kvm_pgtable *pgt, u64 addr, u64 size)
		.arg	= pgt,
	};

	if (stage2_has_fwb(pgt))
	if (cpus_have_final_cap(ARM64_HAS_STAGE2_FWB))
		return 0;

	return kvm_pgtable_walk(pgt, addr, size, &walker);