Commit fe4d9e4a authored by Paolo Bonzini's avatar Paolo Bonzini
Browse files
KVM/arm64 updates for v6.1

- Fixes for single-stepping in the presence of an async
  exception as well as the preservation of PSTATE.SS

- Better handling of AArch32 ID registers on AArch64-only
  systems

- Fixes for the dirty-ring API, allowing it to work on
  architectures with relaxed memory ordering

- Advertise the new kvmarm mailing list

- Various minor cleanups and spelling fixes
parents e779ce9d b302ca52
Loading
Loading
Loading
Loading
+15 −2
Original line number Diff line number Diff line
@@ -7918,8 +7918,8 @@ guest according to the bits in the KVM_CPUID_FEATURES CPUID leaf
(0x40000001). Otherwise, a guest may use the paravirtual features
regardless of what has actually been exposed through the CPUID leaf.

8.29 KVM_CAP_DIRTY_LOG_RING
---------------------------
8.29 KVM_CAP_DIRTY_LOG_RING/KVM_CAP_DIRTY_LOG_RING_ACQ_REL
----------------------------------------------------------

:Architectures: x86
:Parameters: args[0] - size of the dirty log ring
@@ -7977,6 +7977,11 @@ on to the next GFN. The userspace should continue to do this until the
flags of a GFN have the DIRTY bit cleared, meaning that it has harvested
all the dirty GFNs that were available.

Note that on weakly ordered architectures, userspace accesses to the
ring buffer (and more specifically the 'flags' field) must be ordered,
using load-acquire/store-release accessors when available, or any
other memory barrier that will ensure this ordering.

It's not necessary for userspace to harvest the all dirty GFNs at once.
However it must collect the dirty GFNs in sequence, i.e., the userspace
program cannot skip one dirty GFN to collect the one next to it.
@@ -8005,6 +8010,14 @@ KVM_CAP_DIRTY_LOG_RING with an acceptable dirty ring size, the virtual
machine will switch to ring-buffer dirty page tracking and further
KVM_GET_DIRTY_LOG or KVM_CLEAR_DIRTY_LOG ioctls will fail.

NOTE: KVM_CAP_DIRTY_LOG_RING_ACQ_REL is the only capability that
should be exposed by weakly ordered architecture, in order to indicate
the additional memory ordering requirements imposed on userspace when
reading the state of an entry and mutating it from DIRTY to HARVESTED.
Architecture with TSO-like ordering (such as x86) are allowed to
expose both KVM_CAP_DIRTY_LOG_RING and KVM_CAP_DIRTY_LOG_RING_ACQ_REL
to userspace.

8.30 KVM_CAP_XEN_HVM
--------------------

+2 −1
Original line number Diff line number Diff line
@@ -11125,7 +11125,8 @@ R: Alexandru Elisei <alexandru.elisei@arm.com>
R:	Suzuki K Poulose <suzuki.poulose@arm.com>
R:	Oliver Upton <oliver.upton@linux.dev>
L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
L:	kvmarm@lists.cs.columbia.edu (moderated for non-subscribers)
L:	kvmarm@lists.linux.dev
L:	kvmarm@lists.cs.columbia.edu (deprecated, moderated for non-subscribers)
S:	Maintained
T:	git git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git
F:	arch/arm64/include/asm/kvm*
+5 −5
Original line number Diff line number Diff line
@@ -384,8 +384,8 @@ alternative_cb_end
	.macro	tcr_compute_pa_size, tcr, pos, tmp0, tmp1
	mrs	\tmp0, ID_AA64MMFR0_EL1
	// Narrow PARange to fit the PS field in TCR_ELx
	ubfx	\tmp0, \tmp0, #ID_AA64MMFR0_PARANGE_SHIFT, #3
	mov	\tmp1, #ID_AA64MMFR0_PARANGE_MAX
	ubfx	\tmp0, \tmp0, #ID_AA64MMFR0_EL1_PARANGE_SHIFT, #3
	mov	\tmp1, #ID_AA64MMFR0_EL1_PARANGE_MAX
	cmp	\tmp0, \tmp1
	csel	\tmp0, \tmp1, \tmp0, hi
	bfi	\tcr, \tmp0, \pos, #3
@@ -512,7 +512,7 @@ alternative_endif
 */
	.macro	reset_pmuserenr_el0, tmpreg
	mrs	\tmpreg, id_aa64dfr0_el1
	sbfx	\tmpreg, \tmpreg, #ID_AA64DFR0_PMUVER_SHIFT, #4
	sbfx	\tmpreg, \tmpreg, #ID_AA64DFR0_EL1_PMUVer_SHIFT, #4
	cmp	\tmpreg, #1			// Skip if no PMU present
	b.lt	9000f
	msr	pmuserenr_el0, xzr		// Disable PMU access from EL0
@@ -524,7 +524,7 @@ alternative_endif
 */
	.macro	reset_amuserenr_el0, tmpreg
	mrs	\tmpreg, id_aa64pfr0_el1	// Check ID_AA64PFR0_EL1
	ubfx	\tmpreg, \tmpreg, #ID_AA64PFR0_AMU_SHIFT, #4
	ubfx	\tmpreg, \tmpreg, #ID_AA64PFR0_EL1_AMU_SHIFT, #4
	cbz	\tmpreg, .Lskip_\@		// Skip if no AMU present
	msr_s	SYS_AMUSERENR_EL0, xzr		// Disable AMU access from EL0
.Lskip_\@:
@@ -612,7 +612,7 @@ alternative_endif
	.macro	offset_ttbr1, ttbr, tmp
#ifdef CONFIG_ARM64_VA_BITS_52
	mrs_s	\tmp, SYS_ID_AA64MMFR2_EL1
	and	\tmp, \tmp, #(0xf << ID_AA64MMFR2_LVA_SHIFT)
	and	\tmp, \tmp, #(0xf << ID_AA64MMFR2_EL1_VARange_SHIFT)
	cbnz	\tmp, .Lskipoffs_\@
	orr	\ttbr, \ttbr, #TTBR1_BADDR_4852_OFFSET
.Lskipoffs_\@ :
+0 −4
Original line number Diff line number Diff line
@@ -45,10 +45,6 @@ static inline unsigned int arch_slab_minalign(void)
#define arch_slab_minalign() arch_slab_minalign()
#endif

#define CTR_CACHE_MINLINE_MASK	\
	(0xf << CTR_EL0_DMINLINE_SHIFT | \
	 CTR_EL0_IMINLINE_MASK << CTR_EL0_IMINLINE_SHIFT)

#define CTR_L1IP(ctr)		SYS_FIELD_GET(CTR_EL0, L1Ip, ctr)

#define ICACHEF_ALIASING	0
+33 −33
Original line number Diff line number Diff line
@@ -553,7 +553,7 @@ cpuid_feature_cap_perfmon_field(u64 features, int field, u64 cap)
	u64 mask = GENMASK_ULL(field + 3, field);

	/* Treat IMPLEMENTATION DEFINED functionality as unimplemented */
	if (val == ID_AA64DFR0_PMUVER_IMP_DEF)
	if (val == ID_AA64DFR0_EL1_PMUVer_IMP_DEF)
		val = 0;

	if (val > cap) {
@@ -597,43 +597,43 @@ static inline s64 arm64_ftr_value(const struct arm64_ftr_bits *ftrp, u64 val)

static inline bool id_aa64mmfr0_mixed_endian_el0(u64 mmfr0)
{
	return cpuid_feature_extract_unsigned_field(mmfr0, ID_AA64MMFR0_BIGENDEL_SHIFT) == 0x1 ||
		cpuid_feature_extract_unsigned_field(mmfr0, ID_AA64MMFR0_BIGENDEL0_SHIFT) == 0x1;
	return cpuid_feature_extract_unsigned_field(mmfr0, ID_AA64MMFR0_EL1_BIGEND_SHIFT) == 0x1 ||
		cpuid_feature_extract_unsigned_field(mmfr0, ID_AA64MMFR0_EL1_BIGENDEL0_SHIFT) == 0x1;
}

static inline bool id_aa64pfr0_32bit_el1(u64 pfr0)
{
	u32 val = cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_EL1_SHIFT);
	u32 val = cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_EL1_EL1_SHIFT);

	return val == ID_AA64PFR0_ELx_32BIT_64BIT;
	return val == ID_AA64PFR0_EL1_ELx_32BIT_64BIT;
}

static inline bool id_aa64pfr0_32bit_el0(u64 pfr0)
{
	u32 val = cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_EL0_SHIFT);
	u32 val = cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_EL1_EL0_SHIFT);

	return val == ID_AA64PFR0_ELx_32BIT_64BIT;
	return val == ID_AA64PFR0_EL1_ELx_32BIT_64BIT;
}

static inline bool id_aa64pfr0_sve(u64 pfr0)
{
	u32 val = cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_SVE_SHIFT);
	u32 val = cpuid_feature_extract_unsigned_field(pfr0, ID_AA64PFR0_EL1_SVE_SHIFT);

	return val > 0;
}

static inline bool id_aa64pfr1_sme(u64 pfr1)
{
	u32 val = cpuid_feature_extract_unsigned_field(pfr1, ID_AA64PFR1_SME_SHIFT);
	u32 val = cpuid_feature_extract_unsigned_field(pfr1, ID_AA64PFR1_EL1_SME_SHIFT);

	return val > 0;
}

static inline bool id_aa64pfr1_mte(u64 pfr1)
{
	u32 val = cpuid_feature_extract_unsigned_field(pfr1, ID_AA64PFR1_MTE_SHIFT);
	u32 val = cpuid_feature_extract_unsigned_field(pfr1, ID_AA64PFR1_EL1_MTE_SHIFT);

	return val >= ID_AA64PFR1_MTE;
	return val >= ID_AA64PFR1_EL1_MTE_MTE2;
}

void __init setup_cpu_features(void);
@@ -659,7 +659,7 @@ static inline bool supports_csv2p3(int scope)
		pfr0 = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);

	csv2_val = cpuid_feature_extract_unsigned_field(pfr0,
							ID_AA64PFR0_CSV2_SHIFT);
							ID_AA64PFR0_EL1_CSV2_SHIFT);
	return csv2_val == 3;
}

@@ -694,10 +694,10 @@ static inline bool system_supports_4kb_granule(void)

	mmfr0 =	read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
	val = cpuid_feature_extract_unsigned_field(mmfr0,
						ID_AA64MMFR0_TGRAN4_SHIFT);
						ID_AA64MMFR0_EL1_TGRAN4_SHIFT);

	return (val >= ID_AA64MMFR0_TGRAN4_SUPPORTED_MIN) &&
	       (val <= ID_AA64MMFR0_TGRAN4_SUPPORTED_MAX);
	return (val >= ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MIN) &&
	       (val <= ID_AA64MMFR0_EL1_TGRAN4_SUPPORTED_MAX);
}

static inline bool system_supports_64kb_granule(void)
@@ -707,10 +707,10 @@ static inline bool system_supports_64kb_granule(void)

	mmfr0 =	read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
	val = cpuid_feature_extract_unsigned_field(mmfr0,
						ID_AA64MMFR0_TGRAN64_SHIFT);
						ID_AA64MMFR0_EL1_TGRAN64_SHIFT);

	return (val >= ID_AA64MMFR0_TGRAN64_SUPPORTED_MIN) &&
	       (val <= ID_AA64MMFR0_TGRAN64_SUPPORTED_MAX);
	return (val >= ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED_MIN) &&
	       (val <= ID_AA64MMFR0_EL1_TGRAN64_SUPPORTED_MAX);
}

static inline bool system_supports_16kb_granule(void)
@@ -720,10 +720,10 @@ static inline bool system_supports_16kb_granule(void)

	mmfr0 =	read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
	val = cpuid_feature_extract_unsigned_field(mmfr0,
						ID_AA64MMFR0_TGRAN16_SHIFT);
						ID_AA64MMFR0_EL1_TGRAN16_SHIFT);

	return (val >= ID_AA64MMFR0_TGRAN16_SUPPORTED_MIN) &&
	       (val <= ID_AA64MMFR0_TGRAN16_SUPPORTED_MAX);
	return (val >= ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MIN) &&
	       (val <= ID_AA64MMFR0_EL1_TGRAN16_SUPPORTED_MAX);
}

static inline bool system_supports_mixed_endian_el0(void)
@@ -738,7 +738,7 @@ static inline bool system_supports_mixed_endian(void)

	mmfr0 =	read_sanitised_ftr_reg(SYS_ID_AA64MMFR0_EL1);
	val = cpuid_feature_extract_unsigned_field(mmfr0,
						ID_AA64MMFR0_BIGENDEL_SHIFT);
						ID_AA64MMFR0_EL1_BIGEND_SHIFT);

	return val == 0x1;
}
@@ -840,13 +840,13 @@ extern int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt);
static inline u32 id_aa64mmfr0_parange_to_phys_shift(int parange)
{
	switch (parange) {
	case ID_AA64MMFR0_PARANGE_32: return 32;
	case ID_AA64MMFR0_PARANGE_36: return 36;
	case ID_AA64MMFR0_PARANGE_40: return 40;
	case ID_AA64MMFR0_PARANGE_42: return 42;
	case ID_AA64MMFR0_PARANGE_44: return 44;
	case ID_AA64MMFR0_PARANGE_48: return 48;
	case ID_AA64MMFR0_PARANGE_52: return 52;
	case ID_AA64MMFR0_EL1_PARANGE_32: return 32;
	case ID_AA64MMFR0_EL1_PARANGE_36: return 36;
	case ID_AA64MMFR0_EL1_PARANGE_40: return 40;
	case ID_AA64MMFR0_EL1_PARANGE_42: return 42;
	case ID_AA64MMFR0_EL1_PARANGE_44: return 44;
	case ID_AA64MMFR0_EL1_PARANGE_48: return 48;
	case ID_AA64MMFR0_EL1_PARANGE_52: return 52;
	/*
	 * A future PE could use a value unknown to the kernel.
	 * However, by the "D10.1.4 Principles of the ID scheme
@@ -868,14 +868,14 @@ static inline bool cpu_has_hw_af(void)

	mmfr1 = read_cpuid(ID_AA64MMFR1_EL1);
	return cpuid_feature_extract_unsigned_field(mmfr1,
						ID_AA64MMFR1_HADBS_SHIFT);
						ID_AA64MMFR1_EL1_HAFDBS_SHIFT);
}

static inline bool cpu_has_pan(void)
{
	u64 mmfr1 = read_cpuid(ID_AA64MMFR1_EL1);
	return cpuid_feature_extract_unsigned_field(mmfr1,
						    ID_AA64MMFR1_PAN_SHIFT);
						    ID_AA64MMFR1_EL1_PAN_SHIFT);
}

#ifdef CONFIG_ARM64_AMU_EXTN
@@ -896,8 +896,8 @@ static inline unsigned int get_vmid_bits(u64 mmfr1)
	int vmid_bits;

	vmid_bits = cpuid_feature_extract_unsigned_field(mmfr1,
						ID_AA64MMFR1_VMIDBITS_SHIFT);
	if (vmid_bits == ID_AA64MMFR1_VMIDBITS_16)
						ID_AA64MMFR1_EL1_VMIDBits_SHIFT);
	if (vmid_bits == ID_AA64MMFR1_EL1_VMIDBits_16)
		return 16;

	/*
Loading